55e8c52bf51440d4f54e4661160cabd3e811ac29
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 void empty_fn(void); /*for misra warnings*/
106 #ifdef __cplusplus
107 #pragma FUNC_CANNOT_INLINE
108 #else
109 #pragma FUNC_CANNOT_INLINE(empty_fn);
110 #endif
111 void empty_fn(void){
112 }
114 /*!
115 * @brief TI Toolchain Utils Entry Hook
116 *
117 * @ingroup pdk_profiling_hooks
118 *
119 * Instruments the entry point and timestamp of the current function into
120 * memory. Note that this function is automatically referenced at entry of
121 * every function by TI Toolchain.
122 *
123 * @param *func_addr Function Assembly Address (Hexadecimal)
124 */
125 void ti_utils_entry(void (* func_addr)(void)){
126 if (log_idx == 0){
127 uint32_t entry_offset = 0;
128 uint32_t exit_offset = 0;
129 log_idx++;
130 log_idx++;
131 int32_t i;
132 for (i = 0; i < 10; i++){
133 empty_fn();
134 }
135 elemlog[0].isEnter = 2;
136 elemlog[0].this_fn = 3;
137 elemlog[0].call_site = 1;
138 /*Taking 10 sample and subtracting (exit_log - entry log) of present for calculating the entry offset*/
139 for(i=1;i<=10;i++)
140 {
141 entry_offset += (elemlog[(2*i)+1].timestamp - elemlog[(2*i)].timestamp);
142 }
143 /* Saving the average of 10 sample */
144 elemlog[0].timestamp = entry_offset/10U;
145 elemlog[1].isEnter = 2;
146 elemlog[1].this_fn = 3;
147 elemlog[1].call_site = 2;
148 /* Taking 9 sample and subtracting (entry_log of next - exit_log of present) for calculating the exit offset*/
149 for(i=2;i<=10;i++)
150 {
151 exit_offset += (elemlog[(2*i)].timestamp - elemlog[(2*i)-1].timestamp);
152 }
153 /* Saving the average of 9 sample */
154 elemlog[1].timestamp = exit_offset/9U;
155 log_idx = 2U;
156 }
157 if (log_idx < MAX_LOG){
158 elemlog[log_idx].isEnter = 1;
159 elemlog[log_idx].this_fn = (int32_t)func_addr;
160 elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
161 log_idx++;
162 }
163 }
165 /*!
166 * @brief TI Toolchain Utils Exit Hook
167 *
168 * @ingroup pdk_profiling_hooks
169 *
170 * Instruments the exit point and timestamp of the current function into
171 * memory. Note that this function is automatically referenced at end of
172 * every function by TI Toolchain.
173 *
174 * @param *func_addr Function Assembly Address (Hexadecimal)
175 */
176 void ti_utils_exit(void (* func_addr)(void)){
177 if (log_idx < MAX_LOG){
178 elemlog[log_idx].isEnter = 0;
179 elemlog[log_idx].this_fn = (int32_t)func_addr;
180 elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
181 log_idx++;
182 }
183 }
185 void TaskRegisterId(int32_t hookSetId); /*for misra warnings*/
186 #ifdef __cplusplus
187 #pragma NO_HOOKS
188 #else
189 #pragma NO_HOOKS(TaskRegisterId);
190 #endif
191 void TaskRegisterId(int32_t hookSetId)
192 {
193 CurrentTaskHookSetId = hookSetId;
194 if(MaxTaskHookSetId < CurrentTaskHookSetId)
195 {
196 MaxTaskHookSetId = CurrentTaskHookSetId;
197 }
198 }
200 /* ======== mySwitch ========
201 * invoked whenever a Task switch occurs/is made ready to run */
202 void mySwitch(const void* prev, const void* next); /*for misra warnings*/
203 #ifdef __cplusplus
204 #pragma NO_HOOKS
205 #else
206 #pragma NO_HOOKS(mySwitch);
207 #endif
208 void mySwitch(const void* prev, const void* next)
209 {
210 if (log_idx < MAX_LOG){
211 elemlog[log_idx].isEnter = 3;
212 elemlog[log_idx].this_fn = (int32_t)next;
213 elemlog[log_idx].call_site = (int32_t)prev;
214 elemlog[log_idx].timestamp = CSL_armR5PmuReadCntr(CSL_ARM_R5_PMU_CYCLE_COUNTER_NUM);
215 log_idx++;
216 }
217 }