Compare commits

...

4 Commits

Author SHA1 Message Date
Kent McLeod
35e91f397e Add 2 new benchmark utilization syscalls
- seL4_BenchmarkDumpAllThreadsUtilisation: Prints the current cycle
counts of every user thread on the current core.
- seL4_BenchmarkResetAllThreadsUtilisation: Resets the current cycle
counts of every user thread on the current core.

These syscalls are only available in a Debug build configuration as they
use a kernel debug list of all of the threads that exist for a given
node.

Signed-off-by: Kent McLeod <Kent.Mcleod@data61.csiro.au>
2020-05-18 17:26:50 +10:00
Kent McLeod
4d43070612 KernelBenchmarksTrackUtilisation: Fix for SMP
Create per-node global definitions for utilization variables.
This enables the tracking to more cleanly work on SMP configurations.
As resetting and starting the counters via SysBenchmarkResetLog only
updates the counters of the current thread and idle thread on the
current node it was not possible to accurately record utilization
statistics across multiple nodes. Now each node can have its tracking
independently started, stopped and queried. It is possible to add
additional syscalls in the future for doing this for all nodes in a
single syscall.

Signed-off-by: Kent McLeod <Kent.Mcleod@data61.csiro.au>
2020-05-18 16:09:10 +10:00
Kent McLeod
86b02ba104 KernelBenchmarksTrackUtilisation: Add kernel time
Add a variable for tracking accumulated time spent in the kernel while
utilization measurements are taking place.

Signed-off-by: Kent McLeod <Kent.Mcleod@data61.csiro.au>
2020-05-18 16:09:10 +10:00
Kent McLeod
cc41ba5d52 Move CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT def
This definition is intended to select functionality for processing a PMU
cycle counter overflow interrupt while using the thread utilization
benchmarking feature. Instead of forcing for all Arm platforms, only set
it if KERNEL_PMU_IRQ is defined and the IRQ has been configured
properly.

The consequence of this change is that aarch64 platforms that
have a 64bit counter that is unlikely to overflow do not need an
overflow interrupt to be defined.

Signed-off-by: Kent McLeod <Kent.Mcleod@data61.csiro.au>
2020-05-18 16:09:10 +10:00
16 changed files with 159 additions and 29 deletions

View File

@@ -18,6 +18,10 @@
#define PMCR_ECNT_RESET 1
#define PMCR_CCNT_RESET 2
#if defined(CONFIG_BENCHMARK_TRACK_UTILISATION) && defined(KERNEL_PMU_IRQ)
#define CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT 1
#endif
void arm_init_ccnt(void);
static inline timestamp_t timestamp(void)
@@ -28,22 +32,22 @@ static inline timestamp_t timestamp(void)
}
#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
extern bool_t benchmark_log_utilisation_enabled;
extern uint64_t ccnt_num_overflows;
static inline void handleOverflowIRQ(void)
{
if (likely(benchmark_log_utilisation_enabled)) {
if (likely(NODE_STATE(benchmark_log_utilisation_enabled))) {
NODE_STATE(ksCurThread)->benchmark.utilisation += UINT32_MAX - NODE_STATE(ksCurThread)->benchmark.schedule_start_time;
NODE_STATE(ksCurThread)->benchmark.schedule_start_time = 0;
ccnt_num_overflows++;
NODE_STATE(ccnt_num_overflows)++;
}
armv_handleOverflowIRQ();
}
#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
static inline void benchmark_arch_utilisation_reset(void)
{
ccnt_num_overflows = 0;
}
#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
NODE_STATE(ccnt_num_overflows) = 0;
#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
}
#endif /* CONFIG_ENABLE_BENCHMARKS */

View File

@@ -23,6 +23,9 @@ NODE_STATE_DECLARE(bool_t, armHSVCPUActive);
NODE_STATE_DECLARE(bool_t, armHSFPUEnabled);
#endif
#endif
#if defined(CONFIG_BENCHMARK_TRACK_UTILISATION) && defined(KERNEL_PMU_IRQ)
NODE_STATE_DECLARE(uint64_t, ccnt_num_overflows);
#endif /* defined(CONFIG_BENCHMARK_TRACK_UTILISATION) && defined(KERNEL_PMU_IRQ) */
NODE_STATE_END(archNodeState);
#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE

View File

@@ -13,10 +13,7 @@
#include <model/statedata.h>
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
extern bool_t benchmark_log_utilisation_enabled;
extern timestamp_t ksEnter;
extern timestamp_t benchmark_start_time;
extern timestamp_t benchmark_end_time;
void benchmark_track_utilisation_dump(void);
@@ -27,7 +24,7 @@ void benchmark_track_reset_utilisation(void);
static inline void benchmark_utilisation_switch(tcb_t *heir, tcb_t *next)
{
/* Add heir thread utilisation */
if (likely(benchmark_log_utilisation_enabled)) {
if (likely(NODE_STATE(benchmark_log_utilisation_enabled))) {
/* Check if an overflow occurred while we have been in the kernel */
if (likely(ksEnter > heir->benchmark.schedule_start_time)) {
@@ -55,8 +52,8 @@ static inline void benchmark_utilisation_finalise(void)
/* Add the time between when NODE_STATE(ksCurThread), and benchmark finalise */
benchmark_utilisation_switch(NODE_STATE(ksCurThread), NODE_STATE(ksIdleThread));
benchmark_end_time = ksEnter;
benchmark_log_utilisation_enabled = false;
NODE_STATE(benchmark_end_time) = ksEnter;
NODE_STATE(benchmark_log_utilisation_enabled) = false;
}
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */

View File

@@ -31,6 +31,13 @@ static inline void c_exit_hook(void)
#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES
benchmark_track_exit();
#endif /* CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES */
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
if (likely(benchmark_log_utilisation_enabled)) {
timestamp_t exit = timestamp();
benchmark_kernel_time += exit - ksEnter;
}
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
arch_c_exit_hook();
}

View File

@@ -80,6 +80,12 @@ NODE_STATE_DECLARE(word_t, ksFPURestoresSinceSwitch);
#ifdef CONFIG_DEBUG_BUILD
NODE_STATE_DECLARE(tcb_t *, ksDebugTCBs);
#endif /* CONFIG_DEBUG_BUILD */
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
NODE_STATE_DECLARE(bool_t, benchmark_log_utilisation_enabled);
NODE_STATE_DECLARE(timestamp_t, benchmark_start_time);
NODE_STATE_DECLARE(timestamp_t, benchmark_end_time);
NODE_STATE_DECLARE(timestamp_t, benchmark_kernel_time);
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
NODE_STATE_END(nodeState);

View File

@@ -748,7 +748,32 @@ LIBSEL4_INLINE_FUNC void seL4_BenchmarkResetThreadUtilisation(seL4_Word tcb_cptr
arm_sys_send_recv(seL4_SysBenchmarkResetThreadUtilisation, tcb_cptr, &unused0, 0, &unused1, &unused2, &unused3,
&unused4, &unused5, 0);
}
#ifdef CONFIG_DEBUG_BUILD
LIBSEL4_INLINE_FUNC void seL4_BenchmarkDumpAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
seL4_Word unused3 = 0;
seL4_Word unused4 = 0;
seL4_Word unused5 = 0;
arm_sys_send_recv(seL4_SysBenchmarkDumpAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, &unused3, &unused4, &unused5, 0);
}
LIBSEL4_INLINE_FUNC void seL4_BenchmarkResetAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
seL4_Word unused3 = 0;
seL4_Word unused4 = 0;
seL4_Word unused5 = 0;
arm_sys_send_recv(seL4_SysBenchmarkResetAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, &unused3, &unused4, &unused5, 0);
}
#endif
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
#endif /* CONFIG_ENABLE_BENCHMARKS */

View File

@@ -64,6 +64,10 @@
<syscall name="BenchmarkGetThreadUtilisation" />
<syscall name="BenchmarkResetThreadUtilisation" />
</config>
<config condition="defined CONFIG_DEBUG_BUILD &amp;&amp; defined CONFIG_BENCHMARK_TRACK_UTILISATION">
<syscall name="BenchmarkDumpAllThreadsUtilisation" />
<syscall name="BenchmarkResetAllThreadsUtilisation" />
</config>
<config condition="defined CONFIG_KERNEL_X86_DANGEROUS_MSR">
<syscall name="X86DangerousWRMSR"/>
<syscall name="X86DangerousRDMSR"/>

View File

@@ -15,7 +15,8 @@ enum benchmark_track_util_ipc_index {
BENCHMARK_TCB_UTILISATION,
BENCHMARK_IDLE_LOCALCPU_UTILISATION,
BENCHMARK_IDLE_TCBCPU_UTILISATION,
BENCHMARK_TOTAL_UTILISATION
BENCHMARK_TOTAL_UTILISATION,
BENCHMARK_KERNEL_UTILISATION
};
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */

View File

@@ -282,6 +282,29 @@ seL4_BenchmarkGetThreadUtilisation(seL4_Word tcb_cptr);
*/
LIBSEL4_INLINE_FUNC void
seL4_BenchmarkResetThreadUtilisation(seL4_Word tcb_cptr);
#ifdef CONFIG_DEBUG_BUILD
/**
* @xmlonly <manual name="Dump All Threads Utilisation" label="sel4_benchmarkdumpallthreadsutilisation"/> @endxmlonly
* @brief Print the current accumulated cycle count for every thread on the current node.
*
* Uses kernel's printf to print number of cycles on each line in the following format: thread_name,thread_cycles
*
*/
LIBSEL4_INLINE_FUNC void
seL4_BenchmarkDumpAllThreadsUtilisation(void);
/**
* @xmlonly <manual name="Reset All Threads Utilisation" label="sel4_benchmarkresetallthreadsutilisation"/> @endxmlonly
* @brief Reset the accumulated cycle count for every thread on the current node.
*
* Reset the cycle count for each thread to 0.
*
*/
LIBSEL4_INLINE_FUNC void
seL4_BenchmarkResetAllThreadsUtilisation(void);
#endif
#endif
#endif
/** @} */

View File

@@ -981,6 +981,29 @@ LIBSEL4_INLINE_FUNC void seL4_BenchmarkResetThreadUtilisation(seL4_Word tcb_cptr
x86_sys_send_recv(seL4_SysBenchmarkResetThreadUtilisation, tcb_cptr, &unused0, 0, &unused1, &unused2, MCS_COND(0,
&unused3));
}
#ifdef CONFIG_DEBUG_BUILD
LIBSEL4_INLINE_FUNC void seL4_BenchmarkDumpAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
LIBSEL4_UNUSED seL4_Word unused3 = 0;
x86_sys_send_recv(seL4_SysBenchmarkDumpAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, MCS_COND(0, &unused3));
}
LIBSEL4_INLINE_FUNC seL4_Word seL4_BenchmarkResetAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
LIBSEL4_UNUSED seL4_Word unused3 = 0;
x86_sys_send_recv(seL4_SysBenchmarkResetAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, MCS_COND(0, &unused3));
}
#endif /* CONFIG_DEBUG_BUILD */
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
#endif /* CONFIG_ENABLE_BENCHMARKS */

View File

@@ -764,6 +764,33 @@ LIBSEL4_INLINE_FUNC void seL4_BenchmarkResetThreadUtilisation(seL4_Word tcb_cptr
x64_sys_send_recv(seL4_SysBenchmarkResetThreadUtilisation, tcb_cptr, &unused0, 0, &unused1, &unused2, &unused3,
&unused4, &unused5, 0);
}
#ifdef CONFIG_DEBUG_BUILD
LIBSEL4_INLINE_FUNC void seL4_BenchmarkDumpAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
seL4_Word unused3 = 0;
seL4_Word unused4 = 0;
seL4_Word unused5 = 0;
x64_sys_send_recv(seL4_SysBenchmarkDumpAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, &unused3, &unused4, &unused5, 0);
}
LIBSEL4_INLINE_FUNC void seL4_BenchmarkResetAllThreadsUtilisation(void)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
seL4_Word unused3 = 0;
seL4_Word unused4 = 0;
seL4_Word unused5 = 0;
x64_sys_send_recv(seL4_SysBenchmarkResetAllThreadsUtilisation, 0, &unused0, 0, &unused1, &unused2, &unused3, &unused4, &unused5, 0);
}
#endif
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
#endif /* CONFIG_ENABLE_BENCHMARKS */

View File

@@ -208,10 +208,11 @@ exception_t handleUnknownSyscall(word_t w)
ksLogIndex = 0;
#endif /* CONFIG_BENCHMARK_USE_KERNEL_LOG_BUFFER */
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
benchmark_log_utilisation_enabled = true;
NODE_STATE(benchmark_log_utilisation_enabled) = true;
NODE_STATE(ksIdleThread)->benchmark.utilisation = 0;
NODE_STATE(ksCurThread)->benchmark.schedule_start_time = ksEnter;
benchmark_start_time = ksEnter;
NODE_STATE(benchmark_start_time) = ksEnter;
NODE_STATE(benchmark_kernel_time) = 0;
benchmark_arch_utilisation_reset();
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
setRegister(NODE_STATE(ksCurThread), capRegister, seL4_NoError);
@@ -247,6 +248,19 @@ exception_t handleUnknownSyscall(word_t w)
benchmark_track_reset_utilisation();
return EXCEPTION_NONE;
}
#ifdef CONFIG_DEBUG_BUILD
else if (w == SysBenchmarkDumpAllThreadsUtilisation) {
for (tcb_t *curr = NODE_STATE(ksDebugTCBs); curr != NULL; curr = curr->tcbDebugNext) {
printf("%s,%ld\n", curr->tcbName, (word_t) curr->benchmark.utilisation);
}
return EXCEPTION_NONE;
} else if (w == SysBenchmarkResetAllThreadsUtilisation) {
for (tcb_t *curr = NODE_STATE(ksDebugTCBs); curr != NULL; curr = curr->tcbDebugNext) {
curr->benchmark.utilisation = 0;
}
return EXCEPTION_NONE;
}
#endif /* CONFIG_DEBUG_BUILD */
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
else if (w == SysBenchmarkNullSyscall) {

View File

@@ -16,7 +16,7 @@ seL4_Word ksLogIndexFinalized = 0;
#endif /* CONFIG_MAX_NUM_TRACE_POINTS > 0 */
#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
uint64_t ccnt_num_overflows;
UP_STATE_DEFINE(uint64_t, ccnt_num_overflows);
#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
#ifdef CONFIG_ENABLE_BENCHMARKS

View File

@@ -194,14 +194,6 @@ if(KernelArchArmV6)
set(KernelSetTLSBaseSelf ON)
endif()
# TODO: this config has no business being in the build system, and should
# be moved to C headers, but for now must be emulated here for compatibility
if(KernelBenchmarksTrackUtilisation AND KernelArchARM)
config_set(KernelArmEnablePMUOverflowInterrupt ARM_ENABLE_PMU_OVERFLOW_INTERRUPT ON)
else()
config_set(KernelArmEnablePMUOverflowInterrupt ARM_ENABLE_PMU_OVERFLOW_INTERRUPT OFF)
endif()
# Provides a 4K region of read-only memory mapped into every vspace to
# provide a virtual thread-id register not otherwise provided by the
# platform.

View File

@@ -9,10 +9,7 @@
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
bool_t benchmark_log_utilisation_enabled;
timestamp_t ksEnter;
timestamp_t benchmark_start_time;
timestamp_t benchmark_end_time;
void benchmark_track_utilisation_dump(void)
{
@@ -43,10 +40,11 @@ void benchmark_track_utilisation_dump(void)
#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
buffer[BENCHMARK_TOTAL_UTILISATION] =
(ccnt_num_overflows * 0xFFFFFFFFU) + benchmark_end_time - benchmark_start_time;
(NODE_STATE(ccnt_num_overflows) * 0xFFFFFFFFU) + NODE_STATE(benchmark_end_time) - NODE_STATE(benchmark_start_time);
#else
buffer[BENCHMARK_TOTAL_UTILISATION] = benchmark_end_time - benchmark_start_time; /* Overall time */
buffer[BENCHMARK_TOTAL_UTILISATION] = NODE_STATE(benchmark_end_time) - NODE_STATE(benchmark_start_time); /* Overall time */
#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
buffer[BENCHMARK_KERNEL_UTILISATION] = NODE_STATE(benchmark_kernel_time);
}

View File

@@ -61,6 +61,12 @@ UP_STATE_DEFINE(sched_context_t *, ksCurSC);
#ifdef CONFIG_DEBUG_BUILD
UP_STATE_DEFINE(tcb_t *, ksDebugTCBs);
#endif /* CONFIG_DEBUG_BUILD */
#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
UP_STATE_DEFINE(bool_t, benchmark_log_utilisation_enabled);
UP_STATE_DEFINE(timestamp_t, benchmark_start_time);
UP_STATE_DEFINE(timestamp_t, benchmark_end_time);
UP_STATE_DEFINE(timestamp_t, benchmark_kernel_time);
#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
/* Units of work we have completed since the last time we checked for
* pending interrupts */