| // 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 <gtest/gtest.h> |
| #include <lib/fxl/logging.h> |
| |
| #include "garnet/lib/cpuperf/events.h" |
| |
| #include "verify_test.h" |
| |
| class LastBranchVerifier : public Verifier { |
| public: |
| static std::unique_ptr<Verifier> Create( |
| const cpuperf::SessionResultSpec* spec) { |
| return std::make_unique<LastBranchVerifier>(spec); |
| } |
| |
| LastBranchVerifier(const cpuperf::SessionResultSpec* spec) |
| : Verifier(spec) { |
| const cpuperf::EventDetails* details; |
| |
| bool rc __UNUSED = |
| cpuperf::LookupEventByName("arch", "instructions_retired", &details); |
| FXL_DCHECK(rc); |
| instructions_retired_id_ = details->id; |
| } |
| |
| private: |
| bool VerifyRecord(const cpuperf::SampleRecord& record) override { |
| if (record.header->event == instructions_retired_id_) { |
| ++instructions_retired_count_; |
| } |
| if (record.type() == CPUPERF_RECORD_LAST_BRANCH) { |
| ++last_branch_record_count_; |
| if (record.header->event != instructions_retired_id_) { |
| FXL_LOG(ERROR) << "Last branch record has wrong event id: " |
| << record.header->event; |
| return false; |
| } |
| const cpuperf_last_branch_record_t* lbr = record.last_branch; |
| uint64_t valid_info_mask = (CPUPERF_LAST_BRANCH_INFO_CYCLES_MASK | |
| CPUPERF_LAST_BRANCH_INFO_MISPRED_MASK); |
| for (size_t i = 0; i < lbr->num_branches; ++i) { |
| if (lbr->aspace == 0) { |
| FXL_LOG(ERROR) << "Last branch record has zero aspace"; |
| return false; |
| } |
| if (lbr->num_branches > CPUPERF_MAX_NUM_LAST_BRANCH) { |
| FXL_LOG(ERROR) << "Last branch record has too many branches"; |
| return false; |
| } |
| // Maybe branch to zero could end up here, so we don't verify from,to |
| // are non-zero, but they both can't be. |
| if (lbr->branches[i].from == 0 && lbr->branches[i].to == 0) { |
| FXL_LOG(ERROR) << "Last branch record with zero from,to"; |
| return false; |
| } |
| if (lbr->branches[i].info & !valid_info_mask) { |
| FXL_LOG(ERROR) << "Last branch record has invalid info bits"; |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| bool VerifyTrace(const RecordCounts& counts) override { |
| bool pass = true; |
| if (instructions_retired_count_ == 0) { |
| FXL_LOG(ERROR) << "Missing instructions_retired events"; |
| pass = false; |
| } |
| if (last_branch_record_count_ == 0) { |
| FXL_LOG(ERROR) << "Missing last-branch records events"; |
| pass = false; |
| } |
| return pass; |
| } |
| |
| // Ids of the events we should see. |
| cpuperf_event_id_t instructions_retired_id_; |
| |
| // Counts of the events we should see. |
| size_t instructions_retired_count_ = 0; |
| size_t last_branch_record_count_ = 0; |
| }; |
| |
| const TestSpec kLastBranchSpec = { |
| "last-branch", |
| &LastBranchVerifier::Create, |
| }; |