liyujie
2025-08-28 b3810562527858a3b3d98ffa6e9c9c5b0f4a9a8e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Copyright (c) 2018 Google, Inc.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * A test schedboost cgroup is created and a task is put inside it. The
 * utilization of that task is monitored and verified while changing the boost
 * of the test schedboost cgroup to different values.
 */
 
#define _GNU_SOURCE
#include <errno.h>
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
#include <time.h>
 
#include "tst_test.h"
#include "tst_safe_file_ops.h"
#include "tst_safe_pthread.h"
#include "tst_safe_macros.h"
 
#include "trace_parse.h"
#include "util.h"
 
#define TRACE_EVENTS "sugov_util_update sched_switch"
 
static sem_t test_sem;
static sem_t result_sem;
static int test_cpu;
static int task_pid;
static unsigned int test_index = 0;
static int test_boost[] = { 0, 25, 50, 75, 100 };
#define NUM_TESTS (sizeof(test_boost)/sizeof(int))
static int test_utils[NUM_TESTS];
#define STUNE_TEST_PATH "/dev/stune/test"
#define STUNE_ROOT_TASKS "/dev/stune/tasks"
 
#define BUSY_USEC 1000
#define SLEEP_USEC 19000
/* Run each test for one second. */
#define TEST_LENGTH_USEC USEC_PER_SEC
static void do_work(void)
{
   struct timespec ts;
   unsigned long long now_usec, end_usec;
 
   /* Calculate overall end time. */
   if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
       printf("clock_gettime() reported an error\n");
       return;
   }
   now_usec = ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / 1000;
   end_usec = now_usec + TEST_LENGTH_USEC;
 
   while (now_usec < end_usec) {
       burn(BUSY_USEC, 0);
       usleep(SLEEP_USEC);
       if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
           printf("clock_gettime() reported an error\n");
           return;
       }
       now_usec = ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / 1000;
   }
}
 
static void *test_fn(void *arg LTP_ATTRIBUTE_UNUSED)
{
   unsigned int tests_done = 0;
 
   affine(test_cpu);
 
   task_pid = gettid();
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/tasks", "%d", task_pid);
   while(tests_done < NUM_TESTS) {
       sem_wait(&test_sem);
       do_work();
       sem_post(&result_sem);
       tests_done++;
   }
   SAFE_FILE_PRINTF(STUNE_ROOT_TASKS, "%d", task_pid);
   return NULL;
}
 
static int parse_results(void)
{
   int i;
   int max_util_seen = 0;
 
   for (i = 0; i < num_trace_records; i++)
       if (trace[i].event_type == TRACE_RECORD_SUGOV_UTIL_UPDATE) {
           struct trace_sugov_util_update *t =
               trace[i].event_data;
           if (t->cpu == test_cpu && t->util > max_util_seen)
               max_util_seen = t->util;
       }
 
   test_utils[test_index] = max_util_seen;
   printf("Max util seen for boost %d: %d\n", test_boost[test_index],
          max_util_seen);
   return 0;
}
 
static void run_test(void)
{
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/schedtune.boost",
            "%d", test_boost[test_index]);
   SAFE_FILE_PRINTF(TRACING_DIR "trace", "\n");
   SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "1");
   sem_post(&test_sem);
   sem_wait(&result_sem);
   SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
   LOAD_TRACE();
   parse_results();
   test_index++;
}
 
#define TEST_MARGIN 50
static void check_results(void)
{
   unsigned int i;
   for (i = 0; i < NUM_TESTS; i++) {
       int target_util = test_boost[i] * 10;
       if (test_utils[i] < target_util - TEST_MARGIN ||
           test_utils[i] > target_util + TEST_MARGIN)
           tst_res(TFAIL, "Test %i (boost %d) failed with "
               "util %d (allowed %d - %d).\n",
               i, test_boost[i], test_utils[i],
               target_util - TEST_MARGIN,
               target_util + TEST_MARGIN);
   }
   tst_res(TPASS, "Boosted utilizations within expected range.");
}
 
static void run(void)
{
   pthread_t test_thread;
 
   sem_init(&test_sem, 0, 0);
   sem_init(&result_sem, 0, 0);
 
   test_cpu = tst_ncpus() - 1;
   printf("Running %ld tests for %d sec\n", NUM_TESTS,
          TEST_LENGTH_USEC / USEC_PER_SEC);
   printf("CPU hog will be bound to CPU %d.\n", test_cpu);
 
   /*
    * If this fails due to ENOSPC the definition of BOOSTGROUPS_COUNT in
    * kernel/sched/tune.c needs to be increased.
    */
   SAFE_MKDIR(STUNE_TEST_PATH, 0777);
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/schedtune.colocate",
            "0");
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/schedtune.prefer_idle",
            "0");
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/schedtune.sched_boost_enabled",
            "1");
   SAFE_FILE_PRINTF(STUNE_TEST_PATH "/schedtune.sched_boost_no_override",
            "0");
 
   SAFE_PTHREAD_CREATE(&test_thread, NULL, test_fn, NULL);
 
   SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
   SAFE_FILE_PRINTF(TRACING_DIR "buffer_size_kb", "16384");
   SAFE_FILE_PRINTF(TRACING_DIR "set_event", TRACE_EVENTS);
 
   while (test_index < NUM_TESTS)
       run_test();
 
   SAFE_PTHREAD_JOIN(test_thread, NULL);
   SAFE_RMDIR(STUNE_TEST_PATH);
   check_results();
}
 
static struct tst_test test = {
   .test_all = run,
   .cleanup = trace_cleanup,
};