Messages in this thread | | | Date | Sun, 29 Aug 2004 09:22:52 -0700 | From | William Lee Irwin III <> | Subject | Re: [util-linux] readprofile ignores the last element in /proc/profile |
| |
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 /* * 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; }
| |