1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17#include <inttypes.h> 18#include <stdio.h> 19#include <chrono> 20#include <string> 21#include <vector> 22 23#include <base/logging.h> 24#include <base/strings.h> 25 26#include "command.h" 27#include "environment.h" 28#include "event_selection_set.h" 29#include "event_type.h" 30#include "perf_event.h" 31#include "utils.h" 32#include "workload.h" 33 34static std::vector<std::string> default_measured_event_types{ 35 "cpu-cycles", "stalled-cycles-frontend", "stalled-cycles-backend", "instructions", 36 "branch-instructions", "branch-misses", "task-clock", "context-switches", "page-faults", 37}; 38 39class StatCommandImpl { 40 public: 41 StatCommandImpl() : verbose_mode_(false), system_wide_collection_(false) { 42 } 43 44 bool Run(const std::vector<std::string>& args); 45 46 private: 47 bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* non_option_args); 48 bool AddMeasuredEventType(const std::string& event_type_name, bool report_unsupported_type = true); 49 bool AddDefaultMeasuredEventTypes(); 50 bool ShowCounters(const std::map<const EventType*, std::vector<PerfCounter>>& counters_map, 51 std::chrono::steady_clock::duration counting_duration); 52 53 EventSelectionSet event_selection_set_; 54 bool verbose_mode_; 55 bool system_wide_collection_; 56}; 57 58bool StatCommandImpl::Run(const std::vector<std::string>& args) { 59 // 1. Parse options. 60 std::vector<std::string> workload_args; 61 if (!ParseOptions(args, &workload_args)) { 62 return false; 63 } 64 65 // 2. Add default measured event types. 66 if (event_selection_set_.Empty()) { 67 if (!AddDefaultMeasuredEventTypes()) { 68 return false; 69 } 70 } 71 72 // 3. Create workload. 73 if (workload_args.empty()) { 74 // TODO: change default workload to sleep 99999, and run stat until Ctrl-C. 75 workload_args = std::vector<std::string>({"sleep", "1"}); 76 } 77 std::unique_ptr<Workload> workload = Workload::CreateWorkload(workload_args); 78 if (workload == nullptr) { 79 return false; 80 } 81 82 // 4. Open perf_event_files. 83 if (system_wide_collection_) { 84 if (!event_selection_set_.OpenEventFilesForAllCpus()) { 85 return false; 86 } 87 } else { 88 event_selection_set_.EnableOnExec(); 89 if (!event_selection_set_.OpenEventFilesForProcess(workload->GetPid())) { 90 return false; 91 } 92 } 93 94 // 5. Count events while workload running. 95 auto start_time = std::chrono::steady_clock::now(); 96 // If monitoring only one process, we use the enable_on_exec flag, and don't need to start 97 // counting manually. 98 if (system_wide_collection_) { 99 if (!event_selection_set_.EnableEvents()) { 100 return false; 101 } 102 } 103 if (!workload->Start()) { 104 return false; 105 } 106 workload->WaitFinish(); 107 auto end_time = std::chrono::steady_clock::now(); 108 109 // 6. Read and print counters. 110 std::map<const EventType*, std::vector<PerfCounter>> counters_map; 111 if (!event_selection_set_.ReadCounters(&counters_map)) { 112 return false; 113 } 114 if (!ShowCounters(counters_map, end_time - start_time)) { 115 return false; 116 } 117 return true; 118} 119 120bool StatCommandImpl::ParseOptions(const std::vector<std::string>& args, 121 std::vector<std::string>* non_option_args) { 122 size_t i; 123 for (i = 1; i < args.size() && args[i].size() > 0 && args[i][0] == '-'; ++i) { 124 if (args[i] == "-a") { 125 system_wide_collection_ = true; 126 } else if (args[i] == "-e") { 127 if (!NextArgumentOrError(args, &i)) { 128 return false; 129 } 130 std::vector<std::string> event_types = android::base::Split(args[i], ","); 131 for (auto& event_type : event_types) { 132 if (!AddMeasuredEventType(event_type)) { 133 return false; 134 } 135 } 136 } else if (args[i] == "--verbose") { 137 verbose_mode_ = true; 138 } else { 139 LOG(ERROR) << "Unknown option for stat command: " << args[i]; 140 LOG(ERROR) << "Try `simpleperf help stat`"; 141 return false; 142 } 143 } 144 145 if (non_option_args != nullptr) { 146 non_option_args->clear(); 147 for (; i < args.size(); ++i) { 148 non_option_args->push_back(args[i]); 149 } 150 } 151 return true; 152} 153 154bool StatCommandImpl::AddMeasuredEventType(const std::string& event_type_name, 155 bool report_unsupported_type) { 156 const EventType* event_type = 157 EventTypeFactory::FindEventTypeByName(event_type_name, report_unsupported_type); 158 if (event_type == nullptr) { 159 return false; 160 } 161 event_selection_set_.AddEventType(*event_type); 162 return true; 163} 164 165bool StatCommandImpl::AddDefaultMeasuredEventTypes() { 166 for (auto& name : default_measured_event_types) { 167 // It is not an error when some event types in the default list are not supported by the kernel. 168 AddMeasuredEventType(name, false); 169 } 170 if (event_selection_set_.Empty()) { 171 LOG(ERROR) << "Failed to add any supported default measured types"; 172 return false; 173 } 174 return true; 175} 176 177bool StatCommandImpl::ShowCounters( 178 const std::map<const EventType*, std::vector<PerfCounter>>& counters_map, 179 std::chrono::steady_clock::duration counting_duration) { 180 printf("Performance counter statistics:\n\n"); 181 182 for (auto& pair : counters_map) { 183 auto& event_type = pair.first; 184 auto& counters = pair.second; 185 if (verbose_mode_) { 186 for (auto& counter : counters) { 187 printf("%s: value %'" PRId64 ", time_enabled %" PRId64 ", time_running %" PRId64 188 ", id %" PRId64 "\n", 189 event_selection_set_.FindEventFileNameById(counter.id).c_str(), counter.value, 190 counter.time_enabled, counter.time_running, counter.id); 191 } 192 } 193 194 PerfCounter sum_counter; 195 memset(&sum_counter, 0, sizeof(sum_counter)); 196 for (auto& counter : counters) { 197 sum_counter.value += counter.value; 198 sum_counter.time_enabled += counter.time_enabled; 199 sum_counter.time_running += counter.time_running; 200 } 201 bool scaled = false; 202 int64_t scaled_count = sum_counter.value; 203 if (sum_counter.time_running < sum_counter.time_enabled) { 204 if (sum_counter.time_running == 0) { 205 scaled_count = 0; 206 } else { 207 scaled = true; 208 scaled_count = static_cast<int64_t>(static_cast<double>(sum_counter.value) * 209 sum_counter.time_enabled / sum_counter.time_running); 210 } 211 } 212 printf("%'30" PRId64 "%s %s\n", scaled_count, scaled ? "(scaled)" : " ", 213 event_type->name); 214 } 215 printf("\nTotal test time: %lf seconds.\n", 216 std::chrono::duration_cast<std::chrono::duration<double>>(counting_duration).count()); 217 return true; 218} 219 220class StatCommand : public Command { 221 public: 222 StatCommand() 223 : Command("stat", "gather performance counter information", 224 "Usage: simpleperf stat [options] [command [command-args]]\n" 225 " Gather performance counter information of running [command]. If [command]\n" 226 " is not specified, sleep 1 is used instead.\n\n" 227 " -a Collect system-wide information.\n" 228 " -e event1,event2,... Select the event list to count. Use `simpleperf list`\n" 229 " to find all possible event names.\n" 230 " --verbose Show result in verbose mode.\n") { 231 } 232 233 bool Run(const std::vector<std::string>& args) override { 234 // Keep the implementation in StatCommandImpl, so the resources used are cleaned up when the 235 // command finishes. This is useful when we need to call some commands multiple times, like 236 // in unit tests. 237 StatCommandImpl impl; 238 return impl.Run(args); 239 } 240}; 241 242StatCommand stat_command; 243