34 #include <sys/param.h>
38 #include <boost/format.hpp>
89 Timer::Timer(
const CodePoint &cp,
int parent)
96 hash_idx_(cp.hash_idx_),
101 for(
unsigned int i=0; i< max_n_childs ;i++) child_timers[i]=-1;
114 Timer::TimeData Timer::get_time() {
120 double Timer::cumulative_time()
const
122 return 1000.0 * double(cumul_time) / CLOCKS_PER_SEC;
127 void Timer::start() {
128 if (start_count == 0) start_time = get_time();
135 void Timer::update() {
136 TimeData time = get_time();
137 cumul_time += time - start_time;
142 bool Timer::stop(
bool forced) {
144 if (forced) start_count=1;
146 if (start_count == 1) {
147 TimeData time = get_time();
148 cumul_time += time - start_time;
159 void Timer::add_child(
int child_index,
const Timer &child)
161 unsigned int idx = child.hash_idx_;
162 if (child_timers[idx] >0) {
165 i=( i < max_n_childs ? i+1 : 0);
166 }
while (i!=idx && child_timers[i] >0);
167 ASSERT(i!=idx,
"Too many children of the timer with tag '%s'\n", tag() );
170 child_timers[idx] = child_index;
175 string Timer::code_point_str()
const {
176 return boost::str( boost::format(
"%s:%d, %s()") % code_point_->file_ % code_point_->line_ % code_point_->func_ );
190 CodePoint Profiler::null_code_point = CodePoint(
"__no_tag__",
"__no_file__",
"__no_func__", 0);
206 start_time( time(NULL) )
209 #ifdef DEBUG_PROFILER
210 static CONSTEXPR_ CodePoint main_cp = CODE_POINT(
"Whole Program");
211 timers_.push_back( Timer(main_cp, 0) );
220 task_description_ = description;
227 flow_name_ = program_name;
228 flow_version_ = program_version;
229 flow_branch_ = branch;
230 flow_revision_ = revision;
236 int Profiler::start_timer(
const CodePoint &cp) {
238 int child_idx = find_child(cp);
241 child_idx=timers_.size();
242 timers_.push_back( Timer(cp, actual_node) );
243 timers_[actual_node].add_child(child_idx , timers_.back() );
246 timers_[child_idx].start();
247 actual_node=child_idx;
254 int Profiler::find_child(
const CodePoint &cp) {
255 Timer &timer =timers_[actual_node];
256 int idx = cp.hash_idx_;
259 child_idx=timer.child_timers[idx];
261 if (child_idx < 0)
break;
264 if (timers_[child_idx].full_hash_ == cp.hash_)
return child_idx;
265 idx = ( (
unsigned int)(idx)==Timer::max_n_childs ? 0 : idx+1 );
266 }
while ( (
unsigned int)(idx) != cp.hash_idx_ );
272 void Profiler::stop_timer(
const CodePoint &cp) {
273 #ifdef Flow123d_DEBUG
275 Timer &timer=timers_[actual_node];
276 for(
unsigned int i=0; i < Timer::max_n_childs; i++)
277 if (timer.child_timers[i] >0)
278 ASSERT( ! timers_[timer.child_timers[i]].running() ,
"Child timer '%s' running while closing timer '%s'.\n", timers_[timer.child_timers[i]].tag(), timer.tag() );
280 if ( cp.hash_ != timers_[actual_node].full_hash_) {
282 for(
unsigned int node=actual_node; node != 0; node=timers_[node].parent_timer) {
283 if ( cp.hash_ == timers_[node].full_hash_) {
285 for(; (
unsigned int)(actual_node) != node; actual_node=timers_[actual_node].parent_timer) {
286 xprintf(
Warn,
"Timer to close '%s' do not match actual timer '%s'. Force closing actual.\n", cp.tag_, timers_[actual_node].tag());
287 timers_[actual_node].stop(
true);
290 timers_[actual_node].stop(
false);
291 actual_node=timers_[actual_node].parent_timer;
299 timers_[actual_node].stop(
false);
300 actual_node=timers_[actual_node].parent_timer;
305 void Profiler::stop_timer(
int timer_index) {
306 if (timer_index <0) timer_index=actual_node;
309 if (! timers_[timer_index].running() )
return;
311 if ( timer_index != actual_node ) {
313 for(
unsigned int node=actual_node; node != 0; node=timers_[node].parent_timer)
314 if ( (
unsigned int)(timer_index) == node) {
316 for(; (
unsigned int)(actual_node) != node; actual_node=timers_[actual_node].parent_timer) {
317 xprintf(
Warn,
"Timer to close '%s' do not match actual timer '%s'. Force closing actual.\n", timers_[timer_index].tag(), timers_[actual_node].tag());
318 timers_[actual_node].stop(
true);
321 timers_[actual_node].stop(
false);
322 actual_node=timers_[actual_node].parent_timer;
330 timers_[actual_node].stop(
false);
331 actual_node=timers_[actual_node].parent_timer;
336 void Profiler::add_calls(
unsigned int n_calls) {
337 timers_[actual_node].call_count += n_calls-1;
343 timers_[actual_node].total_allocated_ += size;
349 timers_[actual_node].total_deallocated_ += size;
359 Timer &timer = timers_[timer_idx];
361 ASSERT( timer_idx >=0,
"Wrong timer index %d.\n", timer_idx);
362 ASSERT( timer.parent_timer >=0 ,
"Inconsistent tree.\n");
367 int call_count = timer.call_count;
372 double cumul_time = timer.cumulative_time() / 1000;
377 if (timer_idx == 0) parent_time = cumul_time_sum;
380 double percent = parent_time > 1.0e-10 ? cumul_time_sum / parent_time * 100.0 : 0.0;
381 string tree_info = string(2*indent,
' ') +
382 boost::str( boost::format(
"[%.1f] ") % percent )+
384 info.push_back( tree_info );
386 info.push_back( boost::str(boost::format(
"%i%s") % call_count % (call_count_min != call_count_max ?
"*" :
" ")) );
387 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_max) ) );
388 info.push_back( boost::str(boost::format(
"%.2f") % (cumul_time_min > 1.0e-10 ? cumul_time_max / cumul_time_min : 1)) );
389 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_sum / call_count_sum) ) );
390 info.push_back( boost::str( boost::format(
"%.2f") % (cumul_time_sum) ) );
391 info.push_back( timer.code_point_str() );
393 timers_info.push_back(info);
395 for (
unsigned int i = 0; i < Timer::max_n_childs; i++)
396 if (timer.child_timers[i] > 0)
397 add_timer_info(comm, timers_info, timer.child_timers[i], indent + 1, cumul_time_sum);
402 void Profiler::update_running_timers() {
403 for(
int node=actual_node; node !=0; node = timers_[node].parent_timer)
404 timers_[node].update();
412 const int column_space = 3;
416 update_running_timers();
420 ASSERT(ierr == 0,
"Error in MPI test of rank.");
425 timers_info[0].push_back(
"tag tree");
426 timers_info[0].push_back(
"calls");
427 timers_info[0].push_back(
"Tmax");
428 timers_info[0].push_back(
"max/min");
429 timers_info[0].push_back(
"T/calls");
430 timers_info[0].push_back(
"Ttotal");
431 timers_info[0].push_back(
"code_point");
433 add_timer_info(comm, timers_info, 0, 0, 0.0);
440 for (
unsigned int i = 0; i < timers_info.size(); i++)
441 for (
unsigned int j = 0; j < timers_info[i].size(); j++) width[j] = max( width[j] , (
unsigned int)timers_info[i][j].size() );
443 unsigned int common_length=timers_info[1].back().size();
444 for (
unsigned int i = 2; i < timers_info.size(); i++) {
445 common_length = min( common_length, (
unsigned int) timers_info[i].back().size() );
446 for (
unsigned int j = 0; j < common_length; j++ ) {
447 if (timers_info[1].back().at(j) != timers_info[i].back().at(j)) {
454 for (
unsigned int i = 1; i < timers_info.size(); i++) timers_info[i].back().erase(0, common_length);
460 time_t end_time = time(NULL);
462 const char format[] =
"%x %X";
463 char start_time_string[BUFSIZ] = {0};
464 strftime(start_time_string,
sizeof (start_time_string) - 1, format, localtime(&start_time));
466 char end_time_string[BUFSIZ] = {0};
467 strftime(end_time_string,
sizeof (end_time_string) - 1, format, localtime(&end_time));
471 os <<
"Program name: " << flow_name_ << endl
472 <<
"Program version: " << flow_version_ << endl
473 <<
"Program branch: " << flow_branch_ << endl
474 <<
"Program revision: " << flow_revision_ << endl
475 <<
"Program build: " << flow_build_ << endl << endl;
478 os <<
"Task description: " << task_description_ << endl
479 <<
"Task size: " << task_size_ << endl << endl;
482 os <<
"Run processes count: " << mpi_size << endl;
483 os <<
"Run started at: " << start_time_string << endl;
484 os <<
"Run finished at: " << end_time_string << endl;
486 os << setfill (
'-') << setw (80) <<
"" << endl;
490 for(
unsigned int j=0; j< timers_info[0].size(); j++)
491 os <<
left << setw(width[j]) << timers_info[0][j] << setw(column_space) <<
"";
494 os << setfill (
'-') << setw (80) <<
"" << endl;
497 for (
unsigned int i = 1; i < timers_info.size(); i++) {
498 for(
unsigned int j=0; j< timers_info[i].size(); j++) {
500 if (j==0 || j==timers_info[i].size()-1 ) os <<
left;
else os<<
right;
501 os << setw(width[j]) << timers_info[i][j] << setw(column_space) <<
"";
513 char filename[PATH_MAX];
514 strftime(filename,
sizeof (filename) - 1,
"profiler_info_%y.%m.%d_%H-%M-%S.log", localtime(&start_time));
518 ofstream os(full_fname.c_str());
528 ASSERT(
_instance->actual_node==0 ,
"Forbidden to uninitialize the Profiler when actual timer is not zero (but '%s').\n",
536 #else // def DEBUG_PROFILER
538 Profiler* Profiler::_instance = NULL;
552 #endif // def DEBUG_PROFILER
static int min(int *val, MPI_Comm comm)
static int sum(int *val, MPI_Comm comm)
void notify_free(const size_t size)
#define MPI_Reduce(sendbuf, recvbuf, count, datatype, op, root, comm)
static void uninitialize()
#define ASSERT_LESS(a, b)
static int max(int *val, MPI_Comm comm)
void set_program_info(string program_name, string program_version, string branch, string revision, string build)
Dedicated class for storing path to input and output files.
static Profiler * _instance
#define MPI_Barrier(comm)
void output(MPI_Comm comm, ostream &os)
void set_task_info(string description, int size)
void notify_malloc(const size_t size)