3
* sh.time.c: Shell time keeping and printing.
6
* Copyright (c) 1980, 1991 The Regents of the University of California.
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
* 3. All advertising materials mentioning features or use of this software
18
* must display the following acknowledgement:
19
* This product includes software developed by the University of
20
* California, Berkeley and its contributors.
21
* 4. Neither the name of the University nor the names of its contributors
22
* may be used to endorse or promote products derived from this software
23
* without specific prior written permission.
25
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42
# include <machine/param.h>
46
* C Shell - routines handling process timing and niceing
50
# define RUSAGE_SELF 0
51
# define RUSAGE_CHILDREN -1
52
# endif /* RUSAGE_SELF */
57
#if !defined(BSDTIMES) && !defined(_SEQUENT_)
59
static void pdtimet __P((clock_t, clock_t));
61
static void pdtimet __P((time_t, time_t));
63
#else /* BSDTIMES || _SEQUENT_ */
64
static void tvadd __P((timeval_t *, timeval_t *));
65
static void pdeltat __P((timeval_t *, timeval_t *));
66
#endif /* BSDTIMES || _SEQUENT_ */
72
struct sysrusage ruch;
74
memset(&ru0, 0, sizeof(ru0));
75
memset(&ruch, 0, sizeof(ruch));
78
(void) gettimeofday(&time0, NULL);
79
(void) getrusage(RUSAGE_SELF, (struct rusage *) &ru0);
80
(void) getrusage(RUSAGE_CHILDREN, (struct rusage *) &ruch);
84
struct process_stats ruch;
86
(void) get_process_stats(&time0, PS_SELF, &ru0, &ruch);
88
# else /* _SEQUENT_ */
90
time0 = times(×0);
91
# else /* !COHERENT */
92
time0 = HZ * time(NULL);
94
# endif /* !COHERENT */
95
times0.tms_stime += times0.tms_cstime;
96
times0.tms_utime += times0.tms_cutime;
97
times0.tms_cstime = 0;
98
times0.tms_cutime = 0;
99
# endif /* _SEQUENT_ */
100
#endif /* BSDTIMES */
104
* dotime is only called if it is truly a builtin function and not a
105
* prefix to another command
115
struct sysrusage ru1, ruch;
117
memset(&ru1, 0, sizeof(ru1));
118
memset(&ruch, 0, sizeof(ruch));
121
(void) getrusage(RUSAGE_SELF, (struct rusage *) &ru1);
122
(void) getrusage(RUSAGE_CHILDREN, (struct rusage *) &ruch);
124
(void) gettimeofday(&timedol, NULL);
125
prusage(&ru0, &ru1, &timedol, &time0);
129
struct process_stats ru1, ruch;
131
(void) get_process_stats(&timedol, PS_SELF, &ru1, &ruch);
133
prusage(&ru0, &ru1, &timedol, &time0);
134
# else /* _SEQUENT_ */
141
struct tms times_dol;
144
timedol = times(×_dol);
146
timedol = HZ * time(NULL);
149
times_dol.tms_stime += times_dol.tms_cstime;
150
times_dol.tms_utime += times_dol.tms_cutime;
151
times_dol.tms_cstime = 0;
152
times_dol.tms_cutime = 0;
153
prusage(×0, ×_dol, timedol, time0);
154
# endif /* _SEQUENT_ */
155
#endif /* BSDTIMES */
161
* donice is only called when it on the line by itself or with a +- value
176
else if (*v == 0 && any("+-", cp[0]))
179
(void) setpriority(PRIO_PROCESS, 0, nval);
188
register struct sysrusage *ru, *ru2;
190
tvadd(&ru->ru_utime, &ru2->ru_utime);
191
tvadd(&ru->ru_stime, &ru2->ru_stime);
192
if (ru2->ru_maxrss > ru->ru_maxrss)
193
ru->ru_maxrss = ru2->ru_maxrss;
195
ru->ru_ixrss += ru2->ru_ixrss;
196
ru->ru_idrss += ru2->ru_idrss;
197
ru->ru_isrss += ru2->ru_isrss;
198
ru->ru_minflt += ru2->ru_minflt;
199
ru->ru_majflt += ru2->ru_majflt;
200
ru->ru_nswap += ru2->ru_nswap;
201
ru->ru_inblock += ru2->ru_inblock;
202
ru->ru_oublock += ru2->ru_oublock;
203
ru->ru_msgsnd += ru2->ru_msgsnd;
204
ru->ru_msgrcv += ru2->ru_msgrcv;
205
ru->ru_nsignals += ru2->ru_nsignals;
206
ru->ru_nvcsw += ru2->ru_nvcsw;
207
ru->ru_nivcsw += ru2->ru_nivcsw;
210
tvadd(&ru->ru_exutime, &ru2->ru_exutime);
211
ru->ru_utotal += ru2->ru_utotal;
212
ru->ru_usamples += ru2->ru_usamples;
213
ru->ru_stotal += ru2->ru_stotal;
214
ru->ru_ssamples += ru2->ru_ssamples;
222
register struct process_stats *ru, *ru2;
224
tvadd(&ru->ps_utime, &ru2->ps_utime);
225
tvadd(&ru->ps_stime, &ru2->ps_stime);
226
if (ru2->ps_maxrss > ru->ps_maxrss)
227
ru->ps_maxrss = ru2->ps_maxrss;
229
ru->ps_pagein += ru2->ps_pagein;
230
ru->ps_reclaim += ru2->ps_reclaim;
231
ru->ps_zerofill += ru2->ps_zerofill;
232
ru->ps_pffincr += ru2->ps_pffincr;
233
ru->ps_pffdecr += ru2->ps_pffdecr;
234
ru->ps_swap += ru2->ps_swap;
235
ru->ps_syscall += ru2->ps_syscall;
236
ru->ps_volcsw += ru2->ps_volcsw;
237
ru->ps_involcsw += ru2->ps_involcsw;
238
ru->ps_signal += ru2->ps_signal;
239
ru->ps_lread += ru2->ps_lread;
240
ru->ps_lwrite += ru2->ps_lwrite;
241
ru->ps_bread += ru2->ps_bread;
242
ru->ps_bwrite += ru2->ps_bwrite;
243
ru->ps_phread += ru2->ps_phread;
244
ru->ps_phwrite += ru2->ps_phwrite;
247
# endif /* _SEQUENT_ */
248
#endif /* BSDTIMES */
253
* PWP: the LOG1024 and pagetok stuff taken from the top command,
254
* written by William LeFebvre
256
/* Log base 2 of 1024 is 10 (2^10 == 1024) */
259
/* Convert clicks (kernel pages) to kbytes ... */
260
/* If there is no PGSHIFT defined, assume it is 11 */
261
/* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
264
# define pagetok(size) ((size) << 1)
267
# define pagetok(size) ((size) << (PGSHIFT - LOG1024))
269
# define pagetok(size) ((size) >> (LOG1024 - PGSHIFT))
275
* if any other machines return wierd values in the ru_i* stuff, put
276
* the adjusting macro here:
279
# define IADJUST(i) (pagetok(i)/2)
283
* convex has megabytes * CLK_TCK
284
* multiply by 100 since we use time in 100ths of a second in prusage
286
# define IADJUST(i) (((i) << 10) / CLK_TCK * 100)
288
# define IADJUST(i) (i)
293
prusage(r0, r1, e, b)
294
register struct sysrusage *r0, *r1;
300
prusage(r0, r1, e, b)
301
register struct process_stats *r0, *r1;
304
# else /* _SEQUENT_ */
306
prusage(bs, es, e, b)
316
# endif /* _SEQUENT_ */
317
#endif /* BSDTIMES */
321
(r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 +
322
(r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 +
323
(r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 +
324
(r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000;
329
(r1->ps_utime.tv_sec - r0->ps_utime.tv_sec) * 100 +
330
(r1->ps_utime.tv_usec - r0->ps_utime.tv_usec) / 10000 +
331
(r1->ps_stime.tv_sec - r0->ps_stime.tv_sec) * 100 +
332
(r1->ps_stime.tv_usec - r0->ps_stime.tv_usec) / 10000;
334
# else /* _SEQUENT_ */
336
register time_t t = (es->tms_utime - bs->tms_utime +
337
es->tms_stime - bs->tms_stime) * 100 / HZ;
340
register clock_t t = (es->tms_utime - bs->tms_utime +
341
es->tms_stime - bs->tms_stime) * 100 / clk_tck;
344
# endif /* _SEQUENT_ */
345
#endif /* BSDTIMES */
349
register struct varent *vp = adrof(STRtime);
353
static struct system_information sysinfo;
354
long long memtmp; /* let memory calculations exceede 2Gb */
357
((e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000);
359
cp = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww";
360
#else /* !BSDTIMES */
363
((e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000);
365
cp = "%Uu %Ss %E %P %I+%Oio %Fpf+%Ww";
366
# else /* !_SEQUENT_ */
368
time_t ms = ((time_t)((e - b) / HZ) * 100) +
369
(time_t)(((e - b) % HZ) * 100) / HZ;
371
clock_t ms = ((clock_t)((e - b) / clk_tck) * 100) +
372
(clock_t)(((e - b) % clk_tck) * 100) / clk_tck;
375
cp = "%Uu %Ss %E %P";
378
* the tms stuff is not very precise, so we fudge it.
379
* granularity fix: can't be more than 100%
380
* this breaks in multi-processor systems...
381
* maybe I should take it out and let people see more then 100%
385
if (ms < t && ms != 0)
388
# endif /*! _SEQUENT_ */
389
#endif /* !BSDTIMES */
391
xprintf("es->tms_utime %lu bs->tms_utime %lu\n",
392
es->tms_utime, bs->tms_utime);
393
xprintf("es->tms_stime %lu bs->tms_stime %lu\n",
394
es->tms_stime, bs->tms_stime);
395
xprintf("ms %lu e %lu b %lu\n", ms, e, b);
396
xprintf("t %lu\n", t);
399
if (vp && vp->vec[0] && vp->vec[1])
400
cp = short2str(vp->vec[1]);
407
case 'U': /* user CPU time used */
409
pdeltat(&r1->ru_utime, &r0->ru_utime);
412
pdeltat(&r1->ps_utime, &r0->ps_utime);
413
# else /* _SEQUENT_ */
415
pdtimet(es->tms_utime, bs->tms_utime);
417
pdtimet(es->tms_utime, bs->tms_utime);
419
# endif /* _SEQUENT_ */
420
#endif /* BSDTIMES */
423
case 'S': /* system CPU time used */
425
pdeltat(&r1->ru_stime, &r0->ru_stime);
428
pdeltat(&r1->ps_stime, &r0->ps_stime);
429
# else /* _SEQUENT_ */
431
pdtimet(es->tms_stime, bs->tms_stime);
433
pdtimet(es->tms_stime, bs->tms_stime);
435
# endif /* _SEQUENT_ */
436
#endif /* BSDTIMES */
439
case 'E': /* elapsed (wall-clock) time */
444
#endif /* BSDTIMES */
447
case 'P': /* percent time spent running */
448
/* check if the process did not run */
451
* scale the cpu %- ages by the number of processors
452
* available on this machine
454
if ((sysinfo.cpu_count == 0) &&
455
(getsysinfo(SYSINFO_SIZE, &sysinfo) < 0))
456
sysinfo.cpu_count = 1;
457
i = (ms == 0) ? 0 : (t * 1000 / (ms * sysinfo.cpu_count));
459
i = (ms == 0) ? 0 : (t * 1000 / ms);
461
xprintf("%ld.%01ld%%", i / 10, i % 10); /* nn.n% */
465
case 'W': /* number of swaps */
466
i = r1->ru_nswap - r0->ru_nswap;
471
case 'X': /* (average) shared text size */
472
memtmp = (t == 0 ? 0LL : IADJUST((long long)r1->ru_ixrss -
473
(long long)r0->ru_ixrss) /
475
xprintf("%lu", (unsigned long)memtmp);
479
case 'D': /* (average) unshared data size */
480
memtmp = (t == 0 ? 0LL : IADJUST((long long)r1->ru_idrss +
481
(long long)r1->ru_isrss -
482
((long long)r0->ru_idrss +
483
(long long)r0->ru_isrss)) /
485
xprintf("%lu", (unsigned long)memtmp);
488
case 'K': /* (average) total data memory used */
489
memtmp = (t == 0 ? 0LL : IADJUST(((long long)r1->ru_ixrss +
490
(long long)r1->ru_isrss +
491
(long long)r1->ru_idrss) -
492
((long long)r0->ru_ixrss +
493
(long long)r0->ru_idrss +
494
(long long)r0->ru_isrss)) /
496
xprintf("%lu", (unsigned long)memtmp);
499
case 'X': /* (average) shared text size */
500
xprintf("%ld", t == 0 ? 0L :
501
IADJUST(r1->ru_ixrss - r0->ru_ixrss) / t);
504
case 'D': /* (average) unshared data size */
505
xprintf("%ld", t == 0 ? 0L :
506
IADJUST(r1->ru_idrss + r1->ru_isrss -
507
(r0->ru_idrss + r0->ru_isrss)) / t);
510
case 'K': /* (average) total data memory used */
511
xprintf("%ld", t == 0 ? 0L :
512
IADJUST((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) -
513
(r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t);
516
case 'M': /* max. Resident Set Size */
518
xprintf("%ld", pagetok(r1->ru_maxrss));
521
xprintf("%ld", r1->ru_maxrss * 4L);
523
xprintf("%ld", r1->ru_maxrss / 2L);
528
case 'F': /* page faults */
529
xprintf("%ld", r1->ru_majflt - r0->ru_majflt);
532
case 'R': /* page reclaims */
533
xprintf("%ld", r1->ru_minflt - r0->ru_minflt);
536
case 'I': /* FS blocks in */
537
xprintf("%ld", r1->ru_inblock - r0->ru_inblock);
540
case 'O': /* FS blocks out */
541
xprintf("%ld", r1->ru_oublock - r0->ru_oublock);
545
case 'C': /* CPU parallelization factor */
546
if (r1->ru_usamples != 0LL) {
547
long long parr = ((r1->ru_utotal * 100LL) /
549
xprintf("%d.%02d", (int)(parr/100), (int)(parr%100));
554
case 'r': /* PWP: socket messages recieved */
555
xprintf("%ld", r1->ru_msgrcv - r0->ru_msgrcv);
558
case 's': /* PWP: socket messages sent */
559
xprintf("%ld", r1->ru_msgsnd - r0->ru_msgsnd);
562
case 'k': /* PWP: signals received */
563
xprintf("%ld", r1->ru_nsignals - r0->ru_nsignals);
566
case 'w': /* PWP: voluntary context switches (waits) */
567
xprintf("%ld", r1->ru_nvcsw - r0->ru_nvcsw);
570
case 'c': /* PWP: involuntary context switches */
571
xprintf("%ld", r1->ru_nivcsw - r0->ru_nivcsw);
575
case 'W': /* number of swaps */
576
i = r1->ps_swap - r0->ps_swap;
581
xprintf("%ld", r1->ps_maxrss / 2);
585
xprintf("%ld", r1->ps_pagein - r0->ps_pagein);
589
xprintf("%ld", r1->ps_reclaim - r0->ps_reclaim);
593
xprintf("%ld", r1->ps_bread - r0->ps_bread);
597
xprintf("%ld", r1->ps_bwrite - r0->ps_bwrite);
601
xprintf("%ld", r1->ps_signal - r0->ps_signal);
605
xprintf("%ld", r1->ps_volcsw - r0->ps_volcsw);
609
xprintf("%ld", r1->ps_involcsw - r0->ps_involcsw);
613
xprintf("%ld", r1->ps_zerofill - r0->ps_zerofill);
617
xprintf("%ld", r1->ps_pffincr - r0->ps_pffincr);
621
xprintf("%ld", r1->ps_pffdecr - r0->ps_pffdecr);
625
xprintf("%ld", r1->ps_syscall - r0->ps_syscall);
629
xprintf("%ld", r1->ps_lread - r0->ps_lread);
633
xprintf("%ld", r1->ps_lwrite - r0->ps_lwrite);
637
xprintf("%ld", r1->ps_phread - r0->ps_phread);
641
xprintf("%ld", r1->ps_phwrite - r0->ps_phwrite);
643
# endif /* _SEQUENT_ */
644
#endif /* BSDTIMES */
651
#if defined(BSDTIMES) || defined(_SEQUENT_)
659
xprintf("%ld.%03ld", td.tv_sec, td.tv_usec / 1000L);
664
timeval_t *tsum, *t0;
667
tsum->tv_sec += t0->tv_sec;
668
tsum->tv_usec += t0->tv_usec;
669
if (tsum->tv_usec >= 1000000)
670
tsum->tv_sec++, tsum->tv_usec -= 1000000;
675
timeval_t *tdiff, *t1, *t0;
678
tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
679
tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
680
if (tdiff->tv_usec < 0)
681
tdiff->tv_sec--, tdiff->tv_usec += 1000000;
684
#else /* !BSDTIMES && !_SEQUENT_ */
704
val = (eval - bval) * 100 / HZ;
706
val = (eval - bval) * 100 / clk_tck;
709
xprintf("%ld.%02ld", val / 100, val - (val / 100 * 100));
711
#endif /* BSDTIMES || _SEQUENT_ */