blob: 9ff6fc75ffd774351666ca11114845cf8b68be42 [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 <string.h>
#include <string>
#include <gtest/gtest.h>
#include <src/lib/fxl/command_line.h>
#include "src/lib/files/file.h"
#include <src/lib/fxl/log_settings.h>
#include <src/lib/fxl/log_settings_command_line.h>
#include <src/lib/fxl/logging.h>
#include <src/lib/fxl/macros.h>
#include <src/lib/fxl/strings/string_printf.h>
#include "garnet/bin/cpuperf/session_result_spec.h"
#include "garnet/bin/cpuperf/session_spec.h"
#include "garnet/lib/perfmon/file_reader.h"
#include "verify_test.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 FXL_DCHECK which will terminate the test, just
// flag an error.
FXL_LOG(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)) {
FXL_LOG(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;
}
}
FXL_LOG(INFO)
<< fxl::StringPrintf("Counts: %zu time, %zu tick",
counts.time_records, counts.tick_records);
FXL_LOG(INFO)
<< fxl::StringPrintf("Counts: %zu count, %zu value",
counts.count_records, counts.value_records);
FXL_LOG(INFO)
<< fxl::StringPrintf("Counts: %zu pc",
counts.pc_records);
if (status != perfmon::ReaderStatus::kNoMoreRecords) {
FXL_LOG(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) {
FXL_LOG(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) {
FXL_VLOG(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();
}