1 //===-- PerfTests.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
13 #include "llvm/Support/Error.h"
15 #include "gtest/gtest.h"
20 using namespace lldb_private
;
21 using namespace process_linux
;
24 /// Helper function to read current TSC value.
26 /// This code is based on llvm/xray.
27 static Expected
<uint64_t> readTsc() {
29 unsigned int eax
, ebx
, ecx
, edx
;
31 // We check whether rdtscp support is enabled. According to the x86_64 manual,
32 // level should be set at 0x80000001, and we should have a look at bit 27 in
33 // EDX. That's 0x8000000 (or 1u << 27).
34 __asm__
__volatile__("cpuid"
35 : "=a"(eax
), "=b"(ebx
), "=c"(ecx
), "=d"(edx
)
37 if (!(edx
& (1u << 27))) {
38 return createStringError(inconvertibleErrorCode(),
39 "Missing rdtscp support.");
43 unsigned long rax
, rdx
;
45 __asm__
__volatile__("rdtscp\n" : "=a"(rax
), "=d"(rdx
), "=c"(cpu
)::);
47 return (rdx
<< 32) + rax
;
50 // Test TSC to walltime conversion based on perf conversion values.
51 TEST(Perf
, TscConversion
) {
52 // This test works by first reading the TSC value directly before
53 // and after sleeping, then converting these values to nanoseconds, and
54 // finally ensuring the difference is approximately equal to the sleep time.
56 // There will be slight overhead associated with the sleep call, so it isn't
57 // reasonable to expect the difference to be exactly equal to the sleep time.
59 const int SLEEP_SECS
= 1;
60 std::chrono::nanoseconds SLEEP_NANOS
{std::chrono::seconds(SLEEP_SECS
)};
62 Expected
<LinuxPerfZeroTscConversion
> params
=
63 LoadPerfTscConversionParameters();
65 // Skip the test if the conversion parameters aren't available.
67 GTEST_SKIP() << toString(params
.takeError());
69 Expected
<uint64_t> tsc_before_sleep
= readTsc();
71 Expected
<uint64_t> tsc_after_sleep
= readTsc();
73 // Skip the test if we are unable to read the TSC value.
74 if (!tsc_before_sleep
)
75 GTEST_SKIP() << toString(tsc_before_sleep
.takeError());
77 GTEST_SKIP() << toString(tsc_after_sleep
.takeError());
79 uint64_t converted_tsc_diff
=
80 params
->ToNanos(*tsc_after_sleep
) - params
->ToNanos(*tsc_before_sleep
);
82 std::chrono::microseconds
acceptable_overhead(500);
84 ASSERT_GE(converted_tsc_diff
, static_cast<uint64_t>(SLEEP_NANOS
.count()));
85 ASSERT_LT(converted_tsc_diff
,
86 static_cast<uint64_t>((SLEEP_NANOS
+ acceptable_overhead
).count()));