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