From cd10b487e24f495abba772d0f926fd8e6cd79b7b Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Mon, 22 May 2023 22:27:17 +0100 Subject: [PATCH] u/linux: Add helpers to raise thread scheduling priority --- src/xrt/auxiliary/util/CMakeLists.txt | 5 + src/xrt/auxiliary/util/u_linux.c | 139 ++++++++++++++++++++++++++ src/xrt/auxiliary/util/u_linux.h | 39 ++++++++ 3 files changed, 183 insertions(+) create mode 100644 src/xrt/auxiliary/util/u_linux.c create mode 100644 src/xrt/auxiliary/util/u_linux.h diff --git a/src/xrt/auxiliary/util/CMakeLists.txt b/src/xrt/auxiliary/util/CMakeLists.txt index 5e8347ca1..e541ea66c 100644 --- a/src/xrt/auxiliary/util/CMakeLists.txt +++ b/src/xrt/auxiliary/util/CMakeLists.txt @@ -117,6 +117,11 @@ if(WIN32) target_sources(aux_util PRIVATE u_windows.c u_windows.h) endif() +# Only uses POSIX/Linux libraries, doesn't add anything extra. +if(XRT_HAVE_LINUX OR ANDROID) + target_sources(aux_util PRIVATE u_linux.c u_linux.h) +endif() + # Is basically used everywhere, unavoidable. if(XRT_HAVE_SYSTEM_CJSON) target_link_libraries(aux_util PUBLIC cJSON::cJSON) diff --git a/src/xrt/auxiliary/util/u_linux.c b/src/xrt/auxiliary/util/u_linux.c new file mode 100644 index 000000000..1724825c3 --- /dev/null +++ b/src/xrt/auxiliary/util/u_linux.c @@ -0,0 +1,139 @@ +// Copyright 2023, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Various helpers for doing Linux specific things. + * @author Jakob Bornecrantz + * + * @ingroup aux_util + */ + +#include "util/u_linux.h" +#include "util/u_pretty_print.h" + +#include +#include +#include +#include +#include + +#define LOG_D(...) U_LOG_IFL_D(log_level, __VA_ARGS__) +#define LOG_I(...) U_LOG_IFL_I(log_level, __VA_ARGS__) +#define LOG_W(...) U_LOG_IFL_W(log_level, __VA_ARGS__) +#define LOG_E(...) U_LOG_IFL_E(log_level, __VA_ARGS__) + +#define NAME_LENGTH 32 + + +/* + * + * Helper functions. + * + */ + +static const char * +policy_to_string(int policy) +{ + switch (policy) { + case SCHED_FIFO: return "SCHED_FIFO"; + case SCHED_RR: return "SCHED_RR"; + case SCHED_OTHER: return "SCHED_OTHER(normal)"; + case SCHED_IDLE: return "SCHED_IDLE"; + case SCHED_BATCH: return "SCHED_BATCH"; + default: return "SCHED_"; + } +} + +static void +get_name(char *str, size_t count) +{ + assert(str != NULL); + assert(count > 0); + + // First init. + str[0] = '\0'; + + // Get name of thread. + pthread_t this_thread = pthread_self(); + pthread_getname_np(this_thread, str, count); + + if (str[0] == '\0') { + snprintf(str, count, "tid(%i)", gettid()); + } +} + +static void +print_thread_info(struct u_pp_delegate dg, enum u_logging_level log_level, pthread_t thread) +{ + struct sched_param params; + int policy = 0; + int ret = 0; + + // Get the policy and scheduling priority. + ret = pthread_getschedparam(thread, &policy, ¶ms); + if (ret != 0) { + LOG_E("pthread_getschedparam: %i", ret); + return; + } + + u_pp(dg, "policy: '%s', priority: '%i'", policy_to_string(policy), params.sched_priority); +} + + +/* + * + * 'Exported' functions. + * + */ + +void +u_linux_try_to_set_realtime_priority_on_thread(enum u_logging_level log_level, const char *name) +{ + pthread_t this_thread = pthread_self(); + struct u_pp_sink_stack_only sink; + struct sched_param params; + char str[NAME_LENGTH]; + int ret; + + // Add printing delegate. + struct u_pp_delegate dg = u_pp_sink_stack_only_init(&sink); + + // Always have some name. + if (name == NULL) { + get_name(str, ARRAY_SIZE(str)); + name = str; + } + + if (log_level <= U_LOGGING_DEBUG) { + u_pp(dg, "Trying to raise priority on thread '%s'\n\t", name); + u_pp(dg, "before: "); + print_thread_info(dg, log_level, this_thread); + } + + // Get the maximum on this platform. + params.sched_priority = sched_get_priority_max(SCHED_FIFO); + + // Here we try to set the realtime scheduling with the max priority available. + ret = pthread_setschedparam(this_thread, SCHED_FIFO, ¶ms); + + // Print different amount depending on log level. + if (log_level <= U_LOGGING_DEBUG) { + u_pp(dg, "after: "); + print_thread_info(dg, log_level, this_thread); + u_pp(dg, "\n\tResult: %i", ret); + } else { + if (ret != 0) { + u_pp(dg, "Could not raise priority for thread '%s'", name); + } else { + u_pp(dg, "Raised priority of thread '%s' to ", name); + print_thread_info(dg, log_level, this_thread); + } + } + + // Always print as warning or information. + if (ret != 0) { + LOG_W("%s", sink.buffer); + } else { + LOG_I("%s", sink.buffer); + } +} diff --git a/src/xrt/auxiliary/util/u_linux.h b/src/xrt/auxiliary/util/u_linux.h new file mode 100644 index 000000000..31209049d --- /dev/null +++ b/src/xrt/auxiliary/util/u_linux.h @@ -0,0 +1,39 @@ +// Copyright 2023, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Various helpers for doing Linux specific things. + * @author Jakob Bornecrantz + * + * @ingroup aux_util + */ + +#pragma once + +#include "xrt/xrt_compiler.h" +#include "xrt/xrt_windows.h" +#include "util/u_logging.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*! + * Try to set realtime priority on this thread. Passing in log_level to control + * how chatty this function is, the name is to make the logging pretty, can be + * NULL and the code will try to figure out the name itself. + * + * @param name Thread name to be used in logging. + * @param log_level Logging level to control chattiness. + * + * @aux_util + */ +void +u_linux_try_to_set_realtime_priority_on_thread(enum u_logging_level log_level, const char *name); + + +#ifdef __cplusplus +} +#endif