source: ThirdParty/mpqc_open/src/lib/util/misc/regtime.cc

Candidate_v1.6.1
Last change on this file was 860145, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit '0b990dfaa8c6007a996d030163a25f7f5fc8a7e7' as 'ThirdParty/mpqc_open'

  • Property mode set to 100644
File size: 16.9 KB
Line 
1//
2// regtime.cc
3//
4// Copyright (C) 1996 Limit Point Systems, Inc.
5//
6// Author: Curtis Janssen <cljanss@limitpt.com>
7// Maintainer: LPS
8//
9// This file is part of the SC Toolkit.
10//
11// The SC Toolkit is free software; you can redistribute it and/or modify
12// it under the terms of the GNU Library General Public License as published by
13// the Free Software Foundation; either version 2, or (at your option)
14// any later version.
15//
16// The SC Toolkit is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Library General Public License for more details.
20//
21// You should have received a copy of the GNU Library General Public License
22// along with the SC Toolkit; see the file COPYING.LIB. If not, write to
23// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24//
25// The U.S. Government is granted a limited license as per AL 91-7.
26//
27
28#ifdef __GNUC__
29#pragma implementation
30#endif
31
32#ifdef HAVE_CONFIG_H
33# include <scconfig.h>
34#endif
35
36#include <stdexcept>
37
38#include <math.h>
39#include <iostream>
40#include <iomanip>
41
42// getrusage and gettimeofday don't exit under SUNMOS
43// so if NX is being used call dclock() instead.
44#ifdef HAVE_NX
45#include <nx.h>
46#define HAVE_WALL_TIME 1
47#define HAVE_CPU_TIME 0
48#else //HAVE_NX
49#include <time.h>
50#include <sys/types.h>
51#ifdef HAVE_SYS_TIME_H
52# include <sys/time.h>
53#endif
54#ifdef HAVE_SYS_TIMES_H
55# include <sys/times.h>
56#endif
57#ifdef HAVE_SYS_RESOURCE_H
58# include <sys/resource.h>
59#endif
60#ifdef HAVE_UNISTD_H
61# include <unistd.h>
62#endif
63#define HAVE_WALL_TIME 1
64#define HAVE_CPU_TIME 1
65#endif //HAVE_NX
66
67#ifdef HAVE_PERF
68# define HAVE_FLOPS 1
69#else
70# define HAVE_FLOPS 0
71#endif
72
73#if HAVE_FLOPS
74extern "C" {
75# include <perf.h>
76}
77#endif
78
79// AIX 3.2 has broken include files, likewise SunOS
80#if defined(_AIX32) || defined(__sun)
81extern "C" {
82int getrusage (
83 int Who,
84 struct rusage *RUsage); }
85#endif
86
87#include <util/keyval/keyval.h>
88#include <util/misc/regtime.h>
89#include <util/misc/timer.h>
90#include <util/class/scexception.h>
91
92using namespace std;
93using namespace sc;
94
95namespace sc {
96
97//////////////////////////////////////////////////////////////////////
98
99TimedRegion::TimedRegion(const char *name)
100{
101 name_ = strcpy(new char[strlen(name)+1], name);
102 flops_ = wall_time_ = cpu_time_ = 0.0;
103 up_ = 0;
104 subregions_ = 0;
105 next_ = prev_ = 0;
106}
107
108TimedRegion::~TimedRegion()
109{
110 delete[] name_;
111 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
112 delete subregions_;
113 delete next_;
114}
115
116int
117TimedRegion::nregion()
118{
119 int n = 1;
120 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
121 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
122 n += i->nregion();
123 }
124 return n;
125}
126
127void
128TimedRegion::get_region_names(const char *names[])
129{
130 names[0] = name();
131 int n = 1;
132 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
133 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
134 i->get_region_names(names + n);
135 n += i->nregion();
136 }
137}
138
139void
140TimedRegion::get_depth(int *depth, int current_depth)
141{
142 depth[0] = current_depth;
143 int n = 1;
144 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
145 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
146 i->get_depth(depth + n, current_depth + 1);
147 n += i->nregion();
148 }
149}
150
151void
152TimedRegion::get_wall_times(double *t)
153{
154 t[0] = wall_time_;
155 int n = 1;
156 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
157 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
158 i->get_wall_times(t + n);
159 n += i->nregion();
160 }
161}
162
163void
164TimedRegion::get_cpu_times(double *t)
165{
166 t[0] = cpu_time_;
167 int n = 1;
168 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
169 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
170 i->get_cpu_times(t + n);
171 n += i->nregion();
172 }
173}
174
175void
176TimedRegion::get_flops(double *t)
177{
178 t[0] = flops_;
179 int n = 1;
180 if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
181 for (TimedRegion *i = subregions_; i!=0; i=i->next_) {
182 i->get_flops(t + n);
183 n += i->nregion();
184 }
185}
186
187TimedRegion *
188TimedRegion::findinsubregion(const char *soughtname)
189{
190 if (!subregions_) {
191 subregions_ = new TimedRegion(soughtname);
192 subregions_->up_ = this;
193 return subregions_;
194 }
195 int cmp = strcmp(subregions_->name_, soughtname);
196 if (cmp < 0) {
197 do {
198 if (!subregions_->next_) {
199 return subregions_->insert_after(soughtname);
200 }
201 subregions_ = subregions_->next_;
202 } while ((cmp = strcmp(subregions_->name_, soughtname)) < 0);
203 if (cmp == 0) return subregions_;
204 subregions_ = subregions_->insert_before(soughtname);
205 }
206 else if (cmp > 0) {
207 do {
208 if (!subregions_->prev_) {
209 return subregions_->insert_before(soughtname);
210 }
211 subregions_ = subregions_->prev_;
212 } while ((cmp = strcmp(subregions_->name_, soughtname)) > 0);
213 if (cmp == 0) return subregions_;
214 subregions_ = subregions_->insert_after(soughtname);
215 }
216 return subregions_;
217}
218
219TimedRegion *
220TimedRegion::insert_after(const char *name)
221{
222 TimedRegion *res = new TimedRegion(name);
223 res->prev_ = this;
224 res->next_ = this->next_;
225 if (res->next_) res->next_->prev_ = res;
226 res->up_ = up_;
227 this->next_ = res;
228 return res;
229}
230
231TimedRegion *
232TimedRegion::insert_before(const char *name)
233{
234 TimedRegion *res = new TimedRegion(name);
235 res->next_ = this;
236 res->prev_ = this->prev_;
237 if (res->prev_) res->prev_->next_ = res;
238 res->up_ = up_;
239 this->prev_ = res;
240 return res;
241}
242
243void
244TimedRegion::cpu_enter(double t)
245{
246 cpu_enter_ = t;
247}
248
249void
250TimedRegion::wall_enter(double t)
251{
252 wall_enter_ = t;
253}
254
255void
256TimedRegion::flops_enter(double f)
257{
258 flops_enter_ = f;
259}
260
261void
262TimedRegion::cpu_exit(double t)
263{
264 cpu_time_ += t - cpu_enter_;
265 cpu_enter_ = t;
266}
267
268void
269TimedRegion::wall_exit(double t)
270{
271 wall_time_ += t - wall_enter_;
272 wall_enter_ = t;
273}
274
275void
276TimedRegion::flops_exit(double f)
277{
278 flops_ += f - flops_enter_;
279 flops_enter_ = f;
280}
281
282//////////////////////////////////////////////////////////////////////
283
284static ClassDesc RegionTimer_cd(
285 typeid(RegionTimer),"RegionTimer",1,"public DescribedClass");
286
287RegionTimer::RegionTimer(const Ref<KeyVal> &keyval)
288{
289 KeyValValueboolean yes(1);
290 KeyValValueboolean no(0);
291 KeyValValuepchar defname("total");
292
293 wall_time_ = keyval->booleanvalue("wall_time",yes);
294 cpu_time_ = keyval->booleanvalue("cpu_time",yes);
295 flops_ = keyval->booleanvalue("flops",no);
296
297#if !HAVE_CPU_TIME
298 cpu_time_ = 0;
299#endif
300#if !HAVE_WALL_TIME
301 wall_time_ = 0;
302#endif
303#if !HAVE_FLOPS
304 flops_ = 0;
305#endif
306
307#if HAVE_FLOPS
308 if (flops_) {
309 if (perf_reset() || perf_set_config(0, PERF_FLOPS) || perf_start())
310 flops_ = 0;
311 }
312#endif
313
314 char *topname = keyval->pcharvalue("name", defname);
315 top_ = new TimedRegion(topname);
316 if (cpu_time_) top_->cpu_enter(get_cpu_time());
317 if (wall_time_) top_->wall_enter(get_wall_time());
318 if (flops_) top_->flops_enter(get_flops());
319 current_ = top_;
320}
321
322RegionTimer::RegionTimer(const char *topname, int cpu_time, int wall_time):
323 wall_time_(0),
324 cpu_time_(0),
325 flops_(0),
326 default_(0)
327{
328#if HAVE_CPU_TIME
329 cpu_time_ = cpu_time;
330#endif
331#if HAVE_WALL_TIME
332 wall_time_ = wall_time;
333#endif
334 top_ = new TimedRegion(topname);
335 if (cpu_time_) top_->cpu_enter(get_cpu_time());
336 if (wall_time_) top_->wall_enter(get_wall_time());
337 if (flops_) top_->flops_enter(get_flops());
338 current_ = top_;
339}
340
341RegionTimer::~RegionTimer()
342{
343 delete top_;
344}
345
346double
347RegionTimer::get_cpu_time() const
348{
349#if defined(HAVE_NX)
350 return 0.0;
351#endif
352 double res;
353 struct rusage r;
354 getrusage(RUSAGE_SELF,&r);
355 res = r.ru_utime.tv_sec + r.ru_stime.tv_sec;
356 res += 0.000001 * ( r.ru_utime.tv_usec + r.ru_stime.tv_usec );
357 return res;
358}
359
360double
361RegionTimer::get_wall_time() const
362{
363#if defined(HAVE_NX)
364 return dclock();
365#endif
366 struct timeval tod;
367 gettimeofday(&tod,0);
368 return tod.tv_sec + 0.000001 * tod.tv_usec;
369}
370
371double
372RegionTimer::get_flops() const
373{
374#if !HAVE_FLOPS
375 return 0.0;
376#else
377 unsigned long long counter;
378 perf_read(0,&counter);
379 return (double)counter;
380#endif
381}
382
383void
384RegionTimer::enter(const char *name)
385{
386 current_ = current_->findinsubregion(name);
387 if (cpu_time_) current_->cpu_enter(get_cpu_time());
388 if (wall_time_) current_->wall_enter(get_wall_time());
389 if (flops_) current_->flops_enter(get_flops());
390}
391
392void
393RegionTimer::exit(const char *name, bool do_not_throw)
394{
395 if (!current_ || (name && strcmp(name, current_->name()))) {
396 if (do_not_throw) {
397 // we have an error but cannot throw. ignore this call
398 return;
399 }
400 else {
401 throw ProgrammingError("region mismatch",
402 __FILE__, __LINE__, this->class_desc());
403 }
404 }
405 if (cpu_time_) current_->cpu_exit(get_cpu_time());
406 if (wall_time_) current_->wall_exit(get_wall_time());
407 if (flops_) current_->flops_exit(get_flops());
408 if (! current_->up()) {
409 if (do_not_throw) {
410 // we have an error but cannot throw. ignore this call
411 return;
412 }
413 else {
414 throw ProgrammingError("tried to exit top level",
415 __FILE__, __LINE__, this->class_desc());
416 }
417 }
418 current_ = current_->up();
419}
420
421void
422RegionTimer::add_wall_time(const char *name, double t)
423{
424 if (wall_time_) {
425 current_ = current_->findinsubregion(name);
426 current_->wall_add(t);
427 current_ = current_->up();
428 }
429}
430
431void
432RegionTimer::add_cpu_time(const char *name, double t)
433{
434 if (cpu_time_) {
435 current_ = current_->findinsubregion(name);
436 current_->cpu_add(t);
437 current_ = current_->up();
438 }
439}
440
441void
442RegionTimer::add_flops(const char *name, double t)
443{
444 if (flops_) {
445 current_ = current_->findinsubregion(name);
446 current_->flops_add(t);
447 current_ = current_->up();
448 }
449}
450
451
452void
453RegionTimer::enter_default()
454{
455 if (cpu_time_) default_->cpu_enter(get_cpu_time());
456 if (wall_time_) default_->wall_enter(get_wall_time());
457 if (flops_) default_->flops_enter(get_flops());
458}
459
460void
461RegionTimer::exit_default()
462{
463 if (cpu_time_) default_->cpu_exit(get_cpu_time());
464 if (wall_time_) default_->wall_exit(get_wall_time());
465 if (flops_) default_->flops_exit(get_flops());
466}
467
468void
469RegionTimer::set_default(const char *name)
470{
471 default_ = current_->findinsubregion(name);
472}
473
474void
475RegionTimer::unset_default()
476{
477 default_ = 0;
478}
479
480void
481RegionTimer::change(const char *newname, const char *oldname)
482{
483 if (!current_ || (oldname && strcmp(oldname, current_->name()))) {
484 ExEnv::errn() << "RegionTimer::change("
485 << "\"" << newname << "\","
486 << "\"" << oldname << "\""
487 << "):"
488 << " current region"
489 << " (\"" << current_->name() << "\")"
490 << " doesn't match name"
491 << endl;
492 abort();
493 }
494 double cpu=0.0, wall=0.0, flops=0.0;
495 if (cpu_time_) current_->cpu_exit(cpu = get_cpu_time());
496 if (wall_time_) current_->wall_exit(wall = get_wall_time());
497 if (flops_) current_->flops_exit(flops = get_flops());
498 if (! current_->up()) {
499 ExEnv::errn() << "RegionTimer::change: already at top level" << endl;
500 abort();
501 }
502 current_ = current_->up();
503 current_ = current_->findinsubregion(newname);
504 if (cpu_time_) current_->cpu_enter(cpu);
505 if (wall_time_) current_->wall_enter(wall);
506 if (flops_) current_->flops_enter(flops);
507}
508
509int
510RegionTimer::nregion() const
511{
512 return top_->nregion();
513}
514
515void
516RegionTimer::get_region_names(const char *region_names[]) const
517{
518 top_->get_region_names(region_names);
519}
520
521void
522RegionTimer::get_cpu_times(double *cpu_time) const
523{
524 top_->get_cpu_times(cpu_time);
525}
526
527void
528RegionTimer::get_wall_times(double *wall_time) const
529{
530 top_->get_wall_times(wall_time);
531}
532
533void
534RegionTimer::get_flops(double *flops) const
535{
536 top_->get_flops(flops);
537}
538
539void
540RegionTimer::get_depth(int *depth) const
541{
542 top_->get_depth(depth);
543}
544
545void
546RegionTimer::update_top() const
547{
548 if (cpu_time_) top_->cpu_exit(get_cpu_time());
549 if (wall_time_) top_->wall_exit(get_wall_time());
550 if (flops_) top_->flops_exit(get_flops());
551}
552
553void
554RegionTimer::print(ostream& o) const
555{
556 update_top();
557
558 int n = nregion();
559 double *cpu_time = 0;
560 double *wall_time = 0;
561 double *flops = 0;
562 const char *flops_name = 0;
563 if (cpu_time_) {
564 cpu_time = new double[n];
565 get_cpu_times(cpu_time);
566 }
567 if (wall_time_) {
568 wall_time = new double[n];
569 get_wall_times(wall_time);
570 }
571 if (flops_) {
572 flops = new double[n];
573 get_flops(flops);
574 if (cpu_time_) {
575 for (int i=0; i<n; i++) {
576 if (fabs(cpu_time[i]) > 1.0e-10) flops[i] /= cpu_time[i]*1000000.;
577 else flops[i] = 0.0;
578 }
579 flops_name = "MFLOP/S";
580 }
581 else if (wall_time_) {
582 for (int i=0; i<n; i++) {
583 if (fabs(wall_time[i]) > 1.0e-10) flops[i] /= wall_time[i]*1000000.;
584 else flops[i] = 0.0;
585 }
586 flops_name = "MFLOP/WS";
587 }
588 else {
589 for (int i=0; i<n; i++) {
590 flops[i] /= 1000000.;
591 }
592 flops_name = "mflops";
593 }
594 }
595 const char **names = new const char*[n];
596 get_region_names(names);
597 int *depth = new int[n];
598 get_depth(depth);
599
600 int i,j;
601 int maxwidth = 0;
602 double maxcputime = 0.0;
603 double maxwalltime = 0.0;
604 double maxflops = 0.0;
605 for (i=0; i<n; i++) {
606 int width = strlen(names[i]) + 2 * depth[i] + 2;
607 if (width > maxwidth) maxwidth = width;
608 if (cpu_time_ && cpu_time[i] > maxcputime) maxcputime = cpu_time[i];
609 if (wall_time_ && wall_time[i] > maxwalltime) maxwalltime = wall_time[i];
610 if (flops_ && flops[i] > maxflops) maxflops = flops[i];
611 }
612
613 size_t maxwallwidth = 4;
614 while (maxwalltime >= 10.0) { maxwalltime/=10.0; maxwallwidth++; }
615
616 size_t maxcpuwidth = 4;
617 while (maxcputime >= 10.0) { maxcputime/=10.0; maxcpuwidth++; }
618
619 size_t maxflopswidth = 4;
620 if (flops_) {
621 while (maxflops >= 10.0) { maxflops/=10.0; maxflopswidth++; }
622 if (maxflopswidth < strlen(flops_name)) maxflopswidth = strlen(flops_name);
623 }
624
625 o.setf(ios::right);
626 for (i=0; i<maxwidth; i++) o << " ";
627 if (cpu_time_) o << " " << setw(maxcpuwidth) << "CPU";
628 if (wall_time_) o << " " << setw(maxwallwidth) << "Wall";
629 if (flops_) o << " " << setw(maxflopswidth) << flops_name;
630 o << endl;
631
632 o.setf(ios::fixed);
633 o.precision(2);
634 for (i=0; i<n; i++) {
635 int width = strlen(names[i]) + 2 * depth[i] + 2;
636 for (j=0; j<depth[i]; j++) o << " ";
637 o << names[i] << ": ";
638 for (j=width; j<maxwidth; j++) o << " ";
639 if (cpu_time_) {
640 o << " " << setw(maxcpuwidth) << cpu_time[i];
641 }
642 if (wall_time_) {
643 o << " " << setw(maxwallwidth) << wall_time[i];
644 }
645 if (flops_) {
646 o << " " << setw(maxflopswidth) << flops[i];
647 }
648 o << endl;
649 }
650
651 delete[] cpu_time;
652 delete[] wall_time;
653 delete[] flops;
654 delete[] names;
655 delete[] depth;
656}
657
658static Ref<RegionTimer> default_regtimer;
659
660RegionTimer *
661RegionTimer::default_regiontimer()
662{
663 return default_regtimer.pointer();
664}
665
666void
667RegionTimer::set_default_regiontimer(const Ref<RegionTimer>& t)
668{
669 default_regtimer = t;
670}
671
672//////////////////////////////////////////////////////////////////////
673// Timer functions
674
675Timer::Timer(const char *name):
676 active_(false)
677{
678 timer_ = RegionTimer::default_regiontimer();
679 if (timer_.nonnull() && name != 0) {
680 name_ = name;
681 timer_->enter(name);
682 active_ = true;
683 }
684}
685
686Timer::Timer(const Ref<RegionTimer>&t, const char *name):
687 active_(false),
688 timer_(t)
689{
690 if (timer_.nonnull() && name != 0) {
691 name_ = name;
692 timer_->enter(name);
693 active_ = true;
694 }
695}
696
697Timer::~Timer()
698{
699 if (active_) {
700 timer_->exit(name_.c_str(), true);
701 }
702}
703
704void
705Timer::reset(const char *name)
706{
707 if (active_) {
708 timer_->exit(name_.c_str());
709 active_ = false;
710 }
711 if (timer_.nonnull() && name) {
712 timer_->enter(name);
713 name_ = name;
714 active_ = true;
715 }
716}
717
718//////////////////////////////////////////////////////////////////////
719// Shorthand to manipulate the global region timer
720
721void
722tim_enter(const char *name) {
723 if (default_regtimer.nonnull()) default_regtimer->enter(name);
724}
725
726void
727tim_exit(const char *name)
728{
729 if (default_regtimer.nonnull()) default_regtimer->exit(name);
730}
731
732void
733tim_set_default(const char *name)
734{
735 if (default_regtimer.nonnull()) default_regtimer->set_default(name);
736}
737
738void
739tim_enter_default()
740{
741 if (default_regtimer.nonnull()) default_regtimer->enter_default();
742}
743
744void
745tim_exit_default()
746{
747 if (default_regtimer.nonnull()) default_regtimer->exit_default();
748}
749
750void
751tim_change(const char *name)
752{
753 if (default_regtimer.nonnull()) default_regtimer->change(name);
754}
755
756void
757tim_print(int)
758{
759 if (default_regtimer.nonnull()) default_regtimer->print();
760}
761
762}
763
764/////////////////////////////////////////////////////////////////////////////
765
766// Local Variables:
767// mode: c++
768// c-file-style: "CLJ"
769// End:
Note: See TracBrowser for help on using the repository browser.