EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

how to prevent timer code firmware running on Microblaze from being optimised

Started by Unknown June 9, 2008
Hi,
   I am trying to do the following on Microblaze. Here is the program
structure.


void main() {
   Xuint32 countvalue;

   enable_timer();
   // do some stuff on Microblaze

   ...  //some lines of code ....

  countvalue = readback_timer();
  disable_timer();

  //send count value back to serial port
  ...

  return1;
 }

In short, I am trying to keep tab of how fast various sections of code
takes to run using a timer running on Microblaze.

when i do compile with some compiler optimization level set to -O1 or -
O2 or -O3, the compiler cleverly enables the timer at the WRONG place.
it enables the timer and then disables the timer again, giving me a
very short compute time. this is not what i want. :( since i want to
be able to accurately measure how long it takes for the code to
execute. I tried declaring countvalue as

   volatile Xuint32 countvalue;

It doesn't quite work. Does anybody have an idea on how i could go
about solving this?

thanks for your patience; I have not much experience developing
embedded firmware.

Chris
On Jun 9, 9:08 am, chrisde...@gmail.com wrote:
> Hi, > I am trying to do the following on Microblaze. Here is the program > structure. > > void main() { > Xuint32 countvalue; > > enable_timer(); > // do some stuff on Microblaze > > ... //some lines of code .... > > countvalue = readback_timer(); > disable_timer(); > > //send count value back to serial port > ... > > return1; > } > > In short, I am trying to keep tab of how fast various sections of code > takes to run using a timer running on Microblaze. > > when i do compile with some compiler optimization level set to -O1 or - > O2 or -O3, the compiler cleverly enables the timer at the WRONG place. > it enables the timer and then disables the timer again, giving me a > very short compute time. this is not what i want. :( since i want to > be able to accurately measure how long it takes for the code to > execute. I tried declaring countvalue as > > volatile Xuint32 countvalue; > > It doesn't quite work. Does anybody have an idea on how i could go > about solving this? > > thanks for your patience; I have not much experience developing > embedded firmware. > > Chris
Something you could try Recode enable_timer to return a value (say zero) - use the return value to initialize a variable (starting sum, whatever) in your "do stuff" section, real close to the start. Similar, re-code disable_timer to accept (and probably ignore) a parameter. Pass the result of "do stuff" to disable_timer. That should prevent the optimizer from moving the calls. At least, it had better not move them very far. Oh, and if it were me, I would disable (stop) the timer before reading it, not the other way around. Take a look at the assembler output to verify that you're getting what you want. G.
> In short, I am trying to keep tab of how fast various sections of code=
> takes to run using a timer running on Microblaze.
I've done that before, like this : int timer_value =3D * (volatile int *) TIMED_REG_ADDRESS; .. do stuff.. timer_value =3D (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; printf( "Elapsed cycles : %d", timer_value )
> volatile Xuint32 countvalue;
It is the timer register which is incremented unbeknowst to gcc, not yo= ur = int variable. Therefore it is the pointer to the timer register you read which must b= e = declared (volatile int *), not the int variable (this is useless). I put the explicit code in the example above. You can use defines or = functions to make it prettier. Note also that this handles wraparound : instant 1 : you get 0xFFFFFFFF from timer instant 2 : you get 0x00000001 from timer (it wrapped) (int)0xFFFFFFFF =3D -1 (int)0x00000001 =3D 1 Difference : 1 - (-1) =3D 2 cycles. int arithmetic handles the wraparound nicely for you. Note that if you set the timer to wraparound at some random value it = won't work. = "volatile int x" is a contradiction so gcc optimized away which is the = = expected behaviour. However *(volatile *)address has a very specific meaning which is what = = you want. Accesses to volatiles create barriers that gcc instruction = reordering cannot skip so it will do what you want.
On Jun 9, 1:43 pm, PFC <li...@peufeu.com> wrote:

> "volatile int x" is a contradiction so gcc optimized away which is the > expected behaviour.
How is it a contradiction? You can still get it's address and modify or examine it that way behind the compiler's back, so the compiler must assume that when you say it's volatile, you might mean it. Granted you want to be careful that you only do this during a time when the compiler is obligated to ensure that the variable exists, but that's not unreasonable within the scope, or when playing with a hardware-based debugger.
PFC wrote:
> >> In short, I am trying to keep tab of how fast various sections of code >> takes to run using a timer running on Microblaze. > > I've done that before, like this : > > int timer_value = * (volatile int *) TIMED_REG_ADDRESS; > > .. do stuff.. > > timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > printf( "Elapsed cycles : %d", timer_value ) > >> volatile Xuint32 countvalue; > > It is the timer register which is incremented unbeknowst to gcc, not > your int variable. > Therefore it is the pointer to the timer register you read which > must be declared (volatile int *), not the int variable (this is useless). > > I put the explicit code in the example above. You can use defines or > functions to make it prettier. > > Note also that this handles wraparound : > > instant 1 : you get 0xFFFFFFFF from timer > instant 2 : you get 0x00000001 from timer (it wrapped) > > (int)0xFFFFFFFF = -1 > (int)0x00000001 = 1 > > Difference : 1 - (-1) = 2 cycles. > int arithmetic handles the wraparound nicely for you. > > Note that if you set the timer to wraparound at some random value it > won't work. > > "volatile int x" is a contradiction so gcc optimized away which is > the expected behaviour. > However *(volatile *)address has a very specific meaning which is > what you want. Accesses to volatiles create barriers that gcc > instruction reordering cannot skip so it will do what you want.
This is a common misconception about volatile in C. The compiler cannot change volatile accesses with respect to other volatile accesses - but it can happily re-order non-volatile accesses around the volatile access. Thus it is perfectly allowed to do "...do stuff..." either before or after the two volatile reads of the timer. Even if you write something like : int timer_value = * (volatile int *) TIMED_REG_ADDRESS; volatile int result = doSomething(); timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; The compiler can call doSomething(), storing the result in a temporary register, then read TIMED_REG_ADDRESS, store the result in "result", then re-read TIMED_REG_ADDRESS - all without violating the volatile requirements. What's important is that you read the timer with a volatile access, then call doSomthing() in a way that requires a volatile access at the start and the end of the process, then re-read the timer with a volatile access at the end.
On Mon, 09 Jun 2008 21:30:17 +0200, David Brown
<david.brown@hesbynett.removethisbit.no> wrote:

>This is a common misconception about volatile in C. The compiler cannot >change volatile accesses with respect to other volatile accesses - but >it can happily re-order non-volatile accesses around the volatile >access. Thus it is perfectly allowed to do "...do stuff..." either >before or after the two volatile reads of the timer. Even if you write >something like : > >int timer_value = * (volatile int *) TIMED_REG_ADDRESS; >volatile int result = doSomething(); >timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > >The compiler can call doSomething(), storing the result in a temporary >register, then read TIMED_REG_ADDRESS, store the result in "result", >then re-read TIMED_REG_ADDRESS - all without violating the volatile >requirements.
Pardon me for jumping in, but doesn't the above violate the constraints on all side-effects of previous expressions, and none of subsequent expressions, being evaluated at each sequence point? -- Rich Webb Norfolk, VA
On Jun 9, 3:30 pm, David Brown
<david.br...@hesbynett.removethisbit.no> wrote:
> PFC wrote: > > >> In short, I am trying to keep tab of how fast various sections of code > >> takes to run using a timer running on Microblaze. > > > I've done that before, like this : > > > int timer_value = * (volatile int *) TIMED_REG_ADDRESS; > > > .. do stuff.. > > > timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > > printf( "Elapsed cycles : %d", timer_value ) > > >> volatile Xuint32 countvalue; > > > It is the timer register which is incremented unbeknowst to gcc, not > > your int variable. > > Therefore it is the pointer to the timer register you read which > > must be declared (volatile int *), not the int variable (this is useless). > > > I put the explicit code in the example above. You can use defines or > > functions to make it prettier. > > > Note also that this handles wraparound : > > > instant 1 : you get 0xFFFFFFFF from timer > > instant 2 : you get 0x00000001 from timer (it wrapped) > > > (int)0xFFFFFFFF = -1 > > (int)0x00000001 = 1 > > > Difference : 1 - (-1) = 2 cycles. > > int arithmetic handles the wraparound nicely for you. > > > Note that if you set the timer to wraparound at some random value it > > won't work. > > > "volatile int x" is a contradiction so gcc optimized away which is > > the expected behaviour. > > However *(volatile *)address has a very specific meaning which is > > what you want. Accesses to volatiles create barriers that gcc > > instruction reordering cannot skip so it will do what you want. > > This is a common misconception about volatile in C. The compiler cannot > change volatile accesses with respect to other volatile accesses - but > it can happily re-order non-volatile accesses around the volatile > access. Thus it is perfectly allowed to do "...do stuff..." either > before or after the two volatile reads of the timer. Even if you write > something like : > > int timer_value = * (volatile int *) TIMED_REG_ADDRESS; > volatile int result = doSomething(); > timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > The compiler can call doSomething(), storing the result in a temporary > register, then read TIMED_REG_ADDRESS, store the result in "result", > then re-read TIMED_REG_ADDRESS - all without violating the volatile > requirements.
Can you declare doSomething() itself to be volatile?
> int timer_value =3D * (volatile int *) TIMED_REG_ADDRESS; > volatile int result =3D doSomething(); > timer_value =3D (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; > > The compiler can call doSomething(), storing the result in a temporary=
=
> register, then read TIMED_REG_ADDRESS, store the result in "result", =
> then re-read TIMED_REG_ADDRESS - all without violating the volatile =
> requirements.
Does the compiler know that doSomething() will never access any volatil= e = variable ? (the generated assembly code was correct last time I checked). Anyway you can always put your timer code in functions. I don't think g= cc = reorders function calls ?...
>> "volatile int x" is a contradiction so gcc optimized away whi=
ch =
>> is the >> expected behaviour. > > How is it a contradiction? > > You can still get it's address and modify or examine it that way > behind the compiler's back, so the compiler must assume that when you > say it's volatile, you might mean it. Granted you want to be careful > that you only do this during a time when the compiler is obligated to > ensure that the variable exists, but that's not unreasonable within > the scope, or when playing with a hardware-based debugger.
Sounds like a big shiny foot-gun. But you're right... C is so perverse, lol.
On Mon, 9 Jun 2008 12:02:34 -0700 (PDT), cs_posting@hotmail.com wrote
in comp.arch.embedded:

> On Jun 9, 1:43 pm, PFC <li...@peufeu.com> wrote: > > > "volatile int x" is a contradiction so gcc optimized away which is the > > expected behaviour. > > How is it a contradiction? > > You can still get it's address and modify or examine it that way > behind the compiler's back, so the compiler must assume that when you > say it's volatile, you might mean it. Granted you want to be careful > that you only do this during a time when the compiler is obligated to > ensure that the variable exists, but that's not unreasonable within > the scope, or when playing with a hardware-based debugger.
Actually, the compiler can still optimize this away. To simplify: void some_function(void) { volatile int x = func1(); /* do stuff */ x = func2(); return; } Since the variable, even though it is declared volatile, has automatic storage duration and its address is never taken, it cannot possibly be modified without the compiler's knowledge. On the other hand, if it was defined at file scope, and therefore had external linkage, that would be a different story. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://c-faq.com/ comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
PFC wrote:
> >> int timer_value = * (volatile int *) TIMED_REG_ADDRESS; >> volatile int result = doSomething(); >> timer_value = (* (volatile int *) TIMED_REG_ADDRESS) - timer_value; >> >> The compiler can call doSomething(), storing the result in a temporary >> register, then read TIMED_REG_ADDRESS, store the result in "result", >> then re-read TIMED_REG_ADDRESS - all without violating the volatile >> requirements. > > Does the compiler know that doSomething() will never access any > volatile variable ? > (the generated assembly code was correct last time I checked). > > Anyway you can always put your timer code in functions. I don't > think gcc reorders function calls ?... > >>> "volatile int x" is a contradiction so gcc optimized away >>> which is the >>> expected behaviour. >> >> How is it a contradiction? >> >> You can still get it's address and modify or examine it that way >> behind the compiler's back, so the compiler must assume that when you >> say it's volatile, you might mean it. Granted you want to be careful >> that you only do this during a time when the compiler is obligated to >> ensure that the variable exists, but that's not unreasonable within >> the scope, or when playing with a hardware-based debugger. > > Sounds like a big shiny foot-gun. > But you're right... C is so perverse, lol. >
In answer to this and the other replies to my post: You are right that the compiler can only re-order "doSomething()" around volatile accesses if it knows that doSomething() does not make volatile accesses itself. But the compiler can be surprisingly knowledgeable about such things - if the doSomething() function is in the same source file, and you have at least some optimisations enabled, then it probably has this knowledge. In fact, in many common cases when you are writing test code like this, the doSomething() function is not only in the same file, but it is only used the one time, and the compiler may well inline the function. Thus even if it *does* use volatile accesses, non-volatile accesses in doSomething() can be shuffled around about and below the timer accesses. Just to add to the fun, the compiler might also figure out that parts of the code in doSomething() can be calculated at compile time, and eliminated from the object code. You can't make a function itself "volatile", but you can use the "noinline" function attribute to ensure it is not inlined - that's probably enough to make sure it is called properly. As has been said, check the assembly listing to make sure you are measuring the code you want to measure.

The 2024 Embedded Online Conference