diff options
| author | Keith Packard <keithp@keithp.com> | 2012-10-23 22:17:49 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2012-10-25 00:07:14 -0700 | 
| commit | b119e19604aa557a40e848c60d98a67b5f259bbd (patch) | |
| tree | 2391c2fb7db1843096ec4e3d288cb26f7cb88b92 /src/core | |
| parent | 7d34811ba035367bbf26a8510265754f3fbb5a95 (diff) | |
altos: profiling on STM32L
Add sample-based profiling, using a 1kHz timer
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/ao_flight.c | 2 | ||||
| -rw-r--r-- | src/core/ao_sample_profile.c | 173 | ||||
| -rw-r--r-- | src/core/ao_sample_profile.h | 29 | ||||
| -rw-r--r-- | src/core/ao_task.c | 16 | ||||
| -rw-r--r-- | src/core/ao_task.h | 13 | 
5 files changed, 230 insertions, 3 deletions
diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c index aa4f6961..64c95063 100644 --- a/src/core/ao_flight.c +++ b/src/core/ao_flight.c @@ -115,7 +115,7 @@ ao_flight(void)   			{  				/* Set pad mode - we can fly! */  				ao_flight_state = ao_flight_pad; -#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG +#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE  				/* Disable the USB controller in flight mode  				 * to save power  				 */ diff --git a/src/core/ao_sample_profile.c b/src/core/ao_sample_profile.c new file mode 100644 index 00000000..1d9ed414 --- /dev/null +++ b/src/core/ao_sample_profile.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_sample_profile.h> +#include <ao_task.h> + +#ifndef AO_SAMPLE_PROFILE_LOW_PC +#define AO_SAMPLE_PROFILE_LOW_PC	0x08000000 +#endif + +#ifndef AO_SAMPLE_PROFILE_HIGH_PC +#define AO_SAMPLE_PROFILE_HIGH_PC	(AO_SAMPLE_PROFILE_LOW_PC + 44 * 1024) +#endif + +#ifndef AO_SAMPLE_PROFILE_SHIFT +#define AO_SAMPLE_PROFILE_SHIFT		6 +#endif + +#define AO_SAMPLE_PROFILE_RANGE		(AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC) +#define AO_SAMPLE_PROFILE_NUM		(AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT) + +static uint16_t	prev_tick; +static uint16_t	samples[AO_SAMPLE_PROFILE_NUM]; +static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8]; +static uint16_t max_miss; +static uint32_t task, isr, os, idle; + +extern uint8_t ao_idle_loc; + +void +ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr) +{ +	uint16_t	delta = tick - prev_tick; + +	if (pc < AO_SAMPLE_PROFILE_LOW_PC) +		return; +	if (pc >= AO_SAMPLE_PROFILE_HIGH_PC) +		return; +	if (ao_cur_task) { +		uint8_t		*sp; +		int32_t		sp_delta; +		 +		asm("mov %0,sp" : "=&r" (sp)); +		sp_delta = sp - (uint8_t *) ao_cur_task->stack; +		if (-96 < sp_delta && sp_delta < 16) +			ao_panic(AO_PANIC_STACK); +	} + +	if (in_isr) +		isr += delta; +	else if (ao_cur_task) { +		ao_cur_task->ticks += delta; +		task += delta; +	} else if (pc == (uint32_t) &ao_idle_loc) +		idle += delta; +	else +		os += delta; + +	pc -= AO_SAMPLE_PROFILE_LOW_PC; +	pc >>= AO_SAMPLE_PROFILE_SHIFT; +	samples[pc] += delta; + +	if (delta > 1) +		missed[pc >> 3] |= (1 << (pc & 7)); +	if (delta > max_miss) +		max_miss = delta; +	prev_tick = tick; +} + +static void +ao_sample_profile_start(void) +{ +	prev_tick = ao_sample_profile_timer_start(); +} + +static void +ao_sample_profile_stop(void) +{ +	ao_sample_profile_timer_stop(); +} + +static void +ao_sample_profile_dump(void) +{ +	uint16_t	a; +	uint8_t		t; + +	printf ("task %6d\n", task); +	printf ("isr  %6d\n", isr); +	printf ("os   %6d\n", os); +	printf ("idle %6d\n", idle); +	printf ("irq blocked %d\n", max_miss); +	for (t = 0; t < ao_num_tasks; t++) +		printf ("task %6d %6d %6d %s\n", +			ao_tasks[t]->ticks, +			ao_tasks[t]->yields, +			ao_tasks[t]->max_run, +			ao_tasks[t]->name); +	for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) { +		if (samples[a]) +			printf ("%04x %c %u\n", +				(a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC, +				missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ', +				samples[a]); +	} +} + +static void +ao_sample_profile_clear(void) +{ +	int t; + +	task = isr = os = idle = 0; +	max_miss = 0; +	memset(samples, '\0', sizeof (samples)); +	memset(missed, '\0', sizeof (missed)); +	for (t = 0; t < ao_num_tasks; t++) { +		ao_tasks[t]->ticks = 0; +		ao_tasks[t]->yields = 0; +		ao_tasks[t]->max_run = 0; +	} +} + +static void +ao_sample_profile_cmd(void) +{ +	ao_cmd_white(); +	switch (ao_cmd_lex_c) { +	case '1': +		ao_sample_profile_start(); +		break; +	case '0': +		ao_sample_profile_stop(); +		break; +	case 'd': +		ao_sample_profile_dump(); +		break; +	case 'c': +		ao_sample_profile_clear(); +		break; +	default: +		ao_cmd_status = ao_cmd_syntax_error; +		break; +	} +} + +static __code struct ao_cmds ao_sample_profile_cmds[] = { +	{ ao_sample_profile_cmd,	"S <1 start,0 stop, d dump,c clear>\0Sample profile" }, +	{ 0, NULL } +}; + +void +ao_sample_profile_init(void) +{ +	ao_sample_profile_timer_init(); +	ao_cmd_register(&ao_sample_profile_cmds[0]); +	ao_sample_profile_clear(); +} diff --git a/src/core/ao_sample_profile.h b/src/core/ao_sample_profile.h new file mode 100644 index 00000000..dbc29d3d --- /dev/null +++ b/src/core/ao_sample_profile.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_SAMPLE_PROFILE_H_ +#define _AO_SAMPLE_PROFILE_H_ + +#include <ao_sample_profile_timer.h> + +void +ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr); + +void +ao_sample_profile_init(void); + +#endif /* _AO_SAMPLE_PROFILE_H_ */ diff --git a/src/core/ao_task.c b/src/core/ao_task.c index 65654731..c2b1b270 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -16,6 +16,10 @@   */  #include <ao.h> +#include <ao_task.h> +#if HAS_SAMPLE_PROFILE +#include <ao_sample_profile.h> +#endif  #define AO_NO_TASK_INDEX	0xff @@ -67,6 +71,8 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam  	ao_arch_init_stack(task, start);  } +__xdata uint8_t	ao_idle; +  /* Task switching function. This must not use any stack variables */  void  ao_yield(void) ao_arch_naked_define @@ -77,6 +83,13 @@ ao_yield(void) ao_arch_naked_define  		ao_cur_task_index = ao_num_tasks-1;  	else  	{ +#if HAS_SAMPLE_PROFILE +		uint16_t	tick = ao_sample_profile_timer_value(); +		uint16_t	run = tick - ao_cur_task->start; +		if (run > ao_cur_task->max_run) +			ao_cur_task->max_run = run; +		++ao_cur_task->yields; +#endif  		ao_arch_save_stack();  	} @@ -110,6 +123,9 @@ ao_yield(void) ao_arch_naked_define  			if (ao_cur_task_index == ao_last_task_index)  				ao_arch_cpu_idle();  		} +#if HAS_SAMPLE_PROFILE +	ao_cur_task->start = ao_sample_profile_timer_value(); +#endif  	}  #if AO_CHECK_STACK  	cli(); diff --git a/src/core/ao_task.h b/src/core/ao_task.h index 18edd866..4319d632 100644 --- a/src/core/ao_task.h +++ b/src/core/ao_task.h @@ -26,13 +26,22 @@ struct ao_task {  	uint8_t task_id;		/* unique id */  	__code char *name;		/* task name */  	uint8_t	stack[AO_STACK_SIZE];	/* saved stack */ +#if HAS_SAMPLE_PROFILE +	uint32_t ticks; +	uint32_t yields; +	uint16_t start; +	uint16_t max_run; +#endif  }; -extern __xdata struct ao_task *__data ao_cur_task; -  #define AO_NUM_TASKS		16	/* maximum number of tasks */  #define AO_NO_TASK		0	/* no task id */ +extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS]; +extern __data uint8_t ao_num_tasks; +extern __data uint8_t ao_cur_task_index; +extern __xdata struct ao_task *__data ao_cur_task; +  /*   ao_task.c   */  | 
