This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320C6678: Collect Profiling Statistics via DSS Scripting

Part Number: TMS320C6678

Background:

In addition to a test automation framework, I also want to implement a benchmark automation framework which collects profiling statistics. The most important profiling quantity is the number of CPU cycles a certain code snippet needed. However, other quantities such as cache misses would also be nice. A code snippet is defined via 2 breakpoint hits, namely, a breakpoint which defines the starting point and a breakpoint which defines the endpoint. This code snippet could be run several times, so that we create an array of a specific profiling quantity. At the end we derive some statistics (Average, median, max, min, ...) from this array. From my point of view, we can benchmark highly dynamic code snippets and account for changing circumstances over time.

Problem:

So far I have found out several ways to implement my approach. However, each approach comes along with one or several issues.

  • 1)  I could use a breakpoint of type "Count Event". This approach enables me to profile a bunch of events. However, as soon as the code snippet which is defined by the "Start Location" and "End Location" is run several times, I have no clue how to accumulate my profiling data in an array. My experience I've made so far says that the counts are accumulated. Well, this certainly prevents me of deriving statistics. I could imagine, that I could implement a GEL-File in combination with another breakpoint which is hit after my endpoint breakpoint. That would enable me to retrieve the current count value, but that sounds like smelling code.

  • 2) I could define 2 breakpoints of type "Breakpoint" in combination with an action "Execute Expression (GEL)". These breakpoints define my to be profiled code snippet. On each breakpoint hit, I read the TSCL value, which enables me to determine at least how much CPU cycles were needed for this code snippet. However, this approach comes along with 2 issues: I can only profile CPU cycles, my CPU count value does not equal the reference value of approach 1). The first issue is not a big deal, because the most import quantity is the number of CPU cycles. However, the great difference between this approach and the "Count Event" approach is certainly a problem, because I assume they must be in the same range. 

Questions:

  • 1) What would be the recommended way to implement a profiling algorithm which also supports statistics?

  • 2) If the "Count Event" approach is the way to go, is there any approach to add a feature to the breakpoint by using a GEL file which enables me to save the current counts on the fly as soon as the breakpoint is hit?

  • 3) If the other approach ("Breakpoint" in combination with an action "Execute Expression (GEL)") is the way to go, why is there a great difference in my measurements?

  • 1) What would be the recommended way to implement a profiling algorithm which also supports statistics?

    As of now, either we can use the ccs feature of profile clock :https://software-dl.ti.com/ccs/esd/documents/ccs_counting_cycles.html#profile-clock

    or

    Using source code and TSCL, measure the time : https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1117651/faq-tms320c6678-how-to-utilize-the-clock-ticks-to-measure-the-time-taken-for-the-code-execution/4142341#4142341

    Please refer this too:- TMS320C6678: DSP benchmarking for C66xx: Cycles profile - Processors forum - Processors - TI E2E support forums

    2) If the "Count Event" approach is the way to go, is there any approach to add a feature to the breakpoint by using a GEL file which enables me to save the current counts on the fly as soon as the breakpoint is hit?

    No such thing exists, as of today. 

    You are one trying to do. Good attempt. If successful, please share it to other customers too in e2e.

    3) If the other approach ("Breakpoint" in combination with an action "Execute Expression (GEL)") is the way to go, why is there a great difference in my measurements?

    You mean to say, the profile clock feature in ccs differ with the time measurement thorugh TSCL? 

    Regards

    Shankari G

  • Background:

    Yes, you are right, we could also use a debugSessions's profileClock in combination with a GEL-file. Well, I have also implemented this version. To do so, I again defined a start breakpoint and an end breakpoint. For each breakpoint, I define a gel-function as action. In these gel-functions I read out the CLK (Clock). The ccs manual states, that the target processor must be halted to read out CLK. However, if do so my results a screwed up. By screwed up, I mean, that the breakpoints are not hit as often as they should. My gel functions are defined in the following code snippet (Note: That I used the comments to show how my code looks like in both scenarios): 

    hitStart() {

    // GEL_Halt();
    // while(GEL_IsHalted() == 0){}

    CLK = 0;

    // GEL_Run();

    }

    hitEnd() {

    // GEL_Halt();
    // while(GEL_IsHalted() == 0){}

    countAvg = ((countAvg * counter) + CLK)/(counter + 1);
    if (countMax < CLK) countMax = CLK;
    if(countMin > CLK) countMin = CLK;

    counter++;

    // GEL_Run();

    }

    Yes, my measurements via the profile clock feature differ from my measurements via the TSCL register. The difference is huge, so we are not talking about a few cycles. As an experiment, I have measured some code which is executed in a nested for-loop. The start and end breakpoint are defined at the lines 3 and 7 respectively. I have not halted the target in this experiment: 

    0    volatile int k = 0;
    1    for(volatile int l = 0; l < 5; l++){
    2       for(volatile int i = 0; i < 100; i++){
    3           k += 1;
    4            k++;
    5            for(volatile int p = 0; p < 1000; p++){}
    6            k -=2;
    7            k++;
    8        }
    9    }
     
    I get the following results:
    • TSCL approach: Average=Min=Max = 19036
    • ProfileClock approach: Average=4775039, Min=19069, Max=9531141

    Since the code is not of dynamic nature, the TSCL approach's results make more sense to me.

    Questions:

    These results lead to some follow up questions:

    • Why are the results screwed up when halting the target?
    • Do I need to halt the target when reading the TSCL register (Haven't seen any reference which states so)?
    • Why there is this difference between my measurements?
  • Niklas,

    Let me do some experiments and compare the CCS- "Profile clock" and "TSCL-cycles" and get back.

    Prioritizing, other work , It may take 3 - 4 days .. to reply.

    Regards

    Shankari G

  • Alright, good to hear. Well, yesterday I also implemented some further experiments using the TSCL approach. For instance, I tried to reproduce the results of the benchmark "Post Software Interrupt with Context Switch" (https://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/bios/sysbios/6_83_00_18/exports/bios_6_83_00_18/packages/ti/sysbios/benchmarks/doc-files/TI_C66_ti_platforms_evm6678_time.html). I've got 130 cycles which almost equals the reference benchmark result. This result leads me to stick with the TSCL approach. Nevertheless, I am interested in the answers to my questions.

  • Niklas,

    I did an experiment using the TSCL and the CCS-profile clock.

    The CCS-profile clock doesnot work as expected.

    Measuring through TSCL is reliable and accurate.

    Regards

    Shankari G

  • Measuring through TSCL is reliable and accurate.

    Yes it is recommended to use TSCH/TSCL on C66x. 

    Since automation was mentioned, you can also use the DSS profile clock APIs to get cycle counts. Please note that this is different that using CLK (which is not recommended).

  • Yes, you are right, we could also use a debugSessions's profileClock in combination with a GEL-file

    yes the DSS profileClock should work fine. 

    • Yes, it seems like the time stamp counters (TSCL/TSCH) lead to reasonable results which match up with provided TI benchmark results.
    • How is the CLK different to the DSS profile clock? I read a Code Composer Studio manual which states "the profile clock counts processor instruction cycles or other events during run and single step operations when profiling. It is accessible via CLK and can also be used in GEL files." I thought the DSS profile clock javaScript class is just a neat API to access the same counter.
  • How is the CLK different to the DSS profile clock? I read a Code Composer Studio manual which states "the profile clock counts processor instruction cycles or other events during run and single step operations when profiling. It is accessible via CLK and can also be used in GEL files."

    The issue is that CLK can vary depending on device and the CLK and the CCS profile clock can vary in regards to what counter is used. What DSS uses for the profile clock can also vary depending on the device. I believe DSS will use the CCS profile clock. But what counter is used to get the value of the CCS profile clock.

    On C6678, I can't recall if CLK maps to a 32-bit counter on the emulation logic for the CPU/device or if maps to the TSCL counter. I will defer to the device experts on this (Shankari?). In any case, the limitation of using CLK is that it is a 32-bit variable that can overflow pretty often on that device. I think the CCS profile clock maps to TSCL and TSCH to have a 64-bit counter. 

    In any case, I believe most users use TSCL and TSCH directly to be sure.

  • Niklas,

    If you attempt to use directly, use something like below.

    As this is a c code. Please change it as a DSS scripting code....

    --

    // For 32 bit, just use the TSCL.

    /*****************************************************************************
    * Function: Utility function for a cycle clock
    ****************************************************************************/
    //shankari
    extern cregister volatile unsigned int TSCL;

    uint32_t utilReadTime32()
    {
    uint32_t timeVal;
    timeVal = TSCL;
    return timeVal;
    }

    [or]

    // For 64 bit, you can use both TSCH and TSCL

    /*****************************************************************************
    * Read TSCL+TSCH
    ****************************************************************************/
    static inline uint64_t ReadTime ()
    {

    uint32_t low = TSCL;
    uint32_t high = TSCH;
    return _itoll(high,low);

    }

    ( I have exclusively created an FAQ on how to use the TSCL. Please have a look:- https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1117651/faq-tms320c6678-how-to-utilize-the-clock-ticks-to-measure-the-time-taken-for-the-code-execution/4142341#4142341

    Regards

    Shankari G

    • Right now, I am using the TSCL and TSCH. However, I am using these counters in functions within a self-written GEL file. These functions are invoked when breakpoints are hit. And after reading your answers, I will stick with this approach.
    • As a summary (To avoid this thread getting bloated): In my opinion, using the TSCL/TSCH registers is the most reliable way to measure performance of your code as you can be sure that you are using the correct counters. There seem to be too many questions (Which counter do we use?, Do we have to invoke other Gel-functions when reading the counter?, ...) in this regard when using the DSS APIs (CLK,  profile clock javaScript class). However, as soon as you want to measure other metrics such as memory accesses, you may want to use the DSS API. However, I haven't implemented anything in this regard. So I can't say anything useful to this.