summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDavid Lechner <david@lechnology.com>2022-05-03 22:26:29 -0500
committerDamien George <damien@micropython.org>2022-05-24 00:51:47 +1000
commitc012318d74fed232b1c872a1a0cacf91ebcb1b6d (patch)
tree90952f1815a9e1edc4d06e4d85a818b6a25ad66a
parentbe5657b64ff718bfeeab8f60d8ae12b31bbcbb89 (diff)
downloadmicropython-c012318d74fed232b1c872a1a0cacf91ebcb1b6d.tar.gz
micropython-c012318d74fed232b1c872a1a0cacf91ebcb1b6d.zip
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 #8621. Signed-off-by: David Lechner <david@pybricks.com>
-rw-r--r--docs/unix/quickref.rst2
-rw-r--r--ports/unix/main.c13
-rw-r--r--ports/unix/mpthreadport.c43
-rw-r--r--ports/unix/mpthreadport.h7
4 files changed, 65 insertions, 0 deletions
diff --git a/docs/unix/quickref.rst b/docs/unix/quickref.rst
index ec5312a535..2eac1edc79 100644
--- a/docs/unix/quickref.rst
+++ b/docs/unix/quickref.rst
@@ -73,6 +73,8 @@ General options:
- ``-X heapsize=<n>[w][K|M]`` sets the heap size for the garbage collector.
The suffix ``w`` means words instead of bytes. ``K`` means x1024 and ``M``
means x1024x1024.
+ - ``-X realtime`` sets thread priority to realtime. This can be used to
+ improve timer precision. Only available on macOS.
diff --git a/ports/unix/main.c b/ports/unix/main.c
index 8d7fcf4843..0e00db7fa2 100644
--- a/ports/unix/main.c
+++ b/ports/unix/main.c
@@ -328,6 +328,10 @@ STATIC void print_help(char **argv) {
, heap_size);
impl_opts_cnt++;
#endif
+ #if defined(__APPLE__)
+ printf(" realtime -- set thread priority to realtime\n");
+ impl_opts_cnt++;
+ #endif
if (impl_opts_cnt == 0) {
printf(" (none)\n");
@@ -399,6 +403,15 @@ STATIC void pre_process_options(int argc, char **argv) {
goto invalid_arg;
}
#endif
+ #if defined(__APPLE__)
+ } else if (strcmp(argv[a + 1], "realtime") == 0) {
+ #if MICROPY_PY_THREAD
+ mp_thread_is_realtime_enabled = true;
+ #endif
+ // main thread was already intialized before the option
+ // was parsed, so we have to enable realtime here.
+ mp_thread_set_realtime();
+ #endif
} else {
invalid_arg:
exit(invalid_args());
diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c
index 2ec7e65d3b..6a267e7236 100644
--- a/ports/unix/mpthreadport.c
+++ b/ports/unix/mpthreadport.c
@@ -192,6 +192,13 @@ void mp_thread_set_state(mp_state_thread_t *state) {
}
void mp_thread_start(void) {
+ // enable realtime priority if `-X realtime` command line parameter was set
+ #if defined(__APPLE__)
+ if (mp_thread_is_realtime_enabled) {
+ mp_thread_set_realtime();
+ }
+ #endif
+
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
mp_thread_unix_begin_atomic_section();
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) {
}
#endif // MICROPY_PY_THREAD
+
+// this is used even when MICROPY_PY_THREAD is disabled
+
+#if defined(__APPLE__)
+#include <mach/mach_error.h>
+#include <mach/mach_time.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+
+bool mp_thread_is_realtime_enabled;
+
+// based on https://developer.apple.com/library/archive/technotes/tn2169/_index.html
+void mp_thread_set_realtime(void) {
+ mach_timebase_info_data_t timebase_info;
+
+ mach_timebase_info(&timebase_info);
+
+ const uint64_t NANOS_PER_MSEC = 1000000ULL;
+ double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
+
+ thread_time_constraint_policy_data_t policy;
+ policy.period = 0;
+ policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
+ policy.constraint = (uint32_t)(10 * clock2abs);
+ policy.preemptible = FALSE;
+
+ int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
+ THREAD_TIME_CONSTRAINT_POLICY,
+ (thread_policy_t)&policy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+
+ if (kr != KERN_SUCCESS) {
+ mach_error("thread_policy_set:", kr);
+ }
+}
+#endif
diff --git a/ports/unix/mpthreadport.h b/ports/unix/mpthreadport.h
index a7dbe08c49..b365f200ed 100644
--- a/ports/unix/mpthreadport.h
+++ b/ports/unix/mpthreadport.h
@@ -25,6 +25,7 @@
*/
#include <pthread.h>
+#include <stdbool.h>
typedef pthread_mutex_t mp_thread_mutex_t;
@@ -36,3 +37,9 @@ void mp_thread_gc_others(void);
// Functions as a port-global lock for any code that must be serialised.
void mp_thread_unix_begin_atomic_section(void);
void mp_thread_unix_end_atomic_section(void);
+
+// for `-X realtime` command line option
+#if defined(__APPLE__)
+extern bool mp_thread_is_realtime_enabled;
+void mp_thread_set_realtime(void);
+#endif