Skip to content

Commit b45e855

Browse files
Cleanup continues
1 parent b0083a2 commit b45e855

File tree

1 file changed

+118
-113
lines changed

1 file changed

+118
-113
lines changed

cores/rp2040/gprof_gmon.c

Lines changed: 118 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ struct tostruct {
143143
*/
144144
struct 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. */
210214
static 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-
284271
static void moncontrol(int mode);
285272

286-
int __profileMemSize = 0;
287273

288274
void __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
423349
void __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

547473
void __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

Comments
 (0)