From: Dan Kegel <dank@kegel.com>
To: Pete Wyckoff <pw@osc.edu>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: getrusage vs /proc/pid/stat?
Date: Mon, 18 Jun 2001 14:20:20 -0700 [thread overview]
Message-ID: <3B2E7094.D53308BD@kegel.com> (raw)
In-Reply-To: <3B2D8ED0.40B299B5@kegel.com> <20010618134433.C9415@osc.edu>
Pete Wyckoff wrote:
>
> dank@kegel.com said:
> > I'd like to monitor CPU, memory, and I/O utilization in a
> > long-running multithreaded daemon under kernels 2.2, 2.4,
> > and possibly also Solaris (#ifdefs are ok).
>
> getrusage() isn't really the system call you want for this.
I'll buy that. Looks like a lot of unices don't implement that
call fully, and Linux is one of them.
What is the proper way to measure total CPU time used by a multithreaded program?
The only way I can figure to do it is to sum /proc/pid/stat across
the threads of interest (see below). Is this the easiest way,
or am I missing something? (Forgive the C++. I'd recode this in C
if it were for general use.)
========= LinuxTimes.h ==========
#include <sys/times.h>
#include <pthread.h>
/*--------------------------------------------------------------------------
Source and test case at http://www.kegel.com/lt.tar.gz
Monitor the CPU usage of a bunch of threads in the same process.
This is a simulation of the system call times()
providing traditional semantics under LinuxThreads.
On e.g. Solaris, you don't need this; you just call the standard times().
--------------------------------------------------------------------------*/
class LinuxTimes {
const static int MAXTHREADS = 100;
/// number of threads being monitored
int m_nthreads;
/// fd open to /proc/pid/stat for each thread
int m_proc_pid_stat_fd[MAXTHREADS];
/// make addSelf threadsafe
pthread_mutex_t m_lock;
public:
LinuxTimes() { m_nthreads = 0; pthread_mutex_init(&m_lock, NULL); }
/**
New threads call this to add themselves to the group.
Threadsafe.
@return 0 on success, Unix error code on failure
*/
int addSelf();
/**
Calculate user and system time accumulated by all threads in group.
Return result in tms_utime and tms_stime fields of given struct tms.
Similar to 'man 2 times' on Solaris (where all CPU time of all threads
is counted as CPU time towards the process).
@return 0 on success, Unix error code on failure
*/
int times(struct tms *buf);
};
========= LinuxTimes.cc ==========
#include "LinuxTimes.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
/**
New threads call this to add themselves to the group.
Threadsafe.
@return 0 on success, Unix error code on failure
*/
int LinuxTimes::addSelf()
{
int fd;
char fname[256];
int err = 0;
if (pthread_mutex_lock(&m_lock))
return EINVAL;
if (m_nthreads >= MAXTHREADS) {
err = E2BIG;
} else {
// Under LinuxThreads, each thread has its own pid
sprintf(fname, "/proc/%d/stat", getpid());
fd = open(fname, O_RDONLY);
if (fd == -1)
err = errno;
else {
m_proc_pid_stat_fd[m_nthreads++] = fd;
}
}
if (pthread_mutex_unlock(&m_lock))
return EINVAL;
return err;
}
/* Skip to char after nth whitespace. Returns NULL on failure. */
static const char *skipNspace(const char *p, int n)
{
while (*++p)
if (isspace(*p) && ! --n)
return p+1;
return NULL;
}
/**
Calculate user and system time accumulated by all threads in group.
Return result in tms_utime and tms_stime fields of given struct tms.
Similar to 'man 2 times' on Solaris (where all CPU time of all threads
is counted as CPU time towards the process).
@return 0 on success, Unix error code on failure
*/
int LinuxTimes::times(struct tms *buf)
{
int i;
int nread;
buf->tms_utime = 0;
buf->tms_stime = 0;
for (i=0; i<m_nthreads; i++) {
char scratch[1024]; // FIXME: is that big enough?
int fd = m_proc_pid_stat_fd[i];
// rewind to start of stat file. (Not all /proc entries support this.)
if (lseek(fd, 0, SEEK_SET))
return EBADF;
// Read in ASCII data and parse out utime and stime fields
// (see 'man proc')
nread = read(fd, scratch, sizeof(scratch)-1);
if (nread < 50) // FIXME: cheesy
return EINVAL;
scratch[nread] = 0;
// Skip to end of command field
// FIXME: what if executable has ) in its filename? Bleh.
const char *p = strchr(scratch, ')') + 2;
// Skip to utime field
p = skipNspace(p, 11);
if (!p) return EINVAL;
buf->tms_utime += atoi(p);
// Skip to stime field
p = skipNspace(p, 1);
if (!p) return EINVAL;
buf->tms_stime += atoi(p);
}
return 0;
}
==============
Thanks,
Dan
--
"A computer is a state machine.
Threads are for people who can't program state machines."
- Alan Cox
next prev parent reply other threads:[~2001-06-18 21:19 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-06-18 5:17 getrusage vs /proc/pid/stat? Dan Kegel
2001-06-18 17:44 ` Pete Wyckoff
2001-06-18 21:20 ` Dan Kegel [this message]
2001-06-18 23:34 ` J . A . Magallon
2001-06-19 15:05 ` Dan Kegel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3B2E7094.D53308BD@kegel.com \
--to=dank@kegel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=pw@osc.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.