ls1-MarDyn
ls1-MarDyn molecular dynamics code
Timer.h
1#ifndef TIMER_H_
2#define TIMER_H_
3
4#include <assert.h>
5#include <iostream>
6
7/* We use MPIs Wtime in parallel application, else clock */
8#ifdef ENABLE_MPI
9#include <mpi.h>
10#else
11#include <sys/time.h>
12#endif
13
14/* PAPI hardware performance counter support */
15/*
16 * Take care when using multiple timers because calls to the constructor
17 * reset the hw counters to zero!
18 */
19#ifdef WITH_PAPI
20#include <papi.h>
21
22#ifndef NDEBUG
23#define PAPI_CHECK(BOOL,MSG) do { \
24 if ((BOOL)) { \
25 std::cerr << "PAPI_ERROR: " << MSG << std::endl; \
26 } \
27 } while (0);
28#else /* NDEBUG */
29#define PAPI_CHECK(BOOL,MSG) (BOOL);
30#endif /* NDEBUG */
31
32
33class PAPI_Initializer{
34public:
35 PAPI_Initializer() {
36 static bool initialized = false;
37 if (!initialized) {
38 initialized = true;
39 PAPI_CHECK( PAPI_library_init(PAPI_VER_CURRENT) != PAPI_OK, "Failed initializing PAPI library." );
40 PAPI_CHECK( PAPI_thread_init(pthread_self) != PAPI_OK, "Failed initializing PAPI thread support." );
41 this->initialized = true;
42 }
43 }
44
45 bool papi_initialized() { return this->initialized; }
46
47private:
48 bool initialized = false;
49};
50#endif /* WITH_PAPI */
51
52typedef enum {
53 TIMER_HALTED = 0,
54 TIMER_RUNNING = 1
55} timer_state;
56
59class Timer {
60 double _start; // stop time
61 double _stop; // start time
62 double _etime; // elapsed time
63 timer_state _state; // timer state
64 bool _synced; // timer should be synced at start and end across processes/threads
65
66#ifdef WITH_PAPI
67 long long *_papi_start;
68 long long *_papi_stop;
69 long long *_papi_counter;
70 int _papi_num_counters;
71 int _papi_num_avail_counters;
72 int _papi_EventSet;
73 bool _collect_papi;
74#endif /* WITH_PAPI */
75
76private:
77 bool _active; // timer can be active or not; if not active, then all function calls will have no effect on the timer
78
79public:
80 Timer() :
81 _start(0), _stop(0), _etime(0), _state(TIMER_HALTED), _synced(false), _active(true)
82#ifdef WITH_PAPI
83 , _papi_start(0), _papi_stop(0), _papi_counter(0), _papi_num_counters(0), _papi_num_avail_counters(0), _papi_EventSet(0), _collect_papi(false)
84#endif /* WITH_PAPI */
85 {
86#ifdef WITH_PAPI
87 // static dummy used to make PAPI initialization thread-safe (according C++11)
88 static PAPI_Initializer pi;
89 if (!pi.papi_initialized()) {
90 std::cerr << "PAPI not initialized!!!1" << std::endl;
91 }
92#endif
93 reset();
94 }
95
96 ~~Timer() {
97#ifdef WITH_PAPI
98 delete[] _papi_start;
99 delete[] _papi_stop;
100 delete[] _papi_counter;
101#endif /* WITH_PAPI */
102 }
103 void start();
104 void stop();
105 void reset();
106
107 double get_start() {
108 return _start;
109 }
110 double get_end() {
111 return _stop;
112 }
113 double get_etime() {
114 return _etime;
115 }
116 double get_etime_running() {
117 return timer() - _start;
118 }
119 timer_state get_state() {
120 return _state;
121 }
122
123 void activateTimer(){ _active = true; }
124 void deactivateTimer(){ _active = false; }
125 bool isActive(){ return _active; }
126
128 void set_sync(bool sync) {
129 _synced = sync;
130 }
131
132#ifdef WITH_PAPI
133 int add_papi_counters(int n, char *papi_event_list[]) {
134 if(_collect_papi) {
135 std::cerr << "PAPI ERROR: PAPI counters already started." << std::endl;
136 }
137 _papi_num_avail_counters = PAPI_num_counters();
138 if(_papi_num_avail_counters < 0) {
139 std::cerr << "PAPI ERROR: This machine does not provide hardware counters.";
140 }
141 else {
142 _papi_start = new long long[_papi_num_avail_counters];
143 _papi_stop = new long long[_papi_num_avail_counters];
144 _papi_counter = new long long[_papi_num_avail_counters];
145 _papi_num_counters = n;
146 _papi_EventSet = PAPI_NULL;
147 PAPI_CHECK( (PAPI_create_eventset(&_papi_EventSet) != PAPI_OK), "Failed creating event set.");
148 if (_papi_num_avail_counters < _papi_num_counters) {
149 std::cerr << "PAPI WARNING: Not enough hw counter available. Skipping counters " << _papi_num_avail_counters << " - " << _papi_num_counters << std::endl;
150 _papi_num_counters = _papi_num_avail_counters;
151 }
152 for (int i = 0; i < _papi_num_counters; i++) {
153#ifndef NDEBUG
154 std::cerr << "PAPI INFO: adding HW Counter [" << i << "] " << papi_event_list[i] << std::endl;
155#endif
156 PAPI_CHECK( (PAPI_add_named_event(_papi_EventSet, papi_event_list[i]) != PAPI_OK), "Could not add counter to event set.");
157 _papi_counter[i] = 0;
158 }
159 PAPI_CHECK( (PAPI_start(_papi_EventSet) != PAPI_OK), "Could not start PAPI counters.");
160 }
161 _collect_papi = true;
162 return _papi_num_counters;
163 }
164 /* get number of used papi_counters */
165 int get_papi_num_counters() {
166 return _papi_num_counters;
167 }
168 /* get counter value between stop and last start */
169 long long get_papi_counter(int index) {
170 return (_papi_counter[index]);
171 }
172 long long get_global_papi_counter(int index) {
173 long long counter = _papi_counter[index];
174#if ENABLE_MPI
175 MPI_Allreduce(MPI_IN_PLACE, &counter, 1, MPI_LONG_LONG, MPI_SUM, MPI_COMM_WORLD);
176#endif /* ENABLE_MPI */
177 return counter;
178 }
179#endif /* WITH_PAPI */
180
181private:
182 double timer() {
183 double time;
184#ifdef ENABLE_MPI
185 if (_synced)
186 MPI_Barrier(MPI_COMM_WORLD);
187 time = MPI_Wtime();
188#else
189 struct timeval tmp_time;
190 gettimeofday(&tmp_time, NULL);
191 time = (1.0e6 * (double) tmp_time.tv_sec + (double) tmp_time.tv_usec) / 1.0e6;
192#endif
193 return time;
194 }
195};
196#endif /*TIMER_H_*/
This class is used to measure times in sequential and parallel versions.
Definition: Timer.h:59
void set_sync(bool sync)
Synchronize counter (across MPI processes)
Definition: Timer.h:128
::xsd::cxx::tree::time< char, simple_type > time
C++ type corresponding to the time XML Schema built-in type.
Definition: vtk-punstructured.h:438