|
From: Jacek P. <ja...@s3...> - 2005-10-18 12:27:59
|
What is function cycle in callgrind? I don't know how to work with them, I don't understand why they are created and how to interpret results. I have method: A:I() called 7743 times. I look at its graph - over it there is only <cycle 4>. So I look at its callers - and I see method AC:gUP() called 7736 times. So I click on AC:gUP() and look at its graph.... and I see arrow from AC:gUP() to A:I() but with only 6x! I see also arrows to another methods with 7742x. How to interpret such result? The information contained in this e-mail and in any attachments is confidential and is designated solely for the attention of the intended recipient(s). If you are not an intended recipient, you must not use, disclose, copy, distribute or retain this e-mail or any part thereof. If you have received this e-mail in error, please notify the sender by return e-mail and delete all copies of this e-mail from your computer system(s). Please direct any additional queries to: com...@s3.... Thank You. |
|
From: Josef W. <Jos...@gm...> - 2005-10-18 21:12:20
|
On Tuesday 18 October 2005 14:27, Jacek Poplawski wrote: > What is function cycle in callgrind? A recursive cycle is a strongly connected component in the call graph. This means that by following calls, you can reach every function in a cycle from any other function in the cycle. Note that this does not mean that there really was a recursive call chain; there could have been multiple call chains in a program run so that the superposition of the calls generates the cycle. I.e. there could have been a call chain A->B->C->D and A->D->B at different times in the run. Because callgrind does profiling (only summing up numbers), it outputs only the full set of calls happening, without any time relation. > I don't know how to work with them, The best way to look at them is to not look at the calls inside a cycle; but better regard the full set of functions in the cycle as one function only. The call graph visualization shows the cycle object, which seems to call all the functions in the cycle. These "calls" from the cycle object to real functions in a cycle are only a specification for the container relationship of the function to the cycle, and are drawn in blue. For calculation of inclusive cost of functions which are part of a cycle, only calls going outside are used. > I don't understand why they are > created See above. > and how to interpret results. There is not much to interpret for functions inside a cycle. If you have all your functions in a big cycle, the profiling run simply was not useful at all (besides getting self costs). Either switch off cycle detection (and keep in mind that this can lead to inclusive cost > 100%, i.e. a wrong calculation), or try to avoid such cycles in the call graph. A typical case which produces big cycles is a event dispatcher function, e.g. used in GUI programming. These dispatchers are often called multiple times in very long call chains (one event generates another event...), and they will "drag" a lot of functions into a cycle. You can specify that such dispatcher functions should not appear in the call graph, i.e. instead of "A > dispatcher > C" you will get "A > C", and cycles will not appear any longer. Use for this callgrind --fn-skip=dispatcher ... Another way is to append an artifical recursion depth to a function, with callgrind --separate-recs=10 ... every function which is called recursive will be renamed to "dispatcher'2", "dispatcher'3" and so on. The number in the command line option is used to limit the different function symbols generated (could potentially be huge). And finally, you can encode in the function name produced by callgrind not pure functions, but call chains instead. I.e. a function symbol "A'B'C" would represent the function "A only when called from B called from C". You can try this with callgrind --separate-callers=3 ... Confused ? :-) > I have method: A:I() called 7743 times. > I look at its graph - over it there is only <cycle 4>. I.e.: A:I() is part of recursive cycle, arbitrary numbered with 4. > So I look at its callers - and I see method AC:gUP() called 7736 times. What is calling what here? Are you saying that AC:gUP() calls 7736 times into the cycle, or that AC:gUP is another function in the cycle? > So I click on AC:gUP() and look at its graph.... > and I see arrow from AC:gUP() to A:I() but with only 6x! I suppose now that AC:gUP() is outside of the cycle, and calling 6x function A:I(), which is in the cycle. What is the problem here? Probably A:I() was called 7737x from another function in the cycle. Note that the call graph view usually only shows arrows for calls of importance, i.e. which add significantly to the inclusive cost of a caller (default: >5%). But calls inside one cycle have no cost attributed, and thus, will not appear in the call graph. If you ask why calls in cycles have no cost attributed: What would the cost need to be if 2 functions 1000x call each other recursively, and at the end of the call chain, 10% of the program time is spent? I.e. each call is worth 10%, and the same call is nested 1000x ? If you switch off cycle detection, KCachegrind will happily say you that the cost is 10,000% which obviously is bogus. > I see also arrows to another methods with 7742x. Simply keep in mind that the calls among functions in a cycle do not show up in the call graph picture. But you can see them on the "callers"/"callees" tabs. > How to interpret such result? Hope this helps. Josef |
|
From: Josef W. <Jos...@gm...> - 2005-10-19 09:04:23
|
On Wednesday 19 October 2005 09:36, you wrote: > Josef Weidendorfer wrote: > >The best way to look at them is to not look at the calls inside a cycle; > > When function is under cycle on graph it means, that it is called from > cycle, No, any function which looks like directly called from a <cycle X> in fact is part of this cycle itself, and the arrow should be blue. I thought it is an interesting fact which real functions are involved in calls. If I get some time, I will draw the cycle as big rect, containing inner functions inside. This is a little bit more complicated on the programming side than the current solution. > i.e. may be called from any other function which is called from > cycle. Do I understand correctly? Yes. Calls among functions which are part of the same cycle will not be drawn. This is because you can not associate any meaningful cost to them. > >If you have all your functions in a big cycle, the profiling run simply > > was not useful at all (besides getting self costs). > > I have 6 function cycles in my profile. > <cycle 5> Incl. is 88%, self 0.32% > <cycle 3> Incl. is 35%, self 3.63% > <cycle 6> Incl. is 19%, self 0.09% > <cycle 4> Incl. is 15%, self.0.48% > Do I have problem with cycles then? Not really. It depends if you are interested in the call/cost relationship of functions which happen to be in the same cycle. In this regard, probably bad would be a cycle with self cost >50%. The thing is that with cycles, you get a somewhat destroyed call graph. The fact that cycle 5 has inclusive cost of 88% means that this is quite beneath the main() function, so the overview of the whole program is not that good. > I didn't know about cycles before, now I understand that I need to check > if AC:gUP() is called from cycle. There is a paper on GNU gprof: http://docs.freebsd.org/44doc/psd/18.gprof/paper.pdf) There, they explain their heuristics to get inclusive cost of functions from the raw things they measure (self cost and call arcs). This includes a discussion of cycles. > >Note that the call graph view usually only shows arrows for calls of > >importance, i.e. which add significantly to the inclusive cost of a caller > >(default: >5%). > > Yes, I know it. BTW could you give more freedom to user here? Minimal > value I can set is 1%, is it possible to just enter numbers for each > setting? I put it on my wishlist. Probably another tab in the configuration dialog under "Call craph defaults"? The thing is that the values For another constant value in the popup, it is only a one-liner away. I could put in a "No limit", which also would draw the calls in a cycle... The thing that this currently is no option has historic reasons: without limits to the call graph, it can get very huge, and in an old version, the layouting was called synchronously, blocking the GUI. But this has changed. Josef |