aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests/nice/nice_test.cpp
blob: c45b047d9ed1bc3413af14adde95b06861ae38f9 (plain) (blame)
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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/util/nice.h>
#include <vespa/vespalib/test/thread_meets.h>
#include <vespa/vespalib/testkit/test_kit.h>
#include <unistd.h>
#include <functional>
#include <thread>

using vespalib::Runnable;
using vespalib::be_nice;
using vespalib::test::ThreadMeets;

double how_nice(int now, int target) {
    int max = 19;
    int wanted_param = (target - now);
    int num_zones = ((max + 1) - now);
    // make sure we are in the middle of the wanted nice zone
    double result = (0.5 + wanted_param) / num_zones;
    fprintf(stderr, " ... using how_nice=%g to get from %d to %d in nice value\n", result, now, target);
    return result;
}

struct RunFun : Runnable {
    std::function<void()> my_fun;
    RunFun(std::function<void()> fun_in) : my_fun(fun_in) {}
    void run() override { my_fun(); }
};

int my_init_fun(Runnable &target) {
    target.run();
    return 1;
}

std::thread run_with_init(std::function<void()> my_fun, Runnable::init_fun_t init_fun = my_init_fun) {
    return std::thread([init_fun, my_fun]
                       {
                           RunFun run_fun(my_fun);
                           init_fun(run_fun);
                       });
}

TEST("require that initial nice value is 0") {
    EXPECT_EQUAL(nice(0), 0);
}

TEST("require that nice value is tracked per thread") {
    ThreadMeets::Nop barrier(5);
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.push_back(run_with_init([my_barrier = &barrier, i]
                                        {
                                            [[maybe_unused]] auto nice_result = nice(i);
                                            (*my_barrier)();
                                            EXPECT_EQUAL(nice(0), i);
                                        }));
    }
    for (auto &thread: threads) {
        thread.join();
    }
}

void verify_max_nice_value() {
    int now = nice(0);
    now = nice(19 - now);
    EXPECT_EQUAL(now, 19);
    now = nice(1);
    EXPECT_EQUAL(now, 19);
}

TEST("require that max nice value is 19") {
    auto thread = run_with_init([]{ verify_max_nice_value(); });
    thread.join();
}

TEST("require that nice value can be set with init function") {
    for (int i = 0; i <= 19; ++i) {
        auto thread = run_with_init([i]()
                                    {
                                        EXPECT_EQUAL(nice(0), i);
                                    }, be_nice(my_init_fun, how_nice(0, i)));
        thread.join();
    }
}

TEST("require that niceness can be nested and will act on a limited nice value range") {
    auto thread1 = run_with_init([]{ EXPECT_EQUAL(nice(0), 7); },
                                 be_nice(be_nice(my_init_fun, how_nice(3, 7)), how_nice(0, 3)));
    auto thread2 = run_with_init([]{ EXPECT_EQUAL(nice(0), 15); },
                                 be_nice(be_nice(my_init_fun, how_nice(10, 15)), how_nice(0, 10)));
    auto thread3 = run_with_init([]{ EXPECT_EQUAL(nice(0), 19); },
                                 be_nice(be_nice(my_init_fun, how_nice(10, 19)), how_nice(0, 10)));
    thread1.join();
    thread2.join();
    thread3.join();
}

TEST_MAIN() { TEST_RUN_ALL(); }