| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ram-info.h" |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/fidl-async/cpp/bind.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| namespace ram_metrics = ::llcpp::fuchsia::hardware::ram::metrics; |
| |
| namespace ram_info { |
| // fake register value used in test. |
| constexpr uint32_t TEST_REGISTER_VALUE = 42; |
| |
| class FakeRamDevice : public ::llcpp::fuchsia::hardware::ram::metrics::Device::Interface { |
| public: |
| FakeRamDevice() = default; |
| |
| void set_close() { completer_action_ = CompleterAction::kClose; } |
| void set_reply_error() { completer_action_ = CompleterAction::kReplyError; } |
| |
| void GetDdrWindowingResults(GetDdrWindowingResultsCompleter::Sync& completer) override { |
| if (completer_action_ == CompleterAction::kClose) { |
| completer.Close(0); |
| return; |
| } |
| if (completer_action_ == CompleterAction::kReplyError) { |
| completer.ReplyError(ZX_ERR_BAD_STATE); |
| return; |
| } |
| completer.ReplySuccess(TEST_REGISTER_VALUE); |
| } |
| |
| void MeasureBandwidth(ram_metrics::BandwidthMeasurementConfig config, |
| MeasureBandwidthCompleter::Sync& completer) override { |
| if (completer_action_ == CompleterAction::kClose) { |
| completer.Close(0); |
| return; |
| } |
| if (completer_action_ == CompleterAction::kReplyError) { |
| completer.ReplyError(ZX_ERR_BAD_STATE); |
| return; |
| } |
| |
| EXPECT_EQ(config.cycles_to_measure % 1024, 0); |
| auto mul = config.cycles_to_measure / 1024; |
| |
| ram_metrics::BandwidthInfo info = {}; |
| info.timestamp = zx::msec(1234).to_nsecs(); |
| info.frequency = 256 * 1024 * 1024; |
| info.bytes_per_cycle = 1; |
| info.channels[0].readwrite_cycles = 10 * mul; |
| info.channels[1].readwrite_cycles = 20 * mul; |
| info.channels[2].readwrite_cycles = 30 * mul; |
| info.channels[3].readwrite_cycles = 40 * mul; |
| info.channels[4].readwrite_cycles = 50 * mul; |
| info.channels[5].readwrite_cycles = 60 * mul; |
| info.channels[6].readwrite_cycles = 70 * mul; |
| info.channels[7].readwrite_cycles = 80 * mul; |
| |
| completer.ReplySuccess(info); |
| } |
| |
| private: |
| enum class CompleterAction { |
| kClose, |
| kReplyError, |
| kReplySuccess, |
| } completer_action_ = CompleterAction::kReplySuccess; |
| }; |
| |
| class RamInfoTest : public zxtest::Test { |
| public: |
| RamInfoTest() : zxtest::Test(), loop_(&kAsyncLoopConfigAttachToCurrentThread) {} |
| |
| void SetUp() override { |
| zx::channel server; |
| ASSERT_OK(zx::channel::create(0, &client_, &server)); |
| ASSERT_OK(fidl::BindSingleInFlightOnly(loop_.dispatcher(), std::move(server), &fake_device_)); |
| loop_.StartThread("ram-info-test-loop"); |
| } |
| |
| protected: |
| zx::channel client_; |
| FakeRamDevice fake_device_; |
| |
| private: |
| async::Loop loop_; |
| }; |
| |
| TEST_F(RamInfoTest, Errors) { |
| constexpr uint64_t kCyclesToMeasure = 1024; |
| |
| char output_buffer[512]; |
| FILE* output_file = fmemopen(output_buffer, sizeof(output_buffer), "w"); |
| ASSERT_NOT_NULL(output_file); |
| |
| DefaultPrinter printer(output_file, kCyclesToMeasure); |
| printer.AddChannelName(0, "channel0"); |
| |
| fake_device_.set_close(); |
| EXPECT_NOT_OK(MeasureBandwith(&printer, std::move(client_), {})); |
| |
| fake_device_.set_reply_error(); |
| EXPECT_NOT_OK(MeasureBandwith(&printer, std::move(client_), {})); |
| |
| fclose(output_file); |
| } |
| |
| TEST_F(RamInfoTest, DefaultPrinter) { |
| constexpr uint64_t kCyclesToMeasure = 1024; |
| |
| char output_buffer[512]; |
| FILE* output_file = fmemopen(output_buffer, sizeof(output_buffer), "w"); |
| ASSERT_NOT_NULL(output_file); |
| |
| DefaultPrinter printer(output_file, kCyclesToMeasure); |
| printer.AddChannelName(0, "channel0"); |
| printer.AddChannelName(1, "channel1"); |
| printer.AddChannelName(2, "channel2"); |
| printer.AddChannelName(3, "channel3"); |
| |
| ram_metrics::BandwidthMeasurementConfig config = {}; |
| config.cycles_to_measure = kCyclesToMeasure; |
| |
| EXPECT_OK(MeasureBandwith(&printer, std::move(client_), config)); |
| fclose(output_file); |
| |
| constexpr char kExpectedOutput[] = |
| "channel \t\t usage (MB/s) time: 1234 ms\n" |
| "channel0 (rw) \t\t 2.5\n" |
| "channel1 (rw) \t\t 5\n" |
| "channel2 (rw) \t\t 7.5\n" |
| "channel3 (rw) \t\t 10\n" |
| "total (rw) \t\t 25\n"; |
| EXPECT_BYTES_EQ(output_buffer, kExpectedOutput, strlen(kExpectedOutput)); |
| } |
| |
| TEST_F(RamInfoTest, CsvPrinter) { |
| constexpr uint64_t kCyclesToMeasure = 1024; |
| |
| char output_buffer[512]; |
| FILE* output_file = fmemopen(output_buffer, sizeof(output_buffer), "w"); |
| ASSERT_NOT_NULL(output_file); |
| |
| CsvPrinter printer(output_file, kCyclesToMeasure); |
| printer.AddChannelName(0, "channel0"); |
| printer.AddChannelName(1, "channel1"); |
| printer.AddChannelName(2, "channel2"); |
| printer.AddChannelName(3, "channel3"); |
| |
| ram_metrics::BandwidthMeasurementConfig config = {}; |
| config.cycles_to_measure = kCyclesToMeasure; |
| |
| EXPECT_OK(MeasureBandwith(&printer, std::move(client_), config)); |
| fclose(output_file); |
| |
| constexpr char kExpectedOutput[] = |
| "time,\"channel0\",\"channel1\",\"channel2\",\"channel3\"\n" |
| "1234,2.5,5,7.5,10\n"; |
| EXPECT_BYTES_EQ(output_buffer, kExpectedOutput, strlen(kExpectedOutput)); |
| } |
| |
| TEST_F(RamInfoTest, ParseChannelString) { |
| auto result = ParseChannelString("1234, 0x1234, 01234"); |
| ASSERT_TRUE(result.is_ok()); |
| |
| std::array<uint64_t, 8> expected_values = {1234, 0x1234, 01234}; |
| for (size_t i = 0; i < expected_values.size(); i++) { |
| EXPECT_EQ(result.value()[i], expected_values[i]); |
| } |
| |
| result = ParseChannelString("0x10000000000000000"); |
| EXPECT_FALSE(result.is_ok()); |
| |
| result = ParseChannelString("0xffffffffffffffff"); |
| ASSERT_TRUE(result.is_ok()); |
| EXPECT_EQ(result.value()[0], 0xffff'ffff'ffff'ffff); |
| |
| result = ParseChannelString("1,2,3,4,5,6,7,8,"); |
| ASSERT_TRUE(result.is_ok()); |
| |
| expected_values = {1, 2, 3, 4, 5, 6, 7, 8}; |
| for (size_t i = 0; i < expected_values.size(); i++) { |
| EXPECT_EQ(result.value()[i], expected_values[i]); |
| } |
| |
| result = ParseChannelString("1,2,3,4,5,6,7,8a"); |
| EXPECT_FALSE(result.is_ok()); |
| |
| result = ParseChannelString("1,2,3,4,5,6,7,8,9"); |
| EXPECT_FALSE(result.is_ok()); |
| |
| result = ParseChannelString(""); |
| EXPECT_FALSE(result.is_ok()); |
| |
| result = ParseChannelString("z"); |
| EXPECT_FALSE(result.is_ok()); |
| } |
| |
| TEST_F(RamInfoTest, CyclesToMeasure) { |
| constexpr uint64_t kCyclesToMeasure = 1024 * 20; |
| |
| char output_buffer[512]; |
| FILE* output_file = fmemopen(output_buffer, sizeof(output_buffer), "w"); |
| ASSERT_NOT_NULL(output_file); |
| |
| DefaultPrinter printer(output_file, kCyclesToMeasure); |
| printer.AddChannelName(0, "channel0"); |
| printer.AddChannelName(1, "channel1"); |
| printer.AddChannelName(2, "channel2"); |
| printer.AddChannelName(3, "channel3"); |
| |
| ram_metrics::BandwidthMeasurementConfig config = {}; |
| config.cycles_to_measure = kCyclesToMeasure; |
| |
| EXPECT_OK(MeasureBandwith(&printer, std::move(client_), config)); |
| fclose(output_file); |
| |
| constexpr char kExpectedOutput[] = |
| "channel \t\t usage (MB/s) time: 1234 ms\n" |
| "channel0 (rw) \t\t 2.5\n" |
| "channel1 (rw) \t\t 5\n" |
| "channel2 (rw) \t\t 7.5\n" |
| "channel3 (rw) \t\t 10\n" |
| "total (rw) \t\t 25\n"; |
| EXPECT_BYTES_EQ(output_buffer, kExpectedOutput, strlen(kExpectedOutput)); |
| } |
| |
| TEST_F(RamInfoTest, GetDdrWindowingResults) { |
| // This test is pretty trivial, since we're faking the interface, and all the |
| // function does is print the resulting value. |
| EXPECT_OK(GetDdrWindowingResults(std::move(client_))); |
| } |
| |
| } // namespace ram_info |