Directory: | ./ |
---|---|
File: | Core/chrono.cpp |
Date: | 2024-04-14 07:32:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 15 | 176 | 8.5% |
Branches: | 6 | 452 | 1.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | // ______ ______ _ _ _____ ______ | ||
2 | // | ____| ____| | (_)/ ____| | ____| | ||
3 | // | |__ | |__ | | _| (___ ___| |__ | ||
4 | // | __| | __| | | | |\___ \ / __| __| | ||
5 | // | | | |____| |____| |____) | (__| |____ | ||
6 | // |_| |______|______|_|_____/ \___|______| | ||
7 | // Finite Elements for Life Sciences and Engineering | ||
8 | // | ||
9 | // License: LGL2.1 License | ||
10 | // FELiScE default license: LICENSE in root folder | ||
11 | // | ||
12 | // Main authors: Vicente Mataix Ferrandiz | ||
13 | // | ||
14 | |||
15 | // System includes | ||
16 | |||
17 | // External includes | ||
18 | |||
19 | // Project includes | ||
20 | #include "Core/chrono.hpp" | ||
21 | |||
22 | namespace felisce | ||
23 | { | ||
24 | |||
25 | 490 | Chrono::Chrono(const bool active): | |
26 | 490 | m_active(active), | |
27 |
1/2✓ Branch 1 taken 490 times.
✗ Branch 2 not taken.
|
490 | m_resultDir("."), |
28 |
2/4✓ Branch 3 taken 490 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 490 times.
✗ Branch 7 not taken.
|
980 | m_comm(MPI_COMM_WORLD) |
29 | { | ||
30 | 490 | m_globalChrono.start(); | |
31 | 490 | } | |
32 | |||
33 | /***********************************************************************************/ | ||
34 | /***********************************************************************************/ | ||
35 | |||
36 | ✗ | Chrono::Chrono(const bool active, const std::string resultDir, MPI_Comm comm): | |
37 | ✗ | m_active(active), | |
38 | ✗ | m_resultDir(resultDir), | |
39 | ✗ | m_comm(comm) | |
40 | { | ||
41 | ✗ | m_globalChrono.start(); | |
42 | } | ||
43 | |||
44 | /***********************************************************************************/ | ||
45 | /***********************************************************************************/ | ||
46 | |||
47 | 1 | void Chrono::Sleep(const int TimeToSleep) | |
48 | { | ||
49 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | std::this_thread::sleep_for(std::chrono::seconds(TimeToSleep)); |
50 | 1 | } | |
51 | |||
52 | /***********************************************************************************/ | ||
53 | /***********************************************************************************/ | ||
54 | |||
55 | 88031 | void Chrono::Start( | |
56 | const std::string& rLabel, | ||
57 | const int SubLabel | ||
58 | ) | ||
59 | { | ||
60 |
1/2✓ Branch 0 taken 88031 times.
✗ Branch 1 not taken.
|
88031 | if ( !m_active ) |
61 | 88031 | return; | |
62 | |||
63 | ✗ | auto find_label_it = m_chrono.find(rLabel); | |
64 | ✗ | if (find_label_it == m_chrono.end()) { | |
65 | ✗ | m_chrono[rLabel] = std::map<int, ChronoInstance>(); | |
66 | ✗ | auto& r_chrono = m_chrono[rLabel]; | |
67 | ✗ | r_chrono[SubLabel] = ChronoInstance(); | |
68 | ✗ | r_chrono[SubLabel].start(); | |
69 | } else { | ||
70 | ✗ | auto& r_sub_map = find_label_it->second; | |
71 | ✗ | auto find_sub_label_it = r_sub_map.find(SubLabel); | |
72 | ✗ | if (find_sub_label_it == r_sub_map.end()) | |
73 | ✗ | r_sub_map[SubLabel] = ChronoInstance(); | |
74 | ✗ | r_sub_map[SubLabel].start(); | |
75 | } | ||
76 | } | ||
77 | |||
78 | /***********************************************************************************/ | ||
79 | /***********************************************************************************/ | ||
80 | |||
81 | 88031 | void Chrono::Stop( | |
82 | const std::string& rLabel, | ||
83 | const int SubLabel | ||
84 | ) | ||
85 | { | ||
86 |
1/2✓ Branch 0 taken 88031 times.
✗ Branch 1 not taken.
|
88031 | if ( !m_active ) |
87 | 88031 | return; | |
88 | |||
89 | ✗ | auto find_label_it = m_chrono.find(rLabel); | |
90 | ✗ | if (find_label_it == m_chrono.end()) { | |
91 | ✗ | std::cerr << "Chrono::Stop: Chrono with name " << rLabel << " not defined. Call Start first" << std::endl; | |
92 | } else { | ||
93 | ✗ | auto& r_sub_map = find_label_it->second; | |
94 | ✗ | auto find_sub_label_it = r_sub_map.find(SubLabel); | |
95 | ✗ | if (find_sub_label_it == r_sub_map.end()) { | |
96 | ✗ | std::cerr << "Chrono::Stop: Chrono with name " << rLabel << " and sublabel " << SubLabel << " not defined. Call Start first" << std::endl; | |
97 | } else { | ||
98 | ✗ | auto& r_chrono = find_sub_label_it->second; | |
99 | ✗ | r_chrono.stop(); | |
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /***********************************************************************************/ | ||
105 | /***********************************************************************************/ | ||
106 | |||
107 | ✗ | double Chrono::Diff( | |
108 | const std::string& rLabel, | ||
109 | const int SubLabel | ||
110 | ) | ||
111 | { | ||
112 | ✗ | if ( !m_active ) | |
113 | ✗ | return 0.0; | |
114 | |||
115 | ✗ | auto find_label_it = m_chrono.find(rLabel); | |
116 | ✗ | if (find_label_it == m_chrono.end()) { | |
117 | ✗ | std::cerr << "Chrono::Diff: Chrono with name " << rLabel << " not defined. Call Start and Stop first" << std::endl; | |
118 | } else { | ||
119 | ✗ | auto& r_sub_map = find_label_it->second; | |
120 | ✗ | auto find_sub_label_it = r_sub_map.find(SubLabel); | |
121 | ✗ | if (find_sub_label_it == r_sub_map.end()) { | |
122 | ✗ | std::cerr << "Chrono::Diff: Chrono with name " << rLabel << " and sublabel " << SubLabel << " not defined. Call Start and Stop first" << std::endl; | |
123 | } else { | ||
124 | ✗ | auto& r_chrono = find_sub_label_it->second; | |
125 | ✗ | return r_chrono.diff(); | |
126 | } | ||
127 | } | ||
128 | |||
129 | ✗ | return 0.0; | |
130 | } | ||
131 | |||
132 | /***********************************************************************************/ | ||
133 | /***********************************************************************************/ | ||
134 | |||
135 | ✗ | void Chrono::fillTable() | |
136 | { | ||
137 | ✗ | if ( m_isTableBuilt ) | |
138 | ✗ | return; | |
139 | |||
140 | ✗ | m_isTableBuilt = true; | |
141 | |||
142 | // Set percentages | ||
143 | ✗ | const double total_time = getTotalTime(); | |
144 | |||
145 | // Get the rank of the process | ||
146 | int rankProc, numProc; | ||
147 | ✗ | MPI_Comm_rank(m_comm,&rankProc); | |
148 | ✗ | MPI_Comm_size(m_comm,&numProc); | |
149 | |||
150 | ✗ | m_table.add_row({"Label", "Sublabel", "Time elapsed [CPU"+std::to_string(rankProc)+"] (s)", "Perc. tot. time (%)", "# Calls", "Average time elapsed [CPU"+std::to_string(rankProc)+"] (s)", "Average perc. tot. time (%)"}); | |
151 | ✗ | m_rows += 1; | |
152 | |||
153 | // Center-align and color header cells | ||
154 | ✗ | for (std::size_t i = 0; i < 7; ++i) { | |
155 | ✗ | m_table[0][i].format() | |
156 | ✗ | .font_color(tabulate::Color::yellow) | |
157 | ✗ | .font_align(tabulate::FontAlign::center) | |
158 | ✗ | .font_style({tabulate::FontStyle::bold}); | |
159 | } | ||
160 | |||
161 | ✗ | for (auto& r_label_chronos: m_chrono) { | |
162 | ✗ | const auto& r_label_name = r_label_chronos.first; | |
163 | ✗ | const auto& r_sub_chronos = r_label_chronos.second; | |
164 | |||
165 | ✗ | for (auto& r_sub_label_chrono: r_sub_chronos) { | |
166 | ✗ | const auto& r_sub_name = r_sub_label_chrono.first; | |
167 | ✗ | const auto& r_sub_chrono = r_sub_label_chrono.second; | |
168 | |||
169 | // Fill the table | ||
170 | ✗ | const double diff = r_sub_chrono.diff_cumul(); | |
171 | ✗ | const double percentage = diff / total_time * 100; | |
172 | ✗ | std::stringstream buffer; | |
173 | ✗ | buffer << std::setprecision(16) << std::scientific << diff; | |
174 | |||
175 | ✗ | const uint64_t num = r_sub_chrono.num_call(); | |
176 | ✗ | const double ave_diff = diff / num; | |
177 | ✗ | const double ave_perc = ave_diff / total_time * 100; | |
178 | ✗ | std::stringstream buffer_ave; | |
179 | ✗ | buffer_ave << std::setprecision(16) << std::scientific << ave_diff; | |
180 | |||
181 | ✗ | m_table.add_row({r_label_name, std::to_string(r_sub_name), buffer.str(), std::to_string(percentage), std::to_string(num), buffer_ave.str(), std::to_string(ave_perc) }); | |
182 | ✗ | m_table[m_rows][0].format() | |
183 | ✗ | .font_color(tabulate::Color::magenta) | |
184 | ✗ | .font_align(tabulate::FontAlign::left) | |
185 | ✗ | .font_style({tabulate::FontStyle::bold}); | |
186 | ✗ | m_rows += 1; | |
187 | } | ||
188 | } | ||
189 | |||
190 | // Center align | ||
191 | ✗ | m_table.column(0).format().font_align(tabulate::FontAlign::left); | |
192 | ✗ | for (std::size_t i = 1; i < 7; ++i) { | |
193 | ✗ | m_table.column(i).format().font_align(tabulate::FontAlign::center); | |
194 | } | ||
195 | } | ||
196 | |||
197 | /***********************************************************************************/ | ||
198 | /***********************************************************************************/ | ||
199 | |||
200 | ✗ | void Chrono::ToScreen() | |
201 | { | ||
202 | // Get the rank of the process | ||
203 | int rankProc, numProc; | ||
204 | ✗ | MPI_Comm_rank(m_comm,&rankProc); | |
205 | ✗ | MPI_Comm_size(m_comm,&numProc); | |
206 | |||
207 | // Build table | ||
208 | ✗ | fillTable(); | |
209 | |||
210 | // Print to screen | ||
211 | ✗ | for (int i = 0; i < numProc; ++i) { | |
212 | |||
213 | ✗ | MPI_Barrier(MPI_COMM_WORLD); | |
214 | |||
215 | ✗ | if ( rankProc == i ) | |
216 | ✗ | std::cout << "\n\n" << m_table << "\n\n" << generateGlobalTable() << std::endl; | |
217 | |||
218 | ✗ | MPI_Barrier(MPI_COMM_WORLD); | |
219 | } | ||
220 | } | ||
221 | |||
222 | /***********************************************************************************/ | ||
223 | /***********************************************************************************/ | ||
224 | |||
225 | ✗ | void Chrono::ToFile() | |
226 | { | ||
227 | // Get the rank of the process | ||
228 | int rankProc, numProc; | ||
229 | ✗ | MPI_Comm_rank(m_comm,&rankProc); | |
230 | ✗ | MPI_Comm_size(m_comm,&numProc); | |
231 | |||
232 | // Build table | ||
233 | ✗ | fillTable(); | |
234 | |||
235 | /* Writes table into file */ | ||
236 | ✗ | for (int i = 0; i < numProc; ++i) { | |
237 | |||
238 | ✗ | if ( rankProc == i ) { | |
239 | ✗ | std::ostringstream filename; | |
240 | ✗ | filename << m_resultDir << "/" << "chrono" << std::to_string(rankProc) << ".md"; | |
241 | ✗ | std::ofstream f; | |
242 | ✗ | f.open(filename.str().c_str()); | |
243 | |||
244 | ✗ | if ( f.good() ) { | |
245 | // Exported Markdown | ||
246 | ✗ | tabulate::MarkdownExporter exporter_md; | |
247 | ✗ | auto markdown = exporter_md.dump(m_table); | |
248 | ✗ | f << markdown << std::endl; | |
249 | ✗ | f.close(); | |
250 | ✗ | } else { | |
251 | ✗ | std::ostringstream msg; | |
252 | ✗ | msg << "Can not write in file " << filename.str() << std::endl; | |
253 | ✗ | FEL_WARNING(msg.str().c_str()); | |
254 | } | ||
255 | } | ||
256 | } | ||
257 | |||
258 | /* Writes table into file */ | ||
259 | ✗ | for (int i = 0; i < numProc; ++i) { | |
260 | |||
261 | ✗ | if ( rankProc == i ) { | |
262 | ✗ | std::ostringstream filename; | |
263 | ✗ | filename << m_resultDir << "/" << "chrono_total" << std::to_string(rankProc) << ".md"; | |
264 | ✗ | std::ofstream f; | |
265 | ✗ | f.open(filename.str().c_str()); | |
266 | |||
267 | ✗ | if ( f.good() ) { | |
268 | // Exported Markdown | ||
269 | ✗ | tabulate::MarkdownExporter exporter_md; | |
270 | ✗ | auto total_table = generateGlobalTable(); | |
271 | ✗ | auto markdown = exporter_md.dump(total_table); | |
272 | ✗ | f << markdown << std::endl; | |
273 | ✗ | f.close(); | |
274 | ✗ | } else { | |
275 | ✗ | std::ostringstream msg; | |
276 | ✗ | msg << "Can not write in file " << filename.str() << std::endl; | |
277 | ✗ | FEL_WARNING(msg.str().c_str()); | |
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /***********************************************************************************/ | ||
284 | /***********************************************************************************/ | ||
285 | |||
286 | ✗ | void Chrono::print(int verbose,std::ostream& c) const | |
287 | { | ||
288 | ✗ | if(verbose) { | |
289 | ✗ | c << m_table << std::endl; | |
290 | } | ||
291 | } | ||
292 | |||
293 | /***********************************************************************************/ | ||
294 | /***********************************************************************************/ | ||
295 | |||
296 | ✗ | tabulate::Table Chrono::generateGlobalTable() | |
297 | { | ||
298 | ✗ | tabulate::Table global_table; | |
299 | |||
300 | // Get the total time | ||
301 | ✗ | const double total_time = getTotalTime(); | |
302 | ✗ | double remaining_time = total_time; | |
303 | ✗ | const std::string total_time_string = std::to_string(total_time); | |
304 | |||
305 | // Get the rank of the process | ||
306 | int rankProc, numProc; | ||
307 | ✗ | MPI_Comm_rank(m_comm,&rankProc); | |
308 | ✗ | MPI_Comm_size(m_comm,&numProc); | |
309 | |||
310 | ✗ | global_table.add_row({"Label", "Time elapsed [CPU"+std::to_string(rankProc)+"] (s)", "T. time elapsed [CPU"+std::to_string(rankProc)+"] (s)", "Perc. tot. time (%)"}); | |
311 | |||
312 | // Center-align and color header cells | ||
313 | ✗ | for (std::size_t i = 0; i < 4; ++i) { | |
314 | ✗ | global_table[0][i].format() | |
315 | ✗ | .font_color(tabulate::Color::yellow) | |
316 | ✗ | .font_align(tabulate::FontAlign::center) | |
317 | ✗ | .font_style({tabulate::FontStyle::bold}); | |
318 | } | ||
319 | |||
320 | // Add rows | ||
321 | ✗ | std::size_t i = 1; | |
322 | ✗ | double total_time_label = 0.0; | |
323 | ✗ | for (auto& r_label_chronos: m_chrono) { | |
324 | ✗ | total_time_label = 0.0; | |
325 | ✗ | const auto& r_label_name = r_label_chronos.first; | |
326 | ✗ | const auto& r_sub_chronos = r_label_chronos.second; | |
327 | ✗ | for (auto& r_sub_label_chrono: r_sub_chronos) { | |
328 | ✗ | total_time_label += (r_sub_label_chrono.second).diff_cumul(); | |
329 | } | ||
330 | ✗ | remaining_time -= total_time_label; | |
331 | ✗ | global_table.add_row({r_label_name, std::to_string(total_time_label), total_time_string, std::to_string((total_time_label/total_time)*100)}); | |
332 | ✗ | global_table[i][0].format() | |
333 | ✗ | .font_color(tabulate::Color::magenta) | |
334 | ✗ | .font_align(tabulate::FontAlign::left) | |
335 | ✗ | .font_style({tabulate::FontStyle::bold}); | |
336 | ✗ | ++i; | |
337 | } | ||
338 | // In case remaining time is not null | ||
339 | ✗ | if (remaining_time > 0.0) { | |
340 | ✗ | global_table.add_row({"Remaining time", std::to_string(remaining_time), total_time_string, std::to_string((remaining_time/total_time)*100)}); | |
341 | ✗ | global_table[i][0].format() | |
342 | ✗ | .font_color(tabulate::Color::magenta) | |
343 | ✗ | .font_align(tabulate::FontAlign::left) | |
344 | ✗ | .font_style({tabulate::FontStyle::bold}); | |
345 | } | ||
346 | |||
347 | // Center align | ||
348 | ✗ | global_table.column(0).format().font_align(tabulate::FontAlign::left); | |
349 | ✗ | for (std::size_t i = 1; i < 4; ++i) { | |
350 | ✗ | global_table.column(i).format().font_align(tabulate::FontAlign::center); | |
351 | } | ||
352 | |||
353 | ✗ | return global_table; | |
354 | } | ||
355 | } | ||
356 |