[Cryptech-Commits] [sw/stm32] 03/08: Port profiling code, using a new SysTick hook and new CLI commands.

git at cryptech.is git at cryptech.is
Thu Sep 7 22:42:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch profiling
in repository sw/stm32.

commit 358d038067b10330011ef4e6596ae37842d516fe
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Fri May 5 22:58:34 2017 -0400

    Port profiling code, using a new SysTick hook and new CLI commands.
---
 Makefile                                           | 15 ++++-
 libraries/libprof/README.txt                       | 65 ++++++++++++++++++++--
 libraries/libprof/gmon.c                           | 61 +++++++-------------
 libraries/libprof/profil.c                         | 22 ++++----
 .../TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c           |  7 +++
 projects/hsm/Makefile                              | 11 +++-
 projects/hsm/mgmt-misc.c                           | 28 ++++++++++
 syscalls.c                                         |  6 ++
 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 ***/



More information about the Commits mailing list