Directory: | ./ |
---|---|
File: | src/PMultiThreadProgress.cpp |
Date: | 2025-05-16 18:34:22 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 92 | 116 | 79.3% |
Branches: | 36 | 75 | 48.0% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /*************************************** | ||
2 | Auteur : Pierre Aubert | ||
3 | Mail : pierre.aubert@lapp.in2p3.fr | ||
4 | Licence : CeCILL-C | ||
5 | ****************************************/ | ||
6 | |||
7 | #include <sys/ioctl.h> | ||
8 | #include <sstream> | ||
9 | #include <iostream> | ||
10 | |||
11 | #include "PMultiThreadProgress.h" | ||
12 | |||
13 | ///Print the parallel progression of the computing | ||
14 | /** @param progress : PMultiThreadProgress which print all progress bars | ||
15 | * @param refreshSecond : number of second between two refresh of the progress bars | ||
16 | */ | ||
17 | 3 | void phoenix_print_parallel_progress(PMultiThreadProgress & progress, int refreshSecond){ | |
18 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
|
9 | while(!progress.isFinished()){ //While computation is ongoing |
19 | 6 | progress.print(); | |
20 |
1/1✓ Branch 2 taken 6 times.
|
6 | std::this_thread::sleep_for(std::chrono::seconds(refreshSecond)); //We check status of computation each second |
21 | } | ||
22 | 3 | progress.printSummary(); | |
23 | 3 | std::cout << "PMultiThreadProgress : Done" << std::endl; | |
24 | 3 | } | |
25 | |||
26 | ///Default constructor of PMultiThreadProgress | ||
27 | /** @param nbExpectedProgressBar : number of expected progress bars | ||
28 | */ | ||
29 | 4 | PMultiThreadProgress::PMultiThreadProgress(size_t nbExpectedProgressBar){ | |
30 |
1/1✓ Branch 1 taken 4 times.
|
4 | initialisationPMultiThreadProgress(nbExpectedProgressBar); |
31 | 4 | } | |
32 | |||
33 | ///Copy constructor of PMultiThreadProgress | ||
34 | /** @param other : class to copy | ||
35 | */ | ||
36 | 1 | PMultiThreadProgress::PMultiThreadProgress(const PMultiThreadProgress & other){ | |
37 |
1/1✓ Branch 1 taken 1 times.
|
1 | copyPMultiThreadProgress(other); |
38 | 1 | } | |
39 | |||
40 | ///Destructor of PMultiThreadProgress | ||
41 | 10 | PMultiThreadProgress::~PMultiThreadProgress(){ | |
42 | |||
43 | } | ||
44 | |||
45 | ///Definition of equal operator of PMultiThreadProgress | ||
46 | /** @param other : class to copy | ||
47 | * @return copied class | ||
48 | */ | ||
49 | 1 | PMultiThreadProgress & PMultiThreadProgress::operator = (const PMultiThreadProgress & other){ | |
50 | 1 | copyPMultiThreadProgress(other); | |
51 | 1 | return *this; | |
52 | } | ||
53 | |||
54 | ///Set the number of expected progress bars in the PMultiThreadProgress | ||
55 | /** @param nbExpectedProgressBar : number of expected progress bars | ||
56 | */ | ||
57 | 2 | void PMultiThreadProgress::setNbExpectedProgressBar(size_t nbExpectedProgressBar){ | |
58 | 2 | p_nbExpectedProgressBar = nbExpectedProgressBar; | |
59 | 2 | } | |
60 | |||
61 | ///Add a progress line | ||
62 | /** @param name : name of the progress line | ||
63 | * @param progressMax : maximum of progression bar | ||
64 | * @return index of the created progress line | ||
65 | */ | ||
66 | 6 | size_t PMultiThreadProgress::addProgressBar(const PString & name, int progressMax){ | |
67 |
1/1✓ Branch 1 taken 6 times.
|
6 | std::lock_guard<std::mutex> guard(p_currentMutex); |
68 | 6 | size_t index = p_vecProgressElement.size(); | |
69 |
1/1✓ Branch 1 taken 6 times.
|
6 | ProgressElement el; |
70 | 6 | el.progress = 0; | |
71 | 6 | el.prevProgress = -1; | |
72 | 6 | el.progressMax = progressMax; | |
73 |
1/1✓ Branch 1 taken 6 times.
|
6 | el.name = name; |
74 | 6 | el.isEndError = false; | |
75 |
1/1✓ Branch 1 taken 6 times.
|
6 | p_vecProgressElement.push_back(el); |
76 | 6 | return index; | |
77 | 6 | } | |
78 | |||
79 | ///Increment the progress of the progress bar at index | ||
80 | /** @param index : index of the progress bar to be incremented | ||
81 | */ | ||
82 | 23 | void PMultiThreadProgress::incrementProgress(size_t index){ | |
83 | 23 | p_vecProgressElement[index].progress++; | |
84 | 23 | } | |
85 | |||
86 | ///Mark the progress bar at index finished with an error | ||
87 | /** @param index : index of the progress bar to be modified | ||
88 | */ | ||
89 | ✗ | void PMultiThreadProgress::setError(size_t index){ | |
90 | ✗ | p_vecProgressElement[index].isEndError = true; | |
91 | } | ||
92 | |||
93 | ///Say if the PMultiThreadProgress is finished | ||
94 | /** @return true if the PMultiThreadProgress is finished, false otherwise | ||
95 | */ | ||
96 | 9 | bool PMultiThreadProgress::isFinished() const{ | |
97 |
4/4✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
|
9 | return p_alreadyPrintedLine == p_vecProgressElement.size() && p_vecProgressElement.size() >= p_nbExpectedProgressBar; |
98 | } | ||
99 | |||
100 | ///Print the multithread progress bar | ||
101 | 6 | void PMultiThreadProgress::print(){ | |
102 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
|
6 | if(!isModified()){return;} //No need to print |
103 | 3 | size_t nbColTerminal = getNbColTerminal(); | |
104 | //Clear all the progress bars on screen | ||
105 | 3 | eraseProgressBar(nbColTerminal); | |
106 | //Check if we can print first finshed lines definitely | ||
107 | 3 | printAllFinshedProgressBar(); | |
108 | //Update the rest of the progress bars to print | ||
109 | 3 | printProgressBar(nbColTerminal); | |
110 | //We save the previous number of progress bars, in case we print some and add other later | ||
111 | 3 | p_previousNbProgressBar = p_vecProgressElement.size(); | |
112 | } | ||
113 | |||
114 | ///Print a summary of all the progress bars | ||
115 | 3 | void PMultiThreadProgress::printSummary() const{ | |
116 | 3 | size_t nbFail(0lu); | |
117 |
2/2✓ Branch 3 taken 6 times.
✓ Branch 4 taken 3 times.
|
9 | for(VecProgressElement::const_iterator it(p_vecProgressElement.begin()); it != p_vecProgressElement.end(); ++it){ |
118 | 6 | nbFail += it->isEndError; | |
119 | } | ||
120 | 3 | size_t nbSuccess(p_vecProgressElement.size() - nbFail); | |
121 | 3 | std::cout << "PMultiThreadProgress : " << p_vecProgressElement.size() << " computations, " << nbSuccess << " success, " << nbFail << " fail" << std::endl; | |
122 | 3 | } | |
123 | |||
124 | ///Copy function of PMultiThreadProgress | ||
125 | /** @param other : class to copy | ||
126 | */ | ||
127 | 2 | void PMultiThreadProgress::copyPMultiThreadProgress(const PMultiThreadProgress & other){ | |
128 | 2 | p_vecProgressElement = other.p_vecProgressElement; | |
129 | 2 | p_alreadyPrintedLine = other.p_alreadyPrintedLine; | |
130 | 2 | p_nbExpectedProgressBar = other.p_nbExpectedProgressBar; | |
131 | 2 | } | |
132 | |||
133 | ///Initialisation function of the class PMultiThreadProgress | ||
134 | /** @param nbExpectedProgressBar : number of expected progress bars | ||
135 | */ | ||
136 | 4 | void PMultiThreadProgress::initialisationPMultiThreadProgress(size_t nbExpectedProgressBar){ | |
137 | 4 | p_alreadyPrintedLine = 0lu; | |
138 | 4 | p_previousNbProgressBar = 0lu; | |
139 | 4 | p_nbExpectedProgressBar = nbExpectedProgressBar; | |
140 | 4 | p_vecProgressElement.reserve(nbExpectedProgressBar); | |
141 | 4 | } | |
142 | |||
143 | ///Check if the PMultiThreadProgress has been modified | ||
144 | /** @return true if the PMultiThreadProgress has been modified, false otherwise | ||
145 | */ | ||
146 | 6 | bool PMultiThreadProgress::isModified(){ | |
147 |
1/1✓ Branch 1 taken 6 times.
|
6 | std::lock_guard<std::mutex> guard(p_currentMutex); |
148 | 6 | bool isModif(false); | |
149 | 6 | size_t i(p_alreadyPrintedLine); | |
150 |
6/6✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 6 times.
|
9 | while(!isModif && i < p_vecProgressElement.size()){ |
151 | 3 | ProgressElement & el = p_vecProgressElement[i]; | |
152 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | isModif = el.progress != el.prevProgress || el.isEndError; |
153 | 3 | ++i; | |
154 | } | ||
155 | 6 | return isModif; | |
156 | 6 | } | |
157 | |||
158 | ///Erase all progress bars | ||
159 | /** @param nbColTerminal : number of columns in the current terminal | ||
160 | */ | ||
161 | 3 | void PMultiThreadProgress::eraseProgressBar(size_t nbColTerminal){ | |
162 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if(p_previousNbProgressBar == 0lu){return;} |
163 | //Advances method but can't write anyting | ||
164 | ✗ | std::cerr << "\33[2K\r"; //Remove a line where the cursor is | |
165 | ✗ | for(size_t i(p_alreadyPrintedLine + 1u); i < p_previousNbProgressBar; ++i){ | |
166 | ✗ | std::cerr << "\033[A"; //Go to one line up | |
167 | ✗ | std::cerr << "\33[2K\r"; //Remove a line where the cursor is | |
168 | } | ||
169 | } | ||
170 | |||
171 | ///Print all progress bars | ||
172 | /** @param nbColTerminal : number of columns in the current terminal | ||
173 | */ | ||
174 | 3 | void PMultiThreadProgress::printProgressBar(size_t nbColTerminal){ | |
175 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | for(size_t i(p_alreadyPrintedLine); i < p_vecProgressElement.size(); ++i){ |
176 | ✗ | ProgressElement & el = p_vecProgressElement[i]; | |
177 | ✗ | std::cerr << el.name << " : "; | |
178 | ✗ | if(el.progress >= el.progressMax || el.isEndError){ //This is a finished progress bar but not finaly drawed | |
179 | ✗ | if(el.isEndError){ | |
180 | ✗ | std::cerr << "\033[31mError\033[0m"; | |
181 | ✗ | for(size_t j(el.name.size() + 8lu); j < nbColTerminal; ++j){ | |
182 | ✗ | std::cerr << " "; | |
183 | } | ||
184 | }else{ | ||
185 | ✗ | std::cerr << "\033[32mDone\033[0m"; | |
186 | ✗ | for(size_t j(el.name.size() + 7lu); j < nbColTerminal; ++j){ | |
187 | ✗ | std::cerr << " "; | |
188 | } | ||
189 | } | ||
190 | }else{ | ||
191 | ✗ | int avencement = (100*el.progress)/el.progressMax; | |
192 | ✗ | std::stringstream strAvencement; | |
193 | ✗ | strAvencement << avencement; | |
194 | ✗ | std::cerr << avencement << "%"; | |
195 | ✗ | for(size_t j(el.name.size() + 4lu + strAvencement.str().size()); j < nbColTerminal; ++j){ | |
196 | ✗ | std::cerr << " "; | |
197 | } | ||
198 | ✗ | el.prevProgress = el.progress; //Update previous progress | |
199 | } | ||
200 | } | ||
201 | 3 | } | |
202 | |||
203 | ///Print all finished progress bars | ||
204 | 3 | void PMultiThreadProgress::printAllFinshedProgressBar(){ | |
205 |
1/1✓ Branch 1 taken 3 times.
|
3 | std::lock_guard<std::mutex> guard(p_currentMutex); |
206 | 3 | size_t i(p_alreadyPrintedLine); | |
207 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
|
9 | while(i < p_vecProgressElement.size()){ |
208 | 6 | ProgressElement & el = p_vecProgressElement[i]; | |
209 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
6 | if(el.progress >= el.progressMax || el.isEndError){ //This is a finished progress bar |
210 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
|
6 | std::cout << el.name << " : "; |
211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(el.isEndError){ |
212 | ✗ | std::cout << "\033[31mError\033[0m" << std::endl; | |
213 | }else{ | ||
214 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
|
6 | std::cout << "\033[32mDone\033[0m" << std::endl; |
215 | } | ||
216 | 6 | ++p_alreadyPrintedLine; | |
217 | }else{ | ||
218 | break; | ||
219 | } | ||
220 | 6 | ++i; | |
221 | } | ||
222 | 3 | } | |
223 | |||
224 | ///Get the number of columns in the current terminal | ||
225 | /** @return number of columns in the current terminal | ||
226 | */ | ||
227 | 3 | size_t PMultiThreadProgress::getNbColTerminal() const{ | |
228 | struct winsize w; | ||
229 | 3 | ioctl(0, TIOCGWINSZ, &w); | |
230 | 3 | return w.ws_col; | |
231 | } | ||
232 | |||
233 | |||
234 |