|
From: Martin H. <hi...@gm...> - 2006-01-11 03:07:06
|
Hi, For cachegrind, the instrumenter inserts calls to functions that drive a cache simulation. The cache simulation only needs to know where memory cells are read or written, not what the contents of those memory cells are, since that doesn't affect whether there is a hit or miss. But I would like to abuse the write instrumentation in a situation where I do need to know the newly written values. Now here is my question: can I just obtain that by reading the current memory contents at the given address at the time the instrumentation function gets executed? From looking at the source code, I assume that yes, because the instrumentation appears to be always after (later in the basic block than) the instruction(s) it instruments. Could someone please confirm or deny whether I understand the code correctly? Thank you, Martin |
|
From: Julian S. <js...@ac...> - 2006-01-11 12:57:25
|
> is my question: can I just obtain that by reading the current memory > contents at the given address at the time the instrumentation function > gets executed? From looking at the source code, I assume that yes, > because the instrumentation appears to be always after (later in the > basic block than) the instruction(s) it instruments. Could someone > please confirm or deny whether I understand the code correctly? I think that's right (not 100% sure). Use --tool=cachegrind --trace-flags=10001000 to see the relationship between the initial IR and the instrumented IR. The calls to simulation functions are grouped in sets of up to 8 for efficiency reasons, so the instrumented IR looks a bit strange at first. J |
|
From: Josef W. <Jos...@gm...> - 2006-01-11 15:02:20
|
On Wednesday 11 January 2006 13:56, Julian Seward wrote:
>
> > is my question: can I just obtain that by reading the current memory
> > contents at the given address at the time the instrumentation function
> > gets executed? From looking at the source code, I assume that yes,
> > because the instrumentation appears to be always after (later in the
> > basic block than) the instruction(s) it instruments. Could someone
> > please confirm or deny whether I understand the code correctly?
>
> I think that's right (not 100% sure). Use --tool=cachegrind
> --trace-flags=10001000 to see the relationship between the initial IR
> and the instrumented IR. The calls to simulation functions are grouped
> in sets of up to 8 for efficiency reasons, so the instrumented IR
> looks a bit strange at first.
Wrong.
I just checked:
int main()
{
volatile int a;
a = 3;
a = 5;
return a;
}
08048240 <main>:
int main()
{
8048240: 55 push %ebp
8048241: 89 e5 mov %esp,%ebp
8048243: 83 ec 18 sub $0x18,%esp
8048246: 83 e4 f0 and $0xfffffff0,%esp
volatile int a;
a = 3;
8048249: c7 45 fc 03 00 00 00 movl $0x3,0xfffffffc(%ebp)
a = 5;
8048250: c7 45 fc 05 00 00 00 movl $0x5,0xfffffffc(%ebp)
return a;
8048257: 8b 45 fc mov 0xfffffffc(%ebp),%eax
804825a: 83 ec 10 sub $0x10,%esp
}
Relevant output of
valgrind --tool=cachegrind --trace-flags=10001000 ./a.out
------ IMark(0x8048249, 7) ------
PUT(60) = 0x8048249:I32
t22 = Add32(t19,0xFFFFFFFC:I32)
STle(t22) = 0x3:I32
------ IMark(0x8048250, 7) ------
PUT(60) = 0x8048250:I32
t24 = Add32(t19,0xFFFFFFFC:I32)
STle(t24) = 0x5:I32
------ IMark(0x8048257, 7) ------
PUT(60) = 0x8048257:I32
t26 = Add32(t19,0xFFFFFFFC:I32)
STle(t26) = 0x7:I32
------ IMark(0x804825E, 3) ------
PUT(32) = 0x6:I32
PUT(36) = t5
PUT(40) = 0x10:I32
PUT(44) = 0x0:I32
PUT(16) = Sub32(t5,0x10:I32)
------ IMark(0x8048261, 3) ------
PUT(60) = 0x8048261:I32
t28 = Add32(t19,0xFFFFFFFC:I32)
PUT(0) = LDle:I32(t28)
------ IMark(0x8048264, 1) ------
PUT(60) = 0x8048264:I32
PUT(16) = t19
PUT(20) = LDle:I32(t19)
t31 = Add32(t19,0x4:I32)
PUT(16) = t31
DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3]{0xb0003e4c}(0x61D55E7C:I32,t19,0x4:I32)
DIRTY 1:I1 ::: log_3I_0D_cache_access[rp=3]{0xb00019a6}(0x61D55E88:I32,0x61D55E94:I32,0x61D55EA0:I32)
DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3]{0xb0003e4c}(0x61D55EAC:I32,t22,0x4:I32)
DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3]{0xb0003e4c}(0x61D55EB8:I32,t24,0x4:I32)
DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3]{0xb0003e4c}(0x61D55EC4:I32,t26,0x4:I32)
DIRTY 1:I1 ::: log_2I_0D_cache_access[rp=2]{0xb0000b00}(0x61D55ED0:I32,0x61D55EDC:I32)
DIRTY 1:I1 ::: log_0I_1Dr_cache_access[rp=3]{0xb0004cf0}(0x61D55EDC:I32,t28,0x4:I32)
DIRTY 1:I1 ::: log_1I_1Dr_cache_access[rp=3]{0xb0002fa8}(0x61D55EE8:I32,t19,0x4:I32)
------ IMark(0x8048265, 1) ------
So all the calls are delayed to the end of main.
The helper has no chance to get at the 3 written first.
Perhaps you should add the read/written value as parameter of the helper.
Josef
>
> J
>
>
> -------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
> for problems? Stop! Download the new AJAX search engine that makes
> searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
> http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
> _______________________________________________
> Valgrind-users mailing list
> Val...@li...
> https://lists.sourceforge.net/lists/listinfo/valgrind-users
>
>
|
|
From: Martin H. <hi...@gm...> - 2006-01-11 15:09:45
|
Hey, thanks for checking that for me!
In other words: the helper comes after the write, but there may be
other writes in the middle.
I think I'll just eagerly flush the pending helpers after each write.
That should avoid the problem you found, while still retaining some of
the benefits of grouping for reads.
Martin
On 1/11/06, Josef Weidendorfer <Jos...@gm...> wrote:
> On Wednesday 11 January 2006 13:56, Julian Seward wrote:
> >
> > > is my question: can I just obtain that by reading the current memory
> > > contents at the given address at the time the instrumentation functio=
n
> > > gets executed? From looking at the source code, I assume that yes,
> > > because the instrumentation appears to be always after (later in the
> > > basic block than) the instruction(s) it instruments. Could someone
> > > please confirm or deny whether I understand the code correctly?
> >
> > I think that's right (not 100% sure). Use --tool=3Dcachegrind
> > --trace-flags=3D10001000 to see the relationship between the initial IR
> > and the instrumented IR. The calls to simulation functions are grouped
> > in sets of up to 8 for efficiency reasons, so the instrumented IR
> > looks a bit strange at first.
>
> Wrong.
>
> I just checked:
>
> int main()
> {
> volatile int a;
> a =3D 3;
> a =3D 5;
> return a;
> }
>
> 08048240 <main>:
> int main()
> {
> 8048240: 55 push %ebp
> 8048241: 89 e5 mov %esp,%ebp
> 8048243: 83 ec 18 sub $0x18,%esp
> 8048246: 83 e4 f0 and $0xfffffff0,%esp
> volatile int a;
>
> a =3D 3;
> 8048249: c7 45 fc 03 00 00 00 movl $0x3,0xfffffffc(%ebp)
> a =3D 5;
> 8048250: c7 45 fc 05 00 00 00 movl $0x5,0xfffffffc(%ebp)
>
> return a;
> 8048257: 8b 45 fc mov 0xfffffffc(%ebp),%eax
> 804825a: 83 ec 10 sub $0x10,%esp
> }
>
> Relevant output of
> valgrind --tool=3Dcachegrind --trace-flags=3D10001000 ./a.out
>
> ------ IMark(0x8048249, 7) ------
> PUT(60) =3D 0x8048249:I32
> t22 =3D Add32(t19,0xFFFFFFFC:I32)
> STle(t22) =3D 0x3:I32
> ------ IMark(0x8048250, 7) ------
> PUT(60) =3D 0x8048250:I32
> t24 =3D Add32(t19,0xFFFFFFFC:I32)
> STle(t24) =3D 0x5:I32
> ------ IMark(0x8048257, 7) ------
> PUT(60) =3D 0x8048257:I32
> t26 =3D Add32(t19,0xFFFFFFFC:I32)
> STle(t26) =3D 0x7:I32
> ------ IMark(0x804825E, 3) ------
> PUT(32) =3D 0x6:I32
> PUT(36) =3D t5
> PUT(40) =3D 0x10:I32
> PUT(44) =3D 0x0:I32
> PUT(16) =3D Sub32(t5,0x10:I32)
> ------ IMark(0x8048261, 3) ------
> PUT(60) =3D 0x8048261:I32
> t28 =3D Add32(t19,0xFFFFFFFC:I32)
> PUT(0) =3D LDle:I32(t28)
> ------ IMark(0x8048264, 1) ------
> PUT(60) =3D 0x8048264:I32
> PUT(16) =3D t19
> PUT(20) =3D LDle:I32(t19)
> t31 =3D Add32(t19,0x4:I32)
> PUT(16) =3D t31
> DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3D3]{0xb0003e4c}(0x61D55E7C:=
I32,t19,0x4:I32)
> DIRTY 1:I1 ::: log_3I_0D_cache_access[rp=3D3]{0xb00019a6}(0x61D55E88:I=
32,0x61D55E94:I32,0x61D55EA0:I32)
> DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3D3]{0xb0003e4c}(0x61D55EAC:=
I32,t22,0x4:I32)
> DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3D3]{0xb0003e4c}(0x61D55EB8:=
I32,t24,0x4:I32)
> DIRTY 1:I1 ::: log_1I_1Dw_cache_access[rp=3D3]{0xb0003e4c}(0x61D55EC4:=
I32,t26,0x4:I32)
> DIRTY 1:I1 ::: log_2I_0D_cache_access[rp=3D2]{0xb0000b00}(0x61D55ED0:I=
32,0x61D55EDC:I32)
> DIRTY 1:I1 ::: log_0I_1Dr_cache_access[rp=3D3]{0xb0004cf0}(0x61D55EDC:=
I32,t28,0x4:I32)
> DIRTY 1:I1 ::: log_1I_1Dr_cache_access[rp=3D3]{0xb0002fa8}(0x61D55EE8:=
I32,t19,0x4:I32)
> ------ IMark(0x8048265, 1) ------
>
> So all the calls are delayed to the end of main.
> The helper has no chance to get at the 3 written first.
>
> Perhaps you should add the read/written value as parameter of the helper.
>
> Josef
>
>
> >
> > J
> >
> >
> > -------------------------------------------------------
> > This SF.net email is sponsored by: Splunk Inc. Do you grep through log =
files
> > for problems? Stop! Download the new AJAX search engine that makes
> > searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
> > http://ads.osdn.com/?ad_id=3D7637&alloc_id=3D16865&op=3Dclick
> > _______________________________________________
> > Valgrind-users mailing list
> > Val...@li...
> > https://lists.sourceforge.net/lists/listinfo/valgrind-users
> >
> >
>
>
> -------------------------------------------------------
> This SF.net email is sponsored by: Splunk Inc. Do you grep through log fi=
les
> for problems? Stop! Download the new AJAX search engine that makes
> searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
> http://ads.osdn.com/?ad_id=3D7637&alloc_id=3D16865&op=3Dclick
> _______________________________________________
> Valgrind-users mailing list
> Val...@li...
> https://lists.sourceforge.net/lists/listinfo/valgrind-users
>
|
|
From: Julian S. <js...@ac...> - 2006-01-11 15:58:28
|
> In other words: the helper comes after the write, but there may be > other writes in the middle. Ah yes. As Josef points out. > I think I'll just eagerly flush the pending helpers after each write. That sounds like a good compromise. J |
|
From: Martin H. <hi...@gm...> - 2006-01-11 16:17:18
|
Does control flow ever leave a basic block in the middle for any reason (e.g. for an exception)? Say, after a write, but before the corresponding helper? If yes, does that happen often? Martin On 1/11/06, Julian Seward <js...@ac...> wrote: > > > In other words: the helper comes after the write, but there may be > > other writes in the middle. > > Ah yes. As Josef points out. > > > I think I'll just eagerly flush the pending helpers after each write. > > That sounds like a good compromise. > > J > > > ------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. Do you grep through log fi= les > for problems? Stop! Download the new AJAX search engine that makes > searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! > http://ads.osdn.com/?ad_id=3D7637&alloc_id=3D16865&op=3Dclick > _______________________________________________ > Valgrind-users mailing list > Val...@li... > https://lists.sourceforge.net/lists/listinfo/valgrind-users > |
|
From: Nicholas N. <nj...@cs...> - 2006-01-11 16:38:56
|
On Wed, 11 Jan 2006, Martin Hirzel wrote: > Does control flow ever leave a basic block in the middle for any > reason (e.g. for an exception)? Yes -- they're not basic blocks but "superblocks" which means they can have multiple exits, usually just for normal jumps, but also for more unusual events like exceptions. > Say, after a write, but before the > corresponding helper? If yes, does that happen often? If you're instrumenting the writes as the occur, as you said, then I think this case would only occur if the write caused a seg fault or something similar, so it should be extremely rare. Nick |
|
From: Josef W. <Jos...@gm...> - 2006-01-11 16:58:26
|
On Wednesday 11 January 2006 17:38, Nicholas Nethercote wrote: > > Say, after a write, but before the > > corresponding helper? If yes, does that happen often? > > If you're instrumenting the writes as the occur, as you said, then I think > this case would only occur if the write caused a seg fault I am curious: How does valgrind "replay" a memory write after a seg fault handled in a user signal handler? Does this create a new superblock starting at the write instruction? Josef |
|
From: Julian S. <js...@ac...> - 2006-01-12 02:35:15
|
On Wednesday 11 January 2006 16:57, Josef Weidendorfer wrote: > On Wednesday 11 January 2006 17:38, Nicholas Nethercote wrote: > > > Say, after a write, but before the > > > corresponding helper? If yes, does that happen often? > > > > If you're instrumenting the writes as the occur, as you said, then I > > think this case would only occur if the write caused a seg fault > > I am curious: How does valgrind "replay" a memory write after a seg fault > handled in a user signal handler? Does this create a new superblock > starting at the write instruction? Yes. In general the same instruction may be part of many superblocks, not just one. J |