| // 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 <fuchsia/kernel/cpp/fidl.h> |
| #include <lib/inspect/cpp/reader.h> |
| #include <lib/sys/cpp/service_directory.h> |
| #include <zircon/status.h> |
| |
| #include <iterator> |
| #include <utility> |
| |
| #include <perftest/results.h> |
| |
| namespace { |
| |
| constexpr std::pair<const char*, const char*> kSteps[] = { |
| {"boot.timeline.zbi", "KernelBootLoader"}, |
| {"boot.timeline.virtual", "KernelBootPhysical"}, |
| {"boot.timeline.threading", "KernelBootThreads"}, |
| {"boot.timeline.userboot", "KernelBootUser"}, |
| {"boot.timeline.init", "KernelBootComplete"}, |
| }; |
| |
| perftest::ResultsSet BootTimeline() { |
| fuchsia::kernel::CounterSyncPtr kcounter; |
| auto environment_services = ::sys::ServiceDirectory::CreateFromNamespace(); |
| environment_services->Connect(kcounter.NewRequest()); |
| |
| fuchsia::mem::Buffer buffer; |
| zx_status_t status; |
| zx_status_t get_status = kcounter->GetInspectVmo(&status, &buffer); |
| ZX_ASSERT_MSG(get_status == ZX_OK, "GetInspectVmo: %s", zx_status_get_string(get_status)); |
| ZX_ASSERT_MSG(status == ZX_OK, "GetInspectVmo yields status %s", |
| zx_status_get_string(get_status)); |
| |
| auto result = inspect::ReadFromVmo(buffer.vmo); |
| ZX_ASSERT_MSG(result.is_ok(), "ReadFromVmo failed"); |
| auto root = result.take_value(); |
| auto timeline = root.GetByPath({"boot", "timeline"}); |
| ZX_ASSERT_MSG(timeline, "boot.timeline not found"); |
| |
| const auto& properties = timeline->node().properties(); |
| |
| ZX_ASSERT(properties.size() == std::size(kSteps)); |
| |
| double ms_per_tick = 1000.0 / static_cast<double>(zx_ticks_per_second()); |
| |
| perftest::ResultsSet results; |
| int64_t last_step_ticks = 0; |
| for (auto [name, result_name] : kSteps) { |
| auto it = std::find_if(properties.begin(), properties.end(), |
| [name = name](const auto& m) { return m.name() == name; }); |
| ZX_ASSERT_MSG(it != properties.end(), "%s not found", name); |
| ZX_ASSERT_MSG( |
| it->Contains<inspect::IntPropertyValue>(), |
| "All properties in kSteps are expected to be IntMetric: name: %s actual format: %d", name, |
| static_cast<int>(it->format())); |
| |
| int64_t step_ticks = it->Get<inspect::IntPropertyValue>().value(); |
| int64_t elapsed = step_ticks - last_step_ticks; |
| double elapsed_ms = static_cast<double>(elapsed) * ms_per_tick; |
| last_step_ticks = step_ticks; |
| |
| auto* t = results.AddTestCase("fuchsia.kernel.boot", result_name, "milliseconds"); |
| t->AppendValue(elapsed_ms); |
| } |
| ZX_ASSERT(results.results()->size() == std::size(kSteps)); |
| |
| return results; |
| } |
| |
| } // namespace |
| |
| int main(int argc, char** argv) { |
| if (argc != 2) { |
| fprintf(stderr, "Usage: %s OUTFILE.json\n", argv[0]); |
| return 1; |
| } |
| const char* outfile = argv[1]; |
| |
| perftest::ResultsSet results = BootTimeline(); |
| |
| return results.WriteJSONFile(outfile) ? 0 : 1; |
| } |