If you want to measure elapsed time in a bare-metal application on the Xilinx Zynq SoC—for example to measure how long your external accelerator takes to get a result—you will soon notice that typical methods do not work. But there is a simple and precise replacement for those methods.
A method that is often recommended is to use gettimeofday() out of sys/time.h to get the current time before and after whatever time interval we want to measure and to take the difference of it. Trying this in a bare-metal application on the Zynq SoC we get the following error:
In function `_gettimeofday_r': gettimeofdayr.c:(.text+0x20): undefined reference to `_gettimeofday'
According to the man page this method is deprecated anyway, so let’s try the recommended replacement: clock_gettime() out of time.h:
undefined reference to `clock_gettime'
So, no luck either… How about just obtaining the clock count using clock() out of time.h?
In function `_times_r': timesr.c:(.text+0x4): undefined reference to `_times'
Luckily, there is a Xilinx specific replacement for the last approach. Here is a short sample program:
#include <stdio.h> #include "platform.h" #include "xparameters.h" #include "xtime_l.h" void print(char *str); int main() { XTime tStart, tEnd; init_platform(); XTime_GetTime(&tStart); print("Hello World\n\r"); XTime_GetTime(&tEnd); printf("Output took %llu clock cycles.\n", 2*(tEnd - tStart)); printf("Output took %.2f us.\n", 1.0 * (tEnd - tStart) / (COUNTS_PER_SECOND/1000000)); return 0; }
This uses the global timer in the Zynq SoC whose counter increases every two clock cycles. So it gives pretty precise results.
Updates to this post:
- Jul 28, 2015: Fix calculation of clock cycles in example program.
Hello,
I think you you did a small mistake calculating the clock cycles.
the define “COUNTS_PER_SECOND” already includes the fact the counter only counts every two clock cycles [ #define (CPU_FREQ /2) ]. so if multiply the difference between tEnd and tStart by 2 your time calculated will be double the original value.
regards
Sven
The 2 is already included in COUNTS_PER_SECOND but I don’t use that constant when calculating the number of clock cycles. I just take the raw value of the counter registers and multiply it by 2.
When calculating the time in µs, I leave out the factor 2 because it is already included in COUNTS_PER_SECOND. Or do I miss something here?
The difference tEnd – tStart always gives me 0 for whatever instructions I put between XTime_GetTime(&tStart) and XTime_GetTime(&tEnd).
Instructions between XTime_GetTime(&tStart) and XTime_GetTime(&tEnd):
————————————-
print(“Hello Worldnr”);
for(int i=0;i< 1000 ;i++)
{
sum += i;
}
Xil_Out32(0x43c00000, 0x5);
Xil_Out32(0x7aa00000, 0x5555);
NumberOfPattern = Xil_In32(0x43c00004);
————————————-
I haven’t encountered this before but I can imagine different reasons:
1. How do you evaluate the result? In a printf, e.g., you have to use %lld instead of %d to get reasonable output: https://forums.xilinx.com/t5/Embedded-Development-Tools/Why-XTime-GetTime-don-t-work-always-return-the-same-value/m-p/293595#M25999
2. With certain devices and older Vivado versions, there is a bug causing similar behavior: https://www.xilinx.com/support/answers/67139.html
3. I don’t know if this is the case, but maybe disabling “Timer 0” when configuring the ZYNQ7 Processing System could cause this behavior. Here is a screenshot of what I mean: https://0xstubs.org/zynq7-timer0/
To rule out an error in your code you may just test the code given in this post. It should definitely output something different to 0.
I read there was a bug in 2016.1 where you had to first call sleep() to kick off the timer. Any subsequent calls to XTime_GetTime() would then work properly.
I can confirm that just running this program in Vivado 2017.2 does not work, and returns a difference of 0. However maybe this is due to never initializing the hardware timer itself?
I retried the exact same code as posted above in Vivado 2017.2 and it works perfectly here on a Digilent Zedboard:
Hello World
Output took 2020 clock cycles.
Output took 3.03 us.
I used two distinct platform definitions: one exported by Vivado after configuring the ‘ZYNQ7 processing system’ IP block and running hardware synthesis, and the pre-defined ‘zed_hw_platform’ which can be chosen in the SDK. Both worked fine. Also, it did not matter if the PL was programmed or not.
Finally, I removed Timer 0 (TTC0) from the hardware configuration and tried again. This time the program got stuck at the call to print(), so I guess the UART needs TTC0 to work. Also, I am not able to run any program without calling ps7_init at least once. So honestly, I have no clue how to reproduce the behavior that you and Mihai observe ?
thanks
Thank you. It worked.
And while giving print make sure u print using printf(). xil_printf() doesnt support long int. so it gives random values mostly ‘0’.
Tested and verified. Thank you this saved me big time!