[0b990d] | 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
|
---|
| 74 | extern "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)
|
---|
| 81 | extern "C" {
|
---|
| 82 | int 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 |
|
---|
| 92 | using namespace std;
|
---|
| 93 | using namespace sc;
|
---|
| 94 |
|
---|
| 95 | namespace sc {
|
---|
| 96 |
|
---|
| 97 | //////////////////////////////////////////////////////////////////////
|
---|
| 98 |
|
---|
| 99 | TimedRegion::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 |
|
---|
| 108 | TimedRegion::~TimedRegion()
|
---|
| 109 | {
|
---|
| 110 | delete[] name_;
|
---|
| 111 | if (subregions_) while (subregions_->prev_) subregions_ = subregions_->prev_;
|
---|
| 112 | delete subregions_;
|
---|
| 113 | delete next_;
|
---|
| 114 | }
|
---|
| 115 |
|
---|
| 116 | int
|
---|
| 117 | TimedRegion::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 |
|
---|
| 127 | void
|
---|
| 128 | TimedRegion::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 |
|
---|
| 139 | void
|
---|
| 140 | TimedRegion::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 |
|
---|
| 151 | void
|
---|
| 152 | TimedRegion::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 |
|
---|
| 163 | void
|
---|
| 164 | TimedRegion::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 |
|
---|
| 175 | void
|
---|
| 176 | TimedRegion::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 |
|
---|
| 187 | TimedRegion *
|
---|
| 188 | TimedRegion::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 |
|
---|
| 219 | TimedRegion *
|
---|
| 220 | TimedRegion::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 |
|
---|
| 231 | TimedRegion *
|
---|
| 232 | TimedRegion::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 |
|
---|
| 243 | void
|
---|
| 244 | TimedRegion::cpu_enter(double t)
|
---|
| 245 | {
|
---|
| 246 | cpu_enter_ = t;
|
---|
| 247 | }
|
---|
| 248 |
|
---|
| 249 | void
|
---|
| 250 | TimedRegion::wall_enter(double t)
|
---|
| 251 | {
|
---|
| 252 | wall_enter_ = t;
|
---|
| 253 | }
|
---|
| 254 |
|
---|
| 255 | void
|
---|
| 256 | TimedRegion::flops_enter(double f)
|
---|
| 257 | {
|
---|
| 258 | flops_enter_ = f;
|
---|
| 259 | }
|
---|
| 260 |
|
---|
| 261 | void
|
---|
| 262 | TimedRegion::cpu_exit(double t)
|
---|
| 263 | {
|
---|
| 264 | cpu_time_ += t - cpu_enter_;
|
---|
| 265 | cpu_enter_ = t;
|
---|
| 266 | }
|
---|
| 267 |
|
---|
| 268 | void
|
---|
| 269 | TimedRegion::wall_exit(double t)
|
---|
| 270 | {
|
---|
| 271 | wall_time_ += t - wall_enter_;
|
---|
| 272 | wall_enter_ = t;
|
---|
| 273 | }
|
---|
| 274 |
|
---|
| 275 | void
|
---|
| 276 | TimedRegion::flops_exit(double f)
|
---|
| 277 | {
|
---|
| 278 | flops_ += f - flops_enter_;
|
---|
| 279 | flops_enter_ = f;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 | //////////////////////////////////////////////////////////////////////
|
---|
| 283 |
|
---|
| 284 | static ClassDesc RegionTimer_cd(
|
---|
| 285 | typeid(RegionTimer),"RegionTimer",1,"public DescribedClass");
|
---|
| 286 |
|
---|
| 287 | RegionTimer::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 |
|
---|
| 322 | RegionTimer::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 |
|
---|
| 341 | RegionTimer::~RegionTimer()
|
---|
| 342 | {
|
---|
| 343 | delete top_;
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | double
|
---|
| 347 | RegionTimer::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 |
|
---|
| 360 | double
|
---|
| 361 | RegionTimer::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 |
|
---|
| 371 | double
|
---|
| 372 | RegionTimer::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 |
|
---|
| 383 | void
|
---|
| 384 | RegionTimer::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 |
|
---|
| 392 | void
|
---|
| 393 | RegionTimer::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 |
|
---|
| 421 | void
|
---|
| 422 | RegionTimer::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 |
|
---|
| 431 | void
|
---|
| 432 | RegionTimer::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 |
|
---|
| 441 | void
|
---|
| 442 | RegionTimer::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 |
|
---|
| 452 | void
|
---|
| 453 | RegionTimer::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 |
|
---|
| 460 | void
|
---|
| 461 | RegionTimer::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 |
|
---|
| 468 | void
|
---|
| 469 | RegionTimer::set_default(const char *name)
|
---|
| 470 | {
|
---|
| 471 | default_ = current_->findinsubregion(name);
|
---|
| 472 | }
|
---|
| 473 |
|
---|
| 474 | void
|
---|
| 475 | RegionTimer::unset_default()
|
---|
| 476 | {
|
---|
| 477 | default_ = 0;
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | void
|
---|
| 481 | RegionTimer::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 |
|
---|
| 509 | int
|
---|
| 510 | RegionTimer::nregion() const
|
---|
| 511 | {
|
---|
| 512 | return top_->nregion();
|
---|
| 513 | }
|
---|
| 514 |
|
---|
| 515 | void
|
---|
| 516 | RegionTimer::get_region_names(const char *region_names[]) const
|
---|
| 517 | {
|
---|
| 518 | top_->get_region_names(region_names);
|
---|
| 519 | }
|
---|
| 520 |
|
---|
| 521 | void
|
---|
| 522 | RegionTimer::get_cpu_times(double *cpu_time) const
|
---|
| 523 | {
|
---|
| 524 | top_->get_cpu_times(cpu_time);
|
---|
| 525 | }
|
---|
| 526 |
|
---|
| 527 | void
|
---|
| 528 | RegionTimer::get_wall_times(double *wall_time) const
|
---|
| 529 | {
|
---|
| 530 | top_->get_wall_times(wall_time);
|
---|
| 531 | }
|
---|
| 532 |
|
---|
| 533 | void
|
---|
| 534 | RegionTimer::get_flops(double *flops) const
|
---|
| 535 | {
|
---|
| 536 | top_->get_flops(flops);
|
---|
| 537 | }
|
---|
| 538 |
|
---|
| 539 | void
|
---|
| 540 | RegionTimer::get_depth(int *depth) const
|
---|
| 541 | {
|
---|
| 542 | top_->get_depth(depth);
|
---|
| 543 | }
|
---|
| 544 |
|
---|
| 545 | void
|
---|
| 546 | RegionTimer::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 |
|
---|
| 553 | void
|
---|
| 554 | RegionTimer::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 |
|
---|
| 658 | static Ref<RegionTimer> default_regtimer;
|
---|
| 659 |
|
---|
| 660 | RegionTimer *
|
---|
| 661 | RegionTimer::default_regiontimer()
|
---|
| 662 | {
|
---|
| 663 | return default_regtimer.pointer();
|
---|
| 664 | }
|
---|
| 665 |
|
---|
| 666 | void
|
---|
| 667 | RegionTimer::set_default_regiontimer(const Ref<RegionTimer>& t)
|
---|
| 668 | {
|
---|
| 669 | default_regtimer = t;
|
---|
| 670 | }
|
---|
| 671 |
|
---|
| 672 | //////////////////////////////////////////////////////////////////////
|
---|
| 673 | // Timer functions
|
---|
| 674 |
|
---|
| 675 | Timer::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 |
|
---|
| 686 | Timer::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 |
|
---|
| 697 | Timer::~Timer()
|
---|
| 698 | {
|
---|
| 699 | if (active_) {
|
---|
| 700 | timer_->exit(name_.c_str(), true);
|
---|
| 701 | }
|
---|
| 702 | }
|
---|
| 703 |
|
---|
| 704 | void
|
---|
| 705 | Timer::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 |
|
---|
| 721 | void
|
---|
| 722 | tim_enter(const char *name) {
|
---|
| 723 | if (default_regtimer.nonnull()) default_regtimer->enter(name);
|
---|
| 724 | }
|
---|
| 725 |
|
---|
| 726 | void
|
---|
| 727 | tim_exit(const char *name)
|
---|
| 728 | {
|
---|
| 729 | if (default_regtimer.nonnull()) default_regtimer->exit(name);
|
---|
| 730 | }
|
---|
| 731 |
|
---|
| 732 | void
|
---|
| 733 | tim_set_default(const char *name)
|
---|
| 734 | {
|
---|
| 735 | if (default_regtimer.nonnull()) default_regtimer->set_default(name);
|
---|
| 736 | }
|
---|
| 737 |
|
---|
| 738 | void
|
---|
| 739 | tim_enter_default()
|
---|
| 740 | {
|
---|
| 741 | if (default_regtimer.nonnull()) default_regtimer->enter_default();
|
---|
| 742 | }
|
---|
| 743 |
|
---|
| 744 | void
|
---|
| 745 | tim_exit_default()
|
---|
| 746 | {
|
---|
| 747 | if (default_regtimer.nonnull()) default_regtimer->exit_default();
|
---|
| 748 | }
|
---|
| 749 |
|
---|
| 750 | void
|
---|
| 751 | tim_change(const char *name)
|
---|
| 752 | {
|
---|
| 753 | if (default_regtimer.nonnull()) default_regtimer->change(name);
|
---|
| 754 | }
|
---|
| 755 |
|
---|
| 756 | void
|
---|
| 757 | tim_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:
|
---|