From 97a61ff23aa9386cff7ee3f93623ef57d47dddf4 Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Thu, 28 Aug 2025 16:43:53 +0200 Subject: [PATCH 1/3] rt-app: Fix page locking order and remove forced lock_pages override - Move page locking (mlockall) to execute before setting thread parameters - Remove forced 'data->lock_pages = 0' override for SCHED_IDLE tasks, as locking pages and scheduling policies are orthogonal and should be configured separately by the user - This ensures page locking happens early in thread initialization The change ensures that when lock_pages is enabled, memory pages are locked before any scheduling policy changes occur, which is important for real-time applications that need deterministic memory access patterns. Especially for SCHED_DEADLINE, locking pages after starting the first iteration might cause deadline misses. Fixes: 5890dd3 ("rt-app: Reorder page locking to properly skip it for SCHED_OTHER/IDLE") Signed-off-by: Juri Lelli --- src/rt-app.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/rt-app.c b/src/rt-app.c index f1b4c14..e5ec181 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -1130,7 +1130,6 @@ static void set_thread_param(thread_data_t *data, sched_data_t *sched_data) case idle: _set_thread_cfs(data, sched_data); _set_thread_uclamp(data, sched_data); - data->lock_pages = 0; /* forced off */ break; case deadline: _set_thread_deadline(data, sched_data); @@ -1199,6 +1198,17 @@ void *thread_body(void *arg) if (!data->forked) pthread_barrier_wait(&threads_barrier); + /* Lock pages */ + if (data->lock_pages == 1) + { + log_notice("[%d] Locking pages in memory", data->ind); + ret = mlockall(MCL_CURRENT | MCL_FUTURE); + if (ret != 0) { + perror("mlockall"); + exit(EXIT_FAILURE); + } + } + t_first = t_zero; log_notice("[%d] starting thread ...\n", data->ind); @@ -1234,17 +1244,6 @@ void *thread_body(void *arg) set_thread_membind(data, &data->numa_data); set_thread_taskgroup(data, data->taskgroup_data); - /* Lock pages */ - if (data->lock_pages == 1) - { - log_notice("[%d] Locking pages in memory", data->ind); - ret = mlockall(MCL_CURRENT | MCL_FUTURE); - if (ret != 0) { - perror("mlockall"); - exit(EXIT_FAILURE); - } - } - /* * phase - index of current phase in data->phases array * phase_loop - current iteration of current phase From 5ba2ec0aeec9795da5360e6ff42dbbf07531a52a Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Thu, 28 Aug 2025 17:07:26 +0200 Subject: [PATCH 2/3] Add ftrace events for lockpages and setparam So it's easier to understand when a task is actually ready for entering the first actual phase. Signed-off-by: Juri Lelli --- src/rt-app.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rt-app.c b/src/rt-app.c index e5ec181..32bdc8f 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -1141,6 +1141,10 @@ static void set_thread_param(thread_data_t *data, sched_data_t *sched_data) } data->curr_sched_data = sched_data; + + log_ftrace(ft_data.marker_fd, FTRACE_TASK, + "rtapp_task: event=setparam policy=%s", + policy_to_string(sched_data->policy)); } void setup_thread_gnuplot(thread_data_t *tdata); @@ -1207,6 +1211,8 @@ void *thread_body(void *arg) perror("mlockall"); exit(EXIT_FAILURE); } + log_ftrace(ft_data.marker_fd, FTRACE_TASK, + "rtapp_task: event=mlockall"); } t_first = t_zero; From 467a784d3cb66a489e131f1ae98db18989524406 Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Thu, 28 Aug 2025 18:20:13 +0200 Subject: [PATCH 3/3] Set t_first right before the first phase Otherwise timers might be skewed. Signed-off-by: Juri Lelli --- src/rt-app.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rt-app.c b/src/rt-app.c index 32bdc8f..5f9f3e5 100644 --- a/src/rt-app.c +++ b/src/rt-app.c @@ -1242,6 +1242,8 @@ void *thread_body(void *arg) * budget as little as possible for the first iteration. */ + clock_gettime(CLOCK_MONOTONIC, &t_first); + /* Set scheduling policy and print pretty info on stdout */ log_notice("[%d] Starting with %s policy with priority %d", data->ind, policy_to_string(data->sched_data->policy),