9c004716e3034b0a8c2c5cccd45ca09858ac8962
[o-du/phy.git] / fhi_lib / test / common / common.cpp
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19
20 #include <cmath>
21 #include <fstream>
22 #include <numeric>
23
24 #ifndef _WIN64
25 #include <unistd.h>
26 #include <sys/syscall.h>
27 #else
28 #include <Windows.h>
29 #endif
30
31 #include "common.hpp"
32
33 #ifndef CPU_ID
34 #define CPU_ID 4
35 #endif
36
37 /* Required to avoid linker errors */
38 json KernelTests::conf;
39 std::string KernelTests::test_type;
40 unsigned long KernelTests::tsc;
41
42
43 long BenchmarkParameters::repetition = 40;
44 long BenchmarkParameters::loop = 30;
45 unsigned BenchmarkParameters::cpu_id = CPU_ID;
46
47 int bind_to_cpu(const unsigned cpu)
48 {
49 #ifndef _WIN64
50     const auto pid = syscall(SYS_gettid);
51     cpu_set_t mask {};
52     CPU_ZERO(&mask);
53     CPU_SET(cpu, &mask);
54     return sched_setaffinity(__pid_t(pid), sizeof(mask), &mask);
55 #else
56     return -1;
57 #endif
58 }
59
60 std::pair<double, double> calculate_statistics(const std::vector<long> values)
61 {
62     const auto sum = std::accumulate(values.begin(), values.end(), 0L);
63
64     const auto number_of_iterations = BenchmarkParameters::repetition *
65             BenchmarkParameters::loop;
66
67     const auto mean = sum / (double) number_of_iterations;
68
69     auto stddev_accumulator = 0.0;
70     for (auto v : values)
71         stddev_accumulator = pow((v / BenchmarkParameters::loop) - mean, 2);
72
73     const auto stddev = sqrt(stddev_accumulator / BenchmarkParameters::repetition);
74
75     return {mean, stddev};
76 }
77
78 std::vector<unsigned> get_sequence(const unsigned number)
79 {
80     std::vector<unsigned> sequence(number);
81     std::iota(sequence.begin(), sequence.end(), 0);
82
83     return sequence;
84 }
85
86 char* read_data_to_aligned_array(const std::string &filename)
87 {
88     std::ifstream input_stream(filename, std::ios::binary);
89
90     std::vector<char> buffer((std::istreambuf_iterator<char>(input_stream)),
91                               std::istreambuf_iterator<char>());
92
93     if(buffer.size() == 0)
94         throw reading_input_file_exception();
95
96     auto aligned_buffer = aligned_malloc<char>((int) buffer.size(), 64);
97
98     if(aligned_buffer == nullptr)
99         throw std::runtime_error("Failed to allocate memory for the test vector!");
100
101     std::copy(buffer.begin(), buffer.end(), aligned_buffer);
102
103     return aligned_buffer;
104 }
105
106 json read_json_from_file(const std::string &filename)
107 {
108     json result;
109
110     std::ifstream json_stream(filename);
111     if(!json_stream.is_open())
112         throw missing_config_file_exception();
113
114     json_stream >> result;
115
116     return result;
117 }
118
119 unsigned long tsc_recovery()
120 {
121 #ifndef _WIN64
122     constexpr auto ns_per_sec = 1E9;
123
124     struct timespec sleeptime = {.tv_nsec = __syscall_slong_t(5E8) };
125
126     struct timespec t_start, t_end;
127
128     if (clock_gettime(CLOCK_MONOTONIC_RAW, &t_start) == 0)
129     {
130         unsigned long start = tsc_tick();
131
132         nanosleep(&sleeptime,NULL);
133         clock_gettime(CLOCK_MONOTONIC_RAW, &t_end);
134
135         unsigned long end = tsc_tick();
136
137         unsigned long ns = (unsigned long)((t_end.tv_sec - t_start.tv_sec) * ns_per_sec + t_end.tv_nsec - t_start.tv_nsec);
138
139         double secs = (double) ns / ns_per_sec;
140
141         unsigned long resolution_timer = (unsigned long)((end - start)/secs);
142         unsigned long tick_per_usec = (resolution_timer / 1000000);
143
144         std::cout << "[----------] System clock (rdtsc) resolution " << resolution_timer << " [Hz]" << std::endl;
145         std::cout << "[----------] Ticks per us " << tick_per_usec << std::endl;
146
147         return tick_per_usec;
148     }
149 #else
150
151     LARGE_INTEGER tick_per_sec;
152     QueryPerformanceFrequency(&tick_per_sec);
153
154     std::cout << "[----------] System clock (rdtsc) resolution unknown" << std::endl;
155     std::cout << "[----------] Ticks per us " << (tick_per_sec.QuadPart / 1000000) << std::endl;
156     return (unsigned long) tick_per_sec.QuadPart;
157
158 #endif
159     return 0;
160 }
161
162 unsigned long tsc_tick()
163 {
164 #ifndef _WIN64
165     unsigned long hi, lo;
166
167     __asm volatile ("rdtsc" : "=a"(lo), "=d"(hi));
168
169     return lo | (hi << 32);
170 #else
171         return 0;
172 #endif
173 }
174
175 void KernelTests::print_and_store_results(const std::string &isa, const std::string &parameters,
176                                           const std::string &module_name, const std::string &test_name,
177                                           const std::string &unit, const int para_factor,
178                                           const double mean, const double stddev)
179 {
180     std::cout << "[----------] " << "Mean" << " = " << std::fixed << mean << " us" << std::endl;
181     std::cout << "[----------] " << "Stddev" << " = " << stddev << " us" << std::endl;
182
183 #ifndef _WIN64
184     /* Two properties below should uniquely identify a test case */
185     RecordProperty("kernelname", module_name);
186     RecordProperty("parameters", parameters);
187
188     RecordProperty("isa", isa);
189     RecordProperty("unit", unit);
190     RecordProperty("parallelization_factor", para_factor);
191
192     RecordProperty("mean", std::to_string(mean));
193     RecordProperty("stddev", std::to_string(stddev));
194 #endif
195 }