|
From: Konstantin S. <kon...@gm...> - 2008-02-22 15:44:46
|
Hi, A question similar to the one discussed in 'thread-change callback' thread. How can I see context change events (i.e. when some thread enters or exits a function)? Thanks, --kcc |
|
From: Josef W. <Jos...@gm...> - 2008-02-22 18:26:57
|
On Friday 22 February 2008, Konstantin Serebryany wrote: > Hi, > > A question similar to the one discussed in 'thread-change callback' thread. > How can I see context change events (i.e. when some thread enters or > exits a function)? Possibilities: * At instrumentation time, check if a given instruction is the first of a function according to debug information. This way, you get "enter function" events, but not "exit" events. Instrumenting also every exit can get complex, and you probably end with something similar to part of Callgrinds functionality. * Extract the according functionality from Callgrind into a core module to make it usable by every tool. There is a shadow callstack which is resynchronized with the real one, making this approach quite robust. E.g. it works with recursion, longjmps etc. Drawback aside from not-existing module: slowdown because of an instrumented callback at beginning of every basic block (could be optimized to do the callback at end of BBs instead at beginning, and only when changing the context). * For specific functions, functions wrappers can be installed. This redirects jumps to the given function to another one you provide in a shared lib which will be loaded by valgrind dependent on the tool. Function exits work this way, as the wrapper has its stack frame on the client stack. Callbacks into your tool have to be done via client requests from the wrapper. AFAIK, this has problems with recursion and longjmps. In general, as VG is running machine code, and you probably define "context change" as C/C++/... function changes, there is not always an exact relation among them, and thus sometimes difficult whether a given execution should really trigger a context change or not (e.g. with end recursion optimization). Josef |
|
From: Konstantin S. <kon...@gm...> - 2008-02-26 09:39:23
|
When I asked this question I thought about detecting context-change during execuction, not instrumentation. But now I think I need this at instrumentation time. :) I implemented a mode in helgrind such that all instrumentation is performed, but no shadow value management (cache and state machine) is done. The difference in performance between this variation of helgrind and nulgrind is about 3x. So, I suppose that these 3x are due to the instrumentation code. Meanwhile there are cases when we can avoid instrumenting large portions of code because it is either trustworthy or we don't care about it and memory locations accessed there. >> At instrumentation time, check if a given instruction is the first of a function according to debug information. Is that reliable? Does valgrind instrument each routine completely before starting another routine (I beg my pardon for my ignorance here). Ideally, I would need to know the name of the instrumented routine inside helgrind's hg_instrument. Is that possible? >> In general, as VG is running machine code, and you probably define "context change" as C/C++/... function changes... What we see in the machine code is enough for me. If one wants more-or-less precise mapping to C/C++ functions he will need to disable all compiler optimizations. Thanks, --kcc On Fri, Feb 22, 2008 at 9:26 PM, Josef Weidendorfer <Jos...@gm...> wrote: > > On Friday 22 February 2008, Konstantin Serebryany wrote: > > Hi, > > > > A question similar to the one discussed in 'thread-change callback' thread. > > How can I see context change events (i.e. when some thread enters or > > exits a function)? > > Possibilities: > > * At instrumentation time, check if a given instruction is the first of > a function according to debug information. This way, you get "enter function" > events, but not "exit" events. Instrumenting also every exit can get complex, > and you probably end with something similar to part of Callgrinds functionality. > > * Extract the according functionality from Callgrind into a core module to > make it usable by every tool. There is a shadow callstack which is > resynchronized with the real one, making this approach quite robust. E.g. > it works with recursion, longjmps etc. > Drawback aside from not-existing module: slowdown because of an > instrumented callback at beginning of every basic block (could be optimized > to do the callback at end of BBs instead at beginning, and only when > changing the context). > > * For specific functions, functions wrappers can be installed. This redirects > jumps to the given function to another one you provide in a shared lib which > will be loaded by valgrind dependent on the tool. Function exits work this > way, as the wrapper has its stack frame on the client stack. Callbacks into > your tool have to be done via client requests from the wrapper. AFAIK, this > has problems with recursion and longjmps. > > In general, as VG is running machine code, and you probably define "context change" > as C/C++/... function changes, there is not always an exact relation among them, > and thus sometimes difficult whether a given execution should really trigger a > context change or not (e.g. with end recursion optimization). > > Josef > > > > |
|
From: Josef W. <Jos...@gm...> - 2008-02-26 09:58:28
|
On Tuesday 26 February 2008, Konstantin Serebryany wrote: > >> At instrumentation time, check if a given instruction is the first > of a function according to debug information. > Is that reliable? > Does valgrind instrument each routine completely before starting > another routine (I beg my pardon for my ignorance here). No. Why is this needed? Only the parts which are to be executed are instrument before, at the granularity of superblocks. This means that the function context can change multiple times for one code piece to instrument. This can be switched off to work on basic blocks instead (which Callgrind is doing). Josef |
|
From: Konstantin S. <kon...@gm...> - 2008-02-26 10:12:12
|
On Tue, Feb 26, 2008 at 12:58 PM, Josef Weidendorfer <Jos...@gm...> wrote: > On Tuesday 26 February 2008, Konstantin Serebryany wrote: > > >> At instrumentation time, check if a given instruction is the first > > of a function according to debug information. > > Is that reliable? > > Does valgrind instrument each routine completely before starting > > another routine (I beg my pardon for my ignorance here). > > No. That's what I though. > Why is this needed? Consider we have function FOO and BAR. (and for simplicity FOO calls BAR) We want to instrument everything in FOO and not instrument BAR. We enter FOO for the first time and instrument it's first superblock. Than we enter BAR and do not instrument it. Than we exit BAR and we are in FOO again, and we need to instrument a new portion of FOO, which is not the first in FOO. So, 'check if a given instruction is the first of a function according to debug information' is not sufficient. Do I miss something? --kcc > Only the parts which are to be executed are instrument before, at the > granularity of superblocks. This means that the function context can > change multiple times for one code piece to instrument. This can be > switched off to work on basic blocks instead (which Callgrind is doing). > > Josef > |
|
From: Josef W. <Jos...@gm...> - 2008-02-26 10:44:59
|
On Tuesday 26 February 2008, Konstantin Serebryany wrote: > On Tue, Feb 26, 2008 at 12:58 PM, Josef Weidendorfer > <Jos...@gm...> wrote: > > On Tuesday 26 February 2008, Konstantin Serebryany wrote: > > > Does valgrind instrument each routine completely before starting > > > another routine (I beg my pardon for my ignorance here). > > > Why is this needed? > > Consider we have function FOO and BAR. (and for simplicity FOO calls BAR) > We want to instrument everything in FOO and not instrument BAR. > > We enter FOO for the first time and instrument it's first superblock. > Than we enter BAR and do not instrument it. > Than we exit BAR and we are in FOO again, and we need to instrument a > new portion of FOO, which is not the first in FOO. > So, 'check if a given instruction is the first of a function according > to debug information' is not sufficient. Do I miss something? You can always request the function any instruction is part of at instrumentation time. The check whether it is the first is about catching the function entry event. Josef |
|
From: Konstantin S. <kon...@gm...> - 2008-02-26 11:05:37
|
> You can always request the function any instruction is part of at > instrumentation time. How? > The check whether it is the first is about catching > the function entry event. Ah, I see. --kcc |
|
From: Julian S. <js...@ac...> - 2008-02-26 11:23:54
|
> > Consider we have function FOO and BAR. (and for simplicity FOO calls BAR) > > We want to instrument everything in FOO and not instrument BAR. > > > > We enter FOO for the first time and instrument it's first superblock. > > Than we enter BAR and do not instrument it. > > Than we exit BAR and we are in FOO again, and we need to instrument a > > new portion of FOO, which is not the first in FOO. > > So, 'check if a given instruction is the first of a function according > > to debug information' is not sufficient. Do I miss something? > > You can always request the function any instruction is part of at > instrumentation time. The check whether it is the first is about catching > the function entry event. I can see that you would want to instrument some functions and not others, eg, FOO but not BAR. But why do you care about knowing if some block is the entry point for a function or not? So there's probably some function you can call in the tool-visible interface to m_debuginfo (that is, in include/pub_tool_debuginfo.h) to find out the name of a function containing a given code address. VG_(get_fnname), it looks like. I assume you will ask for the containing function name and then not instrument it according to some criteria. Right? Uh, that's a bit dangerous because the JIT will create superblocks which go across function calls. Eg if BAR calls XYZZY then there can be a block starting in BAR and ending in XYZZY, and if you say that BAR is not to be instrumented, then you also miss instrumentation for the part of the block in XYZZY. No problem, you just need to disable superblock formation. Put this in the post_clo_init function: VG_(clo_vex_control).guest_chase_thresh = 0; btw, Josef, I see you also have VG_(clo_vex_control).iropt_unroll_thresh = 0; why is that? does the loop unroller confuse Callgrind's profile somehow? J |
|
From: Julian S. <js...@ac...> - 2008-02-26 11:26:27
|
> why is that? does the loop unroller confuse Callgrind's profile somehow? duh. s/profile/instrumentation-function/g J |
|
From: Konstantin S. <kon...@gm...> - 2008-02-26 11:46:50
|
> > I can see that you would want to instrument some functions and not > others, eg, FOO but not BAR. But why do you care about knowing > if some block is the entry point for a function or not? In fact, I don't. :) > > So there's probably some function you can call in the tool-visible > interface to m_debuginfo (that is, in include/pub_tool_debuginfo.h) > to find out the name of a function containing a given code address. > VG_(get_fnname), it looks like. Cool! > I assume you will ask for the containing > function name and then not instrument it according to some criteria. Right? Right. Most likely I will just have a command line with a list of C++ functions and namespaces to skip. > Uh, that's a bit dangerous because the JIT will create superblocks > which go across function calls. Eg if BAR calls XYZZY then there > can be a block starting in BAR and ending in XYZZY, and if you > say that BAR is not to be instrumented, then you also miss > instrumentation for the part of the block in XYZZY. No problem, you > just need to disable superblock formation. Put this in the post_clo_init > function: > > VG_(clo_vex_control).guest_chase_thresh = 0; What is the expected slowdown from limiting superblocks to one BB? --kcc |
|
From: Julian S. <js...@ac...> - 2008-02-26 12:02:42
|
> > I assume you will ask for the containing > > function name and then not instrument it according to some criteria. > > Right? > > Right. Most likely I will just have a command line with a list of C++ > functions and namespaces to skip. See 'VG_(string_match)' in pub_tool_libcbase.h. > > VG_(clo_vex_control).guest_chase_thresh = 0; > > What is the expected slowdown from limiting superblocks to one BB? Minimal. Nothing to worry about. J |
|
From: Josef W. <Jos...@gm...> - 2008-02-26 14:07:22
|
On Tuesday 26 February 2008, Julian Seward wrote: > just need to disable superblock formation. Put this in the post_clo_init > function: > > VG_(clo_vex_control).guest_chase_thresh = 0; > > btw, Josef, I see you also have > > VG_(clo_vex_control).iropt_unroll_thresh = 0; > > why is that? does the loop unroller confuse Callgrind's profile somehow? Good question. This was part of the big commits porting from VG2 to VG3. I think this is not because of the call graph, but I also have this mode to get jump information. And that was confused by unrolling. I think I know the problem I had: The jump statistics is indexed by (BBFrom, BBTo), where BBFrom/BBTo are structures with are generated for each BB. With unrolling, it can be that there are no such structure available. In short, for jump collection, it would get more complex, and because there has to be a callback to increment jump statistics, the benefit of unrolling is not clear. But you are right, when not in jump-collection mode, unrolling should be allowed. Josef |
|
From: Julian S. <js...@ac...> - 2008-02-26 18:23:03
|
> But you are right, when not in jump-collection mode, unrolling should be > allowed. Well, not necessarily. More variants means more overhead in testing/ verification. J |