Skip to content

Commit

Permalink
Add script to profile via qemu and gdb. Simple mixer profile example
Browse files Browse the repository at this point in the history
  • Loading branch information
PhracturedBlue committed Jan 10, 2019
1 parent bb55f80 commit 2316ebf
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ void TOUCH_Handler(); // temporarily in main()
void VIDEO_Update();
void PAGE_Test();

int main() __attribute__((weak));
#if defined (TEST) || defined (PROFILE)
#define main _main
#endif

#ifndef DUMP_BOOTLOADER
int main() {
Expand Down
Binary file removed src/target/qemu/.target_main.c.swp
Binary file not shown.
2 changes: 1 addition & 1 deletion src/target/qemu/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SRC_C := $(wildcard $(SDIR)/target/$(TARGET)/*.c) \

SRC_C := $(filter-out $(SDIR)/target/common/stm32/spi_flash.c, $(SRC_C))

CFLAGS = -D"assert_param(x)=" -DSTM32F10X_HD -DSTM32F1 -mcpu=cortex-m3 -mthumb -mfix-cortex-m3-ldrd -fdata-sections -ffunction-sections -I$(SDIR)/target/common/devo/msc2/lib -I$(SDIR)/target/common/devo/msc2 -I$(SDIR)/libopencm3/include -I$(SDIR)/target/common/filesystems -fno-builtin-printf -Os --specs=nano.specs
CFLAGS = -DPROFILE -D"assert_param(x)=" -DSTM32F10X_HD -DSTM32F1 -mcpu=cortex-m3 -mthumb -mfix-cortex-m3-ldrd -fdata-sections -ffunction-sections -I$(SDIR)/target/common/devo/msc2/lib -I$(SDIR)/target/common/devo/msc2 -I$(SDIR)/libopencm3/include -I$(SDIR)/target/common/filesystems -fno-builtin-printf -Os --specs=nano.specs
MODULE_FLAGS = -fno-builtin

LFLAGS = -nostartfiles -Wl,-gc-sections -Wl,-Map=$(TARGET).map,--cref -lc -lnosys -L$(SDIR) -Lobjs/$(TARGET)
Expand Down
33 changes: 33 additions & 0 deletions src/target/qemu/target_main.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,51 @@
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/systick.h>
#include "common.h"
#include "mixer.h"
#include "config/tx.h"
#include "config/model.h"
#include "../common/devo/devo.h"

void run_profile();
void init_profile();
int main()
{
SCB_VTOR = VECTOR_TABLE_LOCATION;
SCB_SCR &= ~SCB_SCR_SLEEPONEXIT; //sleep immediate on WFI
rcc_clock_setup_in_hse_8mhz_out_72mhz();
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(0x00FFFFFF);
systick_counter_enable();
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
gpio_clear(GPIOC, GPIO12);
gpio_set(GPIOC, GPIO12);
gpio_clear(GPIOC, GPIO12);

init_profile();
run_profile();
}

void init_profile() {
for (int i = 0; i < INP_HAS_CALIBRATION; i++)
{
Transmitter.calibration[i].min = CHAN_MIN_VALUE;
Transmitter.calibration[i].max = CHAN_MAX_VALUE;
Transmitter.calibration[i].zero = 0;
}
memset(Model.mixers, 0, sizeof(Model.mixers));
for (unsigned i = 0; i < 1; i++) {
Model.mixers[i].src = 1;
Model.mixers[i].dest = (2 + i) % 5;
Model.mixers[i].scalar = 100;
Model.mixers[i].flags = MUX_REPLACE;
}
Model.num_channels = 12;
}

void __attribute__ ((noinline)) run_profile() {
MIXER_CalcChannels();
}
89 changes: 89 additions & 0 deletions utils/qemu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# This script will profile the qemu.bin build and produce a calltrace log
# It is meant to be loaded from within gdb via:
# arm-none-eabi-gdb-py
# source gdb
# profile
# An STM32 QEMU is needed (either docker or natively compiled): https://github.com/beckus/qemu_stm32
# QEMU is started before running gdb via:
# qemu-system-arm -S -s -M stm32-p103 -kernel qemu.bin

import gdb

compress = True

class func:
def __init__(self, parent, pc, lr, name):
self.exclusive = 0
self.parent = parent
self.pc = pc
self.lr = lr
self.children = []
self.name = name
def newchild(self, pc, lr, name):
if compress:
for child in self.children:
if child.pc == pc:
child.lr = lr
return child
newfunc = func(self, pc, lr, name)
self.children.append(newfunc)
return newfunc

def printstack(trace, depth=""):
inclusive = trace.exclusive
childstr = ""
for child in trace.children:
_str, incl = printstack(child, depth + " ")
childstr += _str
inclusive += incl
childstr = "{}{} 0x{:02x} (ex:{} inc:{})\n".format(depth, trace.name, trace.pc, trace.exclusive, inclusive) + childstr
if depth == "":
print childstr
else:
return childstr, inclusive

topfunc = func(None, 0, 0, None)

class Profile(gdb.Command):
def __init__(self):
# This registers our class as "simple_command"
super(Profile, self).__init__("profile", gdb.COMMAND_DATA)
gdb.execute("file qemu.elf")
gdb.execute("target remote localhost:1234")
gdb.execute("set pagination off")
self.trace = topfunc

def invoke(self, arg, from_tty):
# When we call "simple_command" from gdb, this is the method
# that will be called.
#gdb.execute("set logging file /dev/null")
#gdb.execute("set logging redirect on")
#gdb.execute("set logging on")
gdb.execute("b run_profile")
gdb.execute("c")
gdb.execute("disable")
stop_pc = gdb.newest_frame().older().pc()

last_lr = int(gdb.parse_and_eval('$lr'))-1
while True:
frame = gdb.newest_frame()
pc = frame.pc()
lr = int(gdb.parse_and_eval('$lr'))-1
if pc == self.trace.lr:
print "Returned from {:02x}".format(self.trace.pc)
self.trace = self.trace.parent
#return
elif lr != last_lr:
self.trace = self.trace.newchild(pc, lr, frame.name())
print "Called {}{:02x} (return: {:02x})".format(frame.name(), pc, lr)
#return
if pc == 0 or pc == stop_pc:
break;
self.trace.exclusive += 1
last_lr = lr
gdb.execute("si")
#gdb.execute("set logging off")
#gdb.execute("display")
printstack(topfunc)

Profile()

0 comments on commit 2316ebf

Please sign in to comment.