blob: f7d668dcf6adfca2639fe44f2118a4774e8d3548 [file] [log] [blame]
// Copyright 2018 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 "verify_test.h"
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <string.h>
#include <string>
#include <gtest/gtest.h>
#include "src/lib/files/file.h"
#include "src/lib/fxl/command_line.h"
#include "src/lib/fxl/log_settings_command_line.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/strings/string_printf.h"
#include "src/performance/cpuperf/session_result_spec.h"
#include "src/performance/cpuperf/session_spec.h"
#include "src/performance/lib/perfmon/file_reader.h"
#if defined(__x86_64__)
#include "intel/intel_tests.h"
#elif defined(__aarch64__)
#include "arm64/arm64_tests.h"
#endif
bool Verifier::VerifyIteration(uint32_t iter) {
auto get_file_name = [this, &iter](uint32_t trace_num) -> std::string {
return session_result_spec_->GetTraceFilePath(iter, trace_num);
};
std::unique_ptr<perfmon::FileReader> reader;
if (!perfmon::FileReader::Create(get_file_name, session_result_spec_->num_traces, &reader)) {
return false;
}
constexpr uint32_t kCurrentTraceUnset = ~0;
uint32_t current_trace = kCurrentTraceUnset;
RecordCounts counts{};
uint32_t trace;
perfmon::SampleRecord record;
perfmon::ReaderStatus status;
while ((status = reader->ReadNextRecord(&trace, &record)) == perfmon::ReaderStatus::kOk) {
if (trace != current_trace) {
current_trace = trace;
}
switch (record.type()) {
case perfmon::kRecordTypeTime:
++counts.time_records;
break;
case perfmon::kRecordTypeTick:
++counts.tick_records;
break;
case perfmon::kRecordTypeCount:
++counts.count_records;
break;
case perfmon::kRecordTypeValue:
++counts.value_records;
break;
case perfmon::kRecordTypePc:
++counts.pc_records;
break;
case perfmon::kRecordTypeLastBranch:
++counts.last_branch_records;
break;
default:
// The reader shouldn't be returning records of unknown types.
// But rather than FX_DCHECK which will terminate the test, just
// flag an error.
FX_LOGS(ERROR) << "Unknown record type: " << record.type() << ", trace " << current_trace
<< ", offset " << reader->GetLastRecordOffset();
// Don't keep reading, we don't know what size the record is.
return false;
}
if (!VerifyRecord(record)) {
FX_LOGS(ERROR) << "Record verification failed: trace " << current_trace << ", offset "
<< reader->GetLastRecordOffset();
// If one record is wrong there could a lot of them, reducing the
// S/N ratio of the output. So just bail.
return false;
}
}
FX_LOGS(INFO) << fxl::StringPrintf("Counts: %zu time, %zu tick", counts.time_records,
counts.tick_records);
FX_LOGS(INFO) << fxl::StringPrintf("Counts: %zu count, %zu value", counts.count_records,
counts.value_records);
FX_LOGS(INFO) << fxl::StringPrintf("Counts: %zu pc", counts.pc_records);
if (status != perfmon::ReaderStatus::kNoMoreRecords) {
FX_LOGS(ERROR) << "Error occurred in record reader: " << perfmon::ReaderStatusToString(status);
return false;
}
return VerifyTrace(counts);
}
void Verifier::Verify() {
for (size_t iter = 0; iter < session_result_spec_->num_iterations; ++iter) {
FX_LOGS(INFO) << "Verifying iteration " << iter;
EXPECT_TRUE(VerifyIteration(iter));
}
}
bool Verifier::LookupEventByName(const char* group_name, const char* event_name,
const perfmon::EventDetails** out_details) {
GetModelEventManager();
return model_event_manager_->LookupEventByName(group_name, event_name, out_details);
}
void Verifier::GetModelEventManager() {
if (!model_event_manager_) {
model_event_manager_ = perfmon::ModelEventManager::Create(session_result_spec_->model_name);
ASSERT_TRUE(model_event_manager_);
}
}
static std::unique_ptr<Verifier> LookupVerifier(const cpuperf::SessionResultSpec* spec) {
for (size_t i = 0; i < kTestSpecCount; ++i) {
const TestSpec* test = kTestSpecs[i];
if (strcmp(spec->config_name.c_str(), test->config_name) == 0) {
return test->make_verifier(spec);
}
}
return nullptr;
}
void VerifySpec(const std::string& spec_file_path) {
FX_VLOGS(1) << "Verifying " << spec_file_path;
std::string content;
ASSERT_TRUE(files::ReadFileToString(spec_file_path, &content));
cpuperf::SessionSpec session_spec;
ASSERT_TRUE(cpuperf::DecodeSessionSpec(content, &session_spec));
ASSERT_TRUE(files::ReadFileToString(session_spec.session_result_spec_path, &content));
cpuperf::SessionResultSpec session_result_spec;
ASSERT_TRUE(cpuperf::DecodeSessionResultSpec(content, &session_result_spec));
std::unique_ptr<Verifier> verifier = LookupVerifier(&session_result_spec);
ASSERT_TRUE(verifier);
verifier->Verify();
}