159 lines
3.6 KiB
C
159 lines
3.6 KiB
C
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
|
/*
|
||
|
|
* Copyright(c) 2022 Huawei Technologies Co., Ltd
|
||
|
|
* Author: Li Mengfei <limengfei4@huawei.com>
|
||
|
|
* Zhao Gongyi <zhaogongyi@huawei.com>
|
||
|
|
*/
|
||
|
|
|
||
|
|
/*\
|
||
|
|
* [Description]
|
||
|
|
*
|
||
|
|
* 1. Create a high nice thread and a low nice thread, the main
|
||
|
|
* thread wake them at the same time
|
||
|
|
* 2. Both threads run on the same CPU
|
||
|
|
* 3. Verify that the low nice thread executes more time than
|
||
|
|
* the high nice thread
|
||
|
|
*/
|
||
|
|
|
||
|
|
#define _GNU_SOURCE
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include "tst_test.h"
|
||
|
|
#include "tst_safe_pthread.h"
|
||
|
|
#include "lapi/syscalls.h"
|
||
|
|
#include "tst_safe_clocks.h"
|
||
|
|
#include "tst_timer.h"
|
||
|
|
|
||
|
|
static pthread_barrier_t barrier;
|
||
|
|
|
||
|
|
static void set_nice(int nice_inc)
|
||
|
|
{
|
||
|
|
int orig_nice;
|
||
|
|
|
||
|
|
orig_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0);
|
||
|
|
|
||
|
|
TEST(nice(nice_inc));
|
||
|
|
|
||
|
|
if (TST_RET != (orig_nice + nice_inc)) {
|
||
|
|
tst_brk(TBROK | TTERRNO, "nice(%d) returned %li, expected %i",
|
||
|
|
nice_inc, TST_RET, orig_nice + nice_inc);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (TST_ERR)
|
||
|
|
tst_brk(TBROK | TTERRNO, "nice(%d) failed", nice_inc);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void do_something(void)
|
||
|
|
{
|
||
|
|
volatile int number = 0;
|
||
|
|
|
||
|
|
while (1) {
|
||
|
|
number++;
|
||
|
|
|
||
|
|
TEST(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
|
||
|
|
if (TST_RET != 0) {
|
||
|
|
tst_brk(TBROK | TRERRNO,
|
||
|
|
"pthread_setcancelstate() failed");
|
||
|
|
}
|
||
|
|
pthread_testcancel();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void *thread_fn(void *arg)
|
||
|
|
{
|
||
|
|
set_nice((intptr_t)arg);
|
||
|
|
SAFE_PTHREAD_BARRIER_WAIT(&barrier);
|
||
|
|
do_something();
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void setup(void)
|
||
|
|
{
|
||
|
|
size_t size;
|
||
|
|
size_t i;
|
||
|
|
int nrcpus = 1024;
|
||
|
|
cpu_set_t *set;
|
||
|
|
int some_cpu;
|
||
|
|
|
||
|
|
set = CPU_ALLOC(nrcpus);
|
||
|
|
if (!set)
|
||
|
|
tst_brk(TBROK | TERRNO, "CPU_ALLOC()");
|
||
|
|
|
||
|
|
size = CPU_ALLOC_SIZE(nrcpus);
|
||
|
|
CPU_ZERO_S(size, set);
|
||
|
|
if (sched_getaffinity(0, size, set) < 0)
|
||
|
|
tst_brk(TBROK | TERRNO, "sched_getaffinity()");
|
||
|
|
|
||
|
|
for (i = 0; i < size * 8; i++)
|
||
|
|
if (CPU_ISSET_S(i, size, set))
|
||
|
|
some_cpu = i;
|
||
|
|
|
||
|
|
CPU_ZERO_S(size, set);
|
||
|
|
CPU_SET_S(some_cpu, size, set);
|
||
|
|
if (sched_setaffinity(0, size, set) < 0)
|
||
|
|
tst_brk(TBROK | TERRNO, "sched_setaffinity()");
|
||
|
|
|
||
|
|
CPU_FREE(set);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void verify_nice(void)
|
||
|
|
{
|
||
|
|
intptr_t nice_inc_high = -1;
|
||
|
|
intptr_t nice_inc_low = -2;
|
||
|
|
clockid_t nice_low_clockid, nice_high_clockid;
|
||
|
|
struct timespec nice_high_ts, nice_low_ts;
|
||
|
|
long long delta;
|
||
|
|
pthread_t thread[2];
|
||
|
|
|
||
|
|
SAFE_PTHREAD_BARRIER_INIT(&barrier, NULL, 3);
|
||
|
|
|
||
|
|
SAFE_PTHREAD_CREATE(&thread[0], NULL, thread_fn,
|
||
|
|
(void *)nice_inc_high);
|
||
|
|
SAFE_PTHREAD_CREATE(&thread[1], NULL, thread_fn,
|
||
|
|
(void *)nice_inc_low);
|
||
|
|
|
||
|
|
SAFE_PTHREAD_BARRIER_WAIT(&barrier);
|
||
|
|
|
||
|
|
sleep(tst_remaining_runtime());
|
||
|
|
|
||
|
|
TEST(pthread_getcpuclockid(thread[1], &nice_low_clockid));
|
||
|
|
if (TST_RET != 0)
|
||
|
|
tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed");
|
||
|
|
|
||
|
|
TEST(pthread_getcpuclockid(thread[0], &nice_high_clockid));
|
||
|
|
if (TST_RET != 0)
|
||
|
|
tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed");
|
||
|
|
|
||
|
|
SAFE_CLOCK_GETTIME(nice_low_clockid, &nice_low_ts);
|
||
|
|
SAFE_CLOCK_GETTIME(nice_high_clockid, &nice_high_ts);
|
||
|
|
|
||
|
|
tst_res(TINFO, "Nice low thread CPU time: %ld.%09ld s",
|
||
|
|
nice_low_ts.tv_sec, nice_low_ts.tv_nsec);
|
||
|
|
tst_res(TINFO, "Nice high thread CPU time: %ld.%09ld s",
|
||
|
|
nice_high_ts.tv_sec, nice_high_ts.tv_nsec);
|
||
|
|
|
||
|
|
delta = tst_timespec_diff_ns(nice_low_ts, nice_high_ts);
|
||
|
|
if (delta < 0) {
|
||
|
|
tst_res(TFAIL, "executes less cycles than "
|
||
|
|
"the high nice thread, delta: %lld ns", delta);
|
||
|
|
} else {
|
||
|
|
tst_res(TPASS, "executes more cycles than "
|
||
|
|
"the high nice thread, delta: %lld ns", delta);
|
||
|
|
}
|
||
|
|
|
||
|
|
SAFE_PTHREAD_CANCEL(thread[0]);
|
||
|
|
SAFE_PTHREAD_CANCEL(thread[1]);
|
||
|
|
SAFE_PTHREAD_BARRIER_DESTROY(&barrier);
|
||
|
|
SAFE_PTHREAD_JOIN(thread[0], NULL);
|
||
|
|
SAFE_PTHREAD_JOIN(thread[1], NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static struct tst_test test = {
|
||
|
|
.setup = setup,
|
||
|
|
.test_all = verify_nice,
|
||
|
|
.needs_root = 1,
|
||
|
|
.max_runtime = 3,
|
||
|
|
};
|