|
From: Julian S. <js...@ac...> - 2010-06-03 09:40:48
|
> I've got some success with the following approach. I steal the address of
> usleep() function from the program with a client request from vgpreload
> part of the tool, and insert a call to that address during code
> instrumentation:
>
> // put sleep duration in %edi
> PUT(56) = 0xF4241:I64
> // put return address on the stack
> t15 = GET:I64(32)
> t16 = Sub64(t15,0x8:I64)
> PUT(32) = t16
> STle(t16) = 0x405F55:I64
> // call the stolen usleep()
> if (1:I1) goto {Call} 0x40A012:I64
>
> This code must be placed immediately before an IMark, whose address is the
> return address of the call (0x405FF5 in this case). It also can not be
> placed at the beginning of an IRSB, because valgrind complains about an
> unknown PC. This approach is very arch-dependent and does not feel right.
I think this will work, but as you say, it is ugly.
> Is there a simpler way to do this? Is it possible to somehow tell the
> valgrind scheduler to let the other threads run for a bit (some kind of
> VG_(sched_yield) or VG_(sleep))?
Yes (I think so .. I tried something like this a couple of months
back).
Let's suppose X is the client instruction after which you want to
let other threads run. After the translation of X, finish the
IRSB, and put a jump to the next instruction. (in the same way
that the front ends will translate an unconditional branch that
they don't chase into).
Except .. for this jump, mark it as Ijk_Yield, not _Boring.
In scheduler.c find this
case VEX_TRC_JMP_YIELD:
/* Explicit yield, because this thread is in a spin-lock
or something. Only let the thread run for a short while
longer. Because swapping to another thread is expensive,
we're prepared to let this thread eat a little more CPU
before swapping to another. That means that short term
spins waiting for hardware to poke memory won't cause a
thread swap. */
if (VG_(dispatch_ctr) > 2000)
VG_(dispatch_ctr) = 2000;
break;
change '2000' to '1'
In scheduler.c find this
/* ------------ now we don't have The Lock ------------ */
...
/* ------------ now we do have The Lock ------------ */
in between these two comments add this
VG_(do_syscall0)(__NR_sched_yield);
this should cause the thread to be placed to the back of the run queue
for threads of this priority, which will allow another thread to run.
but be careful, I think __NR_sched_yield on linux takes a parameter which
controls its behaviour. Google for that.
add debug printing to make sure this is really behaving as you expect.
(it's all pretty fragile, but I'm sure i had something like this working
earlier this year)
J
|