| #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)); | |
| } |