2 * Copyright (C) 2017 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #define SIMPLEPERF_EXPORT __attribute__((visibility("default")))
18 #include "include/simpleperf.h"
25 #include <android-base/logging.h>
27 #include "environment.h"
28 #include "event_attr.h"
30 #include "event_selection_set.h"
31 #include "event_type.h"
33 namespace simpleperf {
35 std::vector<std::string> GetAllEvents() {
36 std::vector<std::string> result;
37 if (!CheckPerfEventLimit()) {
40 for (auto& type : GetAllEventTypes()) {
41 perf_event_attr attr = CreateDefaultPerfEventAttr(type);
42 if (IsEventAttrSupported(attr)) {
43 result.push_back(type.name);
49 bool IsEventSupported(const std::string& name) {
50 if (!CheckPerfEventLimit()) {
53 std::unique_ptr<EventTypeAndModifier> type = ParseEventType(name);
54 if (type == nullptr) {
57 perf_event_attr attr = CreateDefaultPerfEventAttr(type->event_type);
58 return IsEventAttrSupported(attr);
61 class PerfEventSetImpl : public PerfEventSet {
63 virtual ~PerfEventSetImpl() {}
65 bool AddEvent(const std::string& name) override {
66 if (!IsEventSupported(name)) {
69 event_names_.push_back(name);
73 bool MonitorCurrentProcess() override {
74 whole_process_ = true;
78 bool MonitorCurrentThread() override {
79 whole_process_ = false;
80 threads_.insert(gettid());
84 bool MonitorThreadsInCurrentProcess(const std::vector<pid_t>& threads) override {
85 whole_process_ = false;
86 std::vector<pid_t> tids = GetThreadsInProcess(getpid());
87 for (auto& tid : threads) {
88 if (std::find(tids.begin(), tids.end(), tid) == tids.end()) {
89 LOG(ERROR) << "Thread " << tid << " doesn't exist in current process.";
93 threads_.insert(threads.begin(), threads.end());
98 PerfEventSetImpl() : whole_process_(false) {}
100 std::vector<std::string> event_names_;
102 std::set<pid_t> threads_;
105 class PerfEventSetForCounting : public PerfEventSetImpl {
107 PerfEventSetForCounting() : in_counting_state_(false) {}
108 virtual ~PerfEventSetForCounting() {}
110 bool StartCounters() override;
111 bool StopCounters() override;
112 bool ReadCounters(std::vector<Counter>* counters) override;
115 bool CreateEventSelectionSet();
116 void InitAccumulatedCounters();
117 bool ReadRawCounters(std::vector<Counter>* counters);
118 // Add counter b to a.
119 void AddCounter(Counter& a, const Counter& b);
120 // Sub counter b from a.
121 void SubCounter(Counter& a, const Counter& b);
123 bool in_counting_state_;
124 std::unique_ptr<EventSelectionSet> event_selection_set_;
125 // The counters at the last time calling StartCounting().
126 std::vector<Counter> last_start_counters_;
127 // The accumulated counters of counting periods, excluding
129 std::vector<Counter> accumulated_counters_;
132 bool PerfEventSetForCounting::CreateEventSelectionSet() {
133 std::unique_ptr<EventSelectionSet> set(new EventSelectionSet(true));
134 if (event_names_.empty()) {
135 LOG(ERROR) << "No events.";
138 for (const auto& name : event_names_) {
139 if (!set->AddEventType(name)) {
143 if (whole_process_) {
144 set->AddMonitoredProcesses({getpid()});
146 if (threads_.empty()) {
147 LOG(ERROR) << "No monitored threads.";
150 set->AddMonitoredThreads(threads_);
152 if (!set->OpenEventFiles({-1})) {
155 event_selection_set_ = std::move(set);
159 void PerfEventSetForCounting::InitAccumulatedCounters() {
160 for (const auto& name : event_names_) {
162 counter.event = name;
164 counter.time_enabled_in_ns = 0;
165 counter.time_running_in_ns = 0;
166 accumulated_counters_.push_back(counter);
170 bool PerfEventSetForCounting::ReadRawCounters(std::vector<Counter>* counters) {
171 CHECK(event_selection_set_);
172 std::vector<CountersInfo> s;
173 if (!event_selection_set_->ReadCounters(&s)) {
176 CHECK_EQ(s.size(), event_names_.size());
177 counters->resize(s.size());
178 for (size_t i = 0; i < s.size(); ++i) {
179 CountersInfo& info = s[i];
180 std::string name = info.event_modifier.empty() ? info.event_name :
181 info.event_name + ":" + info.event_modifier;
182 CHECK_EQ(name, event_names_[i]);
183 Counter& sum = (*counters)[i];
186 sum.time_enabled_in_ns = 0;
187 sum.time_running_in_ns = 0;
188 for (CounterInfo& c : info.counters) {
189 sum.value += c.counter.value;
190 sum.time_enabled_in_ns += c.counter.time_enabled;
191 sum.time_running_in_ns += c.counter.time_running;
197 void PerfEventSetForCounting::AddCounter(Counter& a, const Counter& b) {
199 a.time_enabled_in_ns += b.time_enabled_in_ns;
200 a.time_running_in_ns += b.time_enabled_in_ns;
203 void PerfEventSetForCounting::SubCounter(Counter& a, const Counter& b) {
205 a.time_enabled_in_ns -= b.time_enabled_in_ns;
206 a.time_running_in_ns -= b.time_running_in_ns;
209 bool PerfEventSetForCounting::StartCounters() {
210 if (in_counting_state_) {
213 if (event_selection_set_ == nullptr) {
214 if (!CreateEventSelectionSet()) {
217 InitAccumulatedCounters();
219 if (!ReadRawCounters(&last_start_counters_)) {
222 in_counting_state_ = true;
226 bool PerfEventSetForCounting::StopCounters() {
227 if (!in_counting_state_) {
230 std::vector<Counter> cur;
231 if (!ReadRawCounters(&cur)) {
234 for (size_t i = 0; i < event_names_.size(); ++i) {
235 SubCounter(cur[i], last_start_counters_[i]);
236 AddCounter(accumulated_counters_[i], cur[i]);
238 in_counting_state_ = false;
242 bool PerfEventSetForCounting::ReadCounters(std::vector<Counter>* counters) {
243 if (!in_counting_state_) {
244 *counters = accumulated_counters_;
247 if (!ReadRawCounters(counters)) {
250 for (size_t i = 0; i < event_names_.size(); ++i) {
251 SubCounter((*counters)[i], last_start_counters_[i]);
252 AddCounter((*counters)[i], accumulated_counters_[i]);
257 PerfEventSet* PerfEventSet::CreateInstance(PerfEventSet::Type type) {
258 if (!CheckPerfEventLimit()) {
261 if (type == Type::kPerfForCounting) {
262 return new PerfEventSetForCounting;
267 bool PerfEventSet::AddEvent(const std::string&) {
271 bool PerfEventSet::MonitorCurrentProcess() {
275 bool PerfEventSet::MonitorCurrentThread() {
279 bool PerfEventSet::MonitorThreadsInCurrentProcess(const std::vector<pid_t>&) {
283 bool PerfEventSet::StartCounters() {
287 bool PerfEventSet::StopCounters() {
291 bool PerfEventSet::ReadCounters(std::vector<Counter>*) {
295 } // namespace simpleperf