Ver código fonte

Updated main-race.c

Lorenz Bung 7 anos atrás
pai
commit
e5983f825c

+ 68
- 0
hw8/simu1/ANSWERS.md Ver arquivo

@@ -0,0 +1,68 @@
1
+# hw8 - Simulation 1 - Antworten
2
+
3
+1. Helgrind markiert die richtigen Stellen im Code:
4
+    ```text
5
+    ==1930== Possible data race during write of size 4 at 0x60207C by thread #1
6
+    ==1930== Locks held: none
7
+    ==1930==    at 0x400C9A: main (main-race.c:15)
8
+    ==1930==
9
+    ==1930== This conflicts with a previous write of size 4 by thread #2
10
+    ==1930== Locks held: none
11
+    ==1930==    at 0x400C5A: worker (main-race.c:8)
12
+    ```
13
+    Weiterhin erhält man die Information über den Lock (hier `none`), die Art des Problems (`Possible data race`) und die Größe der Daten, die geschrieben werden.
14
+
15
+2. Codekorrektur
16
+
17
+    1. Wenn ich eine der Zeilen lösche (bzw. auskommentiere), meldet helgrind keinen Fehler mehr (auch nicht für die zweite betreffende Zeile).
18
+
19
+    2. Wenn man nur bei einer Variable den Lock setzt, erkennt helgrind den Fehler:
20
+        ```text
21
+        ==18432== Possible data race during write of size 4 at 0x602084 by thread #1
22
+        ==18432== Locks held: none
23
+        ==18432==    at 0x400CB2: main (main-race.c:18)
24
+        ==18432==
25
+        ==18432== This conflicts with a previous write of size 4 by thread #2
26
+        ==18432== Locks held: 1, at address 0x6020A0
27
+        ==18432==    at 0x400C68: worker (main-race.c:10)
28
+        ```
29
+    3. Wenn man bei beiden Variablen einen Lock setzt, findet helgrind wieder keine Fehler.
30
+
31
+3. Vermutlich ist der Fehler, dass Thread 1 einen Lock auf v1 setzt, Thread 2 einen Lock auf v2, und anschließend warten beide Threads, bis der jeweils andere diesen Lock wieder freigibt. Auf der Labshell läuft das Programm. Dieser Deadlock tritt nur auf, wenn Thread 1 und Thread 2 wirklich absolut parallel laufen.
32
+
33
+4. Helgrind gibt mir viele Informationen zur Lockreihenfolge. Es sagt, dass es durch das Festlegen des ersten Locks eine feste Reihenfolge gibt, in der neue Locks gesetzt werden müssen. Zusätzlich bekomme ich die Information, wo die Reihenfolge festgelegt wird und wo sie nicht eingehalten wird.
34
+
35
+5. `main-deadlock-global.c`
36
+
37
+    1. Das Problem der Lockreihenfolge sollte hier nicht auftreten, da im Worker ein globaler Lock gesetzt wird. Dieser blockiert während dem kritischen Bereich einfach alle anderen Threads.
38
+
39
+    2. Beim Ausführen des Programms treten keine Fehler auf.
40
+
41
+    3. helgrind sollte eigentlich keinen Fehler melden, da der globale Lock einen Deadlock verhindert.
42
+
43
+    4. Da helgrind den Fehler dennoch erkennt, ist es ein sehr nützliches Werkzeug um Lockfehler zu erkennen.
44
+
45
+6. Dieser Code ist sehr ineffizient, da der Parent-Thread durch seine while-Schleife die CPU zu 100% auslastet und somit zum einen sehr viel Strom verbraucht und zum anderen die anderen Threads ihrer Rechenzeit "beraubt". Dies ist besonders auffällig, wenn das Child sehr lange benötigt.
46
+
47
+7.
48
+
49
+    1. helgrind meldet einen Data-Race-Fehler in der Variable `done`:
50
+        ```text
51
+        ==1064== Possible data race during read of size 4 at 0x602084 by thread #1
52
+        ==1064== Locks held: none
53
+        ==1064==    at 0x400CEB: main (main-signal.c:16)
54
+        ==1064==
55
+        ==1064== This conflicts with a previous write of size 4 by thread #2
56
+        ==1064== Locks held: none
57
+        ```
58
+        Dieser Fehler wird gemeldet, da der Kindthread in `done` eine 1 schreibt, sobald er fertig ist, im Elternthread jedoch eine while-Schleife mit dieser Variable läuft.
59
+
60
+    2. Trotz der Meldung von helgrind ist der Code korrekt, da im Elternthread die Variable `done` nie geschrieben wird, sondern nur gelesen wird. "Verpasst" die while-Schleife die Änderung in `done`, so spielt das keine Rolle und die Schleife läuft einfach noch ein letztes Mal durch.
61
+
62
+8. `main-signal-cv.c`
63
+
64
+    1. Diese Version ist besser als die alte, da der Elternthread nicht mehr die CPU blockiert, während der Kindthread noch nicht fertig ist, sondern auf das Signal des Kinds wartet.
65
+
66
+    2. Da der alte Code korrekt ist, spielt nur die Effizienz des Codes eine Rolle. Natürlich ist die hier angegebene Lösung außerdem deutlich eleganter.
67
+
68
+9. helgrind meldet keine Fehler bei der korrigierten Version. Dies liegt daran, dass nun ein Lock um die Variable `done` gesetzt wird, wenn diese geschrieben wird.

+ 1
- 1
hw8/simu1/main-race.c Ver arquivo

@@ -7,7 +7,7 @@ pthread_mutex_t mut;
7 7
 
8 8
 void* worker(void* arg) {
9 9
     pthread_mutex_lock(&mut);
10
-    balance++; // unprotected access
10
+    balance++; // protected access
11 11
     pthread_mutex_unlock(&mut);
12 12
     return NULL;
13 13
 }

+ 4
- 0
hw8/task1/Cargo.toml Ver arquivo

@@ -4,3 +4,7 @@ version = "0.1.0"
4 4
 authors = ["Joshua Rutschmann <joshua.rutschmann@gmx.de>"]
5 5
 
6 6
 [dependencies]
7
+sha2 = "0.7.0"
8
+clap = {version = "~2.29.0", features = ["yaml"]}
9
+time = "0.1"
10
+sys-info = "*"

+ 2
- 2
hw8/task1/README.md Ver arquivo

@@ -117,7 +117,7 @@ Please wait ...
117 117
 Number: 567621 --> hash: b6bea2a40ed1bd6d9999b2232072092f3df0e02c4b507aa3ad947367b9712345
118 118
 ```
119 119
 
120
-Benutzen Sie für die Systeminformationen die externe [Crate sys-info](<>).
120
+Benutzen Sie für die Systeminformationen die externe [Crate sys-info][].
121 121
 
122 122
 ### Suchen mit mehreren Threads
123 123
 
@@ -130,7 +130,7 @@ Consumer" Lösung an. Viele Producer suchen nach dem Hash. Die zu untersuchende
130 130
 'Menge' an Zahlen muss dazu geeignet auf alle Threads verteilt werden. Der
131 131
 Producer, der ihn findet, sendet den Hash an den Consumer.  
132 132
 
133
-Die Rust Standardbibliothek bietet dafür die [MPSC]() Synchronisationsprimitive
133
+Die Rust Standardbibliothek bietet dafür die [MPSC][] Synchronisationsprimitive
134 134
 an. Einen ähnlichen Mechanismus haben Sie bereits mit der Pipe kennengelernt. 
135 135
 
136 136
 Findet einer der Producer das Ergebnis, so sendet er dies an den Consumer. Der

+ 50
- 0
hw8/task1/src/cli.yml Ver arquivo

@@ -0,0 +1,50 @@
1
+name: "task1"
2
+args:
3
+    - base:
4
+        value_name: "base"
5
+        help: "Sets the base to use"
6
+        takes_value: true
7
+        required: true
8
+
9
+    - difficulty:
10
+        value_name: "difficulty"
11
+        help: "Sets the difficulty to use"
12
+        takes_value: true
13
+        required: true
14
+         
15
+    - threads:
16
+        value_name: "threads"
17
+        help: "Sets the number of the threads to use (default = number of cpus)"
18
+        takes_value: true
19
+        required: false
20
+
21
+    - verbose:
22
+        short: "v"
23
+        help: "Prints help information"
24
+        multiple: true
25
+        required: false
26
+             
27
+    - sync:
28
+        short: "s"
29
+        long: "sync"
30
+        help: "enables sync when solution found"
31
+        required: false
32
+
33
+    - wait:
34
+        short: "w"
35
+        long: "wait"
36
+        help: "consumer waits for all producers"
37
+        required: false
38
+
39
+    - special:
40
+        long: "special"
41
+        value_name: "VALUE"
42
+        help: "sets special sync parameter"
43
+        takes_value: true
44
+
45
+subcommands:
46
+    - timings:
47
+        about: "controls timing features"
48
+        version: "1.0"
49
+        author: "Lorenz Bung & Joshua Rutschmann"
50
+

+ 116
- 5
hw8/task1/src/lib.rs Ver arquivo

@@ -1,7 +1,118 @@
1
-#[cfg(test)]
2
-mod tests {
3
-    #[test]
4
-    fn it_works() {
5
-        assert_eq!(2 + 2, 4);
1
+extern crate sha2;
2
+#[cfg(feature = "SHA2")]
3
+use self::sha2::Sha256;
4
+
5
+
6
+pub struct Sha256;
7
+
8
+pub trait Hasher {
9
+    type Output: HashResult;
10
+    fn hash(input: &[u8]) -> Self::Output;
11
+}
12
+
13
+pub trait HashResult {
14
+    /// Get the output in hex notation.
15
+    fn hex(&self) -> String;
16
+    /// Size of the output in bytes.
17
+    fn size() -> usize;
18
+}
19
+
20
+
21
+impl Hasher for Sha256 {
22
+    type Output = [u8; 32];
23
+
24
+    fn hash(input: &[u8]) -> Self::Output {
25
+        use self::sha2::*;
26
+        let mut tmp = Sha256::new();
27
+        tmp.input(input);
28
+        let r = tmp.result().as_slice().to_vec();
29
+        [
30
+            r[0],
31
+            r[1],
32
+            r[2],
33
+            r[3],
34
+            r[4],
35
+            r[5],
36
+            r[6],
37
+            r[7],
38
+            r[8],
39
+            r[9],
40
+            r[10],
41
+            r[11],
42
+            r[12],
43
+            r[13],
44
+            r[14],
45
+            r[15],
46
+            r[16],
47
+            r[17],
48
+            r[18],
49
+            r[19],
50
+            r[20],
51
+            r[21],
52
+            r[22],
53
+            r[23],
54
+            r[24],
55
+            r[25],
56
+            r[26],
57
+            r[27],
58
+            r[28],
59
+            r[29],
60
+            r[30],
61
+            r[31],
62
+        ]
63
+    }
64
+}
65
+
66
+impl HashResult for [u8; 32] {
67
+    fn hex(&self) -> String {
68
+        const HEX: [char; 16] = [
69
+            '0',
70
+            '1',
71
+            '2',
72
+            '3',
73
+            '4',
74
+            '5',
75
+            '6',
76
+            '7',
77
+            '8',
78
+            '9',
79
+            'a',
80
+            'b',
81
+            'c',
82
+            'd',
83
+            'e',
84
+            'f',
85
+        ];
86
+        let mut tmp = String::with_capacity(32 * 2);
87
+        for byte in self.iter() {
88
+            tmp.push(HEX[*byte as usize / 16]);
89
+            tmp.push(HEX[*byte as usize % 16]);
90
+        }
91
+        tmp
92
+    }
93
+
94
+    fn size() -> usize {
95
+        32
96
+    }
97
+}
98
+
99
+
100
+pub struct Solution {
101
+    pub number: usize,
102
+    pub hash: String,
103
+}
104
+
105
+pub fn verify_product(base: usize, number: usize, difficulty: &String) -> Option<Solution> {
106
+    let sol = base * number;
107
+    let input = sol.to_string();
108
+    let bytes = input.as_bytes();
109
+
110
+    let hash = Sha256::hash(bytes).hex();
111
+
112
+    if hash.ends_with(difficulty) {
113
+        return Some(Solution{ number: number, hash: hash,});
6 114
     }
115
+
116
+    None
7 117
 }
118
+

+ 109
- 0
hw8/task1/src/main.rs Ver arquivo

@@ -0,0 +1,109 @@
1
+#[macro_use]
2
+extern crate clap;
3
+extern crate time;
4
+extern crate task1;
5
+extern crate sys_info;
6
+
7
+use std::sync::mpsc::channel;
8
+use time::get_time;
9
+use clap::App;
10
+use std::{process, thread};
11
+use task1::verify_product;
12
+use std::sync::Arc;
13
+
14
+pub fn main() {
15
+    let yaml = load_yaml!("cli.yml");
16
+    let matches = App::from_yaml(yaml).get_matches();
17
+    let base = matches.value_of("base").unwrap_or("1");
18
+    let diff = Arc::new(matches.value_of("difficulty").unwrap_or("1").to_string());
19
+    let cpus = sys_info::cpu_num().unwrap_or(1).to_string();
20
+    let threads = matches.value_of("threads").unwrap_or(&cpus);
21
+    let sync = matches.is_present("sync");
22
+    let verbosity = matches.occurrences_of("verbose"); 
23
+    
24
+    let mut time_measurement = false;
25
+    let mut found = false;
26
+
27
+    if diff.chars().any(|c| !c.is_digit(16)) {
28
+        println!("Difficulty is not hexadecimal.");
29
+        process::exit(1)
30
+    }
31
+
32
+    if let Some(ref sub_command) = matches.subcommand {
33
+        if sub_command.name.eq("timings") {
34
+            time_measurement = true;
35
+        }
36
+    }
37
+
38
+    if verbosity >= 1 {
39
+        println!("--------------------------------------------");
40
+        println!("Container: \"{}\"", sys_info::hostname().unwrap_or("-".to_string()));
41
+        println!("Physical CPUs : {}", sys_info::cpu_num().unwrap_or(0));
42
+        println!("Logical CPUs  : {}", sys_info::cpu_num().unwrap_or(0));
43
+        println!("CPU Speed     : {}", sys_info::cpu_speed().unwrap_or(0));
44
+        println!("Load Average  : {:?}", sys_info::loadavg().unwrap());
45
+        println!("Processes     : {}", sys_info::proc_total().unwrap_or(0));
46
+        println!("--------------------------------------------");
47
+    }
48
+
49
+    match (base.parse::<usize>(), threads.parse::<usize>()) {
50
+        (Ok(b), Ok(t)) => {
51
+            println!("Please wait...");
52
+
53
+            if verbosity >= 1 {
54
+                println!("Searching with {} threads", t);
55
+            }
56
+
57
+            let start = get_time();
58
+            let max = <usize>::max_value();
59
+            let mut children = vec![];
60
+
61
+            let (tx, rx) = channel();
62
+
63
+            for i in 0..t {
64
+                let d = diff.clone();
65
+                let tx = tx.clone();
66
+
67
+                children.push(thread::spawn(move || {
68
+                    let mut n = i;
69
+                    while n < max {
70
+
71
+                        if found && sync {
72
+                            process::exit(0);
73
+                        }
74
+
75
+                        if let Some(solution) = verify_product(b, n, &d) {
76
+                            found = sync;
77
+                            tx.send(solution).unwrap();
78
+                        }
79
+                        n += t;
80
+                    }
81
+
82
+                }));
83
+            }
84
+
85
+            match rx.recv() {
86
+                Ok(sol) => {
87
+                    let end = get_time();
88
+                    println!("Number: {} --> hash: {}", sol.number, sol.hash);
89
+                    if time_measurement {
90
+                        let diff = end - start;
91
+                        let s = diff.num_seconds();
92
+                        let ms = diff.num_milliseconds();
93
+                        let us = diff.num_microseconds().unwrap_or(ms * 1000);
94
+                        println!("(Duration {}s / {}ms / {}us)", s, ms, us);
95
+                    }
96
+                }
97
+                Err(_) => {}
98
+            }
99
+        }
100
+        (_, Err(_)) => {
101
+            println!("Number of threads is not integer.");
102
+            process::exit(1)
103
+        }
104
+        (Err(_), _) => {
105
+            println!("Base is not integer.");
106
+            process::exit(1)
107
+        }
108
+    };
109
+}

+ 7
- 0
hw8/task1/src/unit_test.rs Ver arquivo

@@ -0,0 +1,7 @@
1
+#[test]
2
+fn test_hash() {
3
+    assert_eq!(
4
+        Sha256::hash("test".as_bytes()).hex(),
5
+        "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
6
+    );
7
+}

Carregando…
Cancelar
Salvar