4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 #pragma ident "%Z%%M% %I% %E% SMI"
33 * This module is intended to collect performance statistics about the
34 * operation of uucico. All instances of uucico will write their log
35 * entries to the files who's path is defined by PERFLOG. Statistics
36 * will only be collected if PERFLOG exists when uucico starts, it will
37 * not be created automatically. This gives the SA an easy way to turn
38 * statistics collection on or off at run time. Three types
39 * of records will be written to the file, and each record will be
40 * identified by a mnemonic type at the begining of the record. The record
41 * types are as follows:
43 * conn - Contains statistics about the establishment of
46 * xfer - Contains statistics about a file transfer.
48 * The intention is to use grep to select the conn and xfer records and put
49 * them in two Unity data bases. No attempt will be made to process the
50 * error records with Unity.
52 * Both the conn and the xfer records will contain a time stamp field.
53 * This field will be written in case there is a desire to do time of
54 * day traffic studies. The time that will be written will be GMT
55 * to avoid the vagaries of time zone setting for uucico. The time
56 * stamp will contain 12 digits of the form YYMMDDhhmmss. This allows
57 * proper sorting by time, and the fixed length field type of Unity
58 * can be used to pick it apart if necessary. The time stamp is the
59 * time that the record is written.
61 * Statistics will be collected on the wall clock (real) time to perform
62 * an action and CPU consumption to perform an action. These times will
63 * be written in seconds and fractions of a second to two decimal places.
65 * The conn and xfer records will be written so that they can be processed
66 * with the following Unity schema (D files). For those not familiar with
67 * Unity, the columns are:
69 * column 1 - field name
70 * column 2 - field type (t=variable width) and field separator.
71 * column 3 - number of columns to use when printing the field
73 * column 4 - a user friendly field name.
77 * type t| 4 record type (always conn)
79 * procid t| 5 uucico's process id
80 * myname t| 6 name of the machine where the record is written
81 * role t| 1 M = master, S = slave
82 * remote t| 6 name of remote system
83 * device t| 6 name of device used for connection
84 * protocol t| 1 the protocal that is used for communication
85 * netid t| 6 physical network ID
86 * real t| 6 real time to connect
87 * user t| 6 user time to connect
88 * sys t\n 6 system (kernal) time to connect
90 * The timer for connection processing starts immediately after the
91 * command line processing is complete, and it is stopped after the
92 * protocol has been selected.
96 * type t| 4 record type (always xfer)
97 * jobgrade t| 1 job grade ID
99 * procid t| 5 uucico's process id
100 * myname t| 6 name of the machine where the record is written
101 * role t| 1 M = master, S = slave
102 * remote t| 6 name of remote system
103 * device t| 6 name of device used for connection
104 * protocol t| 1 the protocal that is used for communication
105 * netid t| 6 physical network ID
106 * job t| 7 name of the job. (Master only).
107 * inqueue t| 6 time in seconds that file was in queue (Master
109 * tat t| 6 turn around time in sec. (Master only).
110 * bytes t| 6 size of the file that was transferred
111 * flags t| 3 m = mail to requester on completion,
112 * n = notify remote user, s = write status
113 * file. (Master only).
114 * streal t| 6 real time to start up transfer (master only).
117 * xfrreal t| 6 real time to transfer file
120 * trmreal t| 6 real time to terminate the transfer
123 * text t| 12 "PARTIAL FILE" if the data is being transmitted
124 * before breaking the transmission; blank if the
125 * partial file after the breakpoint or the whole
126 * file is being transmitted completely.
128 * Start up time includes the time for the master to search the queues
129 * for the next file, for the master and slave to exchange work vectors,
130 * and time to open files. It is only recorded on the master.
131 * Xfer times is the time to transfer the data, close the file, and
132 * exchange confirmation messages. Termination time is the time to send
133 * mail notifications and write status files. Turn around time is the
134 * difference between the time that the file was queued and the time that
135 * the final notification was sent.
145 #define FS '|' /* Field seperator for output records. */
146 #define LOGCHECK {if ((Initialized == FALSE) || \
147 (Collecting == FALSE)) return; }
149 /* Subscripts for connection time marks: */
151 #define CT_START 0 /* Start connection establishment. */
152 #define CT_CONNECTED 1 /* Connection completed. */
153 #define CT_SIZE 2 /* Number of elements in array. */
155 /* Subscripts for xfer time marks: */
157 #define XT_LOOK 0 /* Start looking for a file (master only). */
158 #define XT_FOUND 1 /* File found (master only). */
159 #define XT_BEGXFER 2 /* Start of xfer of data. */
160 #define XT_ENDXFER 3 /* Data xfer complete. */
161 #define XT_ENDFILE 4 /* Done mailing and notifying. */
162 #define XT_SIZE 5 /* Number of elements in array. */
165 * STRUCTURE DEFINITIONS
168 typedef struct timeUsed
/* Time consummed between events. */
170 float tu_real
; /* Real time used. */
171 float tu_user
; /* User time used. */
172 float tu_sys
; /* System time used. */
175 typedef struct timeMark
/* Holds times for an event. */
177 int tm_valid
; /* True if data present. */
178 long tm_real
; /* Relative wall clock. */
179 struct tms tm_cycles
; /* CPU consumption. */
182 struct connData
/* Data for construction of conn record. */
184 char cn_role
; /* Master/slave indicator. */
185 TMARK cn_times
[CT_SIZE
]; /* Event data. */
188 struct xferData
/* Data for construction of xfer record. */
190 char xf_role
; /* Master/slave indicator. */
191 char xf_direction
; /* Send/receive indicator. */
192 time_t xf_intoque
; /* Time that file was placed
193 * in the queue. (master
195 long xf_deque
; /* Time that file was
196 * dequeued. (master only)*/
197 long xf_filedone
; /* Time that file was
199 char xf_jobname
[MODSTR
]; /* C. file (master only)*/
200 char xf_jobgrade
[MODSTR
]; /* job grade id */
201 off_t xf_bytes
; /* Bytes transferred. */
202 char xf_flags
[MODSTR
]; /* Notification flags. */
203 TMARK xf_times
[XT_SIZE
]; /* Event data. */
210 static int Collecting
= FALSE
; /* True if we are collecting
212 static struct connData Conn
= {0}; /* Connection data. */
213 static char Device
[MODSTR
] = ""; /* Type of communication
215 static int Initialized
= FALSE
; /* True if we have been
217 static int LogFile
= CLOSED
; /* Log file file destriptor. */
218 static char LogName
[] = PERFLOG
; /* Name of our log file. */
219 static pid_t Procid
= {0}; /* Our processid. */
220 static char Record
[LOGSIZE
]; /* Place to build log records. */
221 static char Remote
[MODSTR
] = ""; /* Name of the remote system. */
222 static char myname
[MAXBASENAME
+1] = ""; /* Name of the source system
224 static char Protocol
[MODSTR
]; /* Protocol in use */
225 static char Netid
[MODSTR
] = NOTAVAIL
; /* Network ID in use */
226 static struct xferData Xfer
= {0}; /* Transfer data. */
230 static char Msg_badopen
[] = "failed to open %s. Errno=%%d\n";
231 static char Msg_opening
[] = "attempting to open %s\n";
232 static char Msg_write
[] = "error in writing to %s. Errno=%%d.\n";
238 /* Declarations of functions: */
240 STATIC_FUNC
void grabTimes();
241 STATIC_FUNC
void pfloat();
242 STATIC_FUNC
void reportConn();
243 STATIC_FUNC
void reportFile();
244 STATIC_FUNC
void reportTimes();
245 STATIC_FUNC
void subTimes();
249 * Local Function: grabTimes - Get Real and CPU Times
251 * This function uses times(2) to obtain the current real time and CPU
252 * consumption. The time mark is also marked as valid.
256 * markptr - Address of structure to save times.
266 register TMARK
* markptr
;
269 markptr
->tm_real
= times(&markptr
->tm_cycles
);
270 if (markptr
->tm_real
!= FAIL
)
271 markptr
->tm_valid
= TRUE
;
277 * Local Function: pfloat - Print a Floating Number
279 * Format a floating point number for output to the Unity data base.
280 * If the number is NOTIME, "na" will be displayed instead.
284 * dest - The result will be concatenated to this string.
286 * number - The number to be formated.
288 * sep - Field separator character.
292 pfloat (dest
, number
, sep
)
295 double number
; /* float is promoted to double for args. */
299 static char rformat
[] = "%c%.2f";
300 static char naformat
[] = "%c%s";
304 cp
= dest
+ strlen(dest
);
305 if (number
== (float) NOTIME
)
306 sprintf(cp
, naformat
, sep
, NOTAVAIL
);
308 sprintf(cp
, rformat
, sep
, number
);
313 * Local Function: reportConn - Write Out Conn Record
315 * This function writes a conn record to the logfile.
330 TUSED contimes
; /* Times to make connection. */
331 static char format
[] = "%s%c%s%c%ld%c%s%c%c%c%s%c%s%c%s%c%s";
333 sprintf(Record
, format
,
334 "conn", FS
, /* record type. */
335 gmt(), FS
, /* current time. */
336 (long) Procid
, FS
, /* our process id. */
337 myname
, FS
, /* name of local system */
338 Conn
.cn_role
, FS
, /* slave or master. */
339 Remote
, FS
, /* name of remote system. */
340 Device
, FS
, /* device used for communication. */
341 Protocol
, FS
, /* protocol used for comm. */
342 Netid
/* Network ID */
344 subTimes(&contimes
, &Conn
.cn_times
[CT_CONNECTED
],
345 &Conn
.cn_times
[CT_START
]);
346 reportTimes(Record
, &contimes
, FS
);
348 writeLog(Record
,&LogFile
,LogName
,&Collecting
);
353 * Local Function: reportFile - Write File Statistics to Log
355 * This function writes statistics about the current file to the log
364 reportFile (breakmsg
)
368 /* minuend, subtrahand */
369 static int drvtab
[] = {
370 XT_FOUND
, XT_LOOK
, /* startup */
371 XT_ENDXFER
, XT_BEGXFER
, /* xfer */
372 XT_ENDFILE
, XT_ENDXFER
/* term. */
374 static char format1
[] = "%s%c%s%c%s%c%ld%c%s%c%c%c%s%c%s%c%s%c%s%c%s";
375 static char format2
[] = "%c%ld%c%s"; /* Bytes & flags. */
377 register struct xferData
* xdptr
;
378 register TMARK
* tdptr
;
381 TUSED diff
; /* time difference between events. */
382 float inque
; /* time in queue. */
383 int lastbyte
; /* Offset to last byte in Record. */
384 char * na
= NOTAVAIL
; /* String to show data not available*/
385 char role
; /* Current master/slave status. */
386 float tat
; /* Turn around time. */
388 xdptr
= &Xfer
; /* Point to Xfer data. */
389 role
= xdptr
->xf_role
;
390 sprintf(Record
, format1
,
391 "xfer", FS
, /* Record type. */
392 (role
== MCHAR
) ? xdptr
->xf_jobgrade
: na
,FS
, /* job grade */
393 gmt(), FS
, /* Current time. */
394 (long) Procid
, FS
, /* Our process id. */
395 myname
, FS
, /* name of local system */
396 role
, FS
, /* master/slave. */
397 Remote
, FS
, /* remote. */
398 Device
, FS
, /* communications device. */
399 Protocol
, FS
, /* protocol used for comm. */
400 Netid
, FS
, /* Network ID */
401 (role
== MCHAR
) ? xdptr
->xf_jobname
: na
404 /* Do time in queue and turn around time. */
408 inque
= (float) (xdptr
->xf_deque
- xdptr
->xf_intoque
);
409 tat
= (float) (xdptr
->xf_filedone
- xdptr
->xf_intoque
);
412 inque
= (float) NOTIME
; /* Not app. if not master. */
413 tat
= (float) NOTIME
;
415 pfloat(Record
, inque
, FS
);
416 pfloat(Record
, tat
, FS
);
419 * Report bytes transferred and notification flags.
422 lastbyte
= strlen(Record
);
423 (void) sprintf(Record
+lastbyte
, format2
,
424 FS
, getfilesize(),FS
,
425 (role
== MCHAR
) ? xdptr
->xf_flags
: na
429 * Report resource consumption for file startup, file transfer,
430 * and file termination. This means reporting the differences
431 * between pairs of elements in the xf_times array of Xfer. This
432 * will be controled by drvtab which contains pairs of subscripts
433 * to designate the xf_times elements.
436 tdptr
= &xdptr
->xf_times
[0];
437 for (i
= 0; i
< sizeof(drvtab
)/(sizeof(int)); i
+= 2)
439 subTimes(&diff
, (tdptr
+ drvtab
[i
]), (tdptr
+ drvtab
[i
+1]));
440 reportTimes(Record
, &diff
, FS
);
447 lastbyte
= strlen(Record
);
448 (void) sprintf(Record
+lastbyte
, "%c%s%c",
449 FS
, (*breakmsg
== NULLCHAR
) ? NOTAVAIL
: breakmsg
, FS
);
451 /* Terminate the record and write it out. */
453 (void) strcat(Record
, EOR
);
454 writeLog(Record
,&LogFile
,LogName
,&Collecting
);
459 * Local Function: reportTimes - Print Real, User, and Sys Times
461 * This function is used to convert the real, user, and system times from
462 * a TUSED structure to Ascii strings. The results are concatenated to
463 * the dest string. If any of the times are NOTIME, they will be reported
464 * as "na". The fields will be seperated by the sep character and the
465 * sep character will be the first character concatenated to the buffer. No
466 * seperator character will be placed at the end. Thus, the output string
467 * will be of the form:
473 * dest - String to receive Ascii times.
475 * diffptr - Address of the time data.
477 * sep - The field seperator character.
481 reportTimes (dest
, diffptr
, sep
)
483 register char * dest
;
484 register TUSED
* diffptr
;
488 pfloat(dest
, diffptr
->tu_real
, sep
);
489 pfloat(dest
, diffptr
->tu_user
, sep
);
490 pfloat(dest
, diffptr
->tu_sys
, sep
);
495 * Local Function: subTimes - Subtract Times Between Events
497 * This function takes the output from two calls to times(2) in the form
498 * of two TMARK structures, and determines the amount of time consummed
499 * for various categories. The result is stored in the specified
504 * diff - Place to store the result of the subtraction.
505 * minuend - The second time event.
506 * subtra - The subtrahend in the subtraction. This should
507 * be the first of two time events.
509 * On the large scale this function does the following:
511 * diff = minuend - subtra
515 subTimes (diff
, minuend
, subtra
)
517 register TUSED
* diff
;
518 register TMARK
* minuend
;
519 register TMARK
* subtra
;
522 register struct tms
* mintms
;
523 register struct tms
* subtms
;
525 long ltemp
; /* Temporary storage for long arith. */
526 float ticks
; /* Clock interrupts per second. */
528 if ((minuend
->tm_valid
!= TRUE
) || (subtra
->tm_valid
!= TRUE
))
529 { /* If data has not been collected. */
530 diff
->tu_real
= NOTIME
;
531 diff
->tu_user
= NOTIME
;
532 diff
->tu_sys
= NOTIME
;
535 ticks
= (float) HZ
; /* HZ defined in <sys/param.h>. */
536 mintms
= &minuend
->tm_cycles
;
537 subtms
= &subtra
->tm_cycles
;
539 /* Calculate real time. */
541 ltemp
= minuend
->tm_real
- subtra
->tm_real
;
542 diff
->tu_real
= ((float) ltemp
)/ticks
;
544 /* Calculate user time. */
546 ltemp
= mintms
->tms_utime
549 - subtms
->tms_cutime
;
550 diff
->tu_user
= ((float) ltemp
)/ticks
;
552 /* Calculate user time. */
554 ltemp
= mintms
->tms_stime
557 - subtms
->tms_cstime
;
558 diff
->tu_sys
= ((float) ltemp
)/ticks
;
568 * Function: gmt - Generate Current Time String
570 * This function returns the address a string containing the current
571 * GMT in the form YYMMDDhhmmss.
579 * An address of a static character array containing the date.
586 static char date
[] = "YYMMDDhhmmss";
588 register struct tm
* td
;
589 time_t now
; /* Current time. */
591 now
= time((time_t *) 0);
593 (void) sprintf(date
, "%02d%02d%02d%02d%02d%02d",
606 * Function: writeLog - Write String to Log File
608 * After insuring that the log file is open, this function will write
609 * the specified string to the log file. If a write error occurs,
610 * statistics collection will be disabled.
614 * string - Null terminated string to be written out.
615 * logfile - file descripter
616 * logname - name of log file.
617 * collecting - log enable/disable
621 writeLog (string
, logfile
, logname
, collecting
)
629 register int length
; /* Length of the string. */
630 register int rv
; /* Return value from write. */
632 char errmsg
[BUFSIZ
]; /* Place for error messages. */
634 if (openLog(logfile
,logname
) != SUCCESS
){
638 length
= strlen(string
);
641 rv
= write(*logfile
, string
, (unsigned) length
);
642 } while ((rv
< 0) && (errno
== EINTR
)); /* Retry if interrupted. */
644 { /* Error or incomplete output. */
645 (void) sprintf(errmsg
, Msg_write
, logname
);
646 DEBUG(DB_IMPORTANT
, errmsg
, errno
);
648 /* If we had a write error, lets give up on loggine. */
657 * Function: closeLog - Close the Log File
659 * This function allows uucico to close the log file in preparation for
664 * log file descriptor
672 if (*logfile
!= CLOSED
)
674 (void) close(*logfile
);
682 * Function: copyText - Copy String to Dynamic Memory
684 * This function copies a string to a buffer. It insures that there is
685 * no overflow of the buffer and that the result is null terminated.
689 * tptr - address of the buffer where the string is to
692 * size - number of bytes in the buffer.
694 * string - string to be saved.
702 copyText (tptr
, size
, string
)
704 register char * tptr
;
709 (void) strncpy(tptr
, string
, size
);
710 *(tptr
+ size
- 1) = NULLCHAR
;
715 * Function: pfConnected - Report Connection Completion
717 * Uucico uses pfConnected to tell this performance package that a connection
718 * has been established with the remote system.
722 * remote - name of the remote system.
724 * device - the type of device being used for communicaitons.
728 pfConnected (remote
, device
)
735 register TMARK
* tptr
;
738 grabTimes(&Conn
.cn_times
[CT_CONNECTED
]);
739 copyText(Remote
, sizeof(Remote
), remote
);
740 copyText(Device
, sizeof(Device
), device
);
742 tptr
= &Conn
.cn_times
[0];
745 * Mark connection times as invalid. This is really unnecessary
746 * since there should only be one connection per invocation of uucico.
747 * We do it for consistency with use of the transfer data.
750 for (i
= 0; i
< CT_SIZE
; i
++, tptr
++)
751 tptr
->tm_valid
= FALSE
;
757 * Function: pfEndFile - Report End of File
759 * Uucico uses pfEndFile to tell our statistics collection package that
760 * all processing has been finished on the current file. PfEndfile should
761 * be called after all notifications have been done and after the status
762 * file has been written. PfEndfile writes out a xfer record for the
763 * file that just completed.
775 register TMARK
* tdptr
;
776 register struct xferData
* xptr
= &Xfer
;
779 grabTimes(&Xfer
.xf_times
[XT_ENDFILE
]);
780 Xfer
.xf_filedone
= time((time_t *) 0);
781 reportFile(breakmsg
);
783 /* Now that we have reported them, mark all times as invalid. */
785 copyText(xptr
->xf_flags
, sizeof(xptr
->xf_flags
), NOTAVAIL
);
786 tdptr
= &Xfer
.xf_times
[0];
787 for (i
= 0; i
< XT_SIZE
; i
++, tdptr
++)
788 tdptr
->tm_valid
= FALSE
;
793 * Function: pfEndXfer - File Transfer Complete
795 * Calling pfEndXfer tells the performance package that a file transfer
796 * has been completed. It should be called after the destination site
797 * closes the file and confirms receipt, but before notifications are done.
809 grabTimes(&Xfer
.xf_times
[XT_ENDXFER
]);
814 * Function: pfFindFile - Looking for Another File
816 * Uucico uses pfFindFile to announce that it is going to explore the
817 * queues for another file transfer to do. PfFindFile is only called
818 * when uucico is in the role of master.
830 grabTimes(&Xfer
.xf_times
[XT_LOOK
]);
835 * Function: pfFound - Found Another File
837 * PfFound is a counterpart of pfFindFile. It is called when a new file
838 * has been found. Like pfFindFile it is called only by a master uucico.
842 * jobid - The name of the job that was found.
844 * flags - Options flags that were stored in the queue.
845 * These flags are originally set by uucp.
847 * intoQue - The time that the C. file was placed in the queue.
851 pfFound (jobid
, flags
, intoQue
)
858 register struct xferData
* xptr
= &Xfer
;
861 grabTimes(&xptr
->xf_times
[XT_FOUND
]);
862 copyText(xptr
->xf_jobname
, sizeof(xptr
->xf_jobname
), jobid
);
863 xptr
->xf_jobgrade
[0] = jobid
[strlen(jobid
)-5];
864 xptr
->xf_jobgrade
[1] = NULLCHAR
;/* get job grade from jobid */
865 copyText(xptr
->xf_flags
, sizeof(xptr
->xf_flags
), flags
);
867 /* Save time that file was placed in queue and current time. */
869 xptr
->xf_intoque
= intoQue
;
870 xptr
->xf_deque
= time((time_t *) 0);
875 * Function: pfInit - Initialize Performance Package
877 * This function allows the performance package to initialize its internal
878 * data structures. It should be called one time only when uucico starts
890 register struct xferData
* xptr
= &Xfer
;
892 if (Initialized
== TRUE
)
896 copyText(xptr
->xf_flags
, sizeof(xptr
->xf_flags
), NOTAVAIL
);
899 * Attempt to open the log file. If we can't do it, then we
900 * won't collect statistics.
903 if (openLog(&LogFile
,LogName
) == SUCCESS
)
912 * Function: pfStrtConn - Going to Establish Connection
914 * Uucico uses pfStrtConn to announce that it is going to attempt
915 * to establish a connection.
919 * role - An indication of whether uucico is currently
920 * running in master or slave mode. M = master,
930 grabTimes(&Conn
.cn_times
[CT_START
]);
936 * Function: pfStrtXfer - Starting File Transfer
938 * This function should be called just as the first byte of data is
939 * about to be transferred.
943 * role - An indication of whether uucico is currently
944 * running in master or slave mode. M = master,
947 * direction - Direction of file transfer. S = sending to
948 * remote, R = receiving from remote.
952 pfStrtXfer(role
, direction
)
958 register struct xferData
* xptr
= &Xfer
;
961 grabTimes(&xptr
->xf_times
[XT_BEGXFER
]);
962 xptr
->xf_role
= role
;
963 xptr
->xf_direction
= direction
;
968 A protocol which both master and slave sides agree on
975 strcpy(Protocol
,str
);
980 * Function: openLog - Open the Log File
982 * If the log file is already open this function immediately returns
983 * success. Otherwise, an attempt is made to open the logfile in append
988 * logfile - file descripter
989 * logname - name of log file.
993 * SUCCESS - The log file is open.
994 * FAIL - Unable to open logfile.
998 openLog (logfile
,logname
)
1002 register int fd
; /* File descriptor of log file. */
1004 int level
; /* Level for debug message. */
1005 char msgbuf
[BUFSIZ
];
1007 /* See if file already open. */
1009 if (*logfile
!= CLOSED
)
1012 /* Attempt to open the file. */
1014 DEBUG(DB_TRACE
, Msg_opening
, logname
);
1017 fd
= open(logname
, O_WRONLY
| O_APPEND
);
1018 } while ((fd
< 0) && (errno
== EINTR
)); /* Retry if interrupted. */
1019 if (fd
< 0) { /* Error on open. */
1020 (void) sprintf(msgbuf
, Msg_badopen
, logname
);
1021 if (errno
== ENOENT
)
1022 level
= DB_DETAIL
; /* If the file is not there
1023 * it will usually mean
1024 * that the SA doesn't
1028 level
= DB_IMPORTANT
; /* Unexpected error */
1029 DEBUG(level
, msgbuf
, errno
); /* No log file. */
1038 #include <sys/time.h>
1039 #include <sys/times.h>
1040 #include <sys/resource.h>
1044 register struct timeval
*tvp
;
1046 return (tvp
->tv_sec
* 60 + tvp
->tv_usec
/ 16667);
1051 register struct tms
*tmsp
;
1055 static time_t epoch
;
1057 if (getrusage(RUSAGE_SELF
, &ru
) < 0)
1058 return (clock_t)(-1);
1059 tmsp
->tms_utime
= scale60(&ru
.ru_utime
);
1060 tmsp
->tms_stime
= scale60(&ru
.ru_stime
);
1061 if (getrusage(RUSAGE_CHILDREN
, &ru
) < 0)
1062 return (clock_t)(-1);
1063 tmsp
->tms_cutime
= scale60(&ru
.ru_utime
);
1064 tmsp
->tms_cstime
= scale60(&ru
.ru_stime
);
1065 if (gettimeofday(&now
, (struct timezone
*)0) < 0)
1066 return (clock_t)(-1);
1069 now
.tv_sec
-= epoch
;
1070 return (scale60(&now
));