blob: 99283124bf461c29a7f138349d3da34daf98edf1 [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 <lib/fxl/command_line.h>
#include <lib/fxl/files/file.h>
#include <lib/fxl/log_settings.h>
#include <lib/fxl/log_settings_command_line.h>
#include <lib/fxl/logging.h>
#include <lib/fxl/macros.h>
#include <lib/fxl/strings/string_printf.h>
#include "garnet/bin/cpuperf/session_result_spec.h"
#include "garnet/bin/cpuperf/session_spec.h"
#include "garnet/lib/cpuperf/file_reader.h"
#include "verify_test.h"
// List of tests.
// A test automatically fails if it's not listed here.
const TestSpec* const kTestSpecs[] = {
&kFixedCounterSpec,
&kLastBranchSpec,
&kOsFlagSpec,
&kProgrammableCounterSpec,
&kTallySpec,
&kUserFlagSpec,
&kValueRecordsSpec,
};
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<cpuperf::FileReader> reader;
if (!cpuperf::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;
cpuperf::SampleRecord record;
cpuperf::ReaderStatus status;
while ((status = reader->ReadNextRecord(&trace, &record)) ==
cpuperf::ReaderStatus::kOk) {
if (trace != current_trace) {
current_trace = trace;
}
switch (record.type()) {
case CPUPERF_RECORD_TIME:
++counts.time_records;
break;
case CPUPERF_RECORD_TICK:
++counts.tick_records;
break;
case CPUPERF_RECORD_COUNT:
++counts.count_records;
break;
case CPUPERF_RECORD_VALUE:
++counts.value_records;
break;
case CPUPERF_RECORD_PC:
++counts.pc_records;
break;
case CPUPERF_RECORD_LAST_BRANCH:
++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 != cpuperf::ReaderStatus::kNoMoreRecords) {
FXL_LOG(ERROR) << "Error occurred in record reader: "
<< cpuperf::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));
}
}
static std::unique_ptr<Verifier> LookupVerifier(
const cpuperf::SessionResultSpec* spec) {
for (const auto& test : kTestSpecs) {
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();
}