GCC Code Coverage Report


Directory: ./
File: Core/chrono.hpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 25 60 41.7%
Branches: 4 62 6.5%

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 #ifndef _CHRONO_HPP_INCLUDE
16 #define _CHRONO_HPP_INCLUDE
17
18 // System includes
19 #include <chrono>
20 #include <iomanip>
21 #include <thread>
22 #include <fstream>
23 #include <map>
24 #include <stdint.h>
25 // Windows
26 #ifdef _WIN32
27 #include <intrin.h>
28 #endif
29
30 // External includes
31 #include <mpi.h>
32 #include <tabulate/single_include/tabulate/tabulate.hpp>
33
34 // Project includes
35 #include "Core/felisce_error.hpp"
36 #include "Core/shared_pointers.hpp"
37
38 namespace felisce
39 {
40 ///@name felisce Globals
41 ///@{
42
43 ///@}
44 ///@name Type Definitions
45 ///@{
46
47 ///@}
48 ///@name Enum's
49 ///@{
50
51 ///@}
52 ///@name Functions
53 ///@{
54
55 ///@}
56 ///@name felisce Classes
57 ///@{
58
59 /**
60 * @class ChronoInstance
61 * @details It is used to measure the time between two events.
62 * @brief Minimal class to manage chrono.
63 */
64 class ChronoInstance
65 {
66 public:
67 ///@name Type Definitions
68 ///@{
69
70 /// Pointer definition of ChronoInstance
71 FELISCE_CLASS_POINTER_DEFINITION(ChronoInstance);
72
73 ///@}
74 ///@name Life Cycle
75 ///@{
76
77 /// Constructor
78 558 ChronoInstance() = default;
79
80 /// Destructor
81 ~ChronoInstance() = default;
82
83 ///@}
84 ///@name Operators
85 ///@{
86
87 ///@}
88 ///@name Operations
89 ///@{
90
91 // Windows
92 #if defined(_WIN32)
93 static uint64_t rdtsc(){
94 return __rdtsc();
95 }
96 #elif defined(__ARM_ARCH)
97 // Support for Apple Silicon (arm64), following https://github.com/google/benchmark/blob/main/src/cycleclock.h
98 static uint64_t rdtsc(){
99 // System timer of ARMv8 runs at a different frequency than the CPU's.
100 // The frequency is fixed, typically in the range 1-50MHz. It can be
101 // read at CNTFRQ special register. We assume the OS has set up
102 // the virtual timer properly.
103 int64_t virtual_timer_value;
104 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
105 return virtual_timer_value;
106 }
107 #else // Linux/GCC
108 1796 static uint64_t rdtsc(){
109 unsigned int lo,hi;
110 1796 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
111 1796 return ((uint64_t)hi << 32) | lo;
112 }
113 #endif
114
115 /**
116 * @brief Start the chrono
117 */
118 1143 std::chrono::system_clock::time_point& start() {
119 1143 m_start_cycles = rdtsc();
120 1143 m_start = std::chrono::system_clock::now();
121 1143 m_started = true;
122 1143 return m_start;
123 }
124
125 /**
126 * @brief Stop the chrono
127 */
128 653 std::chrono::system_clock::time_point& stop() {
129 653 m_end_cycles = rdtsc();
130 653 m_stop = std::chrono::system_clock::now();
131 653 m_stopped = true;
132 653 m_dt += this->diff();
133 653 m_cn++;
134 653 return m_stop;
135 }
136
137 /**
138 * @brief Returns if the chrono is started
139 * @return True if the chrono is started, false otherwise
140 */
141 657 bool isStarted() {
142 657 return m_started;
143 }
144
145 /**
146 * @brief Returns if the chrono is started
147 * @return True if the chrono is started, false otherwise
148 */
149 bool isStarted() const{
150 return m_started;
151 }
152
153 /**
154 * @brief Returns if the chrono is stopped
155 * @return True if the chrono is stopped, false otherwise
156 */
157 657 bool isStopped() {
158 657 return m_stopped;
159 }
160
161 /**
162 * @brief Returns if the chrono is stopped
163 * @return True if the chrono is stopped, false otherwise
164 */
165 bool isStopped() const { return m_stopped; }
166
167 /**
168 * @brief Resets the chrono instance
169 */
170 void reset()
171 {
172 this->start();
173 m_dt = 0;
174 m_cn = 0;
175 }
176
177 /**
178 * @brief Returns the chrono duration accumulated
179 * @return The chrono duration accumulated
180 */
181 36 double diff_cumul() const
182 {
183 36 return std::max(m_dt, 0.);
184 }
185
186 /**
187 * @brief Returns the number of calls to chrono
188 * @return The number of calls to chrono
189 */
190 uint64_t num_call() const
191 {
192 return m_cn;
193 }
194
195 /**
196 * @brief Returns the chrono duration
197 * @return The chrono duration
198 */
199 653 double diff() {
200
3/6
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 653 times.
✗ Branch 7 not taken.
653 if (isStarted() && isStopped()) {
201
1/2
✓ Branch 2 taken 653 times.
✗ Branch 3 not taken.
653 return std::chrono::duration_cast<std::chrono::duration<double>>(m_stop - m_start).count();
202 } else {
203 std::cerr << "ChronoInstance:: start() and stop() must be called first." << std::endl;
204 return 0.0;
205 }
206 }
207
208 /**
209 * @brief Returns the chrono duration
210 * @return The chrono duration
211 */
212 double diff() const {
213 if (isStarted() && isStopped()) {
214 return std::chrono::duration_cast<std::chrono::duration<double>>(m_stop - m_start).count();
215 } else {
216 std::cerr << "ChronoInstance:: start() and stop() must be called first." << std::endl;
217 return 0.0;
218 }
219 }
220
221 /**
222 * @brief Returns the chrono duration in CPU cycles
223 * @return The chrono duration
224 */
225 uint64_t diffCycles() {
226 if (isStarted() && isStopped()) {
227 return m_end_cycles - m_start_cycles;
228 } else {
229 std::cerr << "ChronoInstance:: start() and stop() must be called first." << std::endl;
230 return 0.0;
231 }
232 }
233
234 /**
235 * @brief Returns the chrono duration in CPU cycles
236 * @return The chrono duration
237 */
238 uint64_t diffCycles() const {
239 if (isStarted() && isStopped()) {
240 return m_end_cycles - m_start_cycles;
241 } else {
242 std::cerr << "ChronoInstance:: start() and stop() must be called first." << std::endl;
243 return 0.0;
244 }
245 }
246
247 /**
248 * @brief Returns the start time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
249 * @return The start time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
250 */
251 std::string startTime() {
252 if (isStarted()) {
253 std::stringstream ss;
254 const std::time_t tt = std::chrono::system_clock::to_time_t(m_start);
255 ss << std::put_time(std::localtime(&tt), "%T") << std::flush;
256 return ss.str();
257 }
258 return "Not started";
259 }
260
261 /**
262 * @brief Returns the start time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
263 * @return The start time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
264 */
265 std::string startTime() const {
266 if (isStarted()) {
267 std::stringstream ss;
268 const std::time_t tt = std::chrono::system_clock::to_time_t(m_start);
269 ss << std::put_time(std::localtime(&tt), "%T") << std::flush;
270 return ss.str();
271 }
272 return "Not started";
273 }
274
275 /**
276 * @brief Returns the stop time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
277 * @return The stop time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
278 */
279 std::string stopTime() const {
280 if (isStopped()) {
281 std::stringstream ss;
282 const std::time_t tt = std::chrono::system_clock::to_time_t(m_stop);
283 ss << std::put_time(std::localtime(&tt), "%T") << std::flush;
284 return ss.str();
285 }
286 return "Not stopped";
287 }
288
289 /**
290 * @brief Returns the stop time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
291 * @return The stop time in equivalent to "%H:%M:%S" (the ISO 8601 time format) in a string
292 */
293 std::string stopTime() {
294 if (isStopped()) {
295 std::stringstream ss;
296 const std::time_t tt = std::chrono::system_clock::to_time_t(m_stop);
297 ss << std::put_time(std::localtime(&tt), "%T") << std::flush;
298 return ss.str();
299 }
300 return "Not stopped";
301 }
302
303 /**
304 * @brief Returns chrono as a file
305 */
306 void toFile()
307 {
308 std::string resultDir = "."; // Directory where to write the results
309 MPI_Comm comm = MPI_COMM_WORLD; // MPI communicator
310 int rankProc = -1; // Rank of the process
311 int numProc = -1; // Number of processes
312
313 MPI_Comm_rank(comm,&rankProc);
314 MPI_Comm_size(comm,&numProc);
315
316 // Process 0 gathers diff from all process
317 double my_diff = this->diff();
318 double * allProcessDiff = nullptr;
319
320 if (rankProc == 0)
321 allProcessDiff = new double[numProc];
322
323 MPI_Barrier(comm);
324 MPI_Gather(&my_diff,1,MPI_DOUBLE, allProcessDiff,1,MPI_DOUBLE, 0,comm);
325 MPI_Barrier(comm);
326
327 // remaining of the code is done by only process 0
328 if (rankProc != 0)
329 return;
330
331 // write all process diff in a file
332 std::ostringstream filename;
333 filename << resultDir << "/" << "chrono.txt";
334 std::ofstream f;
335 f.open(filename.str().c_str());
336
337 if ( f.good() ) {
338 f << "# seconds, one line per processor" << std::endl;
339 for (int rankProc = 0; rankProc < numProc; ++rankProc)
340 f << allProcessDiff[rankProc] << std::endl;
341 } else {
342 std::ostringstream msg;
343 msg << "dumpAllProcess: can not write in file " << filename.str() << std::endl;
344 FEL_WARNING(msg.str().c_str());
345 }
346
347 delete[] allProcessDiff;
348 }
349
350 /**
351 * @brief Returns chrono as a file max
352 */
353 void toFileMax()
354 {
355 std::string resultDir = "."; // Directory where to write the results
356 MPI_Comm comm = MPI_COMM_WORLD; // MPI communicator
357 int rankProc = -1; // Rank of the process
358 int numProc = -1; // Number of processes
359
360 MPI_Comm_rank(comm,&rankProc);
361 MPI_Comm_size(comm,&numProc);
362
363 // Process 0 gathers diff from all process
364 double my_diff = this->diff();
365 double maxDiff(0);
366
367 MPI_Reduce(&my_diff, &maxDiff, 1, MPI_DOUBLE, MPI_MAX, 0, comm);
368
369 // rest of the code is done by only process 0
370 if (rankProc != 0)
371 return;
372
373 // write all process diff in a file
374 std::ostringstream filename;
375 filename << resultDir << "/" << "chrono.txt";
376 std::ofstream f;
377 f.open(filename.str().c_str(), std::ios::app);
378
379 if ( f.good() ) {
380 f << maxDiff << std::endl;
381 } else {
382 std::ostringstream msg;
383 msg << "dumpAllProcess: can not write in file " << filename.str() << std::endl;
384 FEL_WARNING(msg.str().c_str());
385 }
386 }
387
388 ///@}
389 ///@name Access
390 ///@{
391
392 ///@}
393 ///@name Inquiry
394 ///@{
395
396 ///@}
397 ///@name Input and output
398 ///@{
399
400 ///@}
401 ///@name Friends
402 ///@{
403
404 ///@}
405 protected:
406 ///@name Protected static Member Variables
407 ///@{
408
409 ///@}
410 ///@name Protected member Variables
411 ///@{
412
413 ///@}
414 ///@name Protected Operators
415 ///@{
416
417 ///@}
418 ///@name Protected Operations
419 ///@{
420
421 ///@}
422 ///@name Protected Access
423 ///@{
424
425 ///@}
426 ///@name Protected Inquiry
427 ///@{
428
429 ///@}
430 ///@name Protected LifeCycle
431 ///@{
432
433 ///@}
434 private:
435 ///@name Private static Member Variables
436 ///@{
437
438 ///@}
439 ///@name Private member Variables
440 ///@{
441
442 uint64_t m_start_cycles = 0; /// The starting point in cycles
443 std::chrono::system_clock::time_point m_start; /// The starting point of the chrono
444 bool m_started = false; /// True if the chrono is started
445
446 uint64_t m_end_cycles = 0; /// The stopping point in cycles
447 std::chrono::system_clock::time_point m_stop; /// The stopping point of the chrono
448 bool m_stopped = false; /// True if the chrono is stopped
449
450 double m_dt = 0.0; /// Time increment
451
452 uint64_t m_cn = 0; /// Number of call
453
454 ///@}
455 ///@name Private Operations
456 ///@{
457
458 ///@}
459 ///@name Private Access
460 ///@{
461
462 ///@}
463 ///@name Private Inquiry
464 ///@{
465
466 ///@}
467 ///@name Private LifeCycle
468 ///@{
469
470 ///@}
471 };
472
473 /**
474 * @class Chrono
475 * @brief A chrono general instance class
476 * @details This class is a general chrono instance class. It stores all times in several chronos instances. Generates a table with all the information.
477 */
478 class Chrono
479 {
480 public:
481 ///@name Type Definitions
482 ///@{
483
484 /// Pointer definition of Chrono
485 FELISCE_CLASS_POINTER_DEFINITION(Chrono);
486
487 ///@}
488 ///@name Life Cycle
489 ///@{
490
491 /// Constructor
492 Chrono(const bool active);
493
494 /// Constructor with additional information
495 Chrono(const bool active, const std::string resultDir, MPI_Comm comm = MPI_COMM_WORLD);
496
497 /// Destructor
498 ~Chrono() = default;
499
500 ///@}
501 ///@name Operators
502 ///@{
503
504 ///@}
505 ///@name Operations
506 ///@{
507
508 /**
509 * @brief Sleep the current thread for a given time
510 * @param Time Time to be elapsed
511 */
512 static void Sleep(const int TimeToSleep);
513
514 /**
515 * @brief Start the chronometer
516 * @param rLabel The label of the chrono
517 * @param SubLabel The sublabel of the chrono (integer)
518 */
519 void Start(
520 const std::string& rLabel,
521 const int SubLabel = 0
522 );
523
524 /**
525 * @brief Stop the chronometer
526 * @param rLabel The label of the chrono
527 * @param SubLabel The sublabel of the chrono (integer)
528 */
529 void Stop(
530 const std::string& rLabel,
531 const int SubLabel = 0
532 );
533
534 /**
535 * @brief The difference of the chrono instance
536 * @param rLabel The label of the chrono
537 * @param SubLabel The sublabel of the chrono (integer)
538 * @return time measured in last [start,stop] interval
539 */
540 double Diff(
541 const std::string& rLabel,
542 const int SubLabel = 0
543 );
544
545 /**
546 * @brief The difference of the chrono instance since its creation
547 * @details Once is called, the chrono is stopped if it is not already stopped.
548 * @param StopChrono If true, the chrono is stopped manually
549 * @return Time measured since creation of instance
550 */
551 double getTotalTime(const bool StopChrono = false) {
552 if (!m_globalChrono.isStopped()) {
553 m_globalChrono.stop();
554 } else if (StopChrono) {
555 m_globalChrono.stop();
556 }
557 return m_globalChrono.diff();
558 }
559
560 /**
561 * @brief The difference of the chrono instance since its creation
562 * @return Time measured since creation of instance
563 */
564 double getTotalTime() const {
565 return m_globalChrono.diff();
566 }
567
568 /**
569 * @brief Write chrono measures to screen
570 */
571 void ToScreen();
572
573 /**
574 * @brief Write chrono measures to file <resultDir>/chrono_<chronoName>.md
575 */
576 void ToFile();
577
578 ///@}
579 ///@name Access
580 ///@{
581
582 /**
583 * @brief Returns the result directory
584 * @return The result directory
585 */
586 std::string& resultDir()
587 {
588 return m_resultDir;
589 }
590
591 /**
592 * @brief The table where the chrono information is stored
593 * @return The table where the chrono information is stored
594 */
595 tabulate::Table& table()
596 {
597 return m_table;
598 }
599
600 ///@}
601 ///@name Inquiry
602 ///@{
603
604 inline const bool& State() const { return m_active; }
605 inline bool& State() { return m_active; }
606
607 ///@}
608 ///@name Input and output
609 ///@{
610
611 void print(int verbose,std::ostream& c=std::cout) const;
612
613 ///@}
614 ///@name Friends
615 ///@{
616
617 ///@}
618 protected:
619 ///@name Protected static Member Variables
620 ///@{
621
622 ///@}
623 ///@name Protected member Variables
624 ///@{
625
626 ///@}
627 ///@name Protected Operators
628 ///@{
629
630 ///@}
631 ///@name Protected Operations
632 ///@{
633
634 ///@}
635 ///@name Protected Access
636 ///@{
637
638 ///@}
639 ///@name Protected Inquiry
640 ///@{
641
642 ///@}
643 ///@name Protected LifeCycle
644 ///@{
645
646 ///@}
647 private:
648 ///@name Private static Member Variables
649 ///@{
650
651 ///@}
652 ///@name Private member Variables
653 ///@{
654
655 bool m_active; /// Bool chrono is active or not
656 bool m_isTableBuilt = false; /// Bool m_table is built or not
657
658 std::string m_resultDir; /// Directory where to write the results
659 MPI_Comm m_comm; /// MPI communicator
660
661 std::map<std::string, std::map<int, ChronoInstance>> m_chrono; /// Chrono map
662
663 ChronoInstance m_globalChrono; /// Global chrono
664
665 tabulate::Table m_table; /// Table containing all the chrono measures
666 std::size_t m_rows = 0; /// Number of rows in the table
667
668 ///@}
669 ///@name Private Operations
670 ///@{
671
672 /**
673 * @brief This method fills the table
674 */
675 void fillTable();
676
677 /**
678 * @brief
679 * @return tabulate::Table
680 */
681 tabulate::Table generateGlobalTable();
682
683 ///@}
684 ///@name Private Access
685 ///@{
686
687 ///@}
688 ///@name Private Inquiry
689 ///@{
690
691 ///@}
692 ///@name Private LifeCycle
693 ///@{
694
695 ///@}
696 };
697 ///@}
698 ///@name Type Definitions
699 ///@{
700
701 ///@}
702 } /* namespace felisce.*/
703
704 #endif
705