aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Gerrand <adg@golang.org>2013-10-18 13:53:33 +0900
committerAndrew Gerrand <adg@golang.org>2013-10-18 13:53:33 +0900
commit309e16554aab1686c5bb744cababfbaa2d83db4d (patch)
treea3532eb1009338729fe5bf5e4476b35a6c20e3a5
parent04e95a1a56c35f63e3ac51c9d9973297a57c2b10 (diff)
downloadgo1.2rc2.tar.gz
go1.2rc2.zip
go1.2rc2go1.2rc2
-rw-r--r--VERSION1
-rw-r--r--src/cmd/prof/Makefile5
-rw-r--r--src/cmd/prof/doc.go49
-rw-r--r--src/cmd/prof/main.c910
4 files changed, 1 insertions, 964 deletions
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000000..5bea254304
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+go1.2rc2 \ No newline at end of file
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
deleted file mode 100644
index 3f528d7517..0000000000
--- a/src/cmd/prof/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2012 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../Make.dist
diff --git a/src/cmd/prof/doc.go b/src/cmd/prof/doc.go
deleted file mode 100644
index 2640167d3f..0000000000
--- a/src/cmd/prof/doc.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-
-Prof is a rudimentary real-time profiler.
-
-Given a command to run or the process id (pid) of a command already
-running, it samples the program's state at regular intervals and reports
-on its behavior. With no options, it prints a histogram of the locations
-in the code that were sampled during execution.
-
-Since it is a real-time profiler, unlike a traditional profiler it samples
-the program's state even when it is not running, such as when it is
-asleep or waiting for I/O. Each thread contributes equally to the
-statistics.
-
-Usage:
- go tool prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
-
-The output modes (default -h) are:
-
- -P file.prof:
- Write the profile information to file.prof, in the format used by pprof.
- At the moment, this only works on Linux amd64 binaries and requires that the
- binary be written using 6l -e to produce ELF debug info.
- See http://code.google.com/p/google-perftools for details.
- -h: histograms
- How many times a sample occurred at each location.
- -f: dynamic functions
- At each sample period, print the name of the executing function.
- -l: dynamic file and line numbers
- At each sample period, print the file and line number of the executing instruction.
- -r: dynamic registers
- At each sample period, print the register contents.
- -s: dynamic function stack traces
- At each sample period, print the symbolic stack trace.
-
-Flag -t sets the maximum real time to sample, in seconds, and -d
-sets the sampling interval in milliseconds. The default is to sample
-every 100ms until the program completes.
-
-It is installed as go tool prof and is architecture-independent.
-
-*/
-package main
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
deleted file mode 100644
index 6c591ba180..0000000000
--- a/src/cmd/prof/main.c
+++ /dev/null
@@ -1,910 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !plan9
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-
-#define Ureg Ureg_amd64
- #include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg_x86
- #include <ureg_x86.h>
-#undef Ureg
-#include <mach.h>
-
-char* file = "6.out";
-static Fhdr fhdr;
-int have_syms;
-int fd;
-struct Ureg_amd64 ureg_amd64;
-struct Ureg_x86 ureg_x86;
-int total_sec = 0;
-int delta_msec = 100;
-int nsample;
-int nsamplethread;
-
-// pprof data, stored as sequences of N followed by N PC values.
-// See http://code.google.com/p/google-perftools .
-uvlong *ppdata; // traces
-Biobuf* pproffd; // file descriptor to write trace info
-long ppstart; // start position of current trace
-long nppdata; // length of data
-long ppalloc; // size of allocated data
-char ppmapdata[10*1024]; // the map information for the output file
-
-// output formats
-int pprof; // print pprof output to named file
-int functions; // print functions
-int histograms; // print histograms
-int linenums; // print file and line numbers rather than function names
-int registers; // print registers
-int stacks; // print stack traces
-
-int pid; // main process pid
-
-int nthread; // number of threads
-int thread[32]; // thread pids
-Map *map[32]; // thread maps
-
-void
-Usage(void)
-{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
- fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
- fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
- fprint(2, "\t\t-h: histograms\n");
- fprint(2, "\t\t-f: dynamic functions\n");
- fprint(2, "\t\t-l: dynamic file and line numbers\n");
- fprint(2, "\t\t-r: dynamic registers\n");
- fprint(2, "\t\t-s: dynamic function stack traces\n");
- fprint(2, "\t\t-hs: include stack info in histograms\n");
- exit(2);
-}
-
-typedef struct PC PC;
-struct PC {
- uvlong pc;
- uvlong callerpc;
- unsigned int count;
- PC* next;
-};
-
-enum {
- Ncounters = 256
-};
-
-PC *counters[Ncounters];
-
-// Set up by setarch() to make most of the code architecture-independent.
-typedef struct Arch Arch;
-struct Arch {
- char* name;
- void (*regprint)(void);
- int (*getregs)(Map*);
- int (*getPC)(Map*);
- int (*getSP)(Map*);
- uvlong (*uregPC)(void);
- uvlong (*uregSP)(void);
- void (*ppword)(uvlong w);
-};
-
-void
-amd64_regprint(void)
-{
- fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
- fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
- fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
- fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
- fprint(2, "si\t0x%llux\n", ureg_amd64.si);
- fprint(2, "di\t0x%llux\n", ureg_amd64.di);
- fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
- fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
- fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
- fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
- fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
- fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
- fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
- fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
- fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
- fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
- fprint(2, "es\t0x%llux\n", ureg_amd64.es);
- fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
- fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
- fprint(2, "type\t0x%llux\n", ureg_amd64.type);
- fprint(2, "error\t0x%llux\n", ureg_amd64.error);
- fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
- fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
- fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
- fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
- fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
-}
-
-int
-amd64_getregs(Map *map)
-{
- int i;
- union {
- uvlong regs[1];
- struct Ureg_amd64 ureg;
- } u;
-
- for(i = 0; i < sizeof ureg_amd64; i+=8) {
- if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
- return -1;
- }
- ureg_amd64 = u.ureg;
- return 0;
-}
-
-int
-amd64_getPC(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
- ureg_amd64.ip = x;
- return r;
-}
-
-int
-amd64_getSP(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
- ureg_amd64.sp = x;
- return r;
-}
-
-uvlong
-amd64_uregPC(void)
-{
- return ureg_amd64.ip;
-}
-
-uvlong
-amd64_uregSP(void)
-{
- return ureg_amd64.sp;
-}
-
-void
-amd64_ppword(uvlong w)
-{
- uchar buf[8];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- buf[4] = w >> 32;
- buf[5] = w >> 40;
- buf[6] = w >> 48;
- buf[7] = w >> 56;
- Bwrite(pproffd, buf, 8);
-}
-
-void
-x86_regprint(void)
-{
- fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
- fprint(2, "si\t0x%ux\n", ureg_x86.si);
- fprint(2, "di\t0x%ux\n", ureg_x86.di);
- fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
- fprint(2, "es\t0x%ux\n", ureg_x86.es);
- fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
-}
-
-int
-x86_getregs(Map *map)
-{
- int i;
-
- for(i = 0; i < sizeof ureg_x86; i+=4) {
- if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
- return -1;
- }
- return 0;
-}
-
-int
-x86_getPC(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
-}
-
-int
-x86_getSP(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
-}
-
-uvlong
-x86_uregPC(void)
-{
- return (uvlong)ureg_x86.pc;
-}
-
-uvlong
-x86_uregSP(void)
-{
- return (uvlong)ureg_x86.sp;
-}
-
-void
-x86_ppword(uvlong w)
-{
- uchar buf[4];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- Bwrite(pproffd, buf, 4);
-}
-
-Arch archtab[] = {
- {
- "amd64",
- amd64_regprint,
- amd64_getregs,
- amd64_getPC,
- amd64_getSP,
- amd64_uregPC,
- amd64_uregSP,
- amd64_ppword,
- },
- {
- "386",
- x86_regprint,
- x86_getregs,
- x86_getPC,
- x86_getSP,
- x86_uregPC,
- x86_uregSP,
- x86_ppword,
- },
- {
- nil
- }
-};
-
-Arch *arch;
-
-int
-setarch(void)
-{
- int i;
-
- if(mach != nil) {
- for(i = 0; archtab[i].name != nil; i++) {
- if (strcmp(mach->name, archtab[i].name) == 0) {
- arch = &archtab[i];
- return 0;
- }
- }
- }
- return -1;
-}
-
-int
-getthreads(void)
-{
- int i, j, curn, found;
- Map *curmap[nelem(map)];
- int curthread[nelem(map)];
- static int complained = 0;
-
- curn = procthreadpids(pid, curthread, nelem(curthread));
- if(curn <= 0)
- return curn;
-
- if(curn > nelem(map)) {
- if(complained == 0) {
- fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
- complained = 1;
- }
- curn = nelem(map);
- }
- if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
- return curn; // no changes
-
- // Number of threads has changed (might be the init case).
- // A bit expensive but rare enough not to bother being clever.
- for(i = 0; i < curn; i++) {
- found = 0;
- for(j = 0; j < nthread; j++) {
- if(curthread[i] == thread[j]) {
- found = 1;
- curmap[i] = map[j];
- map[j] = nil;
- break;
- }
- }
- if(found)
- continue;
-
- // map new thread
- curmap[i] = attachproc(curthread[i], &fhdr);
- if(curmap[i] == nil) {
- fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
- return -1;
- }
- }
-
- for(j = 0; j < nthread; j++)
- if(map[j] != nil)
- detachproc(map[j]);
-
- nthread = curn;
- memmove(thread, curthread, nthread*sizeof thread[0]);
- memmove(map, curmap, sizeof map);
- return nthread;
-}
-
-int
-sample(Map *map)
-{
- static int n;
-
- n++;
- if(registers) {
- if(arch->getregs(map) < 0)
- goto bad;
- } else {
- // we need only two registers
- if(arch->getPC(map) < 0)
- goto bad;
- if(arch->getSP(map) < 0)
- goto bad;
- }
- return 1;
-bad:
- if(n == 1)
- fprint(2, "prof: can't read registers: %r\n");
- return 0;
-}
-
-void
-addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
-{
- int h;
- PC *x;
-
- USED(sp);
-
- h = (pc + callerpc*101) % Ncounters;
- for(x = counters[h]; x != NULL; x = x->next) {
- if(x->pc == pc && x->callerpc == callerpc) {
- x->count++;
- return;
- }
- }
- x = malloc(sizeof(PC));
- if(x == nil)
- sysfatal("out of memory");
- x->pc = pc;
- x->callerpc = callerpc;
- x->count = 1;
- x->next = counters[h];
- counters[h] = x;
-}
-
-void
-addppword(uvlong pc)
-{
- if(pc == 0) {
- return;
- }
- if(nppdata == ppalloc) {
- ppalloc = (1000+nppdata)*2;
- ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
- if(ppdata == nil) {
- fprint(2, "prof: realloc failed: %r\n");
- exit(2);
- }
- }
- ppdata[nppdata++] = pc;
-}
-
-void
-startpptrace(void)
-{
- ppstart = nppdata;
- addppword(~0);
-}
-
-void
-endpptrace(void)
-{
- ppdata[ppstart] = nppdata-ppstart-1;
-}
-
-uvlong nextpc;
-
-void
-xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
-{
- USED(map);
-
- char buf[1024];
- if(sym == nil){
- fprint(2, "syms\n");
- return;
- }
- if(histograms)
- addtohistogram(nextpc, pc, sp);
- if(!histograms || stacks > 1 || pprof) {
- if(nextpc == 0)
- nextpc = sym->value;
- if(stacks){
- fprint(2, "%s(", sym->name);
- fprint(2, ")");
- if(nextpc != sym->value)
- fprint(2, "+%#llux ", nextpc - sym->value);
- if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
- fprint(2, " %s", buf);
- }
- fprint(2, "\n");
- }
- if (pprof) {
- addppword(nextpc);
- }
- }
- nextpc = pc;
-}
-
-void
-stacktracepcsp(Map *map, uvlong pc, uvlong sp)
-{
- nextpc = pc;
- if(pprof){
- startpptrace();
- }
- if(machdata->ctrace==nil)
- fprint(2, "no machdata->ctrace\n");
- else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
- fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
- else {
- addtohistogram(nextpc, 0, sp);
- if(stacks)
- fprint(2, "\n");
- }
- if(pprof){
- endpptrace();
- }
-}
-
-void
-printpc(Map *map, uvlong pc, uvlong sp)
-{
- char buf[1024];
- if(registers)
- arch->regprint();
- if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
- fprint(2, "%s\n", buf);
- if(have_syms > 0 && functions) {
- symoff(buf, sizeof(buf), pc, CANY);
- fprint(2, "%s\n", buf);
- }
- if(stacks || pprof){
- stacktracepcsp(map, pc, sp);
- }
- else if(histograms){
- addtohistogram(pc, 0, sp);
- }
-}
-
-void
-ppmaps(void)
-{
- int fd, n;
- char tmp[100];
- Seg *seg;
-
- // If it's Linux, the info is in /proc/$pid/maps
- snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
- fd = open(tmp, 0);
- if(fd >= 0) {
- n = read(fd, ppmapdata, sizeof ppmapdata - 1);
- close(fd);
- if(n < 0) {
- fprint(2, "prof: can't read %s: %r\n", tmp);
- exit(2);
- }
- ppmapdata[n] = 0;
- return;
- }
-
- // It's probably a mac. Synthesize an entry for the text file.
- // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
- for(n = 0; n < 3; n++){
- seg = &map[0]->seg[n];
- if(seg->b == 0) {
- continue;
- }
- snprint(ppmapdata, sizeof ppmapdata,
- "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
- seg->b, seg->e, seg->f, "/home/r/6.out"
- );
- return;
- }
- fprint(2, "prof: no text segment in maps for %s\n", file);
- exit(2);
-}
-
-void
-samples(void)
-{
- int i, pid, msec;
- struct timespec req;
- int getmaps;
-
- req.tv_sec = delta_msec/1000;
- req.tv_nsec = 1000000*(delta_msec % 1000);
- getmaps = 0;
- if(pprof)
- getmaps= 1;
- for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
- nsample++;
- nsamplethread += nthread;
- for(i = 0; i < nthread; i++) {
- pid = thread[i];
- if(ctlproc(pid, "stop") < 0)
- return;
- if(!sample(map[i])) {
- ctlproc(pid, "start");
- return;
- }
- printpc(map[i], arch->uregPC(), arch->uregSP());
- ctlproc(pid, "start");
- }
- nanosleep(&req, NULL);
- getthreads();
- if(nthread == 0)
- break;
- if(getmaps) {
- getmaps = 0;
- ppmaps();
- }
- }
-}
-
-typedef struct Func Func;
-struct Func
-{
- Func *next;
- Symbol s;
- uint onstack;
- uint leaf;
-};
-
-Func *func[257];
-int nfunc;
-
-Func*
-findfunc(uvlong pc)
-{
- Func *f;
- uint h;
- Symbol s;
-
- if(pc == 0)
- return nil;
-
- if(!findsym(pc, CTEXT, &s))
- return nil;
-
- h = s.value % nelem(func);
- for(f = func[h]; f != NULL; f = f->next)
- if(f->s.value == s.value)
- return f;
-
- f = malloc(sizeof *f);
- if(f == nil)
- sysfatal("out of memory");
- memset(f, 0, sizeof *f);
- f->s = s;
- f->next = func[h];
- func[h] = f;
- nfunc++;
- return f;
-}
-
-int
-compareleaf(const void *va, const void *vb)
-{
- Func *a, *b;
-
- a = *(Func**)va;
- b = *(Func**)vb;
- if(a->leaf != b->leaf)
- return b->leaf - a->leaf;
- if(a->onstack != b->onstack)
- return b->onstack - a->onstack;
- return strcmp(a->s.name, b->s.name);
-}
-
-void
-dumphistogram(void)
-{
- int i, h, n;
- PC *x;
- Func *f, **ff;
-
- if(!histograms)
- return;
-
- // assign counts to functions.
- for(h = 0; h < Ncounters; h++) {
- for(x = counters[h]; x != NULL; x = x->next) {
- f = findfunc(x->pc);
- if(f) {
- f->onstack += x->count;
- f->leaf += x->count;
- }
- f = findfunc(x->callerpc);
- if(f)
- f->leaf -= x->count;
- }
- }
-
- // build array
- ff = malloc(nfunc*sizeof ff[0]);
- if(ff == nil)
- sysfatal("out of memory");
- n = 0;
- for(h = 0; h < nelem(func); h++)
- for(f = func[h]; f != NULL; f = f->next)
- ff[n++] = f;
-
- // sort by leaf counts
- qsort(ff, nfunc, sizeof ff[0], compareleaf);
-
- // print.
- fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
- for(i = 0; i < nfunc; i++) {
- f = ff[i];
- fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
- if(stacks)
- fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
- fprint(2, "%s\n", f->s.name);
- }
-}
-
-typedef struct Trace Trace;
-struct Trace {
- int count;
- int npc;
- uvlong *pc;
- Trace *next;
-};
-
-void
-dumppprof(void)
-{
- uvlong i, n, *p, *e;
- int ntrace;
- Trace *trace, *tp, *up, *prev;
-
- if(!pprof)
- return;
- e = ppdata + nppdata;
- // Create list of traces. First, count the traces
- ntrace = 0;
- for(p = ppdata; p < e;) {
- n = *p++;
- p += n;
- if(n == 0)
- continue;
- ntrace++;
- }
- if(ntrace <= 0)
- return;
- // Allocate and link the traces together.
- trace = malloc(ntrace * sizeof(Trace));
- if(trace == nil)
- sysfatal("out of memory");
- tp = trace;
- for(p = ppdata; p < e;) {
- n = *p++;
- if(n == 0)
- continue;
- tp->count = 1;
- tp->npc = n;
- tp->pc = p;
- tp->next = tp+1;
- tp++;
- p += n;
- }
- trace[ntrace-1].next = nil;
- // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
- // the list collapses fast.
- for(tp = trace; tp != nil; tp = tp->next) {
- prev = tp;
- for(up = tp->next; up != nil; up = up->next) {
- if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
- tp->count++;
- prev->next = up->next;
- } else {
- prev = up;
- }
- }
- }
- // Write file.
- // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
- // 1) Header
- arch->ppword(0); // must be zero
- arch->ppword(3); // 3 words follow in header
- arch->ppword(0); // must be zero
- arch->ppword(delta_msec * 1000); // sampling period in microseconds
- arch->ppword(0); // must be zero (padding)
- // 2) One record for each trace.
- for(tp = trace; tp != nil; tp = tp->next) {
- arch->ppword(tp->count);
- arch->ppword(tp->npc);
- for(i = 0; i < tp->npc; i++) {
- arch->ppword(tp->pc[i]);
- }
- }
- // 3) Binary trailer
- arch->ppword(0); // must be zero
- arch->ppword(1); // must be one
- arch->ppword(0); // must be zero
- // 4) Mapped objects.
- Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
- // 5) That's it.
- Bterm(pproffd);
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0){
- fprint(2, "prof: child process could not hang\n");
- exits(0);
- }
- execv(argv[0], argv);
- fprint(2, "prof: could not exec %s: %r\n", argv[0]);
- exits(0);
- }
-
- if(pid == -1) {
- fprint(2, "prof: could not fork\n");
- exit(1);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
- fprint(2, "prof: could not attach to child process: %r\n");
- exit(1);
- }
- return pid;
-}
-
-void
-detach(void)
-{
- int i;
-
- for(i = 0; i < nthread; i++)
- detachproc(map[i]);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- char *ppfile;
-
- ARGBEGIN{
- case 'P':
- pprof =1;
- ppfile = EARGF(Usage());
- pproffd = Bopen(ppfile, OWRITE);
- if(pproffd == nil) {
- fprint(2, "prof: cannot open %s: %r\n", ppfile);
- exit(2);
- }
- break;
- case 'd':
- delta_msec = atoi(EARGF(Usage()));
- break;
- case 't':
- total_sec = atoi(EARGF(Usage()));
- break;
- case 'p':
- pid = atoi(EARGF(Usage()));
- break;
- case 'f':
- functions = 1;
- break;
- case 'h':
- histograms = 1;
- break;
- case 'l':
- linenums = 1;
- break;
- case 'r':
- registers = 1;
- break;
- case 's':
- stacks++;
- break;
- default:
- Usage();
- }ARGEND
- if(pid <= 0 && argc == 0)
- Usage();
- if(functions+linenums+registers+stacks+pprof == 0)
- histograms = 1;
- if(!machbyname("amd64")) {
- fprint(2, "prof: no amd64 support\n", pid);
- exit(1);
- }
- if(argc > 0)
- file = argv[0];
- else if(pid) {
- file = proctextfile(pid);
- if (file == NULL) {
- fprint(2, "prof: can't find file for pid %d: %r\n", pid);
- fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
- exit(1);
- }
- }
- fd = open(file, 0);
- if(fd < 0) {
- fprint(2, "prof: can't open %s: %r\n", file);
- exit(1);
- }
- if(crackhdr(fd, &fhdr)) {
- have_syms = syminit(fd, &fhdr);
- if(!have_syms) {
- fprint(2, "prof: no symbols for %s: %r\n", file);
- }
- } else {
- fprint(2, "prof: crack header for %s: %r\n", file);
- exit(1);
- }
- if(pid <= 0)
- pid = startprocess(argv);
- attachproc(pid, &fhdr); // initializes thread list
- if(setarch() < 0) {
- detach();
- fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
- exit(1);
- }
- if(getthreads() <= 0) {
- detach();
- fprint(2, "prof: can't find threads for pid %d\n", pid);
- exit(1);
- }
- for(i = 0; i < nthread; i++)
- ctlproc(thread[i], "start");
- samples();
- detach();
- dumphistogram();
- dumppprof();
- exit(0);
-}