Skip to content

Commit 59a3e61

Browse files
committed
cpu/cortexm_common: measure time spent with IRQ disabled
1 parent 8145c42 commit 59a3e61

4 files changed

Lines changed: 70 additions & 4 deletions

File tree

core/lib/include/irq.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extern "C" {
3535
#define MAYBE_INLINE
3636
#endif /* IRQ_API_INLINED */
3737

38+
#ifndef IRQ_API_INLINED
3839
/**
3940
* @brief This function sets the IRQ disable bit in the status register
4041
*
@@ -89,7 +90,7 @@ MAYBE_INLINE bool irq_is_enabled(void);
8990
*/
9091
MAYBE_INLINE bool irq_is_in(void);
9192

92-
#ifdef IRQ_API_INLINED
93+
#else
9394
#include "irq_arch.h"
9495
#endif /* IRQ_API_INLINED */
9596

cpu/cortexm_common/include/irq_arch.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,33 @@
2222
#include <stdbool.h>
2323
#include <stdint.h>
2424
#include "cpu_conf.h"
25+
#include "kernel_defines.h"
26+
#include "debug_irq_disable.h"
2527

2628
#ifdef __cplusplus
2729
extern "C" {
2830
#endif
2931

32+
/**
33+
* @brief Start SysTick timer to measure time spent with IRQ disabled
34+
*/
35+
static inline void _irq_debug_start_count(void)
36+
{
37+
SysTick->VAL = 0;
38+
SysTick->LOAD = SysTick_LOAD_RELOAD_Msk;
39+
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
40+
}
41+
42+
/**
43+
* @brief Stop SysTick timer, return time spent with IRQ disabled
44+
*/
45+
static inline uint32_t _irq_debug_stop_count(void)
46+
{
47+
uint32_t ticks = SysTick_LOAD_RELOAD_Msk - SysTick->VAL;
48+
SysTick->CTRL = 0;
49+
return ticks;
50+
}
51+
3052
/**
3153
* @brief Disable all maskable interrupts
3254
*/
@@ -35,6 +57,10 @@ unsigned int irq_disable(void)
3557
{
3658
uint32_t mask = __get_PRIMASK();
3759

60+
if ((mask == 0) && IS_USED(MODULE_DEBUG_IRQ_DISABLE)) {
61+
_irq_debug_start_count();
62+
}
63+
3864
__disable_irq();
3965
return mask;
4066
}
@@ -55,10 +81,28 @@ unsigned int irq_enable(void)
5581
* @brief Restore the state of the IRQ flags
5682
*/
5783
static inline __attribute__((always_inline))
84+
#if !IS_USED(MODULE_DEBUG_IRQ_DISABLE)
5885
void irq_restore(unsigned int state)
5986
{
6087
__set_PRIMASK(state);
6188
}
89+
#else
90+
void _irq_restore(unsigned int state, const char *file, unsigned line)
91+
{
92+
uint32_t ticks = 0;
93+
94+
if (state == 0) {
95+
ticks = _irq_debug_stop_count();
96+
}
97+
98+
__set_PRIMASK(state);
99+
100+
if (ticks) {
101+
debug_irq_disable_print(file, line, ticks);
102+
}
103+
}
104+
#define irq_restore(state) _irq_restore(state, __FILE__, __LINE__);
105+
#endif /* MODULE_DEBUG_IRQ_DISABLE */
62106

63107
/**
64108
* @brief See if IRQs are currently enabled

sys/debug_irq_disable/debug_irq_disable.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,28 @@
1919

2020
#include <stdbool.h>
2121
#include "fmt.h"
22+
#include "debug_irq_disable.h"
2223

2324
void debug_irq_disable_print(const char *file, unsigned line, uint32_t ticks)
2425
{
25-
static bool is_printing;
26+
static unsigned is_printing;
27+
static unsigned init_skip = 10;
28+
29+
/* if we try to print before libc is initialized, we will hard fault */
30+
if (init_skip && --init_skip) {
31+
return;
32+
}
2633

2734
if (is_printing) {
2835
return;
2936
}
3037

38+
if (ticks < CONFIG_DEBUG_IRQ_DISABLE_THRESHOLD) {
39+
return;
40+
}
41+
3142
/* prevent infinite recursion if stdio driver uses irq_disable() */
32-
is_printing = true;
43+
++is_printing;
3344

3445
print_str("irq disabled for ");
3546
print_u32_dec(ticks);
@@ -39,5 +50,5 @@ void debug_irq_disable_print(const char *file, unsigned line, uint32_t ticks)
3950
print_u32_dec(line);
4051
print_str("\n");
4152

42-
is_printing = false;
53+
--is_printing;
4354
}

sys/include/debug_irq_disable.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@
2626
extern "C" {
2727
#endif
2828

29+
/**
30+
* @brief Threshold (in CPU ticks) below which periods with IRQs
31+
* disabled are not printed.
32+
*
33+
* Use this to prevent *a lot* of output when debugging.
34+
*/
35+
#ifndef CONFIG_DEBUG_IRQ_DISABLE_THRESHOLD
36+
#define CONFIG_DEBUG_IRQ_DISABLE_THRESHOLD (1)
37+
#endif
38+
2939
/**
3040
* @brief Print time spent with IRQ disabled
3141
* @internal

0 commit comments

Comments
 (0)