summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/exec.c50
-rw-r--r--Src/init.c2
-rw-r--r--Src/jobs.c110
-rw-r--r--Src/signals.c4
-rw-r--r--Src/zsh.h11
-rw-r--r--configure.ac2
7 files changed, 148 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index 423827b0a..453ec96da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2004-10-07  Peter Stephenson  <pws@csr.com>
+
+	* 20462: configure.ac, Src/exec.c, Src/init.c, Src/jobs.c,
+	Src/signals.c, Src/zsh.h: Improve process timing by using
+	getrusage() where available (everywhere?) and by starting
+	the wallclock just before a process is forked.
+
 2004-10-07  Wayne Davison  <wayned@users.sourceforge.net>
 
 	* unposted: Completion/Unix/Command/_rsync: added options that
diff --git a/Src/exec.c b/Src/exec.c
index 8c2124c43..47d20bb93 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -212,9 +212,10 @@ setlimits(char *nam)
 
 /**/
 static pid_t
-zfork(void)
+zfork(struct timeval *tv)
 {
     pid_t pid;
+    struct timezone dummy_tz;
 
     /*
      * Is anybody willing to explain this test?
@@ -223,6 +224,8 @@ zfork(void)
 	zerr("job table full", NULL, 0);
 	return -1;
     }
+    if (tv)
+	gettimeofday(tv, &dummy_tz);
     pid = fork();
     if (pid == -1) {
 	zerr("fork failed: %e", NULL, errno);
@@ -313,6 +316,7 @@ zfork(void)
 int list_pipe = 0, simple_pline = 0;
 
 static pid_t list_pipe_pid;
+static struct timeval list_pipe_start;
 static int nowait, pline_level = 0;
 static int list_pipe_child = 0, list_pipe_job;
 static char list_pipe_text[JOBTEXTSIZE];
@@ -1101,7 +1105,8 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 
 		    curjob = newjob;
 		    DPUTS(!list_pipe_pid, "invalid list_pipe_pid");
-		    addproc(list_pipe_pid, list_pipe_text, 0);
+		    addproc(list_pipe_pid, list_pipe_text, 0,
+			    &list_pipe_start);
 
 		    /* If the super-job contains only the sub-shell, the
 		       sub-shell is the group leader. */
@@ -1157,9 +1162,13 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		      (jobtab[list_pipe_job].stat & STAT_STOPPED)))) {
 		    pid_t pid;
 		    int synch[2];
+		    struct timezone dummy_tz;
+		    struct timeval bgtime;
 
 		    pipe(synch);
 
+		    gettimeofday(&bgtime, &dummy_tz);
+		    /* Any reason this isn't zfork? */
 		    if ((pid = fork()) == -1) {
 			trashzle();
 			close(synch[0]);
@@ -1177,6 +1186,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 			lpforked = 
 			    (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
 			list_pipe_pid = pid;
+			list_pipe_start = bgtime;
 			nowait = errflag = 1;
 			breaks = loops;
 			close(synch[1]);
@@ -1289,8 +1299,12 @@ execpline2(Estate state, wordcode pcode,
 	 * rest of the pipeline in the current shell.         */
 	if (wc_code(code) >= WC_CURSH && (how & Z_SYNC)) {
 	    int synch[2];
+	    struct timeval bgtime;
+	    struct timezone dummy_tz;
 
 	    pipe(synch);
+	    gettimeofday(&bgtime, &dummy_tz);
+	    /* any reason this isn't zfork? */
 	    if ((pid = fork()) == -1) {
 		close(synch[0]);
 		close(synch[1]);
@@ -1299,7 +1313,7 @@ execpline2(Estate state, wordcode pcode,
 		char dummy, *text;
 
 		text = getjobtext(state->prog, state->pc);
-		addproc(pid, text, 0);
+		addproc(pid, text, 0, &bgtime);
 		close(synch[1]);
 		read(synch[0], &dummy, 1);
 		close(synch[0]);
@@ -1437,8 +1451,9 @@ closemn(struct multio **mfds, int fd)
 	char buf[TCBUFSIZE];
 	int len, i;
 	pid_t pid;
+	struct timeval bgtime;
 
-	if ((pid = zfork())) {
+	if ((pid = zfork(&bgtime))) {
 	    for (i = 0; i < mn->ct; i++)
 		zclose(mn->fds[i]);
 	    zclose(mn->pipe);
@@ -1448,7 +1463,7 @@ closemn(struct multio **mfds, int fd)
 	    }
 	    mn->ct = 1;
 	    mn->fds[0] = fd;
-	    addproc(pid, NULL, 1);
+	    addproc(pid, NULL, 1, &bgtime);
 	    return;
 	}
 	/* pid == 0 */
@@ -2108,11 +2123,12 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	pid_t pid;
 	int synch[2];
 	char dummy;
+	struct timeval bgtime;
 
 	child_block();
 	pipe(synch);
 
-	if ((pid = zfork()) == -1) {
+	if ((pid = zfork(&bgtime)) == -1) {
 	    close(synch[0]);
 	    close(synch[1]);
             opts[AUTOCONTINUE] = oautocont;
@@ -2140,7 +2156,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 			  3 : WC_ASSIGN_NUM(ac) + 2);
 		}
 	    }
-	    addproc(pid, text, 0);
+	    addproc(pid, text, 0, &bgtime);
             opts[AUTOCONTINUE] = oautocont;
 	    return;
 	}
@@ -2697,7 +2713,7 @@ entersubsh(int how, int cl, int fake, int revertpgrp)
     zleactive = 0;
     if (cl)
 	clearjobtab(monitor);
-    times(&shtms);
+    get_usage();
     forklevel = locallevel;
 }
 
@@ -2843,7 +2859,7 @@ getoutput(char *cmd, int qt)
     mpipe(pipes);
     child_block();
     cmdoutval = 0;
-    if ((cmdoutpid = pid = zfork()) == -1) {
+    if ((cmdoutpid = pid = zfork(NULL)) == -1) {
 	/* fork error */
 	zclose(pipes[0]);
 	zclose(pipes[1]);
@@ -2979,7 +2995,7 @@ getoutputfile(char *cmd)
     child_block();
     fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600);
 
-    if (fd < 0 || (cmdoutpid = pid = zfork()) == -1) {
+    if (fd < 0 || (cmdoutpid = pid = zfork(NULL)) == -1) {
 	/* fork or open error */
 	child_unblock();
 	return nam;
@@ -3040,6 +3056,7 @@ getproc(char *cmd)
     int out = *cmd == Inang;
     char *pnam;
     pid_t pid;
+    struct timeval bgtime;
 
 #ifndef PATH_DEV_FD
     int fd;
@@ -3054,11 +3071,11 @@ getproc(char *cmd)
 	jobtab[thisjob].filelist = znewlinklist();
     zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
 
-    if ((pid = zfork())) {
+    if ((pid = zfork(&bgtime))) {
 	if (pid == -1)
 	    return NULL;
 	if (!out)
-	    addproc(pid, NULL, 1);
+	    addproc(pid, NULL, 1, &bgtime);
 	return pnam;
     }
     closem(0);
@@ -3078,7 +3095,7 @@ getproc(char *cmd)
     if (!(prog = parsecmd(cmd)))
 	return NULL;
     mpipe(pipes);
-    if ((pid = zfork())) {
+    if ((pid = zfork(&bgtime))) {
 	sprintf(pnam, "%s/%d", PATH_DEV_FD, pipes[!out]);
 	zclose(pipes[out]);
 	if (pid == -1)
@@ -3089,7 +3106,7 @@ getproc(char *cmd)
 	fdtable[pipes[!out]] = 2;
 	if (!out)
 	{
-	    addproc(pid, NULL, 1);
+	    addproc(pid, NULL, 1, &bgtime);
 	}
 	return pnam;
     }
@@ -3116,17 +3133,18 @@ getpipe(char *cmd)
     Eprog prog;
     int pipes[2], out = *cmd == Inang;
     pid_t pid;
+    struct timeval bgtime;
 
     if (!(prog = parsecmd(cmd)))
 	return -1;
     mpipe(pipes);
-    if ((pid = zfork())) {
+    if ((pid = zfork(&bgtime))) {
 	zclose(pipes[out]);
 	if (pid == -1) {
 	    zclose(pipes[!out]);
 	    return -1;
 	}
-	addproc(pid, NULL, 1);
+	addproc(pid, NULL, 1, &bgtime);
 	return pipes[!out];
     }
     entersubsh(Z_ASYNC, 1, 0, 0);
diff --git a/Src/init.c b/Src/init.c
index ef101069c..370f93782 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -856,7 +856,7 @@ setupvals(void)
 #endif
     }
 
-    times(&shtms);
+    get_usage();
 
     /* Close the file descriptors we opened to block off 0 to 9 */
     for (i = 0; i < 10; i++)
diff --git a/Src/jobs.c b/Src/jobs.c
index a24208759..0c3960e87 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -80,7 +80,15 @@ static int oldmaxjob;
 /* shell timings */
  
 /**/
-struct tms shtms;
+#ifdef HAVE_GETRUSAGE
+/**/
+static struct rusage child_usage;
+/**/
+#else
+/**/
+static struct tms shtms;
+/**/
+#endif
  
 /* 1 if ttyctl -f has been executed */
  
@@ -93,8 +101,6 @@ int ttyfrozen;
 /**/
 int prev_errflag, prev_breaks, errbrk_saved;
 
-static struct timeval dtimeval, now;
-
 /**/
 int numpipestats, pipestats[MAX_PIPESTATS];
 
@@ -250,6 +256,21 @@ handle_sub(int job, int fg)
     return 0;
 }
 
+
+/* Get the latest usage information */
+
+/**/
+void 
+get_usage(void)
+{
+#ifdef HAVE_GETRUSAGE
+    getrusage(RUSAGE_CHILDREN, &child_usage);
+#else
+    times(shtms);
+#endif
+}
+
+
 /* Update status of process that we have just WAIT'ed for */
 
 /**/
@@ -257,17 +278,31 @@ void
 update_process(Process pn, int status)
 {
     struct timezone dummy_tz;
+#ifdef HAVE_GETRUSAGE
+    struct timeval childs, childu;
+#else
     long childs, childu;
+#endif
 
+#ifdef HAVE_GETRUSAGE
+    childs = child_usage.ru_stime;
+    childu = child_usage.ru_utime;
+#else
     childs = shtms.tms_cstime;
     childu = shtms.tms_cutime;
-    times(&shtms);                          /* get time-accounting info          */
+#endif
+    /* get time-accounting info          */
+    get_usage();
+    gettimeofday(&pn->endtime, &dummy_tz);  /* record time process exited        */
 
     pn->status = status;                    /* save the status returned by WAIT  */
+#ifdef HAVE_GETRUSAGE
+    dtime(&pn->ti.sys, &childs, &child_usage.ru_stime);
+    dtime(&pn->ti.usr, &childu, &child_usage.ru_utime);
+#else
     pn->ti.st  = shtms.tms_cstime - childs; /* compute process system space time */
     pn->ti.ut  = shtms.tms_cutime - childu; /* compute process user space time   */
-
-    gettimeofday(&pn->endtime, &dummy_tz);  /* record time process exited        */
+#endif
 }
 
 /* Update status of job, possibly printing it */
@@ -473,6 +508,8 @@ setprevjob(void)
     prevjob = -1;
 }
 
+/**/
+#ifndef HAVE_GETRUSAGE
 static long clktck = 0;
 
 /**/
@@ -501,6 +538,8 @@ set_clktck(void)
 # endif
 #endif
 }
+/**/
+#endif
 
 /**/
 static void
@@ -519,9 +558,8 @@ printhhmmss(double secs)
 	fprintf(stderr,           "%.3f",              secs);
 }
 
-/**/
 static void
-printtime(struct timeval *real, struct timeinfo *ti, char *desc)
+printtime(struct timeval *real, child_times_t *ti, char *desc)
 {
     char *s;
     double elapsed_time, user_time, system_time;
@@ -530,13 +568,21 @@ printtime(struct timeval *real, struct timeinfo *ti, char *desc)
     if (!desc)
 	desc = "";
 
-    set_clktck();
     /* go ahead and compute these, since almost every TIMEFMT will have them */
     elapsed_time = real->tv_sec + real->tv_usec / 1000000.0;
+
+#ifdef HAVE_GETRUSAGE
+    user_time = ti->usr.tv_sec + ti->usr.tv_usec / 1000000.0;
+    system_time = ti->sys.tv_sec + ti->sys.tv_usec / 1000000.0;
+    percent = 100.0 * (user_time + system_time)
+	/ (real->tv_sec + real->tv_usec / 1000000.0);
+#else
+    set_clktck();
     user_time    = ti->ut / (double) clktck;
     system_time  = ti->st / (double) clktck;
     percent      =  100.0 * (ti->ut + ti->st)
 	/ (clktck * real->tv_sec + clktck * real->tv_usec / 1000000.0);
+#endif
 
     queue_signals();
     if (!(s = getsparam("TIMEFMT")))
@@ -598,11 +644,13 @@ static void
 dumptime(Job jn)
 {
     Process pn;
+    struct timeval dtimeval;
 
     if (!jn->procs)
 	return;
     for (pn = jn->procs; pn; pn = pn->next)
-	printtime(dtime(&dtimeval, &pn->bgtime, &pn->endtime), &pn->ti, pn->text);
+	printtime(dtime(&dtimeval, &pn->bgtime, &pn->endtime), &pn->ti,
+		  pn->text);
 }
 
 /* Check whether shell should report the amount of time consumed   *
@@ -617,7 +665,7 @@ should_report_time(Job j)
     struct value vbuf;
     Value v;
     char *s = "REPORTTIME";
-    int reporttime;
+    zlong reporttime;
 
     /* if the time keyword was used */
     if (j->stat & STAT_TIMED)
@@ -634,8 +682,15 @@ should_report_time(Job j)
     if (!j->procs)
 	return 0;
 
+#ifdef HAVE_GETRUSAGE
+    reporttime -= j->procs->ti.usr.tv_sec + j->procs->ti.sys.tv_sec;
+    if (j->procs->ti.usr.tv_usec + j->procs->ti.sys.tv_usec >= 1000000)
+	reporttime--;
+    return reporttime <= 0;
+#else
     set_clktck();
     return ((j->procs->ti.ut + j->procs->ti.st) / clktck >= reporttime);
+#endif
 }
 
 /* !(lng & 3) means jobs    *
@@ -899,10 +954,9 @@ deletejob(Job jn)
 
 /**/
 void
-addproc(pid_t pid, char *text, int aux)
+addproc(pid_t pid, char *text, int aux, struct timeval *bgtime)
 {
     Process pn, *pnlist;
-    struct timezone dummy_tz;
 
     DPUTS(thisjob == -1, "No valid job in addproc.");
     pn = (Process) zshcalloc(sizeof *pn);
@@ -916,7 +970,7 @@ addproc(pid_t pid, char *text, int aux)
 
     if (!aux)
     {
-	gettimeofday(&pn->bgtime, &dummy_tz);
+	pn->bgtime = *bgtime;
 	/* if this is the first process we are adding to *
 	 * the job, then it's the group leader.          */
 	if (!jobtab[thisjob].gleader)
@@ -1158,18 +1212,40 @@ spawnjob(void)
 void
 shelltime(void)
 {
-    struct timeinfo ti;
     struct timezone dummy_tz;
+    struct timeval dtimeval, now;
+#ifdef HAVE_GETRUSAGE
+    struct rusage ru;
+    child_times_t ti;
+#else
+    struct timeinfo ti;
     struct tms buf;
+#endif
+
+    gettimeofday(&now, &dummy_tz);
 
+#ifdef HAVE_GETRUSAGE
+    getrusage(RUSAGE_SELF, &ru);
+    ti.sys = ru.ru_stime;
+    ti.usr = ru.ru_utime;
+#else
     times(&buf);
+
     ti.ut = buf.tms_utime;
     ti.st = buf.tms_stime;
-    gettimeofday(&now, &dummy_tz);
+#endif
     printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
+
+#ifdef HAVE_GETRUSAGE
+    getrusage(RUSAGE_CHILDREN, &ru);
+    ti.sys = ru.ru_stime;
+    ti.usr = ru.ru_utime;
+#else
     ti.ut = buf.tms_cutime;
     ti.st = buf.tms_cstime;
-    printtime(dtime(&dtimeval, &shtimer, &now), &ti, "children");
+#endif
+    printtime(&dtimeval, &ti, "children");
+
 }
 
 /* see if jobs need printing */
diff --git a/Src/signals.c b/Src/signals.c
index 6c6c28159..df9120d2d 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -484,7 +484,7 @@ zhandler(int sig)
 			*procsubval = (0200 | WTERMSIG(status));
 		    else
 			*procsubval = WEXITSTATUS(status);
-		    times(&shtms);
+		    get_usage();
 		    goto cont;
 		}
 		if (!es)
@@ -514,7 +514,7 @@ zhandler(int sig)
 		 * children in sub processes anyway:  otherwise, this
 		 * will get added on to the next found process that terminates.
 		 */
-		times(&shtms);
+		get_usage();
 	    }
         }
         break;
diff --git a/Src/zsh.h b/Src/zsh.h
index b11e8f1e8..bde274d9b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -739,12 +739,21 @@ struct timeinfo {
 
 /* node in job process lists */
 
+#ifdef HAVE_GETRUSAGE
+typedef struct {
+    struct timeval sys;
+    struct timeval usr;
+} child_times_t;
+#else
+typedef struct timeinfo child_times_t;
+#endif
+
 struct process {
     struct process *next;
     pid_t pid;                  /* process id                       */
     char text[JOBTEXTSIZE];	/* text to print when 'jobs' is run */
     int status;			/* return code from waitpid/wait3() */
-    struct timeinfo ti;
+    child_times_t ti;
     struct timeval bgtime;	/* time job was spawned             */
     struct timeval endtime;	/* time job exited                  */
 };
diff --git a/configure.ac b/configure.ac
index 3fdac2104..11b97b9da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1043,7 +1043,7 @@ AC_CHECK_FUNCS(strftime difftime gettimeofday \
 	       initgroups nis_list \
 	       setuid seteuid setreuid setresuid setsid \
 	       memcpy memmove strstr strerror \
-	       getrlimit \
+	       getrlimit getrusage \
 	       setlocale \
 	       uname \
 	       signgam \