|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include <torch/csrc/profiler/events.h> | 
|  | #include <torch/csrc/profiler/perf.h> | 
|  |  | 
|  | double calc_pi() { | 
|  | volatile double pi = 1.0; | 
|  | for (int i = 3; i < 100000; i += 2) { | 
|  | pi += (((i + 1) >> 1) % 2) ? 1.0 / i : -1.0 / i; | 
|  | } | 
|  | return pi * 4.0; | 
|  | } | 
|  |  | 
|  | TEST(ProfilerTest, LinuxPerf) { | 
|  | torch::profiler::impl::linux_perf::PerfProfiler profiler; | 
|  |  | 
|  | std::vector<std::string> standard_events( | 
|  | std::begin(torch::profiler::ProfilerPerfEvents), | 
|  | std::end(torch::profiler::ProfilerPerfEvents)); | 
|  | torch::profiler::perf_counters_t counters; | 
|  | counters.resize(standard_events.size(), 0); | 
|  |  | 
|  | // Use try..catch HACK to check TORCH_CHECK because we don't yet fail | 
|  | // gracefully if the syscall were to fail | 
|  | try { | 
|  | profiler.Configure(standard_events); | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto pi = calc_pi(); | 
|  | profiler.Disable(counters); | 
|  | } catch (const c10::Error&) { | 
|  | // Bail here if something bad happened during the profiling, we don't want | 
|  | // to make the test fail | 
|  | return; | 
|  | } catch (...) { | 
|  | // something else went wrong - this should be reported | 
|  | ASSERT_EQ(0, 1); | 
|  | } | 
|  |  | 
|  | // Should have counted something if worked, so lets test that | 
|  | // And if it not supported the counters should be zeros. | 
|  | #if defined(__ANDROID__) || defined(__linux__) | 
|  | for (auto counter : counters) { | 
|  | ASSERT_GT(counter, 0); | 
|  | } | 
|  | #else /* __ANDROID__ || __linux__ */ | 
|  | for (auto counter : counters) { | 
|  | ASSERT_EQ(counter, 0); | 
|  | } | 
|  | #endif /* __ANDROID__ || __linux__ */ | 
|  | } | 
|  |  | 
|  | TEST(ProfilerTest, LinuxPerfNestedDepth) { | 
|  | torch::profiler::impl::linux_perf::PerfProfiler profiler; | 
|  |  | 
|  | // Only monotonically increasing events will work | 
|  | std::vector<std::string> standard_events( | 
|  | std::begin(torch::profiler::ProfilerPerfEvents), | 
|  | std::end(torch::profiler::ProfilerPerfEvents)); | 
|  |  | 
|  | torch::profiler::perf_counters_t counters_A; | 
|  | torch::profiler::perf_counters_t counters_B; | 
|  | torch::profiler::perf_counters_t counters_C; | 
|  |  | 
|  | counters_A.resize(standard_events.size(), 0); | 
|  | counters_B.resize(standard_events.size(), 0); | 
|  | counters_C.resize(standard_events.size(), 0); | 
|  |  | 
|  | // Use try..catch HACK to check TORCH_CHECK because we don't yet fail | 
|  | // gracefully if the syscall were to fail | 
|  | try { | 
|  | profiler.Configure(standard_events); | 
|  |  | 
|  | // * = work kernel calc_pi() | 
|  | // | 
|  | // A --*---+              +--*-- A | 
|  | //         |              | | 
|  | //         |              | | 
|  | //       B +-*--+    +--*-+ B | 
|  | //              |    | | 
|  | //              |    | | 
|  | //            C +-*--+ C | 
|  | // | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto A = calc_pi(); | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto B = calc_pi(); | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto C = calc_pi(); | 
|  | profiler.Disable(counters_C); | 
|  |  | 
|  | auto B2 = calc_pi(); | 
|  | profiler.Disable(counters_B); | 
|  |  | 
|  | auto A2 = calc_pi(); | 
|  | profiler.Disable(counters_A); | 
|  | } catch (const c10::Error&) { | 
|  | // Bail here if something bad happened during the profiling, we don't want | 
|  | // to make the test fail | 
|  | return; | 
|  | } catch (...) { | 
|  | // something else went wrong - this should be reported | 
|  | ASSERT_EQ(0, 1); | 
|  | } | 
|  |  | 
|  | // for each counter, assert A > B > C | 
|  | #if defined(__ANDROID__) || defined(__linux__) | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_GT(counters_A[i], counters_B[i]); | 
|  | ASSERT_GT(counters_A[i], counters_C[i]); | 
|  | ASSERT_GT(counters_B[i], counters_C[i]); | 
|  | ASSERT_GT(counters_A[i], counters_B[i] + counters_C[i]); | 
|  | } | 
|  | #else /* __ANDROID__ || __linux__ */ | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_EQ(counters_A[i], 0); | 
|  | ASSERT_EQ(counters_B[i], 0); | 
|  | ASSERT_EQ(counters_C[i], 0); | 
|  | } | 
|  | #endif /* __ANDROID__ || __linux__ */ | 
|  | } | 
|  |  | 
|  | TEST(ProfilerTest, LinuxPerfNestedMultiple) { | 
|  | torch::profiler::impl::linux_perf::PerfProfiler profiler; | 
|  |  | 
|  | // Only monotonically increasing events will work | 
|  | std::vector<std::string> standard_events( | 
|  | std::begin(torch::profiler::ProfilerPerfEvents), | 
|  | std::end(torch::profiler::ProfilerPerfEvents)); | 
|  |  | 
|  | torch::profiler::perf_counters_t counters_A; | 
|  | torch::profiler::perf_counters_t counters_B; | 
|  | torch::profiler::perf_counters_t counters_C; | 
|  |  | 
|  | counters_A.resize(standard_events.size(), 0); | 
|  | counters_B.resize(standard_events.size(), 0); | 
|  | counters_C.resize(standard_events.size(), 0); | 
|  |  | 
|  | // Use try..catch HACK to check TORCH_CHECK because we don't yet fail | 
|  | // gracefully if the syscall were to fail | 
|  | try { | 
|  | profiler.Configure(standard_events); | 
|  |  | 
|  | // * = work kernel calc_pi() | 
|  | // | 
|  | // A --*---+    +---*----+    +--*-- A | 
|  | //         |    |        |    | | 
|  | //         |    |        |    | | 
|  | //      B  +-**-+ B    C +-*--+ C | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto A1 = calc_pi(); | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto B1 = calc_pi(); | 
|  | auto B2 = calc_pi(); | 
|  | profiler.Disable(counters_B); | 
|  |  | 
|  | auto A2 = calc_pi(); | 
|  |  | 
|  | profiler.Enable(); | 
|  | auto C1 = calc_pi(); | 
|  | profiler.Disable(counters_C); | 
|  |  | 
|  | auto A3 = calc_pi(); | 
|  | profiler.Disable(counters_A); | 
|  | } catch (const c10::Error&) { | 
|  | // Bail here if something bad happened during the profiling, we don't want | 
|  | // to make the test fail | 
|  | return; | 
|  | } catch (...) { | 
|  | // something else went wrong - this should be reported | 
|  | ASSERT_EQ(0, 1); | 
|  | } | 
|  |  | 
|  | // for each counter, assert A > B > C | 
|  | #if defined(__ANDROID__) || defined(__linux__) | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_GT(counters_A[i], counters_B[i]); | 
|  | ASSERT_GT(counters_A[i], counters_C[i]); | 
|  | ASSERT_GT(counters_B[i], counters_C[i]); | 
|  | ASSERT_GT(counters_A[i], counters_B[i] + counters_C[i]); | 
|  | } | 
|  | #else /* __ANDROID__ || __linux__ */ | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_EQ(counters_A[i], 0); | 
|  | ASSERT_EQ(counters_B[i], 0); | 
|  | ASSERT_EQ(counters_C[i], 0); | 
|  | } | 
|  | #endif /* __ANDROID__ || __linux__ */ | 
|  | } | 
|  |  | 
|  | TEST(ProfilerTest, LinuxPerfNestedSingle) { | 
|  | torch::profiler::impl::linux_perf::PerfProfiler profiler; | 
|  |  | 
|  | // Only monotonically increasing events will work | 
|  | std::vector<std::string> standard_events( | 
|  | std::begin(torch::profiler::ProfilerPerfEvents), | 
|  | std::end(torch::profiler::ProfilerPerfEvents)); | 
|  |  | 
|  | torch::profiler::perf_counters_t counters_A; | 
|  | torch::profiler::perf_counters_t counters_B; | 
|  | torch::profiler::perf_counters_t counters_C; | 
|  |  | 
|  | counters_A.resize(standard_events.size(), 0); | 
|  | counters_B.resize(standard_events.size(), 0); | 
|  | counters_C.resize(standard_events.size(), 0); | 
|  |  | 
|  | // Use try..catch HACK to check TORCH_CHECK because we don't yet fail | 
|  | // gracefully if the syscall were to fail | 
|  | try { | 
|  | profiler.Configure(standard_events); | 
|  |  | 
|  | profiler.Enable(); | 
|  | profiler.Enable(); | 
|  | profiler.Enable(); | 
|  | auto A1 = calc_pi(); | 
|  | profiler.Disable(counters_C); | 
|  | profiler.Disable(counters_B); | 
|  | profiler.Disable(counters_A); | 
|  | } catch (const c10::Error&) { | 
|  | // Bail here if something bad happened during the profiling, we don't want | 
|  | // to make the test fail | 
|  | return; | 
|  | } catch (...) { | 
|  | // something else went wrong - this should be reported | 
|  | ASSERT_EQ(0, 1); | 
|  | } | 
|  |  | 
|  | // for each counter, assert A > B > C | 
|  | #if defined(__ANDROID__) || defined(__linux__) | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_GE(counters_A[i], counters_B[i]); | 
|  | ASSERT_GE(counters_A[i], counters_C[i]); | 
|  | ASSERT_GE(counters_B[i], counters_C[i]); | 
|  | } | 
|  | #else /* __ANDROID__ || __linux__ */ | 
|  | for (auto i = 0; i < standard_events.size(); ++i) { | 
|  | ASSERT_EQ(counters_A[i], 0); | 
|  | ASSERT_EQ(counters_B[i], 0); | 
|  | ASSERT_EQ(counters_C[i], 0); | 
|  | } | 
|  | #endif /* __ANDROID__ || __linux__ */ | 
|  | } |