MetaIRQ Thread Priority Demonstration

Overview

This sample demonstrates the use of a thread running at a MetaIRQ priority level to implement “bottom half” style processing synchronously with the end of a hardware ISR. It implements a simulated “device” that produces messages that need to be dispatched to asynchronous queues feeding several worker threads, each running at a different priority. The dispatch is handled by a MetaIRQ thread fed via a queue from the device ISR (really just a timer interrupt).

Each message has a random (and non-trivial) amount of processing that must happen in the worker thread. This implements a “bursty load” environment where occasional spikes in load require preemption of running threads and delay scheduling of lower priority threads. Messages are accompanied by a timestamp that allows per-message latencies to be computed at several points:

  • The cycle time between message creation in the ISR and receipt by the MetaIRQ thread for dispatch.

  • The time between ISR and receipt by the worker thread.

  • The real time spent processing the message in the worker thread, for comparison with the required processing time. This provides a way to measure preemption overhead where the thread is not scheduled.

Aspects to note in the results:

  • On average, higher priority (lower numbered) threads have better latencies and lower processing delays, as expected.

  • Cooperatively scheduled threads have significantly better processing delay behavior than preemptible ones, as they can only be preempted by the MetaIRQ thread.

  • Because of queueing and the bursty load, all worker threads of any priority will experience some load-dependent delays, as the CPU occasionally has more work to do than time available.

  • But, no matter the system load or thread configuration, the MetaIRQ thread always runs immediately after the ISR. It shows reliable, constant latency under all circumstances because it can preempt all other threads, including cooperative ones that cannot normally be preempted.

Requirements

This sample should run well on any Zephyr platform that provides preemption of running threads by interrupts, a working timer driver, and working log output. For precision reasons, it produces better (and more) data on systems with a high timer tick rate (ideally 10+ kHz).

Note that because the test is fundamentally measuring thread preemption behavior, it does not run without modification on native_sim platforms. In that emulation environment, threads will not be preempted except at specific instrumentation points (e.g. in k_busy_wait()) where they will voluntarily release the CPU.

Building and Running

This application can be built and executed on frdm_k64f as follows:

west build -b frdm_k64f samples/kernel/metairq_dispatch
west flash

To build for another board, change “frdm_k64f” above to that board’s name.

Sample Output

Sample output shown below is from frdm_k64f. The numbers will look different based upon the clock frequency of the board and other factors.

Note: The ‘real’ values may be significantly higher than corresponding ‘proc’ values (intended) for non-cooperative threads like T2 and T3 which is attributed to delays due to thread preemption.

I: Starting Thread0 at priority -2
I: Starting Thread1 at priority -1
II: M0 T0 mirq 4478 disp 7478 proc 24336 real 24613
I: M8 T0 mirq 4273 disp 86983 proc 9824 real 16753
I: M10 T0 mirq 4273 disp 495455 proc 21177 real 28273
I: M11 T0 mirq 4273 disp 981565 proc 48337 real 48918
I: M14 T0 mirq 4273 disp 1403627 proc 7079 real 7690
I: M17 T0 mirq 4273 disp 1810028 proc 42143 real 42925
I: M19 T0 mirq 4273 disp 2369217 proc 42471 real 42925
I: M20 T0 mirq 4273 disp 2940429 proc 30427 real 30775
I: M21 T0 mirq 4273 disp 3524151 proc 35871 real 36850
I: M22 T0 mirq 4273 disp 4042148 proc 33738 real 34420
I: M23 T0 mirq 4273 disp 4557010 proc 5757 real 6475
I: M29 T0 mirq 4273 disp 4759422 proc 49748 real 50215
I: M33 T0 mirq 4273 disp 5218935 proc 32105 real 33205
I: M35 T0 mirq 4273 disp 5732769 proc 32678 real 33205
I: M36 T0 mirq 4273 disp 6294586 proc 9303 real 10120
I: M37 T0 mirq 4273 disp 6819398 proc 29960 real 30775
I: M40 T0 mirq 3189 disp 7199139 proc 19692 real 21055
I: M9 T1 mirq 4273 disp 9417562 proc 53844 real 55075
I: M18 T1 mirq 4273 disp 9522780 proc 4560 real 5260
I: M25 T1 mirq 4273 disp 9713189 proc 56656 real 57505
I: M27 T1 mirq 4273 disp 10238978 proc 48347 real 49000
: Starting Thread2 at priority 0
I: M1 T2 mirq 4273 disp 12740821 proc 40449 real 41710
I: M2 T2 mirq 4273 disp 13311098 proc 43926 real 44140
I: M3 T2 mirq 4273 disp 13824365 proc 41212 real 41710
I: M4 T2 mirq 4273 disp 14382522 proc 12859 real 13765
I: M5 T2 mirq 4273 disp 14869754 proc 17303 real 18625
I: M7 T2 mirq 4273 disp 15368993 proc 10666 real 11335
I: M15 T2 mirq 4273 disp 15364239 proc 45304 real 46570
I: M24 T2 mirq 4273 disp 15602017 proc 39637 real 40495
I: M28 T2 mirq 4273 disp 15989555 proc 24436 real 24700
I: M30 T2 mirq 4273 disp 16493444 proc 44374 real 45355
I: M31 T2 mirq 4273 disp 17078141 proc 21947 real 22270
I: M34 T2 mirq 4273 disp 17555966 proc 47779 real 49000
I: M39 T2 mirq 4273 disp 17843806 proc 10954 real 11335
I: Starting Thread3 at priority 1
I: M6 T3 mirq 4273 disp 20625899 proc 13459 real 13765
I: M12 T3 mirq 4273 disp 20813171 proc 13534 real 13765
I: M13 T3 mirq 4273 disp 21334833 proc 37091 real 38065
I: M16 T3 mirq 4273 disp 21744289 proc 42514 real 42925
I: M26 T3 mirq 4273 disp 21846939 proc 36261 real 36850
I: M32 T3 mirq 4273 disp 22207336 proc 49987 real 50215
I: M38 T3 mirq 4273 disp 22532228 proc 37164 real 38065
I:         ---------- Latency (cyc) ----------
I:             Best    Worst     Mean    Stdev
I: MetaIRQ     4273     4478     4278       32
I: Thread0     7478  6819398  3190200  2183592
I: Thread1  9417562 10238978  9723127   316113
I: Thread2 12740821 17843806 15417286  1525493
I: Thread3 20625899 22532228 21586385   649911
I: MetaIRQ Test Complete