Skip to content

Commit c012318

Browse files
dlechdpgeorge
authored andcommitted
unix: Implement -X realtime command-line option on macOS.
This adds a new command line option to the unix port `-X realtime` to enable realtime priority on threads. This enables high precision timers for applications that need more accurate timers. Related docs: https://developer.apple.com/library/archive/technotes/tn2169/_index.html Fixes issue micropython#8621. Signed-off-by: David Lechner <[email protected]>
1 parent be5657b commit c012318

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

docs/unix/quickref.rst

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ General options:
7373
- ``-X heapsize=<n>[w][K|M]`` sets the heap size for the garbage collector.
7474
The suffix ``w`` means words instead of bytes. ``K`` means x1024 and ``M``
7575
means x1024x1024.
76+
- ``-X realtime`` sets thread priority to realtime. This can be used to
77+
improve timer precision. Only available on macOS.
7678

7779

7880

ports/unix/main.c

+13
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ STATIC void print_help(char **argv) {
328328
, heap_size);
329329
impl_opts_cnt++;
330330
#endif
331+
#if defined(__APPLE__)
332+
printf(" realtime -- set thread priority to realtime\n");
333+
impl_opts_cnt++;
334+
#endif
331335

332336
if (impl_opts_cnt == 0) {
333337
printf(" (none)\n");
@@ -399,6 +403,15 @@ STATIC void pre_process_options(int argc, char **argv) {
399403
goto invalid_arg;
400404
}
401405
#endif
406+
#if defined(__APPLE__)
407+
} else if (strcmp(argv[a + 1], "realtime") == 0) {
408+
#if MICROPY_PY_THREAD
409+
mp_thread_is_realtime_enabled = true;
410+
#endif
411+
// main thread was already intialized before the option
412+
// was parsed, so we have to enable realtime here.
413+
mp_thread_set_realtime();
414+
#endif
402415
} else {
403416
invalid_arg:
404417
exit(invalid_args());

ports/unix/mpthreadport.c

+43
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ void mp_thread_set_state(mp_state_thread_t *state) {
192192
}
193193

194194
void mp_thread_start(void) {
195+
// enable realtime priority if `-X realtime` command line parameter was set
196+
#if defined(__APPLE__)
197+
if (mp_thread_is_realtime_enabled) {
198+
mp_thread_set_realtime();
199+
}
200+
#endif
201+
195202
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
196203
mp_thread_unix_begin_atomic_section();
197204
for (mp_thread_t *th = thread; th != NULL; th = th->next) {
@@ -310,3 +317,39 @@ void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
310317
}
311318

312319
#endif // MICROPY_PY_THREAD
320+
321+
// this is used even when MICROPY_PY_THREAD is disabled
322+
323+
#if defined(__APPLE__)
324+
#include <mach/mach_error.h>
325+
#include <mach/mach_time.h>
326+
#include <mach/thread_act.h>
327+
#include <mach/thread_policy.h>
328+
329+
bool mp_thread_is_realtime_enabled;
330+
331+
// based on https://developer.apple.com/library/archive/technotes/tn2169/_index.html
332+
void mp_thread_set_realtime(void) {
333+
mach_timebase_info_data_t timebase_info;
334+
335+
mach_timebase_info(&timebase_info);
336+
337+
const uint64_t NANOS_PER_MSEC = 1000000ULL;
338+
double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
339+
340+
thread_time_constraint_policy_data_t policy;
341+
policy.period = 0;
342+
policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
343+
policy.constraint = (uint32_t)(10 * clock2abs);
344+
policy.preemptible = FALSE;
345+
346+
int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
347+
THREAD_TIME_CONSTRAINT_POLICY,
348+
(thread_policy_t)&policy,
349+
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
350+
351+
if (kr != KERN_SUCCESS) {
352+
mach_error("thread_policy_set:", kr);
353+
}
354+
}
355+
#endif

ports/unix/mpthreadport.h

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include <pthread.h>
28+
#include <stdbool.h>
2829

2930
typedef pthread_mutex_t mp_thread_mutex_t;
3031

@@ -36,3 +37,9 @@ void mp_thread_gc_others(void);
3637
// Functions as a port-global lock for any code that must be serialised.
3738
void mp_thread_unix_begin_atomic_section(void);
3839
void mp_thread_unix_end_atomic_section(void);
40+
41+
// for `-X realtime` command line option
42+
#if defined(__APPLE__)
43+
extern bool mp_thread_is_realtime_enabled;
44+
void mp_thread_set_realtime(void);
45+
#endif

0 commit comments

Comments
 (0)