mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Rick Lindsley <ricklind@us.ibm.com>
Cc: "Martin J. Bligh" <mbligh@aracnet.com>,
	Con Kolivas <kernel@kolivas.org>,
	linux-kernel@vger.kernel.org
Subject: latency.c [was: Re: 2.6.9-rc1-mm1]
Date: Sun, 5 Sep 2004 01:10:07 +0200	[thread overview]
Message-ID: <200409050110.07728.rjw@sisk.pl> (raw)
In-Reply-To: <200408272154.i7RLsJk02714@owlet.beaverton.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 1256 bytes --]

On Friday 27 of August 2004 23:54, Rick Lindsley wrote:
[- snip -]
> You can also pick up the program "latency.c" at
> 
>     http://eaglet.rain.com/rick/linux/schedstat/v9/latency.c
> 
> With these two things in hand, you should be able to measure the latency
> on 2.6.8.1 of a particular process.
> 
> A patch is not necessary for 2.6.9-rc1-mm1 (schedstats is already in there)
> but you will need to config the kernel to use it.  Then retrieve a slightly
> different latency.c:
>     
>     http://eaglet.rain.com/rick/linux/schedstat/v10/latency.c
> 
> since 2.6.9-rc1-mm1 output format is different (as you noted, it's a
> different scheduler.)  Then you should be able to see if the latency of
> a particular process (updatedb, for instance) changes.

I've fiddled a bit with both the latency.c programs.  I've added some options 
to them etc.  In particular, now you can specify a program to run and monitor 
instead of a pid, which is handy if you need to monitor processes that exit 
quickly.  Everything is documented in the sources (attached).  I thought you 
might find this useful. :-)

Regards,
RJW

-- 
For a successful technology, reality must take precedence over public 
relations, for nature cannot be fooled.
					-- Richard P. Feynman

[-- Attachment #2: latency-v9.c --]
[-- Type: text/x-csrc, Size: 5613 bytes --]

/*
 * latency -- measure the scheduling latency of a particular process from
 *	the extra information provided in /proc/<pid>stat by version 4 of
 *	the schedstat patch. PLEASE NOTE: This program does NOT check to
 *	make sure that extra information is there; it assumes the last
 *	three fields in that line are the ones it's interested in.  Using
 *	it on a kernel that does not have the schedstat patch compiled in
 *	will cause it to happily produce bizarre results.
 *
 *	Note too that this is known to work only with versions 4 and 5
 *	of the schedstat patch, for similar reasons.
 *
 *	This currently monitors only one pid at a time but could easily
 *	be modified to do more.
 */
/*
 * Modified by Rafael J. Wysocki <rjw@sisk.pl> on September 4, 2004
 * Added options:
 * -o -- allows one to specify a log file to store the results in
 * -n -- turns on a numerical-only format (mutually exclusive with -v)
 * -r -- allows one to specify a program to run and monitor for latencies instead of a pid
 *
 * The -r option is handy if you want to monitor a process that exits quickly (eg. gcc or tar etc.).
 * The -o is necessary if -r is specified to separate the output of latency.c with the output of the
 * monitored process
 * The output generated with the -n option may be useful for creating graphs
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <strings.h>

#define STRLEN 256

char procbuf[512];
char statname[64];
char progpath[STRLEN];
char logpath[STRLEN];
char *Progname;
FILE *fp, *outp;

void usage()
{
    fprintf(stderr, "Usage: %s [{-v|-n} ][-s sleeptime ][-o logfile ]{-r program|<pid>}\n", Progname);
    exit(-1);
}

/*
 * execute() is used to spawn a new process that will be monitored for latencies
 * The new process' command line is passed in *file
 */

void execute(char *file)
{
    char *ptr, **args;
    int cnt =  1, j;

    /* See how many arguments are to be passed */
    for (ptr = file; *ptr; ptr++)
	if (*ptr == ' ')  cnt++;
    args = (char **)malloc((cnt + 1) * sizeof(char *));
    /* Extract the arguments */
    args[0] =  file;
    ptr =  file;
    for (j = 1; j < cnt; j++) {
	ptr =  index(ptr, ' ');
	*ptr++ = '\0';
	args[j] =  ptr;
    }
    args[j] =  NULL;
    /* Run the program */
    execvp(args[0], args);
}

/*
 * get_stats() -- we presume that we are interested in the last three
 *	fields of the line we are handed, and further, that they contain
 *	only numbers and single spaces.
 */
void get_stats(char *buf, char *id, unsigned int *run_ticks,
	       unsigned int *wait_ticks, unsigned int *nran)
{
    char *ptr;

    ptr = index(buf, ')') + 1;
    *ptr = 0;
    strcpy(id, buf);
    *ptr = ' ';

    ptr = rindex(buf,' ');
    if (!ptr) return;

    *nran = atoi(ptr--);

    while (isdigit(*ptr) && --ptr != buf);
    if (ptr == buf) return;

    *wait_ticks = atoi(ptr--);

    while (isdigit(*ptr) && --ptr != buf);
    if (ptr == buf) return;

    *run_ticks = atoi(ptr);
}

main(int argc, char *argv[])
{
    int c;
    unsigned int sleeptime = 5, pid = 0, verbose = 0, numeric = 0, runprog = 0, log = 0;
    char id[32];
    unsigned int run_ticks, wait_ticks, nran;
    unsigned int orun_ticks=0, owait_ticks=0, oran=0;

    Progname = argv[0];
    id[0] = 0;
    while ((c = getopt(argc, argv, "s:vnr:o:")) != -1) {
	switch (c) {
	    case 's':
		sleeptime = atoi(optarg);
		break;
	    case 'v':
		verbose++;
		break;
	    case 'n':
		numeric++;
		break;
	    case 'r':
		strncpy(progpath, optarg, STRLEN - 1);
		progpath[STRLEN - 1] =  '\0';
		runprog++;
		break;
	    case 'o':
		strncpy(logpath, optarg, STRLEN - 1);
		logpath[STRLEN - 1] =  '\0';
		log++;
		break;
	    default:
		usage();
	}
    }

    if (verbose && numeric)
	usage();

    if (runprog) {
	pid =  fork();
	if (pid < 0) {
	    puts("fork() failed");
	    exit(pid);
	}
	if (!pid)
	    execute(progpath);
    }
    else if (optind < argc) {
	pid = atoi(argv[optind]);
    }

    if (!pid)
	usage();

    outp =  NULL;
    if (log)
	outp =  fopen(logpath, "w");
    if (!outp) {
	outp =  stdout;
	log = 0;
    }
    /*
     * now just spin collecting the stats
     */
    sprintf(statname,"/proc/%d/stat", pid);
    while (fp = fopen(statname, "r")) {
	    if (runprog)
		waitpid(pid, NULL, WNOHANG);

	    if (!fgets(procbuf, sizeof(procbuf), fp))
		    break;

	    get_stats(procbuf, id, &run_ticks, &wait_ticks, &nran);

	    if (verbose)
		fprintf(outp, "%s %d(%d) %d(%d) %d(%d) %4.2f %4.2f\n",
		    id, run_ticks, run_ticks - orun_ticks,
		    wait_ticks, wait_ticks - owait_ticks,
		    nran, nran - oran,
		    nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    else if (numeric)
		fprintf(outp, "%s %4.2f %4.2f\n",
		    id, nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    else
		fprintf(outp, "%s avgrun=%4.2fms avgwait=%4.2fms\n",
		    id, nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    fclose(fp);
	    oran = nran;
	    orun_ticks = run_ticks;
	    owait_ticks = wait_ticks;
	    sleep(sleeptime);

	    if (runprog)
		waitpid(pid, NULL, WNOHANG);

	    fp = fopen(statname,"r");
	    if (!fp)
		    break;
    }
    if (log)
	fclose(outp);
    if (id[0])
	printf("Process %s has exited.\n", id);
    else
	printf("Process %d does not exist.\n", pid);
    exit(0);
}

[-- Attachment #3: latency-v10.c --]
[-- Type: text/x-csrc, Size: 6230 bytes --]

/*
 * latency -- measure the scheduling latency of a particular process from
 *	the extra information provided in /proc/<pid>stat by version 4 of
 *	the schedstat patch. PLEASE NOTE: This program does NOT check to
 *	make sure that extra information is there; it assumes the last
 *	three fields in that line are the ones it's interested in.  Using
 *	it on a kernel that does not have the schedstat patch compiled in
 *	will cause it to happily produce bizarre results.
 *
 *	Note too that this is known to work only with versions 4 and 5
 *	of the schedstat patch, for similar reasons.
 *
 *	This currently monitors only one pid at a time but could easily
 *	be modified to do more.
 */
/*
 * Modified by Rafael J. Wysocki <rjw@sisk.pl> on September 4, 2004
 * Added options:
 * -o -- allows one to specify a log file to store the results in
 * -n -- turns on a numerical-only format (mutually exclusive with -v)
 * -r -- allows one to specify a program to run and monitor for latencies instead of a pid
 *
 * The -r option is handy if you want to monitor a process that exits quickly (eg. gcc or tar etc.).
 * The -o is necessary if -r is specified to separate the output of latency.c with the output of the
 * monitored process
 * The output generated with the -n option may be useful for creating graphs
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <strings.h>

#define STRLEN 256

extern char *index(), *rindex();
char procbuf[512];
char statname[64];
char progpath[STRLEN];
char logpath[STRLEN];
char *Progname;
FILE *fp, *outp;

void usage()
{
    fprintf(stderr, "Usage: %s [{-v|-n} ][-s sleeptime ][-o logfile ]{-r program|<pid>}\n", Progname);
    exit(-1);
}

/*
 * execute() is used to spawn a new process that will be monitored for latencies
 * The new process' command line is passed in *file
 */

void execute(char *file)
{
    char *ptr, **args;
    int cnt =  1, j;

    /* See how many arguments are to be passed */
    for (ptr = file; *ptr; ptr++)
	if (*ptr == ' ')  cnt++;
    args = (char **)malloc((cnt + 1) * sizeof(char *));
    /* Extract the arguments */
    args[0] =  file;
    ptr =  file;
    for (j = 1; j < cnt; j++) {
	ptr =  index(ptr, ' ');
	*ptr++ = '\0';
	args[j] =  ptr;
    }
    args[j] =  NULL;
    /* Run the program */
    execvp(args[0], args);
}

/*
 * get_stats() -- we presume that we are interested in the first three
 *	fields of the line we are handed, and further, that they contain
 *	only numbers and single spaces.
 */
void get_stats(char *buf, unsigned int *run_ticks, unsigned int *wait_ticks,
    unsigned int *nran)
{
    char *ptr;

    /* sanity */
    if (!buf || !run_ticks || !wait_ticks || !nran)
	return;

    /* leading blanks */
    ptr = buf;
    while (*ptr && isblank(*ptr))
	ptr++;

    /* first number -- run_ticks */
    *run_ticks = atoi(ptr);
    while (*ptr && isdigit(*ptr))
	ptr++;
    while (*ptr && isblank(*ptr))
	ptr++;

    /* second number -- wait_ticks */
    *wait_ticks = atoi(ptr);
    while (*ptr && isdigit(*ptr))
	ptr++;
    while (*ptr && isblank(*ptr))
	ptr++;

    /* last number -- nran */
    *nran = atoi(ptr);
}

/*
 * get_id() -- extract the id field from that /proc/<pid>/stat file
 */
void get_id(char *buf, char *id)

{
    char *ptr;

    /* sanity */
    if (!buf || !id)
	return;

    ptr = index(buf, ')') + 1;
    *ptr = 0;
    strcpy(id, buf);
    *ptr = ' ';

    return;
}

main(int argc, char *argv[])
{
    int c;
    unsigned int sleeptime = 5, pid = 0, verbose = 0, numeric = 0, runprog = 0, log = 0;
    char id[32];
    unsigned int run_ticks, wait_ticks, nran;
    unsigned int orun_ticks=0, owait_ticks=0, oran=0;

    Progname = argv[0];
    id[0] = 0;
    while ((c = getopt(argc,argv,"s:vnr:o:")) != -1) {
	switch (c) {
	    case 's':
		sleeptime = atoi(optarg);
		break;
	    case 'v':
		verbose++;
		break;
	    case 'n':
		numeric++;
		break;
	    case 'r':
		strncpy(progpath, optarg, STRLEN - 1);
		progpath[STRLEN - 1] =  '\0';
		runprog++;
		break;
	    case 'o':
		strncpy(logpath, optarg, STRLEN - 1);
		logpath[STRLEN - 1] =  '\0';
		log++;
		break;
	    default:
		usage();
	}
    }

    if (verbose && numeric)
	usage();

    if (runprog) {
	pid =  fork();
	if (pid < 0) {
	    puts("fork() failed");
	    exit(pid);
	}
	if (!pid)
	    execute(progpath);
    }
    else if (optind < argc) {
	pid = atoi(argv[optind]);
    }

    if (!pid)
	usage();

    outp =  NULL;
    if (log)
	outp =  fopen(logpath, "w");
    if (!outp) {
	outp =  stdout;
	log = 0;
    }

    sprintf(statname, "/proc/%d/stat", pid);
    if (fp = fopen(statname, "r")) {
	if (fgets(procbuf, sizeof(procbuf), fp))
	    get_id(procbuf, id);
	fclose(fp);
    }

    /*
     * now just spin collecting the stats
     */
    sprintf(statname, "/proc/%d/schedstat", pid);
    while (fp = fopen(statname, "r")) {
	    if (runprog)
		waitpid(pid, NULL, WNOHANG);

	    if (!fgets(procbuf, sizeof(procbuf), fp))
		    break;

	    get_stats(procbuf, &run_ticks, &wait_ticks, &nran);

	    if (verbose)
		fprintf(outp, "%s %d(%d) %d(%d) %d(%d) %4.2f %4.2f\n",
		    id, run_ticks, run_ticks - orun_ticks,
		    wait_ticks, wait_ticks - owait_ticks,
		    nran, nran - oran,
		    nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    else if (numeric)
		fprintf(outp, "%s %4.2f %4.2f\n",
		    id, nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    else
		fprintf(outp, "%s avgrun=%4.2fms avgwait=%4.2fms\n",
		    id, nran - oran ?
			(double)(run_ticks-orun_ticks)/(nran - oran) : 0,
		    nran - oran ?
			(double)(wait_ticks-owait_ticks)/(nran - oran) : 0);
	    fclose(fp);
	    oran = nran;
	    orun_ticks = run_ticks;
	    owait_ticks = wait_ticks;
	    sleep(sleeptime);

	    if (runprog)
		waitpid(pid, NULL, WNOHANG);

	    fp = fopen(statname,"r");
	    if (!fp)
		    break;
    }
    if (log)
	fclose(outp);
    if (id[0])
	printf("Process %s has exited.\n", id);
    else
	printf("Process %d does not exist.\n", pid);
    exit(0);
}

  parent reply	other threads:[~2004-09-04 23:10 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-26  8:47 2.6.9-rc1-mm1 Andrew Morton
2004-08-26 11:07 ` 2.6.9-rc1-mm1 Con Kolivas
2004-08-26 14:28   ` 2.6.9-rc1-mm1 Jurriaan
2004-08-26 18:25     ` 2.6.9-rc1-mm1 Thomas Davis
2004-08-26 14:36   ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-08-26 14:45     ` 2.6.9-rc1-mm1 Felipe Alfaro Solana
2004-08-26 15:35       ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-08-26 16:38     ` 2.6.9-rc1-mm1 Con Kolivas
2004-08-26 20:36       ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-08-26 20:55       ` 2.6.9-rc1-mm1 Martin J. Bligh
2004-08-26 23:19         ` 2.6.9-rc1-mm1 Con Kolivas
2004-08-26 23:43           ` 2.6.9-rc1-mm1 Martin J. Bligh
2004-08-27  0:37           ` 2.6.9-rc1-mm1 Nuno Silva
2004-08-27  0:46             ` 2.6.9-rc1-mm1 Con Kolivas
2004-08-27  0:51               ` 2.6.9-rc1-mm1 Martin J. Bligh
2004-08-27  0:55                 ` 2.6.9-rc1-mm1 Con Kolivas
2004-08-27  0:58         ` 2.6.9-rc1-mm1 Rick Lindsley
2004-08-27 20:54           ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-08-27 21:54             ` 2.6.9-rc1-mm1 Rick Lindsley
2004-08-27 22:29               ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-09-03 21:11               ` schedstat-2.6.8.1 [was: Re: 2.6.9-rc1-mm1] Rafael J. Wysocki
2004-09-08  7:09                 ` Rick Lindsley
2004-09-04 18:35               ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-09-08  8:10                 ` 2.6.9-rc1-mm1 Rick Lindsley
2004-09-04 23:10               ` Rafael J. Wysocki [this message]
2004-09-08  8:12                 ` latency.c [was: Re: 2.6.9-rc1-mm1] Rick Lindsley
2004-09-08 12:02                   ` Rafael J. Wysocki
2004-08-26 20:51   ` 2.6.9-rc1-mm1 Martin J. Bligh
2004-08-27  1:43     ` 2.6.9-rc1-mm1 Nick Piggin
2004-08-26 12:06 ` 2.6.9-rc1-mm1 Denis Vlasenko
2004-08-26 19:40   ` 2.6.9-rc1-mm1 Sam Ravnborg
2004-08-26 17:58 ` 2.6.9-rc1-mm1 (compile stats) John Cherry
2004-08-26 18:53 ` 2.6.9-rc1-mm1 - undefined references - [PATCH] Paolo Ornati
2004-08-28  8:54   ` Adrian Bunk
2004-08-28  9:45     ` Paolo Ornati
2004-08-26 22:46 ` 2.6.9-rc1-mm1 Rafael J. Wysocki
2004-08-26 22:50   ` 2.6.9-rc1-mm1 Andrew Morton
2004-08-26 23:53 ` 2.6.9-rc1-mm1 Tomasz Torcz
     [not found] ` <20040827043132.GJ2793@holomorphy.com>
2004-08-27 21:42   ` 2.6.9-rc1-mm1 William Lee Irwin III
2004-08-28  5:26 ` [0/4] standardized waitqueue hashing William Lee Irwin III
2004-08-28  5:31   ` [1/4] standardize bit waiting data type William Lee Irwin III
2004-08-28  5:35     ` [2/4] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28  5:37       ` [3/4] eliminate bh waitqueue hashtable William Lee Irwin III
2004-08-28  5:38         ` [4/4] eliminate inode " William Lee Irwin III
2004-08-28  6:17     ` [1/4] standardize bit waiting data type Andrew Morton
2004-08-28  6:34       ` William Lee Irwin III
2004-08-28  6:40         ` Andrew Morton
2004-08-28  6:48           ` William Lee Irwin III
2004-08-28  9:20             ` William Lee Irwin III
2004-08-28  9:22               ` [2/4] consolidate bit waiting code patterns William Lee Irwin III
2004-08-28  9:23                 ` [3/4] eliminate bh waitqueue hashtable William Lee Irwin III
2004-08-28  9:24                   ` [4/4] eliminate inode " William Lee Irwin III
2004-08-28  9:43                   ` [3/4] eliminate bh " Andrew Morton
2004-08-28  9:34                 ` [2/4] consolidate bit waiting code patterns Andrew Morton
2004-08-28  9:51                   ` William Lee Irwin III
2004-08-28  9:39                 ` Andrew Morton
2004-08-28  9:51                   ` William Lee Irwin III
2004-08-28  9:18     ` [1/4] standardize bit waiting data type Christoph Hellwig
2004-08-28  9:20       ` William Lee Irwin III
2004-08-28  9:06 ` [patch] 2.6.9-rc1-mm1: megaraid_mbox.c compile error with gcc 3.4 Adrian Bunk

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=200409050110.07728.rjw@sisk.pl \
    --to=rjw@sisk.pl \
    --cc=kernel@kolivas.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mbligh@aracnet.com \
    --cc=ricklind@us.ibm.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome