(e-mail address removed) said:
Hi,
I want to profile a C program I am writting, so I compile it with -pg
options and use gprof to obtain information about call graphs, which I
am really interested in. I look at the text files but when I have a
large number of functions, it looks really embarrasing. So somebody
recommended me about graphviz.
Way to go, definitely, if you can't get cflow to work (and believe me,
that's harder than it sounds).
My problem was to find something to
convert between gprof format and graphviz .dot format. I finally found
gprof2dot.py and tried. But it only converts percentage time
functions, and what I want is the call graph.
Well, let's see...
The gprof output is in several sections. The first of these contains a
list of the functions that it profiled:
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
34.12 1.44 1.44 9 160.00 160.00 XORBuffer
27.73 2.61 1.17 37952262 0.00 0.00 Subst
12.56 3.14 0.53 37952263 0.00 0.00 GetSBoxCount
12.56 3.67 0.53 9 58.89 58.89 RotateBufferLeft
12.56 4.20 0.53 1 530.00 4220.00 encrypt
0.47 4.22 0.02 2 10.00 10.00 GetFileLength
0.00 4.22 0.00 1 0.00 0.00 CheckArgs
0.00 4.22 0.00 1 0.00 10.00 GetPass
followed by a blank line, and then some explanatory text. As you can
see, the names on the right side of this section are what we're after,
but this isn't really the best place to capture them. See below.
Do this:
printf("digraph g\n{\n");
In due course, the phrase "Call graph" appears for the first time - and
that's a useful marker for your parsing process. The following five
lines can be ignored, and then we get output like this:
0.53 3.69 1/1 main [2]
[1] 100.0 0.53 3.69 1 encrypt [1]
1.17 0.53 37952262/37952262 Subst [3]
1.44 0.00 9/9 XORBuffer [4]
0.53 0.00 9/9 RotateBufferLeft [6]
0.01 0.00 1/2 GetFileLength [7]
0.00 0.01 1/1 GetPass [8]
0.00 0.00 1/37952263 GetSBoxCount [5]
-----------------------------------------------
POINT A (see below for why I wrote this here)
So - whilst you don't encounter a [number in square brackets] on the
left, ignore the line and read another. Once you encounter the square
bracket as the first character, you're at a calling function. To get at
its name, start at the end, skip backwards past the bracketed number at
the very end, and past the space (banging a '\0' in your buffer at this
point will be a useful thing to do), and then keep going backwards
through the name itself until you hit whitespace again. Slide forward
again to the first character of the function name.
Store that name, and then roll through each subsequent line (stopping
when you hit a line that starts with ---- characters), parsing out the
called function in the same way as above, and doing this for each line:
printf(" %s -> %s;\n", callingfunctionname, calledfunctionname);
for each function name that appears in these subsequent lines.
If the next line is blank, you're done. Otherwise, repeat from POINT A.
When you finally hit that blank line, write this:
printf("}\n");
and you're done. It's ready to go through dot.
I haven't actually written the code (although I'm very tempted to do
just that), but if I work this algorithm by hand on a program whose
profile I've just generated for this article, I get the following dot
file:
digraph g
{
encrypt -> Subst;
encrypt -> XORBuffer;
encrypt -> RotateBufferLeft;
encrypt -> GetFileLength;
encrypt -> GetPass;
encrypt -> GetSBoxCount;
main -> encrypt;
main -> CheckArgs;
Subst -> GetSBoxCount;
GetPass -> GetFileLength;
}
How you use dot to render this into an image is of course off-topic, but
I can attest to the fact that it gives a very nice call-graph indeed.
Furthermore, the C code you'll need for this is reasonably simple, and
shouldn't take you more than an hour or so to write and test.
Using gprof and dot in combination to get a graphical representation of
the program's call graph is an interesting idea. (I'd thought of the
dot part before, of course, but not the gprof part.) Do let us know how
you get on with it. And if you don't, I might have to write it myself
(any decade now), just to scratch that itch.