public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: William Lee Irwin III <wli@holomorphy.com>
To: mita akinobu <amgta@yacht.ocn.ne.jp>
Cc: linux-kernel@vger.kernel.org, Andries Brouwer <aeb@cwi.nl>,
	Alessandro Rubini <rubini@ipvvis.unipv.it>
Subject: Re: [util-linux] readprofile ignores the last element in /proc/profile
Date: Sun, 29 Aug 2004 09:22:52 -0700	[thread overview]
Message-ID: <20040829162252.GG5492@holomorphy.com> (raw)
In-Reply-To: <200408250022.09878.amgta@yacht.ocn.ne.jp>

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

On Wed, Aug 25, 2004 at 12:22:09AM +0900, mita akinobu wrote:
> The readprofile command does not print the number of clock ticks about
> the last element in profiling buffer.
> Since the number of clock ticks which occur on the module functions is
> as same as the value of the last element of prof_buffer[]. when many
> ticks occur on there, some users who browsing the output of readprofile
> may overlook the fact that the bottle-neck may exist in the modules.
> I create the patch which enable to print clock ticks of the last
> element as "*unknown*".

Well, since I couldn't stop vomiting for hours after I looked at the
code for readprofile(1), here's a reimplementation, with various
misfeatures removed, included as a MIME attachment.


-- wli

[-- Attachment #2: readprofile.c --]
[-- Type: text/x-csrc, Size: 4984 bytes --]

/*
 * readprofile(1) implementation.
 * (C) 2004 William Irwin, Oracle
 * Licensed under GPL, or any DFSG-free license of the user's choice.
 */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>

struct sym {
	unsigned long long vaddr;
	char name[64];
	unsigned long hits;
};

struct profile_state {
	int fd, shift;
	uint32_t *buf;
	size_t bufsz;
	struct sym syms[2], *last, *this;
	unsigned long long stext, vaddr;
	unsigned long total;
	char type, sym[64];
};

static int digits(void)
{
	static int ret = 0;
	unsigned long n = ULONG_MAX;

	if (ret)
		return ret;
	for (n = ULONG_MAX; n >= 10; n /= 10)
		++ret;
	ret += !!n;
	return ret;
}

static void shift_syms(struct sym *syms, struct sym **last, struct sym **this)
{
	*last = *this;
	*this = &syms[!(*this - syms)];
}

static int is_text(char c)
{
	return c == 'T' || c == 't' || c == 'W' || c == 'w';
}

static long profile_off(unsigned long long vaddr, struct profile_state *state)
{
	return (((vaddr - state->stext) >> state->shift) + 1)*sizeof(uint32_t);
}

static int state_transition(struct profile_state *state)
{
	int ret = 0;
	long page_mask, start, end;
	unsigned off;

	if (!state->stext) {
		if (!strcmp(state->sym, "_stext"))
			state->stext = state->vaddr;
		goto out;
	} else if ((!state->last || !state->this) && !is_text(state->type)) {
		ret = 1;
		goto out;
	}
	shift_syms(state->syms, &state->last, &state->this);
	state->this->vaddr = state->vaddr;
	state->this->hits = 0;
	if (is_text(state->type)) {
		strcpy(state->this->name, state->sym);
		if (!state->last)
			goto out;
	} else {
		strcpy(state->this->name, "*unknown*");
		ret = 1;
	}
	start = profile_off(state->last->vaddr, state);
	end = profile_off(state->this->vaddr, state)
					+ !!state->shift*sizeof(uint32_t);
	if (lseek(state->fd, start, SEEK_SET) != start) {
		fprintf(stderr, "fseek() failed\n");
		exit(EXIT_FAILURE);
	}
	if (state->bufsz < (size_t)(end - start)) {
		page_mask = getpagesize() - 1;
		state->bufsz = (end - start + page_mask) & ~page_mask;
		free(state->buf);
		if (!(state->buf = malloc(state->bufsz))) {
			fprintf(stderr, "out of memory\n");
			exit(EXIT_FAILURE);
		}
	}
	if (read(state->fd, state->buf, end - start) == end - start) {
		for (off = 0; off < (end - start)/sizeof(uint32_t); ++off)
			state->last->hits += state->buf[off];
	} else {
		ret = 1;
		strcpy(state->last->name, "*unknown*");
	}
	if (state->last->hits)
		printf("%*lu %s\n", digits(), state->last->hits,
							state->last->name);
	state->total += state->last->hits;
out:
	return ret;
}

static int readprofile(FILE *system_map, int profile_buffer)
{
	char *buf = NULL;
	ssize_t nchar, bufsz;
	uint32_t step;
	struct profile_state state = {
		.fd	= profile_buffer,
		.last	= NULL,
		.this	= NULL,
		.total	= 0,
		.stext	= 0,
	};

	if (read(profile_buffer, &step, sizeof(uint32_t)) != sizeof(uint32_t)) {
		fprintf(stderr, "read() failed\n");
		return EXIT_FAILURE;
	}
	state.shift = ffs(step) - 1;
	if (!(state.buf = malloc(getpagesize()))) {
		fprintf(stderr, "out of memory\n");
		return EXIT_FAILURE;
	}
	state.bufsz = getpagesize();
	while ((nchar = getline(&buf, &bufsz, system_map)) > 0) {
		if (sscanf(buf, "%Lx %c %63s", &state.vaddr, &state.type,
							state.sym) != 3)
			continue;
		if (state_transition(&state))
			break;
	}
	printf("%*lu total\n", digits(), state.total);
	if (state.buf)
		free(state.buf);
	return 0;
}

static FILE *open_system_map(void)
{
	struct utsname buf;
	char s[256];

	if (!access("/boot/System.map", R_OK))
		return fopen("/boot/System.map", "r");
	if (uname(&buf))
		return NULL;
	snprintf(s, sizeof(s), "/boot/System.map-%s", buf.release);
	return fopen(s, "r");
}

int main(int argc, char * const argv[])
{
	FILE *system_map = NULL;
	int c, ret, profile_buffer = -1;
	static const char optstr[] = "m:p:";

	while ((c = getopt(argc, argv, optstr)) != EOF) {
		switch (c) {
			case 'm':
				if (!strcmp(optarg, "-"))
					system_map = fdopen(STDIN_FILENO, "r");
				else if (!access(optarg, R_OK))
					system_map = fopen(optarg, "r");
				else {
					fprintf(stderr, "mapfile %s is "
						"inaccessible\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;
			case 'p':
				if (!strcmp(optarg, "-"))
					profile_buffer = STDIN_FILENO;
				else if (!access(optarg, R_OK))
					profile_buffer = open(optarg, O_RDONLY);
				else {
					fprintf(stderr, "profile %s is "
						"inaccessible\n", optarg);
					exit(EXIT_FAILURE);
				}
				break;
			case '?':
			default:
				fprintf(stderr, "usage: %s [ -m mapfile ] "
					"[ -p profile ]\n", argv[0]);
				exit(EXIT_FAILURE);
		}
	}
	if (!system_map)
		system_map = open_system_map();
	if (profile_buffer < 0)
		profile_buffer = open("/proc/profile", O_RDONLY);
	ret = readprofile(system_map, profile_buffer);
	fclose(system_map);
	close(profile_buffer);
	return ret;
}

  reply	other threads:[~2004-08-29 16:23 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-08-24 15:22 [util-linux] readprofile ignores the last element in /proc/profile mita akinobu
2004-08-29 16:22 ` William Lee Irwin III [this message]
2004-08-29 18:41   ` William Lee Irwin III
2004-08-29 19:26     ` Andries Brouwer
2004-08-29 21:23       ` William Lee Irwin III
2004-08-29 21:26         ` William Lee Irwin III
2004-08-29 23:25         ` Andries Brouwer
2004-08-30  0:26           ` William Lee Irwin III
2004-08-30 18:27   ` Paulo Marques
2004-08-30 20:48     ` William Lee Irwin III
2004-08-31 16:45   ` mita akinobu
2004-08-31 17:21     ` mita akinobu
2004-08-31 19:25     ` William Lee Irwin III
2004-08-31 19:45       ` William Lee Irwin III
2004-09-01 16:09         ` mita akinobu
2004-09-01 16:27           ` William Lee Irwin III

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=20040829162252.GG5492@holomorphy.com \
    --to=wli@holomorphy.com \
    --cc=aeb@cwi.nl \
    --cc=amgta@yacht.ocn.ne.jp \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rubini@ipvvis.unipv.it \
    /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