master
cpp 460 lines 9.33 KB
Raw
1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * This C++ plugin ensures we don't have regression when compiling C++.
5 */
6
7 #include <qemu-plugin.h>
8
9 /*
10 * We include all C++ standard headers (without deprecated ones),
11 * taken from: https://en.cppreference.com/w/cpp/headers.html
12 *
13 * To update, copy page text, and then:
14 * grep '^<' |
15 * sort -u |
16 * grep -v strstream |
17 * grep -v codecvt |
18 * sed -e 's/\(.*\)/#if __has_include(\1)\n#include \1\n#endif/'
19 */
20
21 #if __has_include(<algorithm>)
22 #include <algorithm>
23 #endif
24 #if __has_include(<any>)
25 #include <any>
26 #endif
27 #if __has_include(<array>)
28 #include <array>
29 #endif
30 #if __has_include(<atomic>)
31 #include <atomic>
32 #endif
33 #if __has_include(<barrier>)
34 #include <barrier>
35 #endif
36 #if __has_include(<bit>)
37 #include <bit>
38 #endif
39 #if __has_include(<bitset>)
40 #include <bitset>
41 #endif
42 #if __has_include(<cassert>)
43 #include <cassert>
44 #endif
45 #if __has_include(<cctype>)
46 #include <cctype>
47 #endif
48 #if __has_include(<cerrno>)
49 #include <cerrno>
50 #endif
51 #if __has_include(<cfenv>)
52 #include <cfenv>
53 #endif
54 #if __has_include(<cfloat>)
55 #include <cfloat>
56 #endif
57 #if __has_include(<charconv>)
58 #include <charconv>
59 #endif
60 #if __has_include(<chrono>)
61 #include <chrono>
62 #endif
63 #if __has_include(<cinttypes>)
64 #include <cinttypes>
65 #endif
66 #if __has_include(<climits>)
67 #include <climits>
68 #endif
69 #if __has_include(<clocale>)
70 #include <clocale>
71 #endif
72 #if __has_include(<cmath>)
73 #include <cmath>
74 #endif
75 #if __has_include(<compare>)
76 #include <compare>
77 #endif
78 #if __has_include(<complex>)
79 #include <complex>
80 #endif
81 #if __has_include(<concepts>)
82 #include <concepts>
83 #endif
84 #if __has_include(<condition_variable>)
85 #include <condition_variable>
86 #endif
87 #if __has_include(<contracts>)
88 #include <contracts>
89 #endif
90 #if __has_include(<coroutine>)
91 #include <coroutine>
92 #endif
93 #if __has_include(<csetjmp>)
94 #include <csetjmp>
95 #endif
96 #if __has_include(<csignal>)
97 #include <csignal>
98 #endif
99 #if __has_include(<cstdarg>)
100 #include <cstdarg>
101 #endif
102 #if __has_include(<cstddef>)
103 #include <cstddef>
104 #endif
105 #if __has_include(<cstdint>)
106 #include <cstdint>
107 #endif
108 #if __has_include(<cstdio>)
109 #include <cstdio>
110 #endif
111 #if __has_include(<cstdlib>)
112 #include <cstdlib>
113 #endif
114 #if __has_include(<cstring>)
115 #include <cstring>
116 #endif
117 #if __has_include(<ctime>)
118 #include <ctime>
119 #endif
120 #if __has_include(<cuchar>)
121 #include <cuchar>
122 #endif
123 #if __has_include(<cwchar>)
124 #include <cwchar>
125 #endif
126 #if __has_include(<cwctype>)
127 #include <cwctype>
128 #endif
129 #if __has_include(<debugging>)
130 #include <debugging>
131 #endif
132 #if __has_include(<deque>)
133 #include <deque>
134 #endif
135 #if __has_include(<exception>)
136 #include <exception>
137 #endif
138 #if __has_include(<execution>)
139 #include <execution>
140 #endif
141 #if __has_include(<expected>)
142 #include <expected>
143 #endif
144 #if __has_include(<filesystem>)
145 #include <filesystem>
146 #endif
147 #if __has_include(<flat_map>)
148 #include <flat_map>
149 #endif
150 #if __has_include(<flat_set>)
151 #include <flat_set>
152 #endif
153 #if __has_include(<format>)
154 #include <format>
155 #endif
156 #if __has_include(<forward_list>)
157 #include <forward_list>
158 #endif
159 #if __has_include(<fstream>)
160 #include <fstream>
161 #endif
162 #if __has_include(<functional>)
163 #include <functional>
164 #endif
165 #if __has_include(<future>)
166 #include <future>
167 #endif
168 #if __has_include(<generator>)
169 #include <generator>
170 #endif
171 #if __has_include(<hazard_pointer>)
172 #include <hazard_pointer>
173 #endif
174 #if __has_include(<hive>)
175 #include <hive>
176 #endif
177 #if __has_include(<initializer_list>)
178 #include <initializer_list>
179 #endif
180 #if __has_include(<inplace_vector>)
181 #include <inplace_vector>
182 #endif
183 #if __has_include(<iomanip>)
184 #include <iomanip>
185 #endif
186 #if __has_include(<ios>)
187 #include <ios>
188 #endif
189 #if __has_include(<iosfwd>)
190 #include <iosfwd>
191 #endif
192 #if __has_include(<iostream>)
193 #include <iostream>
194 #endif
195 #if __has_include(<istream>)
196 #include <istream>
197 #endif
198 #if __has_include(<iterator>)
199 #include <iterator>
200 #endif
201 #if __has_include(<latch>)
202 #include <latch>
203 #endif
204 #if __has_include(<limits>)
205 #include <limits>
206 #endif
207 #if __has_include(<linalg>)
208 #include <linalg>
209 #endif
210 #if __has_include(<list>)
211 #include <list>
212 #endif
213 #if __has_include(<locale>)
214 #include <locale>
215 #endif
216 #if __has_include(<map>)
217 #include <map>
218 #endif
219 #if __has_include(<mdspan>)
220 #include <mdspan>
221 #endif
222 #if __has_include(<memory>)
223 #include <memory>
224 #endif
225 #if __has_include(<memory_resource>)
226 #include <memory_resource>
227 #endif
228 #if __has_include(<mutex>)
229 #include <mutex>
230 #endif
231 #if __has_include(<new>)
232 #include <new>
233 #endif
234 #if __has_include(<numbers>)
235 #include <numbers>
236 #endif
237 #if __has_include(<numeric>)
238 #include <numeric>
239 #endif
240 #if __has_include(<optional>)
241 #include <optional>
242 #endif
243 #if __has_include(<ostream>)
244 #include <ostream>
245 #endif
246 #if __has_include(<print>)
247 #include <print>
248 #endif
249 #if __has_include(<queue>)
250 #include <queue>
251 #endif
252 #if __has_include(<random>)
253 #include <random>
254 #endif
255 #if __has_include(<ranges>)
256 #include <ranges>
257 #endif
258 #if __has_include(<ratio>)
259 #include <ratio>
260 #endif
261 #if __has_include(<rcu>)
262 #include <rcu>
263 #endif
264 #if __has_include(<regex>)
265 #include <regex>
266 #endif
267 #if __has_include(<scoped_allocator>)
268 #include <scoped_allocator>
269 #endif
270 #if __has_include(<semaphore>)
271 #include <semaphore>
272 #endif
273 #if __has_include(<set>)
274 #include <set>
275 #endif
276 #if __has_include(<shared_mutex>)
277 #include <shared_mutex>
278 #endif
279 #if __has_include(<simd>)
280 #include <simd>
281 #endif
282 #if __has_include(<source_location>)
283 #include <source_location>
284 #endif
285 #if __has_include(<span>)
286 #include <span>
287 #endif
288 #if __has_include(<spanstream>)
289 #include <spanstream>
290 #endif
291 #if __has_include(<sstream>)
292 #include <sstream>
293 #endif
294 #if __has_include(<stack>)
295 #include <stack>
296 #endif
297 #if __has_include(<stacktrace>)
298 #include <stacktrace>
299 #endif
300 #if __has_include(<stdexcept>)
301 #include <stdexcept>
302 #endif
303 #if __has_include(<stdfloat>)
304 #include <stdfloat>
305 #endif
306 #if __has_include(<stop_token>)
307 #include <stop_token>
308 #endif
309 #if __has_include(<streambuf>)
310 #include <streambuf>
311 #endif
312 #if __has_include(<string>)
313 #include <string>
314 #endif
315 #if __has_include(<string_view>)
316 #include <string_view>
317 #endif
318 #if __has_include(<syncstream>)
319 #include <syncstream>
320 #endif
321 #if __has_include(<system_error>)
322 #include <system_error>
323 #endif
324 #if __has_include(<text_encoding>)
325 #include <text_encoding>
326 #endif
327 #if __has_include(<thread>)
328 #include <thread>
329 #endif
330 #if __has_include(<tuple>)
331 #include <tuple>
332 #endif
333 #if __has_include(<typeindex>)
334 #include <typeindex>
335 #endif
336 #if __has_include(<typeinfo>)
337 #include <typeinfo>
338 #endif
339 #if __has_include(<type_traits>)
340 #include <type_traits>
341 #endif
342 #if __has_include(<unordered_map>)
343 #include <unordered_map>
344 #endif
345 #if __has_include(<unordered_set>)
346 #include <unordered_set>
347 #endif
348 #if __has_include(<utility>)
349 #include <utility>
350 #endif
351 #if __has_include(<valarray>)
352 #include <valarray>
353 #endif
354 #if __has_include(<variant>)
355 #include <variant>
356 #endif
357 #if __has_include(<vector>)
358 #include <vector>
359 #endif
360 #if __has_include(<version>)
361 #include <version>
362 #endif
363
364 QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
365
366 class Plugin
367 {
368 public:
369 void tb_exec(std::atomic<uint64_t> &count)
370 {
371 count++;
372 }
373
374 void tb_trans(struct qemu_plugin_tb *tb)
375 {
376 auto vaddr = qemu_plugin_tb_vaddr(tb);
377
378 TbData *data = [&]() {
379 std::lock_guard l(tb_trans_lock);
380 auto [it, is_new] = tb_data.try_emplace(vaddr);
381 TbData &in = it->second;
382 if (is_new) {
383 in.first = 0;
384 in.second = this;
385 }
386 return &in;
387 } ();
388
389 qemu_plugin_register_vcpu_tb_exec_cb(
390 tb,
391 [](unsigned int cpu_index, void *udata) {
392 auto &[counter, p] = *static_cast<TbData*>(udata);
393 p->tb_exec(counter);
394 },
395 QEMU_PLUGIN_CB_NO_REGS,
396 data);
397 }
398
399 void at_exit()
400 {
401 std::vector<std::pair<Vaddr, uint64_t>> v;
402 for (auto &[vaddr, data] : tb_data) {
403 uint64_t count = data.first;
404 v.push_back({vaddr, count});
405 }
406 std::sort(v.begin(), v.end(),
407 [](const auto &a, const auto &b) {
408 return a.second > b.second;
409 });
410 std::stringstream ss;
411 ss << "Top 10 executed TB are:\n";
412 size_t idx = 0;
413 for (auto &tb : v) {
414 if (idx >= 10) {
415 break;
416 }
417 ss << std::hex << "0x" << tb.first << std::dec << ": "
418 << tb.second << '\n';
419 ++idx;
420 }
421 qemu_plugin_outs(ss.str().c_str());
422 }
423
424 private:
425 using Vaddr = uint64_t;
426 using Counter = std::atomic<uint64_t>;
427 using TbData = std::pair<Counter, Plugin*>;
428 std::unordered_map<Vaddr, TbData> tb_data;
429 std::mutex tb_trans_lock;
430 };
431
432 QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
433 const qemu_info_t *info,
434 int argc, char **argv)
435 {
436 Plugin *plugin = new Plugin;
437
438 /*
439 * We can register a cb with any function, which may be a free
440 * function, a static class function, or a captureless lambda.
441 */
442 qemu_plugin_register_vcpu_tb_trans_cb(
443 id,
444 [](struct qemu_plugin_tb *tb, void *userdata) {
445 Plugin *p = static_cast<Plugin*>(userdata);
446 p->tb_trans(tb);
447 },
448 plugin);
449
450 qemu_plugin_register_atexit_cb(
451 id,
452 [](void *userdata) {
453 Plugin *p = static_cast<Plugin*>(userdata);
454 p->at_exit();
455 delete p;
456 },
457 plugin);
458
459 return 0;
460 }