u/linux: Add helpers to raise thread scheduling priority

This commit is contained in:
Jakob Bornecrantz 2023-05-22 22:27:17 +01:00
parent 50bc6c0731
commit cd10b487e2
3 changed files with 183 additions and 0 deletions

View file

@ -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)

View file

@ -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 <jakob@collabora.com>
*
* @ingroup aux_util
*/
#include "util/u_linux.h"
#include "util/u_pretty_print.h"
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <sched.h>
#include <stdio.h>
#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_<UNKNOWN>";
}
}
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, &params);
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, &params);
// 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);
}
}

View file

@ -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 <jakob@collabora.com>
*
* @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