Add support utils for tracing
authorRudolf Marek <r.marek@assembler.cz>
Fri, 2 Sep 2011 21:34:15 +0000 (23:34 +0200)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 6 Sep 2011 23:27:57 +0000 (01:27 +0200)
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>
util/genprof/Makefile [new file with mode: 0644]
util/genprof/README [new file with mode: 0644]
util/genprof/genprof.c [new file with mode: 0644]
util/genprof/log2dress [new file with mode: 0755]

diff --git a/util/genprof/Makefile b/util/genprof/Makefile
new file mode 100644 (file)
index 0000000..2ec77c9
--- /dev/null
@@ -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
diff --git a/util/genprof/README b/util/genprof/README
new file mode 100644 (file)
index 0000000..3483a2b
--- /dev/null
@@ -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.
diff --git a/util/genprof/genprof.c b/util/genprof/genprof.c
new file mode 100644 (file)
index 0000000..9fc39da
--- /dev/null
@@ -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;
+}
diff --git a/util/genprof/log2dress b/util/genprof/log2dress
new file mode 100755 (executable)
index 0000000..429f846
--- /dev/null
@@ -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