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