From 9cec66f9200cb573353928bd3292fb1f710e4b3c Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Thu, 4 May 2017 15:23:10 -0400 Subject: Copy profiling code from MCUOnEclipse. --- libraries/libprof/profil.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 libraries/libprof/profil.c (limited to 'libraries/libprof/profil.c') diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c new file mode 100644 index 0000000..24ede21 --- /dev/null +++ b/libraries/libprof/profil.c @@ -0,0 +1,94 @@ +/* profil.c -- win32 profil.c equivalent + + Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +/* + * This file is taken from Cygwin distribution, adopted to be used for bare embeeded targets. + */ +#include +#include +#include +#include +#include "profil.h" +#include +#include + +/* global profinfo for profil() call */ +static struct profinfo prof = { + PROFILE_NOT_INIT, 0, 0, 0, 0 +}; + +/* sample the current program counter */ +void SysTick_Handler(void) { + void OSA_SysTick_Handler(void); + static size_t pc, idx; + + OSA_SysTick_Handler(); /* call normal Kinetis SDK SysTick handler */ + if (prof.state==PROFILE_ON) { + pc = ((uint32_t*)(__builtin_frame_address(0)))[14]; /* get SP and use it to get the return address from stack */ + if (pc >= prof.lowpc && pc < prof.highpc) { + idx = PROFIDX (pc, prof.lowpc, prof.scale); + prof.counter[idx]++; + } + } +} + +/* Stop profiling to the profiling buffer pointed to by p. */ +static int profile_off (struct profinfo *p) { + p->state = PROFILE_OFF; + return 0; +} + +/* Create a timer thread and pass it a pointer P to the profiling buffer. */ +static int profile_on (struct profinfo *p) { + p->state = PROFILE_ON; + return 0; /* ok */ +} + +/* + * start or stop profiling + * + * profiling goes into the SAMPLES buffer of size SIZE (which is treated + * as an array of u_shorts of size size/2) + * + * each bin represents a range of pc addresses from OFFSET. The number + * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps + * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses, + * a scale of 1 maps each bin to 128k address). Scale may be 1 - 65536, + * or zero to turn off profiling + */ +int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, u_int scale) { + size_t maxbin; + + if (scale > 65536) { + errno = EINVAL; + return -1; + } + profile_off(p); + if (scale) { + memset(samples, 0, size); + memset(p, 0, sizeof *p); + maxbin = size >> 1; + prof.counter = (u_short*)samples; + prof.lowpc = offset; + prof.highpc = PROFADDR(maxbin, offset, scale); + prof.scale = scale; + return profile_on(p); + } + return 0; +} + +/* Equivalent to unix profil() + Every SLEEPTIME interval, the user's program counter (PC) is examined: + offset is subtracted and the result is multiplied by scale. + The word pointed to by this address is incremented. */ +int profil (char *samples, size_t size, size_t offset, u_int scale) { + return profile_ctl (&prof, samples, size, offset, scale); +} + -- cgit v1.2.3 From 1815f1b2aa0a3ff0654f4eb65fdd0a5bdfe8c7b7 Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Fri, 5 May 2017 22:58:34 -0400 Subject: Port profiling code, using a new SysTick hook and new CLI commands. --- libraries/libprof/profil.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'libraries/libprof/profil.c') diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c index 24ede21..07761dd 100644 --- a/libraries/libprof/profil.c +++ b/libraries/libprof/profil.c @@ -9,7 +9,7 @@ details. */ /* - * This file is taken from Cygwin distribution, adopted to be used for bare embeeded targets. + * This file is taken from Cygwin distribution, adapted to be used for bare embedded targets. */ #include #include @@ -19,34 +19,34 @@ #include #include +#include "stm32f4xx_hal.h" /* __get_MSP */ + /* global profinfo for profil() call */ static struct profinfo prof = { PROFILE_NOT_INIT, 0, 0, 0, 0 }; -/* sample the current program counter */ -void SysTick_Handler(void) { - void OSA_SysTick_Handler(void); - static size_t pc, idx; +extern void set_SysTick_hook(void (*hook)(void)); - OSA_SysTick_Handler(); /* call normal Kinetis SDK SysTick handler */ - if (prof.state==PROFILE_ON) { - pc = ((uint32_t*)(__builtin_frame_address(0)))[14]; /* get SP and use it to get the return address from stack */ - if (pc >= prof.lowpc && pc < prof.highpc) { - idx = PROFIDX (pc, prof.lowpc, prof.scale); +/* sample the current program counter */ +static void SysTick_hook(void) { + size_t pc = (size_t)((uint32_t *)__get_MSP())[5]; + if (pc >= prof.lowpc && pc < prof.highpc) { + size_t idx = PROFIDX (pc, prof.lowpc, prof.scale); prof.counter[idx]++; - } } } /* Stop profiling to the profiling buffer pointed to by p. */ static int profile_off (struct profinfo *p) { + set_SysTick_hook(NULL); p->state = PROFILE_OFF; return 0; } /* Create a timer thread and pass it a pointer P to the profiling buffer. */ static int profile_on (struct profinfo *p) { + set_SysTick_hook(SysTick_hook); p->state = PROFILE_ON; return 0; /* ok */ } -- cgit v1.2.3 From 4d69f1a0ef2ef3aa23b0ac9f1b9cbc84582136a7 Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Sat, 6 May 2017 13:07:59 -0400 Subject: Correct offset to get the PC. A previous version of this code ran over the RTOS, where threads used the Process Stack, while the SysTick interrupt used the Main Stack. Now everything's on the main stack, so we need to account for 2 extra words that SysTick_Handler pushes on the stack at entry. --- libraries/libprof/profil.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libraries/libprof/profil.c') diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c index 07761dd..004af77 100644 --- a/libraries/libprof/profil.c +++ b/libraries/libprof/profil.c @@ -30,7 +30,7 @@ extern void set_SysTick_hook(void (*hook)(void)); /* sample the current program counter */ static void SysTick_hook(void) { - size_t pc = (size_t)((uint32_t *)__get_MSP())[5]; + size_t pc = (size_t)((uint32_t *)__get_MSP())[7]; if (pc >= prof.lowpc && pc < prof.highpc) { size_t idx = PROFIDX (pc, prof.lowpc, prof.scale); prof.counter[idx]++; -- cgit v1.2.3 From 65b94ef5ba1981c74a99cb43ee768fbf480c698b Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Wed, 10 May 2017 00:00:04 -0400 Subject: Sigh, right offset for the wrong register. Get the PC (the address we interrupted) rather than LR (the return address from the function we interrupted). Also, change u_short and u_int to unsigned short and unsigned int, since gcc recently decided that those aren't part of the C99 standard. Finally, add profilable versions of memcpy, memset, and friends, because they get called a lot in the course of unit testing, and it would be nice to know who's calling them. --- libraries/libprof/profil.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'libraries/libprof/profil.c') diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c index 004af77..0654879 100644 --- a/libraries/libprof/profil.c +++ b/libraries/libprof/profil.c @@ -17,7 +17,6 @@ #include #include "profil.h" #include -#include #include "stm32f4xx_hal.h" /* __get_MSP */ @@ -30,7 +29,7 @@ extern void set_SysTick_hook(void (*hook)(void)); /* sample the current program counter */ static void SysTick_hook(void) { - size_t pc = (size_t)((uint32_t *)__get_MSP())[7]; + size_t pc = (size_t)((uint32_t *)__get_MSP())[8]; if (pc >= prof.lowpc && pc < prof.highpc) { size_t idx = PROFIDX (pc, prof.lowpc, prof.scale); prof.counter[idx]++; @@ -55,7 +54,7 @@ static int profile_on (struct profinfo *p) { * start or stop profiling * * profiling goes into the SAMPLES buffer of size SIZE (which is treated - * as an array of u_shorts of size size/2) + * as an array of unsigned shorts of size size/2) * * each bin represents a range of pc addresses from OFFSET. The number * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps @@ -63,7 +62,7 @@ static int profile_on (struct profinfo *p) { * a scale of 1 maps each bin to 128k address). Scale may be 1 - 65536, * or zero to turn off profiling */ -int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, u_int scale) { +int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, unsigned int scale) { size_t maxbin; if (scale > 65536) { @@ -75,7 +74,7 @@ int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, memset(samples, 0, size); memset(p, 0, sizeof *p); maxbin = size >> 1; - prof.counter = (u_short*)samples; + prof.counter = (unsigned short*)samples; prof.lowpc = offset; prof.highpc = PROFADDR(maxbin, offset, scale); prof.scale = scale; @@ -88,7 +87,7 @@ int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, Every SLEEPTIME interval, the user's program counter (PC) is examined: offset is subtracted and the result is multiplied by scale. The word pointed to by this address is incremented. */ -int profil (char *samples, size_t size, size_t offset, u_int scale) { +int profil (char *samples, size_t size, size_t offset, unsigned int scale) { return profile_ctl (&prof, samples, size, offset, scale); } -- cgit v1.2.3