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

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

Reply to
chrisdekoh
Loading thread data ...

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 )

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.

Reply to
PFC

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.

Reply to
cs_posting

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.

Reply to
David Brown

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
Reply to
Rich Webb

Can you declare doSomething() itself to be volatile?

Reply to
cs_posting

=

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 ?...

ch =

Sounds like a big shiny foot-gun. But you're right... C is so perverse, lol.

Reply to
PFC

On Mon, 9 Jun 2008 12:02:34 -0700 (PDT), cs snipped-for-privacy@hotmail.com wrote in comp.arch.embedded:

the

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
Reply to
Jack Klein

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.

Reply to
David Brown

Hi all, thanks for your reply. I have tried some suggestions:

1)

this doesnt work.

2)

Hi David, you said this:

how do you make an inline function? can kindly provide give a brief example?

kindly help. I have already tried to dump out the assembly instructions from the compiled binary file beforehand using mb- objdump. I already know that the smart compiler reorders the timer enable and puts it some where at the bottom just before the read back of timer value and timer disabled.

so i get something like this ( in C terms for easy reading):

void main() { Xuint32 countvalue;

// enable_timer();

way

Reply to
chrisdekoh

Making an inline function is easy (assuming you have the compiler flags set to accept the C99 "inline" keyword, or are compiling C++ - I have no idea which version of gcc the Microblaze uses):

static inline int doSomething(void) { }

If you are compiling with a reasonably recent version of gcc, and have optimisations enabled, then any single-use static function will be inlined automatically.

But what you really want here is a non-inlined function:

static int attribute((__noinline__)) doSomething(void) { }

Set your compiler flags to generate a listing file from the C code - it's much easier to follow than using objdump. Alternatively, load the code in the debugger and switch to mixed C and disassembly mode.

This looks like your enable_timer() and readback_timer() (and probably disable_timer()) definitions are wrong - they should be using volatile accesses to read and write the hardware timer registers. If they were doing that correctly, the compiler would not reorder them.

mvh.,

David

Reply to
David Brown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.