| [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: | 
|---|