initial commit
[jalview.git] / forester / archive / RIO / others / hmmer / squid / stopwatch.c
1 /************************************************************
2  * HMMER - Biological sequence analysis with profile HMMs
3  * Copyright (C) 1992-1999 Washington University School of Medicine
4  * All Rights Reserved
5  * 
6  *     This source code is distributed under the terms of the
7  *     GNU General Public License. See the files COPYING and LICENSE
8  *     for details.
9  ************************************************************/
10
11 /* stopwatch.c
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]
14  * 
15  * Reporting of cpu/system/elapsed time used by a process.
16  * thanks to Warren Gish for assistance.
17  * 
18  * Basic API:
19  * 
20  *   Stopwatch_t *w;
21  *   w = StopwatchCreate();
22  *   
23  *   StopwatchStart(w);
24  *   do_lots_of_stuff;
25  *   StopwatchStop(w);
26  *   StopwatchDisplay(stdout, "CPU time: ", w);
27  *   
28  *   StopwatchFree(w);
29  *   
30  * Some behavior can be controlled at compile time by #define's:
31  * 
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.
37  *         
38  *   SRE_ENABLE_PVM:   If compiled with -DSRE_ENABLE_PVM, the
39  *         functions StopwatchPVMPack() and StopwatchPVMUnpack()
40  *         are compiled, providing PVM communications ability.
41  *         
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
52  *         an example.
53  * 
54  * See hmmcalibrate.c for examples of more complex usage
55  * in dealing with pthreads and PVM.
56  */
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <unistd.h>
61 #ifdef SRE_ENABLE_PVM
62 #include <pvm3.h>
63 #endif
64
65 #include "stopwatch.h"
66
67 /* Function: format_time_string()
68  * Date:     SRE, Fri Nov 26 15:06:28 1999 [St. Louis]
69  *
70  * Purpose:  Given a number of seconds, format into
71  *           hh:mm:ss.xx in a provided buffer.
72  *
73  * Args:     buf     - allocated space (128 is plenty!)
74  *           sec     - number of seconds
75  *           do_frac - TRUE (1) to include hundredths of a sec
76  */
77 static void
78 format_time_string(char *buf, double sec, int do_frac)
79 {
80   int h, m, s, hs;
81   
82   h  = (int) (sec / 3600.);
83   m  = (int) (sec / 60.) - h * 60;
84   s  = (int) (sec) - h * 3600 - m * 60;
85   if (do_frac) {
86     hs = (int) (sec * 100.) - h * 360000 - m * 6000 - s * 100;
87     sprintf(buf, "%02d:%02d:%02d.%02d", h,m,s,hs);
88   } else {
89     sprintf(buf, "%02d:%02d:%02d", h,m,s);
90   }
91 }
92
93 /* Function: StopwatchStart()
94  * Date:     SRE, Fri Nov 26 15:07:48 1999 [St. Louis]
95  *
96  * Purpose:  Start a stopwatch.
97  *
98  * Args:     w - the watch
99  */
100 void
101 StopwatchStart(Stopwatch_t *w)
102 {
103   w->t0 = time(NULL);
104 #ifdef SRE_STRICT_ANSI
105   w->cpu0 = clock();
106 #else
107   (void) times(&(w->cpu0));
108 #endif
109
110   w->elapsed = 0.;
111   w->user    = 0.;
112   w->sys     = 0.;
113 }
114
115 /* Function: StopwatchStop()
116  * Date:     SRE, Fri Nov 26 15:08:16 1999 [St. Louis]
117  *
118  * Purpose:  Stop a stopwatch. 
119  *
120  *           The implementation allows "split times":
121  *           you can stop a watch multiple times, reporting
122  *           times at multiple points during program
123  *           execution.
124  *
125  * Args:     w - the watch
126  */
127 void
128 StopwatchStop(Stopwatch_t *w)
129 {
130   time_t t1;
131 #ifdef SRE_STRICT_ANSI
132   clock_t cpu1;
133 #else
134   struct tms cpu1;
135   long       clk_tck;
136 #endif
137
138   t1 = time(NULL);
139   w->elapsed = difftime(t1, w->t0);
140
141 #ifdef SRE_STRICT_ANSI
142   cpu1    = clock();
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 */
145
146 #else /* assume we're on a POSIX system by default */
147   (void) times(&cpu1);
148   
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) /
152             (double) clk_tck;
153
154   w->sys  = (double) (cpu1.tms_stime + cpu1.tms_cstime -
155                       w->cpu0.tms_stime - w->cpu0.tms_cstime) /
156             (double) clk_tck;
157 #endif
158 }
159
160 /* Function: StopwatchInclude()
161  * Date:     SRE, Fri Nov 26 15:09:34 1999 [St. Louis]
162  *
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.
167  *           
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.
171  *           
172  *           Used in two cases:
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
177  *              threads.
178  *              
179  * Args:     w1 - the master stopwatch
180  *           w2 - the slave/worker watch
181  *
182  */
183 void
184 StopwatchInclude(Stopwatch_t *w1, Stopwatch_t *w2)
185 {
186   w1->user    += w2->user;
187   w1->sys     += w2->sys;
188 }
189
190 /* Function: StopwatchAlloc(), StopwatchZero(), StopwatchCopy(), 
191  *           StopwatchFree()
192  * Date:     SRE, Fri Nov 26 15:13:14 1999 [St. Louis]
193  *
194  * Purpose:  The usual creation/manipulation/destruction routines
195  *           for a stopwatch object.
196  */
197 Stopwatch_t *
198 StopwatchCreate(void)
199 {
200   Stopwatch_t *w;
201   w = malloc(sizeof(Stopwatch_t));
202   return w;
203 }
204 void
205 StopwatchZero(Stopwatch_t *w)
206 {
207   w->elapsed = 0.;
208   w->user    = 0.;
209   w->sys     = 0.;
210 }
211 void 
212 StopwatchCopy(Stopwatch_t *w1, Stopwatch_t *w2)
213 {
214   w1->t0   = w2->t0;
215 #ifdef SRE_STRICT_ANSI
216   w1->cpu0 = w2->cpu0;
217 #else
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;
222 #endif
223   w1->elapsed = w2->elapsed;
224   w1->user    = w2->user;
225   w1->sys     = w2->sys;
226 }
227 void
228 StopwatchFree(Stopwatch_t *w)
229 {
230   free(w);
231 }
232
233
234 /* Function: StopwatchDisplay()
235  * Date:     SRE, Fri Nov 26 15:14:12 1999 [St. Louis]
236  *
237  * Purpose:  Output a usage summary line from a *stopped*
238  *           stopwatch (the times will reflect the last
239  *           time StopwatchStop() was called.)
240  *           
241  *           For s = "CPU Time: " an example output line is:
242  *           CPU Time: 142.55u 7.17s 149.72 Elapsed: 00:02:35.00
243  *
244  * Args:     fp - open file for writing (stdout, possibly)
245  *           s  - prefix for the report line
246  *           w  - a (recently stopped) stopwatch     
247  *
248  */
249 void
250 StopwatchDisplay(FILE *fp, char *s, Stopwatch_t *w)
251 {
252   char buf[128];        /* (safely holds up to 10^14 years) */
253   
254   if (s == NULL)
255     fputs("CPU Time: ", fp);
256   else 
257     fputs(s, fp);
258
259   format_time_string(buf, w->user+w->sys, 1);
260 #ifdef SRE_STRICT_ANSI
261   fprintf(fp, "%.2fu %s ", w->user, buf);
262 #else
263   fprintf(fp, "%.2fu %.2fs %s ", w->user, w->sys, buf);
264 #endif
265
266   format_time_string(buf, w->elapsed, 0);
267   fprintf(fp, "Elapsed: %s\n", buf);
268 }
269   
270 #ifdef SRE_ENABLE_PVM
271 /* Function: StopwatchPVMPack(), StopwatchPVMUnpack()
272  * Date:     SRE, Fri Nov 26 15:22:04 1999 [St. Louis]
273  *
274  * Purpose:  Transmission of stopwatch data in a PVM
275  *           cluster.
276  */
277 void
278 StopwatchPVMPack(Stopwatch_t *w)
279 {
280   pvm_pkdouble(&(w->elapsed), 1, 1);
281   pvm_pkdouble(&(w->user),    1, 1);
282   pvm_pkdouble(&(w->sys),     1, 1);
283 }
284 void
285 StopwatchPVMUnpack(Stopwatch_t *w)
286 {
287   pvm_upkdouble(&(w->elapsed), 1, 1);
288   pvm_upkdouble(&(w->user),    1, 1);
289   pvm_upkdouble(&(w->sys),     1, 1);
290 }
291 #endif /*SRE_ENABLE_PVM*/
292
293
294 #ifdef TESTDRIVER
295 int
296 main(int argc, char **argv)
297 {
298   Stopwatch_t stopwatch;
299
300   StopwatchStart(&stopwatch);
301
302   sleep(5);
303
304   StopwatchStop(&stopwatch);
305   StopwatchDisplay(stdout, "CPU Time: ", &stopwatch);
306 }
307 #endif