1.2k views
in Platform Packages by

Dear all,

I'm using embedded winzard pro. And I want to use EW_PRINT_PERF_COUNTERS.

And I followed to guide

https://ask.embedded-wizard.de/289/performance-counters?show=290#a290 and

https://ask.embedded-wizard.de/2347/first-update-taking-a-long-time?show=2498#c2498

But my result that I had (time is zero):

Reset performance counters
-----------------------------------------------------------------------------------------------
Group Name                    [ Calls ]  [  Time  Total  ]
-----------------------------------------------------------------------------------------------
Total Time                            1    0.000 ms 100.0% of real CPU time
Graphics_Engine_API                   6    0.000 ms 100.0%
Platform_Integration_API              3    0.000 ms 100.0%
Bidi_Text_API                         0    0.000 ms 100.0%
-----------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------
Graphics_Engine_API           [ Calls ]  [  Time  Total  ]  [Time Avg]  [Time Min]  [Time Max]
-----------------------------------------------------------------------------------------------
EwBeginUpdate                         1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
EwEndUpdate                           1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
EwFillRectangle                       1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
EwCopyBitmap                          3    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
-----------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------
Platform_Integration_API      [ Calls ]  [  Time  Total  ]  [Time Avg]  [Time Min]  [Time Max]
-----------------------------------------------------------------------------------------------
EwGfxBeginUpdate                      1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
EwGfxEndUpdate                        1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
EwGfxCopy                             1    0.000 ms 100.0%    0.000 ms    0.000 ms    0.000 ms
-----------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------
Bidi_Text_API                 [ Calls ]  [  Time  Total  ]  [Time Avg]  [Time Min]  [Time Max]
-----------------------------------------------------------------------------------------------

I have modify EwGetPerfCounter() function:

void EwGetPerfCounter( unsigned long* aSeconds, unsigned long* aMicroSeconds,
  unsigned long* aCPUMicroseconds )
{

    unsigned long eticks = EwGetTicks();
  *aSeconds         = (eticks/1000);
  *aMicroSeconds    = *aSeconds * 1000000;
  *aCPUMicroseconds = eticks;
}

Could you guide for me how to use performance counters in STM32H7-EVAL?

Thanks,

1 Answer

+1 vote
by
 
Best answer

Hello Francessco,

as mentioned within the referred article, the performance counter functionality requires the target system to provide a high precision timer. For that purpose the function EwGetPerfCounter() in the module ewextrte.c has to be implemented.

Within your implementation you are using EwGetTicks() - which has a resolution in milliseconds. However, the performance measurement is based on microseconds. In order to get reliable measurements you need a more precise time source than EwGetTicks().

I just made an implementation of EwGetPerfCounter() based on the DWT cycle counter (which has a frequency of 400 MHz on the STM32H743 Evalboard). In principle the following implementation works fine - allthough the cycle counter register overflows after a couple of seconds.

Please make the following changes within your ewextrte.c file. First add some includes:

#include "stm32h7xx_hal.h"
#include "stm32h743i_eval.h"

Replace your EwGetPerfCounter implementation with the following code:

#ifdef EW_PRINT_PERF_COUNTERS

/* variables for cycle counter */
static unsigned long        PrevCycCnt   = 0;
static unsigned long        MicroSeconds = 0;
static unsigned long        Seconds      = 0;

/* helper function to initialize measuring unit (cycle counter) */
static void CycleCounterInit( void )
{
  /* Enable TRC */
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

  /* Unlock DWT registers */
  if ((*(uint32_t*)0xE0001FB4) & 1)
    *(uint32_t*)0xE0001FB0 = 0xC5ACCE55;

  /* clear the cycle counter */
  DWT->CYCCNT = 0;

  /* start the cycle counter */
  DWT->CTRL = 0x40000001;

  /* initialize counters */
  PrevCycCnt    = 0;
}

/* helper function to get cycle counter value since last call */
static unsigned long GetCycleCounterDelta( void )
{
  unsigned long cycCnt;
  unsigned long result;

  /* get delta between current counter value and last counter value */
  cycCnt = DWT->CYCCNT;
  result = cycCnt - PrevCycCnt;
  PrevCycCnt = cycCnt;

  return result;
}


/*******************************************************************************
* FUNCTION:
*   EwGetPerfCounter
*
* DESCRIPTION:
*   The function EwGetPerfCounter() should return the current time as number of
*   seconds and microseconds. The reference time point is nonrelevant.
*
* ARGUMENTS:
*   aSeconds         - Pointer to a variable where the current time is stored.
*   aMicroseconds    - Pointer to a variable where the current time is stored.
*   aCPUMicroseconds - Pointer to a variable where the real CPU usage is stored.
*
* RETURN VALUE:
*   None
*
*******************************************************************************/
void EwGetPerfCounter( unsigned long* aSeconds, unsigned long* aMicroSeconds,
  unsigned long* aCPUMicroseconds )
{
  static char initialized = 0;

  if ( !initialized )
  {
    CycleCounterInit();
    initialized = 1;
  }

  MicroSeconds += GetCycleCounterDelta() / 400; /* running with 400 MHz */

  if ( MicroSeconds > 1000000 )
  {
    MicroSeconds -= 1000000;
    Seconds++;
  }

  /* return seconds and milliseconds */
  *aSeconds      = Seconds;
  *aMicroSeconds = MicroSeconds;

  if ( aCPUMicroseconds )
    *aCPUMicroseconds = MicroSeconds;
}

#endif

Within ewmain.c you have to modify the main loop in order to reset and print the measurement results:

    if ( CoreRoot__DoesNeedUpdate( RootObject ))
    {
      EwResetPerfCounters();
      EwUpdate( Viewport, RootObject );
      EwPrintPerfCounters();
    }

Don't forget to define EW_PRINT_PERF_COUNTERS within your makefile and to rebuild the entire project (using source codes of GFX and RTE)!

Now you should get the expected performance measurements on your target...

I hope this helps.

Best regards,

Manfred

by

@Manfred: I correct following your guide and it works.

I have more question

I saw that the EWEndUpdate take so long time compared to others. I don't know why.

Is there any idea to explain it ?

 

by

Hi,

great to hear that it works!

EwEndUpdate() has to wait for the completion of the last DMA2D graphics operations and then it has to wait until the current framebuffer is shown (in case of double buffering).

You can switch off double buffering (set DOUBLE_BUFFER := 0 within your makefile) then you will see that EwEndUpdate() will consume more or less no runtime.

The waiting time for the next V-sync can be used by other tasks.

Anyhow, as you can see within the log, there are many time consuming warp operations used within your GUI application.

Best regards,

Manfred.

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...