298 lines
7.7 KiB
C++
298 lines
7.7 KiB
C++
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define SIMPLEPERF_EXPORT __attribute__((visibility("default")))
|
|
#include "include/simpleperf.h"
|
|
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include "environment.h"
|
|
#include "event_attr.h"
|
|
#include "event_fd.h"
|
|
#include "event_selection_set.h"
|
|
#include "event_type.h"
|
|
|
|
namespace simpleperf {
|
|
|
|
std::vector<std::string> GetAllEvents() {
|
|
std::vector<std::string> result;
|
|
if (!CheckPerfEventLimit()) {
|
|
return result;
|
|
}
|
|
auto callback = [&](const EventType& type) {
|
|
perf_event_attr attr = CreateDefaultPerfEventAttr(type);
|
|
if (IsEventAttrSupported(attr, type.name)) {
|
|
result.push_back(type.name);
|
|
}
|
|
return true;
|
|
};
|
|
EventTypeManager::Instance().ForEachType(callback);
|
|
return result;
|
|
}
|
|
|
|
bool IsEventSupported(const std::string& name) {
|
|
if (!CheckPerfEventLimit()) {
|
|
return false;
|
|
}
|
|
std::unique_ptr<EventTypeAndModifier> type = ParseEventType(name);
|
|
if (type == nullptr) {
|
|
return false;
|
|
}
|
|
perf_event_attr attr = CreateDefaultPerfEventAttr(type->event_type);
|
|
return IsEventAttrSupported(attr, type->name);
|
|
}
|
|
|
|
class PerfEventSetImpl : public PerfEventSet {
|
|
public:
|
|
virtual ~PerfEventSetImpl() {}
|
|
|
|
bool AddEvent(const std::string& name) override {
|
|
if (!IsEventSupported(name)) {
|
|
return false;
|
|
}
|
|
event_names_.push_back(name);
|
|
return true;
|
|
}
|
|
|
|
bool MonitorCurrentProcess() override {
|
|
whole_process_ = true;
|
|
return true;
|
|
}
|
|
|
|
bool MonitorCurrentThread() override {
|
|
whole_process_ = false;
|
|
threads_.insert(gettid());
|
|
return true;
|
|
}
|
|
|
|
bool MonitorThreadsInCurrentProcess(const std::vector<pid_t>& threads) override {
|
|
whole_process_ = false;
|
|
std::vector<pid_t> tids = GetThreadsInProcess(getpid());
|
|
for (auto& tid : threads) {
|
|
if (std::find(tids.begin(), tids.end(), tid) == tids.end()) {
|
|
LOG(ERROR) << "Thread " << tid << " doesn't exist in current process.";
|
|
return false;
|
|
}
|
|
}
|
|
threads_.insert(threads.begin(), threads.end());
|
|
return true;
|
|
}
|
|
|
|
protected:
|
|
PerfEventSetImpl() : whole_process_(false) {}
|
|
|
|
std::vector<std::string> event_names_;
|
|
bool whole_process_;
|
|
std::set<pid_t> threads_;
|
|
};
|
|
|
|
class PerfEventSetForCounting : public PerfEventSetImpl {
|
|
public:
|
|
PerfEventSetForCounting() : in_counting_state_(false) {}
|
|
virtual ~PerfEventSetForCounting() {}
|
|
|
|
bool StartCounters() override;
|
|
bool StopCounters() override;
|
|
bool ReadCounters(std::vector<Counter>* counters) override;
|
|
|
|
private:
|
|
bool CreateEventSelectionSet();
|
|
void InitAccumulatedCounters();
|
|
bool ReadRawCounters(std::vector<Counter>* counters);
|
|
// Add counter b to a.
|
|
void AddCounter(Counter& a, const Counter& b);
|
|
// Sub counter b from a.
|
|
void SubCounter(Counter& a, const Counter& b);
|
|
|
|
bool in_counting_state_;
|
|
std::unique_ptr<EventSelectionSet> event_selection_set_;
|
|
// The counters at the last time calling StartCounting().
|
|
std::vector<Counter> last_start_counters_;
|
|
// The accumulated counters of counting periods, excluding
|
|
// the last one.
|
|
std::vector<Counter> accumulated_counters_;
|
|
};
|
|
|
|
bool PerfEventSetForCounting::CreateEventSelectionSet() {
|
|
std::unique_ptr<EventSelectionSet> set(new EventSelectionSet(true));
|
|
if (event_names_.empty()) {
|
|
LOG(ERROR) << "No events.";
|
|
return false;
|
|
}
|
|
for (const auto& name : event_names_) {
|
|
if (!set->AddEventType(name)) {
|
|
return false;
|
|
}
|
|
}
|
|
if (whole_process_) {
|
|
set->AddMonitoredProcesses({getpid()});
|
|
} else {
|
|
if (threads_.empty()) {
|
|
LOG(ERROR) << "No monitored threads.";
|
|
return false;
|
|
}
|
|
set->AddMonitoredThreads(threads_);
|
|
}
|
|
if (!set->OpenEventFiles({-1})) {
|
|
return false;
|
|
}
|
|
event_selection_set_ = std::move(set);
|
|
return true;
|
|
}
|
|
|
|
void PerfEventSetForCounting::InitAccumulatedCounters() {
|
|
for (const auto& name : event_names_) {
|
|
Counter counter;
|
|
counter.event = name;
|
|
counter.value = 0;
|
|
counter.time_enabled_in_ns = 0;
|
|
counter.time_running_in_ns = 0;
|
|
accumulated_counters_.push_back(counter);
|
|
}
|
|
}
|
|
|
|
bool PerfEventSetForCounting::ReadRawCounters(std::vector<Counter>* counters) {
|
|
CHECK(event_selection_set_);
|
|
std::vector<CountersInfo> s;
|
|
if (!event_selection_set_->ReadCounters(&s)) {
|
|
return false;
|
|
}
|
|
CHECK_EQ(s.size(), event_names_.size());
|
|
counters->resize(s.size());
|
|
for (size_t i = 0; i < s.size(); ++i) {
|
|
CountersInfo& info = s[i];
|
|
std::string name =
|
|
info.event_modifier.empty() ? info.event_name : info.event_name + ":" + info.event_modifier;
|
|
CHECK_EQ(name, event_names_[i]);
|
|
Counter& sum = (*counters)[i];
|
|
sum.event = name;
|
|
sum.value = 0;
|
|
sum.time_enabled_in_ns = 0;
|
|
sum.time_running_in_ns = 0;
|
|
for (CounterInfo& c : info.counters) {
|
|
sum.value += c.counter.value;
|
|
sum.time_enabled_in_ns += c.counter.time_enabled;
|
|
sum.time_running_in_ns += c.counter.time_running;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PerfEventSetForCounting::AddCounter(Counter& a, const Counter& b) {
|
|
a.value += b.value;
|
|
a.time_enabled_in_ns += b.time_enabled_in_ns;
|
|
a.time_running_in_ns += b.time_enabled_in_ns;
|
|
}
|
|
|
|
void PerfEventSetForCounting::SubCounter(Counter& a, const Counter& b) {
|
|
a.value -= b.value;
|
|
a.time_enabled_in_ns -= b.time_enabled_in_ns;
|
|
a.time_running_in_ns -= b.time_running_in_ns;
|
|
}
|
|
|
|
bool PerfEventSetForCounting::StartCounters() {
|
|
if (in_counting_state_) {
|
|
return true;
|
|
}
|
|
if (event_selection_set_ == nullptr) {
|
|
if (!CreateEventSelectionSet()) {
|
|
return false;
|
|
}
|
|
InitAccumulatedCounters();
|
|
}
|
|
if (!ReadRawCounters(&last_start_counters_)) {
|
|
return false;
|
|
}
|
|
in_counting_state_ = true;
|
|
return true;
|
|
}
|
|
|
|
bool PerfEventSetForCounting::StopCounters() {
|
|
if (!in_counting_state_) {
|
|
return true;
|
|
}
|
|
std::vector<Counter> cur;
|
|
if (!ReadRawCounters(&cur)) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < event_names_.size(); ++i) {
|
|
SubCounter(cur[i], last_start_counters_[i]);
|
|
AddCounter(accumulated_counters_[i], cur[i]);
|
|
}
|
|
in_counting_state_ = false;
|
|
return true;
|
|
}
|
|
|
|
bool PerfEventSetForCounting::ReadCounters(std::vector<Counter>* counters) {
|
|
if (!in_counting_state_) {
|
|
*counters = accumulated_counters_;
|
|
return true;
|
|
}
|
|
if (!ReadRawCounters(counters)) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < event_names_.size(); ++i) {
|
|
SubCounter((*counters)[i], last_start_counters_[i]);
|
|
AddCounter((*counters)[i], accumulated_counters_[i]);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
PerfEventSet* PerfEventSet::CreateInstance(PerfEventSet::Type type) {
|
|
if (!CheckPerfEventLimit()) {
|
|
return nullptr;
|
|
}
|
|
if (type == Type::kPerfForCounting) {
|
|
return new PerfEventSetForCounting;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool PerfEventSet::AddEvent(const std::string&) {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::MonitorCurrentProcess() {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::MonitorCurrentThread() {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::MonitorThreadsInCurrentProcess(const std::vector<pid_t>&) {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::StartCounters() {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::StopCounters() {
|
|
return false;
|
|
}
|
|
|
|
bool PerfEventSet::ReadCounters(std::vector<Counter>*) {
|
|
return false;
|
|
}
|
|
|
|
} // namespace simpleperf
|