Hallo,
Om een tool die ik geschreven heb (vector-based image viewer) te laten profiteren van multicore machines, ben ik gestart met het integreren van OpenMP in de code (leek me een makkelijke manier om wat perfomance bij te winnen). Daarbij heb ik momenteel de intensievere routines herschreven op een paralleliseerbare wijze, en dan de OpenMP pragma's geintroduceerd.
Een voorbeeld: de rotate() functie. Die moet adhv een gegeven hoek, alle punten/lijnen/beziers in de datastructuur roteren. Aangezien hierbij geen elementen uit de datastructuur gewist wordt, leek mij dit de een makkelijke methode om bij te beginnen
Eerst heb ik volgens deze paper de std::list met iteratoren wat herschreven, en er voor gekozen om de hele loop te paralleliseren, en de berekening dan in een "single nowait" pragma te laten draaien (toegegeven, oplossing zoals deze zien er een pak interessanter uit, maar ik wil eerst beginnen met OpenMP zonder daarvoor ingrijpende code changes in te moeten voeren).
Uiteindelijk zag de functie er zo uit:
Waarbij de help_rotate functie een inline functie is om mij wat schrijfwerk te besparen:
Allemaal goed en wel, buiten het feit dat m'n programma crasht bij het roteren. Maar het vervelende is dat hij niet altijd crasht: some bij de eerste rotatie, soms moet ik verschillende keren roteren, vroeg of laat heb ik er van. Tweede vervelende feit is dat als ik het geheel onder valgrind draai, hij wijst naar een "unitialised read" in libgomp (onderdeel van OpenMP), maar de backtrace leidt naar het autocrop() commando dat niet eens in een threaded mode draait
Nog vreemder: als ik de autocrop() uitcommentarieer, crasht het geheel minder snel, maar het blijft crashen. Doe ik dit laatste onder valgrind, wordt de het commando voor de autocrop() (die cache boolean op true zette) als schuldige aangewezen... Een fragment van die backtrace:
(regel 233 is die cacheBoundsDirty assignment)
De tweede stap in de backtrace (regel 189) wijst naar die throw(), maar dat kan ik al helemaal niet in het plaatje passen (throw() gecalld door een bool op true te zetten, code die nota-bene niks met elkaar te maken heeft?)...
Kortom, ik snap er weer niks van
Threads introduceren werkt, maar crasht soms, en altijd in de OpenMP library, maar de backtrace leidt naar code die niet onder controle van OpenMP draait...
Alvast bedankt als iemand hier te hulp kan schieten
Om een tool die ik geschreven heb (vector-based image viewer) te laten profiteren van multicore machines, ben ik gestart met het integreren van OpenMP in de code (leek me een makkelijke manier om wat perfomance bij te winnen). Daarbij heb ik momenteel de intensievere routines herschreven op een paralleliseerbare wijze, en dan de OpenMP pragma's geintroduceerd.
Een voorbeeld: de rotate() functie. Die moet adhv een gegeven hoek, alle punten/lijnen/beziers in de datastructuur roteren. Aangezien hierbij geen elementen uit de datastructuur gewist wordt, leek mij dit de een makkelijke methode om bij te beginnen
Uiteindelijk zag de functie er zo uit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| // Rotate all elements list<Element>::iterator it; #pragma omp parallel private(it) { for (it = elements.begin(); it != elements.end(); it++) { #pragma omp single nowait { switch (it->identifier) { // Point case 1: help_rotate(it->parameters[0], it->parameters[1], angle_rad); break; // Polyline case 2: for (unsigned int i = 0; i < it->parameters.size(); i+=2) help_rotate(it->parameters[i], it->parameters[i+1], angle_rad); break; // Polybezier case 3: for (unsigned int i = 0; i < it->parameters.size(); i+=2) help_rotate(it->parameters[i], it->parameters[i+1], angle_rad); break; default: throw Exception("data", "rotate", "unsupported element with ID " + stringify(it->identifier)); } } } // Invalidate caches cacheBoundsDirty = true; // Move the image back to it's original location (TODO: replace with some math) autocrop(); |
Waarbij de help_rotate functie een inline functie is om mij wat schrijfwerk te besparen:
C++:
1
2
3
4
5
6
| inline void help_rotate(double& x, double& y, double angle_rad) { double xc = x; x = x * cos(angle_rad) - y * sin(angle_rad); y = xc * sin(angle_rad) + y* cos(angle_rad); } |
Allemaal goed en wel, buiten het feit dat m'n programma crasht bij het roteren. Maar het vervelende is dat hij niet altijd crasht: some bij de eerste rotatie, soms moet ik verschillende keren roteren, vroeg of laat heb ik er van. Tweede vervelende feit is dat als ik het geheel onder valgrind draai, hij wijst naar een "unitialised read" in libgomp (onderdeel van OpenMP), maar de backtrace leidt naar het autocrop() commando dat niet eens in een threaded mode draait
Nog vreemder: als ik de autocrop() uitcommentarieer, crasht het geheel minder snel, maar het blijft crashen. Doe ik dit laatste onder valgrind, wordt de het commando voor de autocrop() (die cache boolean op true zette) als schuldige aangewezen... Een fragment van die backtrace:
code:
1
2
3
4
5
| ==28158== Use of uninitialised value of size 4 ==28158== at 0x45FC002: (within /usr/lib/libgomp.so.1.0.0) ==28158== by 0x45FB6DA: GOMP_single_start (in /usr/lib/libgomp.so.1.0.0) ==28158== by 0x8068CE2: _ZN4Data6rotateEd.omp_fn.0 (data.cpp:189) ==28158== by 0x806930F: Data::rotate(double) (data.cpp:233) |
(regel 233 is die cacheBoundsDirty assignment)
De tweede stap in de backtrace (regel 189) wijst naar die throw(), maar dat kan ik al helemaal niet in het plaatje passen (throw() gecalld door een bool op true te zetten, code die nota-bene niks met elkaar te maken heeft?)...
Kortom, ik snap er weer niks van
Alvast bedankt als iemand hier te hulp kan schieten