1 /*
2 * Copyright (c) 2018, 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 profilingHooksA15.c
34 *
35 * @brief ARM 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 * For best results, ensure that the optimization levels are consistent between
50 * the library and the project (typically -O3, or optimization level 3).
51 *
52 */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <stdint.h>
57 #include "profilingHooks.h"
58 #include "profiling_osal.h"
61 int32_t CurrentTaskHookSetId, MaxTaskHookSetId;
63 /*!
64 * @brief Maximum log count
65 *
66 * This is a predefined value to indicate when the instrumentation hooks should
67 * stop logging data. This is important for applications that have long polling
68 * loops or a device that has a small cache.
69 */
70 #define MAX_LOG (1U*1024U*1024U)
72 uint32_t log_idx = 0;
74 /*!
75 * @brief Utils profiling log structure
76 *
77 * Utils log elements have a predefined structure of four words (to avoid the
78 * need of malloc) and are stored in an array of predefined length, `elemlog`.
79 */
80 typedef struct{
81 /*! Indicates either enter or exit */
82 int32_t isEnter;
83 /*! Pointer address of the function in current context */
84 uintptr_t this_fn;
85 /*! Optional: Pointer address of calling function in current context */
86 uintptr_t call_site;
87 /*! Timestamp of the entry or exit */
88 uint32_t timestamp;
89 }utilsProfilingElem;
91 utilsProfilingElem elemlog[MAX_LOG] = {{0}};
93 /*!
94 * @brief Empty function for time adjustment
95 *
96 * @ingroup pdk_profiling_hooks
97 *
98 * Nothing more than an empty function that is referenced to measure the time
99 * used by the instrumentation functions themselves. This is recorded and
100 * passed into post-processing for a more accurate result.
101 */
102 void __attribute__ ((noinline)) empty_fn(void); /*for misra warnings*/
103 void __attribute__ ((noinline)) empty_fn(void){
104 }
106 /*!
107 * @brief ARMv7 GCC Utils Entry Hook
108 *
109 * @ingroup pdk_profiling_hooks
110 *
111 * Instruments the entry point, call site and timestamp of the current function
112 * into memory. Note that this is a standard GCC library prototype function and
113 * is automatically referenced at the entry of every function by GCC.
114 *
115 * @param *this_fn Function Assembly Address (Hexadecimal)
116 * @param *call_site Call Site Assembly Address (Hexadecimal)
117 *
118 * TODO: The Hardware Interrupt Disable functions are disabled because there
119 * are still issues with OSAL that need to be resolved. Using these
120 * functions causes memory corruption.
121 */
122 void __attribute__((no_instrument_function))__cyg_profile_func_enter(const void *this_fn, const void *call_site){
123 uint32_t val;
125 asm volatile("mrs %0, pmccntr_el0" : "=r" (val));
127 if (log_idx == 0){
128 uint32_t entry_offset = 0;
129 uint32_t exit_offset = 0;
130 log_idx++;
131 log_idx++;
132 int32_t i;
133 for (i = 0; i < 10; i++){
134 empty_fn();
135 }
136 elemlog[0].isEnter = 2;
137 elemlog[0].this_fn = 1;
138 elemlog[0].call_site = 1;
139 /*Taking 10 sample and subtracting (exit_log - entry log) of present for calculating the entry offset*/
140 for(i=1;i<=10;i++)
141 {
142 entry_offset += (elemlog[(2*i)+1].timestamp - elemlog[(2*i)].timestamp);
143 }
144 /* Saving the average of 10 sample */
145 elemlog[0].timestamp = entry_offset/10U;
146 elemlog[1].isEnter = 2;
147 elemlog[1].this_fn = 1;
148 elemlog[1].call_site = 2;
149 /* Taking 9 sample and subtracting (entry_log of next - exit_log of present) for calculating the exit offset*/
150 for(i=2;i<=10;i++)
151 {
152 exit_offset += (elemlog[(2*i)].timestamp - elemlog[(2*i)-1].timestamp);
153 }
154 /* Saving the average of 9 sample */
155 elemlog[1].timestamp = exit_offset/9U;
156 log_idx = 2U;
157 }
158 if (log_idx < MAX_LOG){
159 elemlog[log_idx].isEnter = 1;
160 elemlog[log_idx].this_fn = (uintptr_t)this_fn;
161 elemlog[log_idx].call_site = (uintptr_t)call_site;
162 elemlog[log_idx].timestamp = (int32_t)val;
163 log_idx++;
164 }
165 }
167 /*!
168 * @brief ARMv7 GCC Utils Exit Hook
169 *
170 * @ingroup pdk_profiling_hooks
171 *
172 * Instruments the entry point, call site and timestamp of the current function
173 * into memory. Note that this is a standard GCC library prototype function and
174 * is automatically referenced at the entry of every function by GCC.
175 *
176 * @param *this_fn Function Assembly Address (Hexadecimal)
177 * @param *call_site Call Site Assembly Address (Hexadecimal)
178 *
179 * TODO: The Hardware Interrupt Disable functions are disabled because there
180 * are still issues with OSAL that need to be resolved. Using these
181 * functions causes memory corruption.
182 */
183 void __attribute__((no_instrument_function))__cyg_profile_func_exit(const void *this_fn, void *call_site){
184 uint32_t val;
186 asm volatile("mrs %0, pmccntr_el0" : "=r" (val));
188 if (log_idx < MAX_LOG){
189 elemlog[log_idx].isEnter = 0;
190 elemlog[log_idx].this_fn = (uintptr_t)this_fn;
191 elemlog[log_idx].timestamp = (int32_t)val;
192 log_idx++;
193 }
194 }
195 void __attribute__((no_instrument_function))TaskRegisterId(int32_t hookSetId); /*for misra warnings*/
196 void __attribute__((no_instrument_function))TaskRegisterId(int32_t hookSetId)
197 {
198 CurrentTaskHookSetId = hookSetId;
199 if(MaxTaskHookSetId < CurrentTaskHookSetId)
200 {
201 MaxTaskHookSetId = CurrentTaskHookSetId;
202 }
203 }
205 /* ======== mySwitch ========
206 * invoked whenever a Task switch occurs/is made ready to run */
207 void __attribute__((no_instrument_function))mySwitch(const void* prev, const void* next); /*for misra warnings*/
208 void __attribute__((no_instrument_function))mySwitch(const void* prev, const void* next)
209 {
210 uint32_t val;
213 asm volatile("mrs %0, pmccntr_el0" : "=r" (val));
215 if (log_idx < MAX_LOG){
216 elemlog[log_idx].isEnter = 3;
217 elemlog[log_idx].this_fn = (uintptr_t)next;
218 elemlog[log_idx].call_site = (uintptr_t)prev;
219 elemlog[log_idx].timestamp = (int32_t)val;
220 log_idx++;
221 }
222 }