@@ -143,9 +143,9 @@ struct tostruct {
143143*/
144144struct gmonparam {
145145 int state ;
146- uint16_t * kcount ; /* histogram PC sample array */
146+ uint16_t * kcount ; /* histogram PC sample array */
147147 size_t kcountsize ; /* size of kcount[] array in bytes */
148- uint16_t * froms ; /* array of hashed 'from' addresses. The 16bit value is an index into the tos[] array */
148+ uint16_t * froms ; /* array of hashed 'from' addresses. The 16bit value is an index into the tos[] array */
149149 size_t fromssize ; /* size of froms[] array in bytes */
150150 struct tostruct * tos ; /* to struct, contains histogram counter */
151151 size_t tossize ; /* size of tos[] array in bytes */
@@ -174,37 +174,41 @@ static struct profinfo prof = {
174174 PROFILE_NOT_INIT , 0 , 0 , 0 , 0
175175};
176176
177- /* convert an addr to an index */
178- #define PROFIDX ( pc , base , scale ) \
179- ({ \
180- size_t i = (pc - base) / 2; \
181- if (sizeof (unsigned long long int) > sizeof (size_t)) \
182- i = (unsigned long long int) i * scale / 65536; \
183- else \
184- i = i / 65536 * scale + i % 65536 * scale / 65536; \
185- i; \
186- })
187-
188- /* convert an index into an address */
189- #define PROFADDR ( idx , base , scale ) \
190- ((base) \
191- + ((((unsigned long long)(idx) << 16) \
192- / (unsigned long long)(scale)) << 1))
193-
177+ static struct gmonparam _gmonparam = { GMON_PROF_OFF , NULL , 0 , NULL , 0 , NULL , 0 , 0L , 0 , 0 , 0 };
178+ static bool already_setup = false; /* flag to indicate if we need to init */
179+ static bool _perf_in_setup = false; // Are we currently trying to initialize? (avoid infinite recursion)
180+ static int s_scale = 0 ;
181+ #define SCALE_1_TO_1 0x10000L
182+ int __profileMemSize = 0 ; // Memory allocated by the profiler to store tables
183+
184+
185+ // Convert an addr to an index
186+ static inline size_t profidx ( size_t pc , size_t base , size_t scale ) {
187+ size_t i = ( pc - base ) / 2 ;
188+ if ( sizeof ( unsigned long long int ) > sizeof ( size_t )) {
189+ return ( unsigned long long int ) i * scale / 65536 ;
190+ } else {
191+ return i / 65536 * scale + i % 65536 * scale / 65536 ;
192+ }
193+ }
194194
195195/* Sample the current program counter */
196- void __no_inline_not_in_flash_func (_SystickHandler )(void ) {
196+ #if defined(__riscv )
197+ // TODO - systick-like handler
198+ #else
199+ static void __no_inline_not_in_flash_func (_SystickHandler )(void ) {
197200 static size_t pc , idx ; // Ensure in heap, not on stack
198201 extern volatile bool __otherCoreIdled ;
199202
200203 if (!__otherCoreIdled && (prof .state == PROFILE_ON )) {
201204 pc = ((uint32_t * )(__builtin_frame_address (0 )))[14 ]; /* get SP and use it to get the return address from stack */
202205 if ((pc >= prof .lowpc ) && (pc < prof .highpc )) {
203- idx = PROFIDX (pc , prof .lowpc , prof .scale );
206+ idx = profidx (pc , prof .lowpc , prof .scale );
204207 prof .counter [idx ]++ ;
205208 }
206209 }
207210}
211+ #endif
208212
209213/* Stop profiling to the profiling buffer pointed to by p. */
210214static int __no_inline_not_in_flash_func (profile_off )(struct profinfo * p ) {
@@ -218,6 +222,11 @@ static int __no_inline_not_in_flash_func(profile_on)(struct profinfo *p) {
218222 return 0 ; /* ok */
219223}
220224
225+ // Convert an index into an address
226+ static inline size_t profaddr (size_t idx , size_t base , size_t scale ) {
227+ return base + ((((unsigned long long )(idx ) << 16 ) / (unsigned long long )(scale )) << 1 );
228+ }
229+
221230/*
222231 start or stop profiling
223232
@@ -230,7 +239,7 @@ static int __no_inline_not_in_flash_func(profile_on)(struct profinfo *p) {
230239 a scale of 1 maps each bin to 128k address). Scale may be 1 - 65536,
231240 or zero to turn off profiling
232241*/
233- int __no_inline_not_in_flash_func (profile_ctl )(struct profinfo * p , char * samples , size_t size , size_t offset , uint32_t scale ) {
242+ static int __no_inline_not_in_flash_func (profile_ctl )(struct profinfo * p , char * samples , size_t size , size_t offset , uint32_t scale ) {
234243 size_t maxbin ;
235244
236245 if (scale > 65536 ) {
@@ -243,7 +252,7 @@ int __no_inline_not_in_flash_func(profile_ctl)(struct profinfo *p, char *samples
243252 maxbin = size >> 1 ;
244253 prof .counter = (uint16_t * )samples ;
245254 prof .lowpc = offset ;
246- prof .highpc = PROFADDR (maxbin , offset , scale );
255+ prof .highpc = profaddr (maxbin , offset , scale );
247256 prof .scale = scale ;
248257 return profile_on (p );
249258 }
@@ -254,36 +263,13 @@ int __no_inline_not_in_flash_func(profile_ctl)(struct profinfo *p, char *samples
254263 Every SLEEPTIME interval, the user's program counter (PC) is examined:
255264 offset is subtracted and the result is multiplied by scale.
256265 The word pointed to by this address is incremented. */
257- int __no_inline_not_in_flash_func (profil )(char * samples , size_t size , size_t offset , uint32_t scale ) {
266+ static int __no_inline_not_in_flash_func (profil )(char * samples , size_t size , size_t offset , uint32_t scale ) {
258267 return profile_ctl (& prof , samples , size , offset , scale );
259268}
260269
261270
262- // These are referenced by RP2040Support.cpp and called by the runtime init SDK
263- #if defined(__riscv )
264- void runtime_init_setup_profiling () {
265- // TODO - is there an equivalent? Or do we need to build a timer IRQ here?
266- }
267- #else
268- #include <hardware/exception.h>
269- #include <hardware/structs/systick.h>
270- void runtime_init_setup_profiling () {
271- exception_set_exclusive_handler (SYSTICK_EXCEPTION , _SystickHandler );
272- systick_hw -> csr = 0x7 ;
273- systick_hw -> rvr = (F_CPU / GMON_HZ ) - 1 ;
274- }
275- #endif
276-
277-
278- static struct gmonparam _gmonparam = { GMON_PROF_OFF , NULL , 0 , NULL , 0 , NULL , 0 , 0L , 0 , 0 , 0 };
279- static char already_setup = 0 ; /* flag to indicate if we need to init */
280- static int s_scale ;
281- /* see profil(2) where this is described (incorrectly) */
282- #define SCALE_1_TO_1 0x10000L
283-
284271static void moncontrol (int mode );
285272
286- int __profileMemSize = 0 ;
287273
288274void __no_inline_not_in_flash_func (monstartup )(size_t lowpc , size_t highpc ) {
289275 register size_t o ;
@@ -314,7 +300,7 @@ void __no_inline_not_in_flash_func(monstartup)(size_t lowpc, size_t highpc) {
314300#endif
315301 if (cp == NULL ) {
316302 // OOM
317- already_setup = 0 ;
303+ already_setup = false ;
318304 return ;
319305 }
320306
@@ -339,68 +325,6 @@ void __no_inline_not_in_flash_func(monstartup)(size_t lowpc, size_t highpc) {
339325}
340326
341327
342- typedef int (* profileWriteCB )(const void * data , int len );
343- void _writeProfile (profileWriteCB writeCB ) {
344- struct gmonhdr { // GMON.OUT header
345- size_t lpc ; /* base pc address of sample buffer */
346- size_t hpc ; /* max pc address of sampled buffer */
347- int ncnt ; /* size of sample buffer (plus this header) */
348- int version ; /* version number */
349- int profrate ; /* profiling clock rate */
350- int spare [3 ]; /* reserved */
351- };
352- const unsigned int GMONVERSION = 0x00051879 ;
353- struct rawarc { // Per-arc on-disk data format
354- size_t raw_frompc ;
355- size_t raw_selfpc ;
356- long raw_count ;
357- };
358- int fromindex ;
359- int endfrom ;
360- size_t frompc ;
361- int toindex ;
362- struct rawarc rawarc ;
363- const int BS = 64 ;
364- struct rawarc rawarcbuff [BS ];
365- int rawarcbuffptr = 0 ;
366- struct gmonparam * p = & _gmonparam ;
367- struct gmonhdr gmonhdr , * hdr ;
368-
369- moncontrol (0 ); /* stop */
370-
371- hdr = (struct gmonhdr * )& gmonhdr ;
372- hdr -> lpc = p -> lowpc ;
373- hdr -> hpc = p -> highpc ;
374- hdr -> ncnt = p -> kcountsize + sizeof (gmonhdr );
375- hdr -> version = GMONVERSION ;
376- hdr -> profrate = GMON_HZ ;
377- writeCB ((void * )hdr , sizeof * hdr );
378- writeCB ((void * )p -> kcount , p -> kcountsize );
379- endfrom = p -> fromssize / sizeof (* p -> froms );
380- for (fromindex = 0 ; fromindex < endfrom ; fromindex ++ ) {
381- if (p -> froms [fromindex ] == 0 ) {
382- continue ;
383- }
384- frompc = p -> lowpc ;
385- frompc += fromindex * HASHFRACTION * sizeof (* p -> froms );
386- for (toindex = p -> froms [fromindex ]; toindex != 0 ; toindex = p -> tos [toindex ].link ) {
387- rawarc .raw_frompc = frompc ;
388- rawarc .raw_selfpc = GETSELFPC (& p -> tos [toindex ]);
389- rawarc .raw_count = GETCOUNT (& p -> tos [toindex ]);
390- // Buffer up writes because Semihosting is really slow per write call
391- rawarcbuff [rawarcbuffptr ++ ] = rawarc ;
392- if (rawarcbuffptr == BS ) {
393- writeCB ((void * )rawarcbuff , BS * sizeof (struct rawarc ));
394- rawarcbuffptr = 0 ;
395- }
396- }
397- }
398- // Write any remaining bits
399- if (rawarcbuffptr ) {
400- writeCB ((void * )rawarcbuff , rawarcbuffptr * sizeof (struct rawarc ));
401- }
402- }
403-
404328/*
405329 Control profiling
406330 profiling is what mcount checks to see if
@@ -419,7 +343,9 @@ static void __no_inline_not_in_flash_func(moncontrol)(int mode) {
419343 p -> state = GMON_PROF_OFF ;
420344 }
421345}
422- static bool _perf_in_setup = false;
346+
347+
348+ // Called by the GCC function shim (gprof_shim.S) on function entry to record an arc hit
423349void __no_inline_not_in_flash_func (_mcount_internal )(uint32_t * frompcindex , uint32_t * selfpc ) {
424350 register struct tostruct * top ;
425351 register struct tostruct * prevtop ;
@@ -434,7 +360,7 @@ void __no_inline_not_in_flash_func(_mcount_internal)(uint32_t *frompcindex, uint
434360 if (!already_setup ) {
435361 extern char __flash_binary_start ; // Start of flash
436362 extern char __etext ; /* end of text/code symbol, defined by linker */
437- already_setup = 1 ;
363+ already_setup = true ;
438364 _perf_in_setup = true;
439365 monstartup ((uint32_t )& __flash_binary_start , (uint32_t )& __etext );
440366 _perf_in_setup = false;
@@ -546,5 +472,84 @@ void __no_inline_not_in_flash_func(_mcount_internal)(uint32_t *frompcindex, uint
546472
547473void __no_inline_not_in_flash_func (_monInit )(void ) {
548474 _gmonparam .state = GMON_PROF_OFF ;
549- already_setup = 0 ;
475+ already_setup = false;
476+ }
477+
478+
479+ // Write out the GMON.OUT file using internal state
480+ void _writeProfile (int (* writeCB )(const void * data , int len )) {
481+ struct gmonhdr { // GMON.OUT header
482+ size_t lpc ; // base pc address of sample buffer
483+ size_t hpc ; // max pc address of sampled buffer
484+ int ncnt ; // size of sample buffer (plus this header)
485+ int version ; // version number
486+ int profrate ; // profiling clock rate
487+ int spare [3 ]; // reserved
488+ };
489+ const unsigned int GMONVERSION = 0x00051879 ;
490+ struct rawarc { // Per-arc on-disk data format
491+ size_t raw_frompc ;
492+ size_t raw_selfpc ;
493+ long raw_count ;
494+ };
495+ int fromindex ;
496+ int endfrom ;
497+ size_t frompc ;
498+ int toindex ;
499+ struct rawarc rawarc ;
500+ const int BS = 64 ;
501+ struct rawarc rawarcbuff [BS ];
502+ int rawarcbuffptr = 0 ;
503+ struct gmonparam * p = & _gmonparam ;
504+ struct gmonhdr hdr ;
505+
506+ moncontrol (0 ); // Stop
507+
508+ hdr .lpc = p -> lowpc ;
509+ hdr .hpc = p -> highpc ;
510+ hdr .ncnt = p -> kcountsize + sizeof (hdr );
511+ hdr .version = GMONVERSION ;
512+ hdr .profrate = GMON_HZ ;
513+ writeCB ((void * )& hdr , sizeof (hdr ));
514+ writeCB ((void * )p -> kcount , p -> kcountsize );
515+ endfrom = p -> fromssize / sizeof (* p -> froms );
516+ for (fromindex = 0 ; fromindex < endfrom ; fromindex ++ ) {
517+ if (p -> froms [fromindex ] == 0 ) {
518+ continue ;
519+ }
520+ frompc = p -> lowpc ;
521+ frompc += fromindex * HASHFRACTION * sizeof (* p -> froms );
522+ for (toindex = p -> froms [fromindex ]; toindex != 0 ; toindex = p -> tos [toindex ].link ) {
523+ rawarc .raw_frompc = frompc ;
524+ rawarc .raw_selfpc = GETSELFPC (& p -> tos [toindex ]);
525+ rawarc .raw_count = GETCOUNT (& p -> tos [toindex ]);
526+ // Buffer up writes because Semihosting is really slow per write call
527+ rawarcbuff [rawarcbuffptr ++ ] = rawarc ;
528+ if (rawarcbuffptr == BS ) {
529+ writeCB ((void * )rawarcbuff , BS * sizeof (struct rawarc ));
530+ rawarcbuffptr = 0 ;
531+ }
532+ }
533+ }
534+ // Write any remaining bits
535+ if (rawarcbuffptr ) {
536+ writeCB ((void * )rawarcbuff , rawarcbuffptr * sizeof (struct rawarc ));
537+ }
550538}
539+
540+
541+ // These are referenced by RP2040Support.cpp and called by the runtime init SDK
542+ // Install a periodic PC sampler at the specified frequency
543+ #if defined(__riscv )
544+ void runtime_init_setup_profiling () {
545+ // TODO - is there an equivalent? Or do we need to build a timer IRQ here?
546+ }
547+ #else
548+ #include <hardware/exception.h>
549+ #include <hardware/structs/systick.h>
550+ void runtime_init_setup_profiling () {
551+ exception_set_exclusive_handler (SYSTICK_EXCEPTION , _SystickHandler );
552+ systick_hw -> csr = 0x7 ;
553+ systick_hw -> rvr = (F_CPU / GMON_HZ ) - 1 ;
554+ }
555+ #endif
0 commit comments