utils: add to PDK
[processor-sdk/pdk.git] / packages / ti / utils / profiling / src / profilingHooksR5.c
1 /*
2  * Copyright (c) 2018-2019, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /**
33  *  @file    profilingHooksR5.c
34  *
35  *  @brief   R5 Implementations of the runtime programming hooks of the Processor SDK Profiling Tool.
36  *
37  *  For more information, see:
38  *  - @subpage profCCS
39  *  - @subpage profDSS
40  *
41  *  ## Usage ##
42  *
43  *  Applications that are included in a profiling session must  set these
44  *  compiler flags for the desired platform:
45  *    - ARM: `-finstrument-functions -gdwarf-3 -g`
46  *    - DSP: `--entry_parm=address --exit_hook=ti_utils_exit --exit_parm=address --entry_hook=ti_utils_entry -g`
47  *    - M4: `--entry_parm=address --exit_hook=ti_utils_exit --exit_parm=address --entry_hook=ti_utils_entry -g`
48  *
49  *  The `_ENABLE_BM` flag is used to indicate in a class at compiletime whether
50  *  or not profiling is being used.
51  *
52  *  For best results, ensure that the optimization levels are consistent between
53  *  the library and the project (typically -O3, or optimization level 3).
54  *
55  */
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <stdint.h>
60 #include "profilingHooks.h"
61 #include <ti/csl/arch/r5/csl_arm_r5_pmu.h>
63 int32_t CurrentTaskHookSetId, MaxTaskHookSetId;
65 /*!
66  *  @brief    Maximum log count
67  *
68  *  This is a predefined value to indicate when the instrumentation hooks should
69  *  stop logging data. This is important for applications that have long polling
70  *  loops or a device that has a small cache.
71  */
72 #define MAX_LOG (1U*1024U*1024U)
74 uint32_t log_idx = 0;
75 uint32_t lvl = 0;
77 /*!
78  *  @brief    Utils profiling log structure
79  *
80  *  Utils log elements have a predefined structure of four words (to avoid the
81  *  need of malloc) and are stored in an array of predefined length, `elemlog`.
82  */
83 typedef struct{
84     /*! Indicates either enter or exit */
85     int32_t isEnter;
86     /*! Pointer address of the function in current context */
87     int32_t this_fn;
88     /*! Optional: Pointer address of calling function in current context */
89     int32_t call_site;
90     /*! Timestamp of the entry or exit */
91     uint32_t timestamp;
92 }utilsProfilingElem;
94 utilsProfilingElem elemlog[MAX_LOG] = {{0}};
96 /*!
97  *  @brief    Empty function for time adjustment
98  *
99  *  @ingroup pdk_profiling_hooks
100  *
101  *  Nothing more than an empty function that is referenced to measure the time
102  *  used by the instrumentation functions themselves. This is recorded and
103  *  passed into post-processing for a more accurate result.
104  */
105 #pragma FUNC_CANNOT_INLINE(empty_fn);
106 void empty_fn(void); /*for misra warnings*/
107 void empty_fn(void){
110 /*!
111  *  @brief    TI Toolchain Utils Entry Hook
112  *
113  *  @ingroup pdk_profiling_hooks
114  *
115  *  Instruments the entry point and timestamp of the current function into
116  *  memory. Note that this function is automatically referenced at entry of
117  *  every function by TI Toolchain.
118  *
119  *  @param    *func_addr  Function Assembly Address (Hexadecimal)
120  */
121 void ti_utils_entry(void (* func_addr)(void)){
122     if (log_idx == 0){
123         uint32_t entry_offset = 0;
124         uint32_t exit_offset = 0;
125         log_idx++;
126         log_idx++;
127         int32_t i;
128         for (i = 0; i < 10; i++){
129             empty_fn();
130         }
131         elemlog[0].isEnter = 2;
132         elemlog[0].this_fn = 3;
133         elemlog[0].call_site = 1;
134         /*Taking 10 sample and subtracting (exit_log - entry log) of present for calculating the entry offset*/
135         for(i=1;i<=10;i++)
136         {
137             entry_offset += (elemlog[(2*i)+1].timestamp - elemlog[(2*i)].timestamp);
138         }
139         /* Saving the average of 10 sample */
140         elemlog[0].timestamp = entry_offset/10U;
141         elemlog[1].isEnter = 2;
142         elemlog[1].this_fn = 3;
143         elemlog[1].call_site = 2;
144         /* Taking 9 sample and subtracting (entry_log of next - exit_log of present) for calculating the exit offset*/
145         for(i=2;i<=10;i++)
146         {
147             exit_offset += (elemlog[(2*i)].timestamp - elemlog[(2*i)-1].timestamp);
148         }
149         /* Saving the average of 9 sample */
150         elemlog[1].timestamp = exit_offset/9U;
151         log_idx = 2U;
152     }
153     if (log_idx < MAX_LOG){
154         elemlog[log_idx].isEnter = 1;
155         elemlog[log_idx].this_fn = (int32_t)func_addr;
156         elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
157       log_idx++;
158     }
161 /*!
162  *  @brief    TI Toolchain Utils Exit Hook
163  *
164  *  @ingroup pdk_profiling_hooks
165  *
166  *  Instruments the exit point and timestamp of the current function into
167  *  memory. Note that this function is automatically referenced at end of
168  *  every function by TI Toolchain.
169  *
170  *  @param    *func_addr  Function Assembly Address (Hexadecimal)
171  */
172 void ti_utils_exit(void (* func_addr)(void)){
173     if (log_idx < MAX_LOG){
174         elemlog[log_idx].isEnter = 0;
175         elemlog[log_idx].this_fn = (int32_t)func_addr;
176         elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
177         log_idx++;
178     }
181 #pragma NO_HOOKS (TaskRegisterId)
182 void TaskRegisterId(int32_t hookSetId); /*for misra warnings*/
183 void TaskRegisterId(int32_t hookSetId)
185         CurrentTaskHookSetId = hookSetId;
186     if(MaxTaskHookSetId < CurrentTaskHookSetId)
187     {
188         MaxTaskHookSetId = CurrentTaskHookSetId;
189     }
192 /* ======== mySwitch ========
193 * invoked whenever a Task switch occurs/is made ready to run */
194 #pragma NO_HOOKS (mySwitch)
195 void mySwitch(const void* prev, const void* next); /*for misra warnings*/
196 void mySwitch(const void* prev, const void* next)
198     if (log_idx < MAX_LOG){
199         elemlog[log_idx].isEnter = 3;
200         elemlog[log_idx].this_fn = (int32_t)next;
201         elemlog[log_idx].call_site = (int32_t)prev;
202         elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
203         log_idx++;
204     }