Add support utils for tracing
Following patch adds a userspace util genprof which is able to convert the console printed traces to gmon.out file used by gprof & friends. The log2dress will replace the adresses in logfile with a line numbers. Change-Id: I9f716f3ff2522a24fbc844a1dd5e32ef49b540c5 Signed-off-by: Rudolf Marek <r.marek@assembler.cz> Reviewed-on: http://review.coreboot.org/179 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
7f0e93060e
commit
8679e52b96
4 changed files with 171 additions and 0 deletions
12
util/genprof/Makefile
Normal file
12
util/genprof/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS=-O2 -Wall
|
||||||
|
|
||||||
|
all: genprof
|
||||||
|
|
||||||
|
genprof: genprof.o
|
||||||
|
$(CC) $(CFLAGS) -o genprof $^
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f genprof *.o *~
|
||||||
|
|
||||||
|
distclean: clean
|
31
util/genprof/README
Normal file
31
util/genprof/README
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Function tracing
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Enable CONFIG_TRACE in debug menu. Run the compiled image on target. You will get
|
||||||
|
a log with a lot of lines like:
|
||||||
|
|
||||||
|
...
|
||||||
|
~0x001072e8(0x00100099)
|
||||||
|
~0x00108bc0(0x0010730a)
|
||||||
|
...
|
||||||
|
|
||||||
|
First address is address of function which was just entered, the second address
|
||||||
|
is address of functions which call that.
|
||||||
|
|
||||||
|
You can use the log2dress to dress the log again:
|
||||||
|
|
||||||
|
...
|
||||||
|
src/arch/x86/lib/c_start.S:85 calls /home/ruik/coreboot/src/boot/selfboot.c:367
|
||||||
|
/home/ruik/coreboot/src/boot/selfboot.c:370 calls /home/ruik/coreboot/src/devices/device.c:325
|
||||||
|
...
|
||||||
|
|
||||||
|
Alternatively, you can use genprof to generate a gmon.out file, which can be used
|
||||||
|
by gprof to show the call traces. You will need to install uthash library to compile
|
||||||
|
that.
|
||||||
|
|
||||||
|
Great use is:
|
||||||
|
|
||||||
|
make
|
||||||
|
./genprof /tmp/yourlog ; gprof ../../build/coreboot_ram | ./gprof2dot.py -e0 -n0 | dot -Tpng -o output.png
|
||||||
|
|
||||||
|
Which generates a PNG with a call graph.
|
108
util/genprof/genprof.c
Normal file
108
util/genprof/genprof.c
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <uthash.h>
|
||||||
|
#include <sys/gmon_out.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define GMON_SEC "seconds s"
|
||||||
|
uint32_t mineip = 0xffffffff;
|
||||||
|
uint32_t maxeip = 0;
|
||||||
|
|
||||||
|
/* a hash structure to hold the arc */
|
||||||
|
struct arec {
|
||||||
|
uint32_t eip;
|
||||||
|
uint32_t from;
|
||||||
|
uint32_t count;
|
||||||
|
UT_hash_handle hh;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arec *arc = NULL;
|
||||||
|
|
||||||
|
void note_arc(uint32_t eip, uint32_t from)
|
||||||
|
{
|
||||||
|
struct arec *s;
|
||||||
|
|
||||||
|
HASH_FIND_INT(arc, &eip, s);
|
||||||
|
if (s == NULL) {
|
||||||
|
s = malloc(sizeof(struct arec));
|
||||||
|
s->eip = eip;
|
||||||
|
s->from = from;
|
||||||
|
s->count = 1;
|
||||||
|
if (eip > maxeip)
|
||||||
|
maxeip = eip;
|
||||||
|
if (eip < mineip)
|
||||||
|
maxeip = eip;
|
||||||
|
|
||||||
|
HASH_ADD_INT(arc, eip, s);
|
||||||
|
} else {
|
||||||
|
s->count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
FILE *f, *fo;
|
||||||
|
struct arec *s;
|
||||||
|
uint32_t eip, from, tmp;
|
||||||
|
uint8_t tag;
|
||||||
|
uint16_t hit;
|
||||||
|
|
||||||
|
if ( argc < 2 )
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Please specify the coreboot trace log as parameter\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
fo = fopen("gmon.out", "w+");
|
||||||
|
|
||||||
|
if ((f == NULL) || (fo == NULL)) {
|
||||||
|
fprintf(stderr, "Unable to manipulate with the input file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(f)) {
|
||||||
|
if (fscanf(f, "~%x(%x)%*[^\n]\n", &eip, &from) == 2) {
|
||||||
|
note_arc(eip, from);
|
||||||
|
} else if (fscanf(f, "%*c~%x(%x)%*[^\n]\n", &eip, &from) == 2) {
|
||||||
|
note_arc(eip, from);
|
||||||
|
} else {
|
||||||
|
/* just drop a line */
|
||||||
|
tmp = fscanf(f, "%*[^\n]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write gprof header */
|
||||||
|
fwrite(GMON_MAGIC, 1, sizeof(GMON_MAGIC) - 1, fo);
|
||||||
|
tmp = GMON_VERSION;
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
tmp = 0;
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
/* write fake histogram */
|
||||||
|
tag = GMON_TAG_TIME_HIST;
|
||||||
|
fwrite(&tag, 1, sizeof(tag), fo);
|
||||||
|
fwrite(&mineip, 1, sizeof(mineip), fo);
|
||||||
|
fwrite(&maxeip, 1, sizeof(maxeip), fo);
|
||||||
|
/* size of histogram */
|
||||||
|
tmp = 1;
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
/* prof rate */
|
||||||
|
tmp = 1000;
|
||||||
|
fwrite(&tmp, 1, sizeof(tmp), fo);
|
||||||
|
fwrite(GMON_SEC, 1, sizeof(GMON_SEC) - 1, fo);
|
||||||
|
hit = 1;
|
||||||
|
fwrite(&hit, 1, sizeof(hit), fo);
|
||||||
|
|
||||||
|
/* write call graph data */
|
||||||
|
tag = GMON_TAG_CG_ARC;
|
||||||
|
for (s = arc; s != NULL; s = s->hh.next) {
|
||||||
|
fwrite(&tag, 1, sizeof(tag), fo);
|
||||||
|
fwrite(&s->from, 1, sizeof(s->from), fo);
|
||||||
|
fwrite(&s->eip, 1, sizeof(s->eip), fo);
|
||||||
|
fwrite(&s->count, 1, sizeof(s->count), fo);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fo);
|
||||||
|
return 0;
|
||||||
|
}
|
20
util/genprof/log2dress
Executable file
20
util/genprof/log2dress
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#Parse a log and get back the function names and line numbers
|
||||||
|
#Provide a log file as first argument
|
||||||
|
|
||||||
|
#Please rewrite to something more saner !
|
||||||
|
|
||||||
|
cat $1 | while read line ; do
|
||||||
|
A=`echo $line | cut -c 1`
|
||||||
|
|
||||||
|
if [ "$A" = '~' ] ; then
|
||||||
|
FROM=`echo $line | tr \~ \( | tr \) \( | awk -F\( '{print $3}'`
|
||||||
|
TO=`echo $line | tr \~ \( | tr \) \(|awk -F\( '{print $2}'`
|
||||||
|
addr2line -e ../../build/coreboot_ram.debug "$FROM" | tr -d "\n"
|
||||||
|
echo -n " calls "
|
||||||
|
addr2line -e ../../build/coreboot_ram.debug "$TO"
|
||||||
|
else
|
||||||
|
echo "$line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
Loading…
Reference in a new issue