aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2017-05-05 22:58:34 -0400
committerPaul Selkirk <paul@psgd.org>2017-09-07 18:11:00 -0400
commit358d038067b10330011ef4e6596ae37842d516fe (patch)
tree72b0ce416958536fff1070ba7c6a8926188cc93b
parent9ecd51ab1028e8033057df3117aac27f6f2cd406 (diff)
Port profiling code, using a new SysTick hook and new CLI commands.
-rw-r--r--Makefile15
-rw-r--r--libraries/libprof/README.txt65
-rw-r--r--libraries/libprof/gmon.c61
-rw-r--r--libraries/libprof/profil.c22
-rw-r--r--libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c7
-rw-r--r--projects/hsm/Makefile11
-rw-r--r--projects/hsm/mgmt-misc.c28
-rw-r--r--syscalls.c6
8 files changed, 157 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index e058edd..8083273 100644
--- a/Makefile
+++ b/Makefile
@@ -51,6 +51,9 @@ LIBCLI_BLD = $(LIBS_DIR)/libcli
LIBTFM_SRC = $(CRYPTECH_ROOT)/sw/thirdparty/libtfm
LIBTFM_BLD = $(LIBS_DIR)/libtfm
+LIBPROF_SRC = $(LIBS_DIR)/libprof
+LIBPROF_BLD = $(LIBS_DIR)/libprof
+
LIBS = $(MBED_DIR)/libstmf4.a
# linker script
@@ -106,7 +109,7 @@ CFLAGS += -DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F429xx
CFLAGS += -D__CORTEX_M4 -DTARGET_STM -DTARGET_STM32F4 -DTARGET_STM32F429ZI -DTOOLCHAIN_GCC -D__FPU_PRESENT=1 -D$(BOARD)
CFLAGS += -DENABLE_WEAK_FUNCTIONS
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections
-CFLAGS += -std=c99
+CFLAGS += -std=gnu99
CFLAGS += -I$(TOPLEVEL)
CFLAGS += -I$(MBED_DIR)/api
CFLAGS += -I$(MBED_DIR)/targets/cmsis
@@ -141,11 +144,20 @@ $(LIBHAL_BLD)/libhal.a: $(LIBTFM_BLD)/libtfm.a .FORCE
$(LIBCLI_BLD)/libcli.a: .FORCE
$(MAKE) -C $(LIBCLI_BLD)
+$(LIBPROF_BLD)/libprof.a: .FORCE
+ $(MAKE) -C $(LIBPROF_BLD)
+
libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE
$(MAKE) -C projects/libhal-test
+ifdef DO_PROFILING
+CFLAGS += -pg -DDO_PROFILING
+hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a $(LIBCLI_BLD)/libcli.a $(LIBPROF_BLD)/libprof.a .FORCE
+ $(MAKE) -C projects/hsm
+else
hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a $(LIBCLI_BLD)/libcli.a .FORCE
$(MAKE) -C projects/hsm
+endif
bootloader: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE
$(MAKE) -C projects/bootloader
@@ -177,3 +189,4 @@ distclean: clean
$(MAKE) -C $(MBED_DIR) clean
$(MAKE) -C $(LIBTFM_BLD) clean
$(MAKE) -C $(LIBCLI_BLD) clean
+ $(MAKE) -C $(LIBPROF_BLD) clean
diff --git a/libraries/libprof/README.txt b/libraries/libprof/README.txt
index 2df8b96..da138c2 100644
--- a/libraries/libprof/README.txt
+++ b/libraries/libprof/README.txt
@@ -1,6 +1,61 @@
-Copied from https://github.com/ErichStyger/mcuoneclipse.git,
-directory Examples/KDS/FRDM-K64F120M/FRDM-K64F_Profiling/Profiling,
-commit 9b7eedddd8b24968128582aedc63be95b61f782c,
-dated Mon Jan 9 16:56:17 2017 +0100.
-(This is in turn adapted from Cygwin, and can be found in newlib distributions.)
+Profiling the Cryptech Alpha
+============================
+Origin
+------
+
+This code was copied from https://github.com/ErichStyger/mcuoneclipse.git,
+directory Examples/KDS/FRDM-K64F120M/FRDM-K64F_Profiling/Profiling, commit
+9b7eedddd8b24968128582aedc63be95b61f782c, dated Mon Jan 9 16:56:17 2017 +0100.
+
+References
+----------
+
+I recommend reading both of these to understand how the profiling code works.
+
+[1]: https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/
+"Tutorial: Using GNU Profiling (gprof) with ARM Cortex-M"
+
+[2]: http://bgamari.github.io/posts/2014-10-31-semihosting.html
+"Semihosting with ARM, GCC, and OpenOCD"
+
+How to build
+------------
+
+From the top level, run
+
+ make DO_PROFILING=1 hsm
+
+By default, all code is profiled, *except* the profiling code itself,
+because that would cause fatal recursion.
+
+How to run
+----------
+
+You need to start OpenOCD on the host, and enable semihosting, at least
+before you try to use it as a remote file system.
+
+I recommend executing the following in the projects/hsm directory, so that
+gmon.out ends up in the same directory as hsm.elf.
+
+Start OpenOCD:
+
+ $ openocd -f /usr/share/openocd/scripts/board/stm32f4discovery.cfg &
+
+Connect to OpenOCD:
+
+ $ telnet localhost 4444
+
+In the OpenOCD console, enable semihosting:
+
+ > arm semihosting enable
+
+In the CLI, type `profile start`, then start the unit test or whatever
+will be exercising the hsm. Afterwards, in the CLI, type `profile stop`.
+
+After invoking `profile stop`, it takes almost 2 minutes to write gmon.out
+over OpenOCD to the host.
+
+In the projects/hsm directory, run gprof to analyse the gmon.out file:
+
+ $ gprof hsm.elf >gprof.txt
diff --git a/libraries/libprof/gmon.c b/libraries/libprof/gmon.c
index 2be8bb2..458028b 100644
--- a/libraries/libprof/gmon.c
+++ b/libraries/libprof/gmon.c
@@ -41,7 +41,6 @@
#include <stdint.h>
#include <string.h>
-#define MINUS_ONE_P (-1)
#define bzero(ptr,size) memset (ptr, 0, size);
#define ERR(s) write(2, s, sizeof(s))
@@ -53,43 +52,30 @@ static int s_scale;
static void moncontrol(int mode);
-/* required for gcc ARM Embedded 4.9-2015-q2 */
-#if 0
-void *_sbrk(int incr) {
- extern char __HeapLimit; /* Defined by the linker */
- static char *heap_end = 0;
- char *prev_heap_end;
-
- if (heap_end==0) {
- heap_end = &__HeapLimit;
- }
- prev_heap_end = heap_end;
- heap_end += incr;
- return (void *)prev_heap_end;
-}
-#endif
-
-static void *fake_sbrk(int size) {
- void *rv = malloc(size);
- if (rv) {
- return rv;
- } else {
- return (void *) MINUS_ONE_P;
- }
-}
-
void monstartup (size_t lowpc, size_t highpc) {
register size_t o;
char *cp;
struct gmonparam *p = &_gmonparam;
+ if (already_setup) {
+ /* zero out cp as value will be added there */
+ bzero(p->tos, p->kcountsize + p->fromssize + p->tossize);
+ moncontrol(1); /* start */
+ return;
+ }
+ already_setup = 1;
+
+ /* enable semihosting, for eventual output */
+ extern void initialise_monitor_handles(void);
+ initialise_monitor_handles();
+
/*
* round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
*/
p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
- p->textsize = p->highpc - p->lowpc;
+ p->textsize = p->highpc - p->lowpc + 0x20;
p->kcountsize = p->textsize / HISTFRACTION;
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
@@ -100,8 +86,9 @@ void monstartup (size_t lowpc, size_t highpc) {
}
p->tossize = p->tolimit * sizeof(struct tostruct);
- cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize);
- if (cp == (char *)MINUS_ONE_P) {
+ extern void *hal_allocate_static_memory(const size_t size);
+ cp = hal_allocate_static_memory(p->kcountsize + p->fromssize + p->tossize);
+ if (cp == NULL) {
ERR("monstartup: out of memory\n");
return;
}
@@ -142,14 +129,13 @@ void monstartup (size_t lowpc, size_t highpc) {
void _mcleanup(void) {
static const char gmon_out[] = "gmon.out";
int fd;
- int hz;
int fromindex;
int endfrom;
size_t frompc;
int toindex;
struct rawarc rawarc;
struct gmonparam *p = &_gmonparam;
- struct gmonhdr gmonhdr, *hdr;
+ struct gmonhdr gmonhdr = {0}, *hdr;
const char *proffile;
#ifdef DEBUG
int log, len;
@@ -159,7 +145,6 @@ void _mcleanup(void) {
if (p->state == GMON_PROF_ERROR) {
ERR("_mcleanup: tos overflow\n");
}
- hz = PROF_HZ;
moncontrol(0); /* stop */
proffile = gmon_out;
fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
@@ -174,7 +159,7 @@ void _mcleanup(void) {
return;
}
len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n",
- p->kcount, p->kcountsize);
+ (unsigned int)p->kcount, p->kcountsize);
write(log, dbuf, len);
#endif
hdr = (struct gmonhdr *)&gmonhdr;
@@ -182,7 +167,8 @@ void _mcleanup(void) {
hdr->hpc = p->highpc;
hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
hdr->version = GMONVERSION;
- hdr->profrate = hz;
+ hdr->profrate = PROF_HZ;
+ hdr->spare[0] = hdr->spare[1] = hdr->spare[2] = 0;
write(fd, (char *)hdr, sizeof *hdr);
write(fd, p->kcount, p->kcountsize);
endfrom = p->fromssize / sizeof(*p->froms);
@@ -195,7 +181,7 @@ void _mcleanup(void) {
for (toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].link) {
#ifdef DEBUG
len = sprintf(dbuf,
- "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
+ "[mcleanup2] frompc 0x%x selfpc 0x%x count %ld\n" ,
frompc, p->tos[toindex].selfpc,
p->tos[toindex].count);
write(log, dbuf, len);
@@ -234,11 +220,6 @@ void _mcount_internal(uint32_t *frompcindex, uint32_t *selfpc) {
register long toindex;
struct gmonparam *p = &_gmonparam;
- if (!already_setup) {
- extern char __etext; /* end of text/code symbol, defined by linker */
- already_setup = 1;
- monstartup(0x410, (uint32_t)&__etext);
- }
/*
* check that we are profiling
* and that we aren't recursively invoked.
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 <stdio.h>
#include <sys/types.h>
@@ -19,34 +19,34 @@
#include <string.h>
#include <stdint.h>
+#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 */
}
diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
index 32b7707..b8b6fce 100644
--- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
+++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c
@@ -64,6 +64,13 @@ void HardFault_Handler(void)
while (1) { ; }
}
+static void default_SysTick_hook(void) { };
+static void (*SysTick_hook)(void) = default_SysTick_hook;
+void set_SysTick_hook(void (*hook)(void))
+{
+ SysTick_hook = (hook == NULL) ? default_SysTick_hook : hook;
+}
+
/**
* @brief This function handles SysTick Handler.
* @param None
diff --git a/projects/hsm/Makefile b/projects/hsm/Makefile
index ecd1a5d..7efd41d 100644
--- a/projects/hsm/Makefile
+++ b/projects/hsm/Makefile
@@ -23,10 +23,19 @@ CFLAGS += -I$(LIBCLI_SRC)
LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a
LIBS += $(LIBCLI_BLD)/libcli.a
+LDFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork
+LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
+LDFLAGS += -Wl,--gc-sections
+
+ifdef DO_PROFILING
+LIBS += $(LIBPROF_BLD)/libprof.a
+LDFLAGS += --specs=rdimon.specs -lc -lrdimon
+endif
+
all: $(PROJ:=.elf)
%.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS)
- $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
+ $(CC) $(LDFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map
$(OBJCOPY) -O binary $*.elf $*.bin
$(SIZE) $*.elf
diff --git a/projects/hsm/mgmt-misc.c b/projects/hsm/mgmt-misc.c
index ccd032b..016d7cb 100644
--- a/projects/hsm/mgmt-misc.c
+++ b/projects/hsm/mgmt-misc.c
@@ -113,6 +113,25 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal
return CLI_ERROR;
}
+#ifdef DO_PROFILING
+static int cmd_profile_start(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ extern uint32_t CRYPTECH_FIRMWARE_START;
+ extern char __etext; /* end of text/code symbol, defined by linker */
+ extern void monstartup (size_t lowpc, size_t highpc);
+ monstartup((size_t)&CRYPTECH_FIRMWARE_START, (size_t)&__etext);
+ return CLI_OK;
+}
+
+static int cmd_profile_stop(struct cli_def *cli, const char *command, char *argv[], int argc)
+{
+ extern void _mcleanup(void);
+ _mcleanup();
+ return CLI_OK;
+}
+
+#endif
+
static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc)
{
cli_print(cli, "\n\n\nRebooting\n\n\n");
@@ -124,6 +143,15 @@ static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], in
void configure_cli_misc(struct cli_def *cli)
{
+#ifdef DO_PROFILING
+ struct cli_command *c_profile = cli_register_command(cli, NULL, "profile", NULL, 0, 0, NULL);
+
+ /* profile start */
+ cli_register_command(cli, c_profile, "start", cmd_profile_start, 0, 0, "Start collecting profiling data");
+
+ /* profile stop */
+ cli_register_command(cli, c_profile, "stop", cmd_profile_stop, 0, 0, "Stop collecting profiling data");
+#endif
/* reboot */
cli_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32");
}
diff --git a/syscalls.c b/syscalls.c
index d7b7211..1624454 100644
--- a/syscalls.c
+++ b/syscalls.c
@@ -48,6 +48,7 @@
/***************************************************************************/
+#ifndef DO_PROFILING
int _read_r (struct _reent *r, int file, char * ptr, int len)
{
r = r;
@@ -103,6 +104,7 @@ int _close_r (struct _reent *r, int file)
{
return 0;
}
+#endif
/***************************************************************************/
@@ -143,6 +145,7 @@ caddr_t _sbrk_r (struct _reent *r, int incr)
/***************************************************************************/
+#ifndef DO_PROFILING
int _fstat_r (struct _reent *r, int file, struct stat * st)
{
r = r;
@@ -181,6 +184,7 @@ int _kill (int a, int b)
return 0;
}
+#endif
/***************************************************************************/
@@ -193,6 +197,7 @@ int _getpid(int a)
/***************************************************************************/
+#ifndef DO_PROFILING
int _open(int a, int b)
{
a = a;
@@ -200,5 +205,6 @@ int _open(int a, int b)
return 0;
}
+#endif
/*** EOF ***/