1 /************************************************************
2 * SQUID - a library of functions for biological sequence analysis
3 * Copyright (C) 1992-2002 Washington University School of Medicine
5 * This source code is freely distributed under the terms of the
6 * GNU General Public License. See the files COPYRIGHT and LICENSE
8 ************************************************************/
11 * SRE, Fri Nov 26 14:54:21 1999 [St. Louis] [HMMER]
12 * SRE, Thu Aug 3 08:11:52 2000 [St. Louis] [moved to SQUID]
14 * Reporting of cpu/system/elapsed time used by a process.
15 * thanks to Warren Gish for assistance.
20 * w = StopwatchCreate();
25 * StopwatchDisplay(stdout, "CPU time: ", w);
29 * Some behavior can be controlled at compile time by #define's:
31 * SRE_STRICT_ANSI: By default, stopwatch module assumes that a
32 * machine is POSIX-compliant (e.g. has struct tms, sys/times.h,
33 * and times()). If compiled with -DSRE_STRICT_ANSI, reverts to
34 * pure ANSI C conformant implementation. This simpler system
35 * won't report system times, only user and elapsed times.
37 * SRE_ENABLE_PVM: If compiled with -DSRE_ENABLE_PVM, the
38 * functions StopwatchPVMPack() and StopwatchPVMUnpack()
39 * are compiled, providing PVM communications ability.
41 * One additional compile-time configuration note:
42 * PTHREAD_TIMES_HACK: Linux pthreads, as of RH6.0/glibc-devel-2.1.1-6,
43 * appears to interact poorly with times() -- usage times in all
44 * but the master thread are lost. A workaround for this bug is
45 * to run stopwatches in each worker thread, and accumulate those
46 * times back into the master stopwatch using StopwatchInclude().
47 * (Just like a PVM implementation has to do.) In HMMER, this
48 * behavior is compiled in with -DPTHREAD_TIMES_HACK. No
49 * changes are made in stopwatch functions themselves, though;
50 * all the extra code is HMMER code. See hmmcalibrate.c for
53 * See hmmcalibrate.c for examples of more complex usage
54 * in dealing with pthreads and PVM.
64 #include "stopwatch.h"
66 /* Function: format_time_string()
67 * Date: SRE, Fri Nov 26 15:06:28 1999 [St. Louis]
69 * Purpose: Given a number of seconds, format into
70 * hh:mm:ss.xx in a provided buffer.
72 * Args: buf - allocated space (128 is plenty!)
73 * sec - number of seconds
74 * do_frac - TRUE (1) to include hundredths of a sec
77 format_time_string(char *buf, double sec, int do_frac)
81 h = (int) (sec / 3600.);
82 m = (int) (sec / 60.) - h * 60;
83 s = (int) (sec) - h * 3600 - m * 60;
85 hs = (int) (sec * 100.) - h * 360000 - m * 6000 - s * 100;
86 sprintf(buf, "%02d:%02d:%02d.%02d", h,m,s,hs);
88 sprintf(buf, "%02d:%02d:%02d", h,m,s);
92 /* Function: StopwatchStart()
93 * Date: SRE, Fri Nov 26 15:07:48 1999 [St. Louis]
95 * Purpose: Start a stopwatch.
100 StopwatchStart(Stopwatch_t *w)
103 #ifdef SRE_STRICT_ANSI
106 (void) times(&(w->cpu0));
114 /* Function: StopwatchStop()
115 * Date: SRE, Fri Nov 26 15:08:16 1999 [St. Louis]
117 * Purpose: Stop a stopwatch.
119 * The implementation allows "split times":
120 * you can stop a watch multiple times, reporting
121 * times at multiple points during program
124 * Args: w - the watch
127 StopwatchStop(Stopwatch_t *w)
130 #ifdef SRE_STRICT_ANSI
138 w->elapsed = difftime(t1, w->t0);
140 #ifdef SRE_STRICT_ANSI
142 w->user = (double) (cpu1- w->cpu0) / (double) CLOCKS_PER_SEC;
143 w->sys = 0.; /* no way to portably get system time in ANSI C */
145 #else /* assume we're on a POSIX system by default */
148 clk_tck = sysconf(_SC_CLK_TCK);
149 w->user = (double) (cpu1.tms_utime + cpu1.tms_cutime -
150 w->cpu0.tms_utime - w->cpu0.tms_cutime) /
153 w->sys = (double) (cpu1.tms_stime + cpu1.tms_cstime -
154 w->cpu0.tms_stime - w->cpu0.tms_cstime) /
159 /* Function: StopwatchInclude()
160 * Date: SRE, Fri Nov 26 15:09:34 1999 [St. Louis]
162 * Purpose: Merge the cpu and system times from a slave into
163 * a master stopwatch. Both watches must be
164 * stopped, and should not be stopped again unless
165 * You Know What You're Doing.
167 * Elapsed time is *not* merged; master is assumed
168 * to be keeping track of the wall clock time,
169 * and the slave/worker watch is ignored.
172 * 1) PVM; merge in the stopwatch(es) from separate
173 * process(es) in a cluster.
174 * 2) Threads, for broken pthreads/times() implementations
175 * that lose track of cpu times used by spawned
178 * Args: w1 - the master stopwatch
179 * w2 - the slave/worker watch
183 StopwatchInclude(Stopwatch_t *w1, Stopwatch_t *w2)
185 w1->user += w2->user;
189 /* Function: StopwatchAlloc(), StopwatchZero(), StopwatchCopy(),
191 * Date: SRE, Fri Nov 26 15:13:14 1999 [St. Louis]
193 * Purpose: The usual creation/manipulation/destruction routines
194 * for a stopwatch object.
197 StopwatchCreate(void)
200 w = malloc(sizeof(Stopwatch_t));
204 StopwatchZero(Stopwatch_t *w)
211 StopwatchCopy(Stopwatch_t *w1, Stopwatch_t *w2)
214 #ifdef SRE_STRICT_ANSI
217 w1->cpu0.tms_utime = w2->cpu0.tms_utime;
218 w1->cpu0.tms_stime = w2->cpu0.tms_stime;
219 w1->cpu0.tms_cutime = w2->cpu0.tms_cutime;
220 w1->cpu0.tms_cstime = w2->cpu0.tms_cstime;
222 w1->elapsed = w2->elapsed;
227 StopwatchFree(Stopwatch_t *w)
233 /* Function: StopwatchDisplay()
234 * Date: SRE, Fri Nov 26 15:14:12 1999 [St. Louis]
236 * Purpose: Output a usage summary line from a *stopped*
237 * stopwatch (the times will reflect the last
238 * time StopwatchStop() was called.)
240 * For s = "CPU Time: " an example output line is:
241 * CPU Time: 142.55u 7.17s 149.72 Elapsed: 00:02:35.00
243 * Args: fp - open file for writing (stdout, possibly)
244 * s - prefix for the report line
245 * w - a (recently stopped) stopwatch
249 StopwatchDisplay(FILE *fp, char *s, Stopwatch_t *w)
251 char buf[128]; /* (safely holds up to 10^14 years) */
254 fputs("CPU Time: ", fp);
258 format_time_string(buf, w->user+w->sys, 1);
259 #ifdef SRE_STRICT_ANSI
260 fprintf(fp, "%.2fu %s ", w->user, buf);
262 fprintf(fp, "%.2fu %.2fs %s ", w->user, w->sys, buf);
265 format_time_string(buf, w->elapsed, 0);
266 fprintf(fp, "Elapsed: %s\n", buf);
269 #ifdef SRE_ENABLE_PVM
270 /* Function: StopwatchPVMPack(), StopwatchPVMUnpack()
271 * Date: SRE, Fri Nov 26 15:22:04 1999 [St. Louis]
273 * Purpose: Transmission of stopwatch data in a PVM
277 StopwatchPVMPack(Stopwatch_t *w)
279 pvm_pkdouble(&(w->elapsed), 1, 1);
280 pvm_pkdouble(&(w->user), 1, 1);
281 pvm_pkdouble(&(w->sys), 1, 1);
284 StopwatchPVMUnpack(Stopwatch_t *w)
286 pvm_upkdouble(&(w->elapsed), 1, 1);
287 pvm_upkdouble(&(w->user), 1, 1);
288 pvm_upkdouble(&(w->sys), 1, 1);
290 #endif /*SRE_ENABLE_PVM*/
295 main(int argc, char **argv)
297 Stopwatch_t stopwatch;
299 StopwatchStart(&stopwatch);
303 StopwatchStop(&stopwatch);
304 StopwatchDisplay(stdout, "CPU Time: ", &stopwatch);