cortex_m: add profiling function
Use DWT_PCSR if present (reads nonzero); otherwise do halt-and-sample pc. Signed-off-by: Simon Schubert <2@0x2c.org> Change-Id: Id2dc4665e5008cc497a2e6e6493522d038d5af42 Reviewed-on: http://openocd.zylin.com/4211 Tested-by: jenkins Reviewed-by: Karl Palsson <karlp@tweak.net.au> Reviewed-by: Christopher Head <chead@zaber.com> Reviewed-by: Paul Fertser <fercerpav@gmail.com>
This commit is contained in:
parent
2b44b52478
commit
64b0d5aac0
|
@ -1707,6 +1707,93 @@ void cortex_m_deinit_target(struct target *target)
|
||||||
free(cortex_m);
|
free(cortex_m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cortex_m_profiling(struct target *target, uint32_t *samples,
|
||||||
|
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds)
|
||||||
|
{
|
||||||
|
struct timeval timeout, now;
|
||||||
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
uint32_t reg_value;
|
||||||
|
bool use_pcsr = false;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
struct reg *reg;
|
||||||
|
|
||||||
|
gettimeofday(&timeout, NULL);
|
||||||
|
timeval_add_time(&timeout, seconds, 0);
|
||||||
|
|
||||||
|
retval = target_read_u32(target, DWT_PCSR, ®_value);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Error while reading PCSR");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg_value != 0) {
|
||||||
|
use_pcsr = true;
|
||||||
|
LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can...");
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Starting profiling. Halting and resuming the"
|
||||||
|
" target as often as we can...");
|
||||||
|
reg = register_get_by_name(target->reg_cache, "pc", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure the target is running */
|
||||||
|
target_poll(target);
|
||||||
|
if (target->state == TARGET_HALTED)
|
||||||
|
retval = target_resume(target, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Error while resuming target");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sample_count = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (use_pcsr) {
|
||||||
|
uint32_t read_count = max_num_samples - sample_count;
|
||||||
|
if (read_count > 1024)
|
||||||
|
read_count = 1024;
|
||||||
|
retval = mem_ap_read_buf_noincr(armv7m->debug_ap,
|
||||||
|
(void *)&samples[sample_count],
|
||||||
|
4, read_count, DWT_PCSR);
|
||||||
|
sample_count += read_count;
|
||||||
|
} else {
|
||||||
|
target_poll(target);
|
||||||
|
if (target->state == TARGET_HALTED) {
|
||||||
|
reg_value = buf_get_u32(reg->value, 0, 32);
|
||||||
|
/* current pc, addr = 0, do not handle breakpoints, not debugging */
|
||||||
|
retval = target_resume(target, 1, 0, 0, 0);
|
||||||
|
samples[sample_count++] = reg_value;
|
||||||
|
target_poll(target);
|
||||||
|
alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
|
||||||
|
} else if (target->state == TARGET_RUNNING) {
|
||||||
|
/* We want to quickly sample the PC. */
|
||||||
|
retval = target_halt(target);
|
||||||
|
} else {
|
||||||
|
LOG_INFO("Target not halted or running");
|
||||||
|
retval = ERROR_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
if (sample_count >= max_num_samples ||
|
||||||
|
(now.tv_sec >= timeout.tv_sec && now.tv_usec >= timeout.tv_usec)) {
|
||||||
|
LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*num_samples = sample_count;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* REVISIT cache valid/dirty bits are unmaintained. We could set "valid"
|
/* REVISIT cache valid/dirty bits are unmaintained. We could set "valid"
|
||||||
* on r/w if the core is not running, and clear on resume or reset ... or
|
* on r/w if the core is not running, and clear on resume or reset ... or
|
||||||
* at least, in a post_restore_context() method.
|
* at least, in a post_restore_context() method.
|
||||||
|
@ -2451,4 +2538,6 @@ struct target_type cortexm_target = {
|
||||||
.init_target = cortex_m_init_target,
|
.init_target = cortex_m_init_target,
|
||||||
.examine = cortex_m_examine,
|
.examine = cortex_m_examine,
|
||||||
.deinit_target = cortex_m_deinit_target,
|
.deinit_target = cortex_m_deinit_target,
|
||||||
|
|
||||||
|
.profiling = cortex_m_profiling,
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
|
|
||||||
#define DWT_CTRL 0xE0001000
|
#define DWT_CTRL 0xE0001000
|
||||||
#define DWT_CYCCNT 0xE0001004
|
#define DWT_CYCCNT 0xE0001004
|
||||||
|
#define DWT_PCSR 0xE000101C
|
||||||
#define DWT_COMP0 0xE0001020
|
#define DWT_COMP0 0xE0001020
|
||||||
#define DWT_MASK0 0xE0001024
|
#define DWT_MASK0 0xE0001024
|
||||||
#define DWT_FUNCTION0 0xE0001028
|
#define DWT_FUNCTION0 0xE0001028
|
||||||
|
|
Loading…
Reference in New Issue