| #include <algorithm> |
| #include <cmath> |
| #include <utility> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| #include <c10/util/irange.h> |
| #include <torch/csrc/profiler/containers.h> |
| #include <torch/csrc/profiler/util.h> |
| |
| TEST(ProfilerTest, AppendOnlyList) { |
| const int n = 4096; |
| torch::profiler::impl::AppendOnlyList<int, 1024> list; |
| for (const auto i : c10::irange(n)) { |
| list.emplace_back(i); |
| ASSERT_EQ(list.size(), i + 1); |
| } |
| |
| int expected = 0; |
| for (const auto i : list) { |
| ASSERT_EQ(i, expected++); |
| } |
| ASSERT_EQ(expected, n); |
| |
| list.clear(); |
| ASSERT_EQ(list.size(), 0); |
| } |
| |
| TEST(ProfilerTest, AppendOnlyList_ref) { |
| const int n = 512; |
| torch::profiler::impl::AppendOnlyList<std::pair<int, int>, 64> list; |
| std::vector<std::pair<int, int>*> refs; |
| for (const auto _ : c10::irange(n)) { |
| refs.push_back(list.emplace_back()); |
| } |
| |
| for (const auto i : c10::irange(n)) { |
| *refs.at(i) = {i, 0}; |
| } |
| |
| int expected = 0; |
| for (const auto& i : list) { |
| ASSERT_EQ(i.first, expected++); |
| } |
| } |
| |
| // Test that we can convert TSC measurements back to wall clock time. |
| TEST(ProfilerTest, clock_converter) { |
| const int n = 10001; |
| torch::profiler::impl::ApproximateClockToUnixTimeConverter converter; |
| std::vector<torch::profiler::impl::ApproximateClockToUnixTimeConverter:: |
| UnixAndApproximateTimePair> |
| pairs; |
| for (const auto i : c10::irange(n)) { |
| pairs.push_back(torch::profiler::impl::ApproximateClockToUnixTimeConverter:: |
| measurePair()); |
| } |
| auto count_to_ns = converter.makeConverter(); |
| std::vector<int64_t> deltas; |
| for (const auto& i : pairs) { |
| deltas.push_back(i.t_ - count_to_ns(i.approx_t_)); |
| } |
| std::sort(deltas.begin(), deltas.end()); |
| |
| // In general it's not a good idea to put clocks in unit tests as it leads |
| // to flakiness. We mitigate this by: |
| // 1) Testing the clock itself. While the time to complete a task may |
| // vary, two clocks measuring the same time should be much more |
| // consistent. |
| // 2) Only testing the interquartile range. Context switches between |
| // calls to the two timers do occur and can result in hundreds of |
| // nanoseconds of noise, but such switches are only a few percent |
| // of cases. |
| // 3) We're willing to accept a somewhat large bias which can emerge from |
| // differences in the cost of calling each clock. |
| EXPECT_LT(std::abs(deltas[n / 2]), 200); |
| EXPECT_LT(deltas[n * 3 / 4] - deltas[n / 4], 50); |
| } |
| |
| TEST(ProfilerTest, soft_assert) { |
| EXPECT_TRUE(SOFT_ASSERT(true)); |
| torch::profiler::impl::setSoftAssertRaises(true); |
| EXPECT_ANY_THROW(SOFT_ASSERT(false)); |
| torch::profiler::impl::setSoftAssertRaises(false); |
| EXPECT_NO_THROW(SOFT_ASSERT(false)); |
| // Reset soft assert behavior to default |
| torch::profiler::impl::setSoftAssertRaises(c10::nullopt); |
| EXPECT_NO_THROW(SOFT_ASSERT(false)); |
| } |