|
From: Jeremy F. <je...@go...> - 2004-07-15 23:27:05
|
On Thu, 2004-07-15 at 23:20 +0100, Nicholas Nethercote wrote: > Hi, > > I'm looking at how new shadow memory pages are allocated when necessary. > It's weird, there seem to be two mechanisms for this. > > First, every tool that uses shadow memory (memcheck, addrcheck, helgrind) > is very careful to call their respective ENSURE_MAPPABLE macros before > accessing shadow memory, which checks if there is a shadow page for the > address and allocates a new one if not. > > That would seem to be enough. But in vg_signals.c, there's a bit in the > SEGV handler with this comment: > > /* If there's a fault within the shadow memory range, and it > is a permissions fault, then it means that the client is > using some memory which had not previously been used. > This catches those faults, makes the memory accessible, > and calls the tool to initialize that page. > */ > > This calls VG_(init_shadow_range)(), which calls the init_shadow_page > trackable event, telling the tool to make itself a shadow page. But none > of the tools actually provide the necessary init_shadow_page callback. > > This 2nd mechanism is simply not being used; I tried removing it and the > entire regression test suite ran fine. > > So I see two options: > > 1. Just rely on the currently used ENSURE_MAPPABLE macros in the tools. > This would allow a couple of functions to be removed or simplified, saving > 50 lines of code. > > 2. Just rely on the SEGV handling bit. This would require adding the > init_shadow_page callback to each of the tools. The advantage with this > option is that it might make things a bit faster, since we wouldn't have > to do ENSURE_MAPPABLE (which is a comparison like "x == y[z >> 16]") for > every shadow memory access. (But it might make no discernible difference, > since this is just arithmetic which might be swamped by the associated > memory accesses. In which case option (1) is clearly better.) > > Any opinions? Jeremy, do you know why both these mechanisms are present? Yup, I put them there. The SIGSEGV mechanism is a result of a discussion we had ages ago about direct-mapping the shadow memory from the client address - basically so that there's a simple addr*scale+offset to map from a client address to a shadow address. The theory was that this computation is simple enough to do inline, so a number of the shadow memory accesses wouldn't require calls to helpers. It would also be, in theory, faster because it removes a memory reference indirecting through the page. There are a couple of problems in practice. The direct-mapped approach also needs a bounds check to make sure that the pointer is actually a user-address-space pointer - if it isn't the computed shadow pointer could end up in the middle of the Valgrind address space. This bounds check approximately doubles the size of the address calculation, and probably undermines any performance improvement. Which leads the other problem: I never actually measured a clear performance improvement. I'm not really sure why. It wasn't because of the overhead of the SIGSEGV handler, since the fault rate dropped a lot once the working set was established. But I was never really sure of what it did to cache access patterns, and the address calculation often ended up being quite fiddly. So, no, nothing is using this at the moment. It looks like it should be a useful mechanism, but it isn't clear that any of the existing tools can easily use it. On the other hand, there's no huge performance hit, so if the code turns out to be simpler with direct mapping, it might be the way to go (ie, it isn't worth changing existing tools, but it might make sense for new ones). J |