1 /************************************************************
2 * HMMER - Biological sequence analysis with profile HMMs
3 * Copyright (C) 1992-1999 Washington University School of Medicine
6 * This source code is distributed under the terms of the
7 * GNU General Public License. See the files COPYING and LICENSE
9 ************************************************************/
12 * SRE, Fri Nov 26 14:54:21 1999 [St. Louis] [HMMER]
13 * SRE, Thu Aug 3 08:11:52 2000 [St. Louis] [moved to SQUID]
15 * Reporting of cpu/system/elapsed time used by a process.
16 * thanks to Warren Gish for assistance.
21 * w = StopwatchCreate();
26 * StopwatchDisplay(stdout, "CPU time: ", w);
30 * Some behavior can be controlled at compile time by #define's:
32 * SRE_STRICT_ANSI: By default, stopwatch module assumes that a
33 * machine is POSIX-compliant (e.g. has struct tms, sys/times.h,
34 * and times()). If compiled with -DSRE_STRICT_ANSI, reverts to
35 * pure ANSI C conformant implementation. This simpler system
36 * won't report system times, only user and elapsed times.
38 * SRE_ENABLE_PVM: If compiled with -DSRE_ENABLE_PVM, the
39 * functions StopwatchPVMPack() and StopwatchPVMUnpack()
40 * are compiled, providing PVM communications ability.
42 * One additional compile-time configuration note:
43 * PTHREAD_TIMES_HACK: Linux pthreads, as of RH6.0/glibc-devel-2.1.1-6,
44 * appears to interact poorly with times() -- usage times in all
45 * but the master thread are lost. A workaround for this bug is
46 * to run stopwatches in each worker thread, and accumulate those
47 * times back into the master stopwatch using StopwatchInclude().
48 * (Just like a PVM implementation has to do.) In HMMER, this
49 * behavior is compiled in with -DPTHREAD_TIMES_HACK. No
50 * changes are made in stopwatch functions themselves, though;
51 * all the extra code is HMMER code. See hmmcalibrate.c for
54 * See hmmcalibrate.c for examples of more complex usage
55 * in dealing with pthreads and PVM.
65 #include "stopwatch.h"
67 /* Function: format_time_string()
68 * Date: SRE, Fri Nov 26 15:06:28 1999 [St. Louis]
70 * Purpose: Given a number of seconds, format into
71 * hh:mm:ss.xx in a provided buffer.
73 * Args: buf - allocated space (128 is plenty!)
74 * sec - number of seconds
75 * do_frac - TRUE (1) to include hundredths of a sec
78 format_time_string(char *buf, double sec, int do_frac)
82 h = (int) (sec / 3600.);
83 m = (int) (sec / 60.) - h * 60;
84 s = (int) (sec) - h * 3600 - m * 60;
86 hs = (int) (sec * 100.) - h * 360000 - m * 6000 - s * 100;
87 sprintf(buf, "%02d:%02d:%02d.%02d", h,m,s,hs);
89 sprintf(buf, "%02d:%02d:%02d", h,m,s);
93 /* Function: StopwatchStart()
94 * Date: SRE, Fri Nov 26 15:07:48 1999 [St. Louis]
96 * Purpose: Start a stopwatch.
101 StopwatchStart(Stopwatch_t *w)
104 #ifdef SRE_STRICT_ANSI
107 (void) times(&(w->cpu0));
115 /* Function: StopwatchStop()
116 * Date: SRE, Fri Nov 26 15:08:16 1999 [St. Louis]
118 * Purpose: Stop a stopwatch.
120 * The implementation allows "split times":
121 * you can stop a watch multiple times, reporting
122 * times at multiple points during program
125 * Args: w - the watch
128 StopwatchStop(Stopwatch_t *w)
131 #ifdef SRE_STRICT_ANSI
139 w->elapsed = difftime(t1, w->t0);
141 #ifdef SRE_STRICT_ANSI
143 w->user = (double) (cpu1- w->cpu0) / (double) CLOCKS_PER_SEC;
144 w->sys = 0.; /* no way to portably get system time in ANSI C */
146 #else /* assume we're on a POSIX system by default */
149 clk_tck = sysconf(_SC_CLK_TCK);
150 w->user = (double) (cpu1.tms_utime + cpu1.tms_cutime -
151 w->cpu0.tms_utime - w->cpu0.tms_cutime) /
154 w->sys = (double) (cpu1.tms_stime + cpu1.tms_cstime -
155 w->cpu0.tms_stime - w->cpu0.tms_cstime) /
160 /* Function: StopwatchInclude()
161 * Date: SRE, Fri Nov 26 15:09:34 1999 [St. Louis]
163 * Purpose: Merge the cpu and system times from a slave into
164 * a master stopwatch. Both watches must be
165 * stopped, and should not be stopped again unless
166 * You Know What You're Doing.
168 * Elapsed time is *not* merged; master is assumed
169 * to be keeping track of the wall clock time,
170 * and the slave/worker watch is ignored.
173 * 1) PVM; merge in the stopwatch(es) from separate
174 * process(es) in a cluster.
175 * 2) Threads, for broken pthreads/times() implementations
176 * that lose track of cpu times used by spawned
179 * Args: w1 - the master stopwatch
180 * w2 - the slave/worker watch
184 StopwatchInclude(Stopwatch_t *w1, Stopwatch_t *w2)
186 w1->user += w2->user;
190 /* Function: StopwatchAlloc(), StopwatchZero(), StopwatchCopy(),
192 * Date: SRE, Fri Nov 26 15:13:14 1999 [St. Louis]
194 * Purpose: The usual creation/manipulation/destruction routines
195 * for a stopwatch object.
198 StopwatchCreate(void)
201 w = malloc(sizeof(Stopwatch_t));
205 StopwatchZero(Stopwatch_t *w)
212 StopwatchCopy(Stopwatch_t *w1, Stopwatch_t *w2)
215 #ifdef SRE_STRICT_ANSI
218 w1->cpu0.tms_utime = w2->cpu0.tms_utime;
219 w1->cpu0.tms_stime = w2->cpu0.tms_stime;
220 w1->cpu0.tms_cutime = w2->cpu0.tms_cutime;
221 w1->cpu0.tms_cstime = w2->cpu0.tms_cstime;
223 w1->elapsed = w2->elapsed;
228 StopwatchFree(Stopwatch_t *w)
234 /* Function: StopwatchDisplay()
235 * Date: SRE, Fri Nov 26 15:14:12 1999 [St. Louis]
237 * Purpose: Output a usage summary line from a *stopped*
238 * stopwatch (the times will reflect the last
239 * time StopwatchStop() was called.)
241 * For s = "CPU Time: " an example output line is:
242 * CPU Time: 142.55u 7.17s 149.72 Elapsed: 00:02:35.00
244 * Args: fp - open file for writing (stdout, possibly)
245 * s - prefix for the report line
246 * w - a (recently stopped) stopwatch
250 StopwatchDisplay(FILE *fp, char *s, Stopwatch_t *w)
252 char buf[128]; /* (safely holds up to 10^14 years) */
255 fputs("CPU Time: ", fp);
259 format_time_string(buf, w->user+w->sys, 1);
260 #ifdef SRE_STRICT_ANSI
261 fprintf(fp, "%.2fu %s ", w->user, buf);
263 fprintf(fp, "%.2fu %.2fs %s ", w->user, w->sys, buf);
266 format_time_string(buf, w->elapsed, 0);
267 fprintf(fp, "Elapsed: %s\n", buf);
270 #ifdef SRE_ENABLE_PVM
271 /* Function: StopwatchPVMPack(), StopwatchPVMUnpack()
272 * Date: SRE, Fri Nov 26 15:22:04 1999 [St. Louis]
274 * Purpose: Transmission of stopwatch data in a PVM
278 StopwatchPVMPack(Stopwatch_t *w)
280 pvm_pkdouble(&(w->elapsed), 1, 1);
281 pvm_pkdouble(&(w->user), 1, 1);
282 pvm_pkdouble(&(w->sys), 1, 1);
285 StopwatchPVMUnpack(Stopwatch_t *w)
287 pvm_upkdouble(&(w->elapsed), 1, 1);
288 pvm_upkdouble(&(w->user), 1, 1);
289 pvm_upkdouble(&(w->sys), 1, 1);
291 #endif /*SRE_ENABLE_PVM*/
296 main(int argc, char **argv)
298 Stopwatch_t stopwatch;
300 StopwatchStart(&stopwatch);
304 StopwatchStop(&stopwatch);
305 StopwatchDisplay(stdout, "CPU Time: ", &stopwatch);