File: tester.cpp

package info (click to toggle)
libdivide 5.2.0-0.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 17,564 kB
  • sloc: ansic: 131,647; cpp: 70,136; python: 47; makefile: 3
file content (149 lines) | stat: -rw-r--r-- 4,789 bytes parent folder | download
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
// Usage: tester [OPTIONS]
//
// You can pass the tester program one or more of the following options:
// u32, s32, u64, s64 or run it without arguments to test all four.
// The tester is multithreaded so it can test multiple cases simultaneously.
// The tester will verify the correctness of libdivide via a set of
// randomly chosen denominators, by comparing the result of libdivide's
// division to hardware division. It may take a long time to run, but it
// will output as soon as it finds a discrepancy.

// Silence MSVC sprintf unsafe warnings
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <thread>
#include <vector>

#include "DivideTest.h"
#include "libdivide.h"

// This is simply a regression test for #96: that the following all compile (and don't crash).
static void test_primitives_compile() {
    libdivide::divider<short> d0(1);
    libdivide::divider<int> d1(1);
    libdivide::divider<long> d2(1);
    libdivide::divider<long long> d3(1);

    libdivide::divider<unsigned short> u0(1);
    libdivide::divider<unsigned int> u1(1);
    libdivide::divider<unsigned long> u2(1);
    libdivide::divider<unsigned long long> u3(1);

    // These should fail to compile.
    // libdivide::divider<float> f0(1);
    // libdivide::divider<double> f1(1);
}

enum TestType {
    type_s16,
    type_u16,
    type_s32,
    type_u32,
    type_s64,
    type_u64,
};

void wait_for_threads(std::vector<std::thread> &test_threads) {
    for (auto &t : test_threads) {
        t.join();
    }
}

uint8_t get_max_threads() { return (uint8_t)std::max(1U, std::thread::hardware_concurrency()); }

template <typename _IntT>
void launch_test_thread(std::vector<std::thread> &test_threads) {
    static uint8_t max_threads = get_max_threads();

    if (max_threads == test_threads.size()) {
        wait_for_threads(test_threads);
        test_threads.clear();
    }
    test_threads.emplace_back(run_test<_IntT>);
}

extern "C" int main(int argc, char *argv[]) {
    bool default_do_test = (argc <= 1);
    std::vector<bool> do_tests(6, default_do_test);

    test_primitives_compile();

    for (int i = 1; i < argc; i++) {
        const std::string arg(argv[i]);
        if (arg == type_tag<int16_t>::get_tag())
            do_tests[type_s16] = true;
        else if (arg == type_tag<uint16_t>::get_tag())
            do_tests[type_u16] = true;
        else if (arg == type_tag<int32_t>::get_tag())
            do_tests[type_s32] = true;
        else if (arg == type_tag<uint32_t>::get_tag())
            do_tests[type_u32] = true;
        else if (arg == type_tag<int64_t>::get_tag())
            do_tests[type_s64] = true;
        else if (arg == type_tag<uint64_t>::get_tag())
            do_tests[type_u64] = true;
        else {
            std::cout
                << "Usage: tester [OPTIONS]\n"
                   "\n"
                   "You can pass the tester program one or more of the following options:\n"
                   "u16, s16, u32, s32, u64, s64 or run it without arguments to test all four.\n"
                   "The tester is multithreaded so it can test multiple cases simultaneously.\n"
                   "The tester will verify the correctness of libdivide via a set of\n"
                   "randomly chosen denominators, by comparing the result of libdivide's\n"
                   "division to hardware division. It may take a long time to run, but it\n"
                   "will output as soon as it finds a discrepancy."
                << std::endl;
            exit(1);
        }
    }

    std::cout << "Testing libdivide v" << LIBDIVIDE_VERSION << std::endl;
    std::string vecTypes = "";
#if defined(LIBDIVIDE_SSE2)
    vecTypes += "sse2 ";
#endif
#if defined(LIBDIVIDE_AVX2)
    vecTypes += "avx2 ";
#endif
#if defined(LIBDIVIDE_AVX512)
    vecTypes += "avx512 ";
#endif
#if defined(LIBDIVIDE_NEON)
    vecTypes += "neon ";
#endif
    if (vecTypes.empty()) {
        vecTypes = "none ";
    }
    vecTypes.back() = '\n';  // trailing space
    std::cout << "Testing with SIMD ISAs: " << vecTypes;

    // Run tests in threads.
    std::vector<std::thread> test_threads;

    if (do_tests[type_s16]) {
        launch_test_thread<int16_t>(test_threads);
    }
    if (do_tests[type_u16]) {
        launch_test_thread<uint16_t>(test_threads);
    }
    if (do_tests[type_s32]) {
        launch_test_thread<int32_t>(test_threads);
    }
    if (do_tests[type_u32]) {
        launch_test_thread<uint32_t>(test_threads);
    }
    if (do_tests[type_s64]) {
        launch_test_thread<int64_t>(test_threads);
    }
    if (do_tests[type_u64]) {
        launch_test_thread<uint64_t>(test_threads);
    }

    wait_for_threads(test_threads);

    std::cout << "\nAll tests passed successfully!" << std::endl;
    return 0;
}