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 "command.h" 18 19 #include <algorithm> 20 #include <map> 21 #include <string> 22 #include <vector> 23 24 #include <android-base/logging.h> 25 #include <android-base/parsedouble.h> 26 #include <android-base/parseint.h> 27 28 #include "utils.h" 29 30 using namespace simpleperf; 31 32 bool Command::NextArgumentOrError(const std::vector<std::string>& args, size_t* pi) { 33 if (*pi + 1 == args.size()) { 34 LOG(ERROR) << "No argument following " << args[*pi] << " option. Try `simpleperf help " << name_ 35 << "`"; 36 return false; 37 } 38 ++*pi; 39 return true; 40 } 41 42 bool Command::GetDoubleOption(const std::vector<std::string>& args, size_t* pi, double* value, 43 double min, double max) { 44 if (!NextArgumentOrError(args, pi)) { 45 return false; 46 } 47 if (!android::base::ParseDouble(args[*pi].c_str(), value, min, max)) { 48 LOG(ERROR) << "Invalid argument for option " << args[*pi - 1] << ": " << args[*pi]; 49 return false; 50 } 51 return true; 52 } 53 54 void Command::ReportUnknownOption(const std::vector<std::string>& args, size_t i) { 55 LOG(ERROR) << "Unknown option for " << name_ << " command: '" << args[i] 56 << "'. Try `simpleperf help " << name_ << "`"; 57 } 58 59 typedef std::function<std::unique_ptr<Command>(void)> callback_t; 60 61 static std::map<std::string, callback_t>& CommandMap() { 62 // commands is used in the constructor of Command. Defining it as a static 63 // variable in a function makes sure it is initialized before use. 64 static std::map<std::string, callback_t> command_map; 65 return command_map; 66 } 67 68 void RegisterCommand(const std::string& cmd_name, 69 const std::function<std::unique_ptr<Command>(void)>& callback) { 70 CommandMap().insert(std::make_pair(cmd_name, callback)); 71 } 72 73 void UnRegisterCommand(const std::string& cmd_name) { 74 CommandMap().erase(cmd_name); 75 } 76 77 std::unique_ptr<Command> CreateCommandInstance(const std::string& cmd_name) { 78 auto it = CommandMap().find(cmd_name); 79 return (it == CommandMap().end()) ? nullptr : (it->second)(); 80 } 81 82 const std::vector<std::string> GetAllCommandNames() { 83 std::vector<std::string> names; 84 for (const auto& pair : CommandMap()) { 85 names.push_back(pair.first); 86 } 87 return names; 88 } 89 90 extern void RegisterDumpRecordCommand(); 91 extern void RegisterHelpCommand(); 92 extern void RegisterInjectCommand(); 93 extern void RegisterListCommand(); 94 extern void RegisterKmemCommand(); 95 extern void RegisterRecordCommand(); 96 extern void RegisterReportCommand(); 97 extern void RegisterReportSampleCommand(); 98 extern void RegisterStatCommand(); 99 extern void RegisterDebugUnwindCommand(); 100 extern void RegisterTraceSchedCommand(); 101 extern void RegisterAPICommands(); 102 103 class CommandRegister { 104 public: 105 CommandRegister() { 106 RegisterDumpRecordCommand(); 107 RegisterHelpCommand(); 108 RegisterInjectCommand(); 109 RegisterKmemCommand(); 110 RegisterReportCommand(); 111 RegisterReportSampleCommand(); 112 #if defined(__linux__) 113 RegisterListCommand(); 114 RegisterRecordCommand(); 115 RegisterStatCommand(); 116 RegisterDebugUnwindCommand(); 117 RegisterTraceSchedCommand(); 118 #if defined(__ANDROID__) 119 RegisterAPICommands(); 120 #endif 121 #endif 122 } 123 }; 124 125 CommandRegister command_register; 126 127 static void StderrLogger(android::base::LogId, android::base::LogSeverity severity, 128 const char*, const char* file, unsigned int line, const char* message) { 129 static const char log_characters[] = "VDIWEFF"; 130 char severity_char = log_characters[severity]; 131 fprintf(stderr, "simpleperf %c %s:%u] %s\n", severity_char, file, line, message); 132 } 133 134 namespace simpleperf { 135 bool log_to_android_buffer = false; 136 } 137 138 bool RunSimpleperfCmd(int argc, char** argv) { 139 android::base::InitLogging(argv, StderrLogger); 140 std::vector<std::string> args; 141 android::base::LogSeverity log_severity = android::base::INFO; 142 log_to_android_buffer = false; 143 144 for (int i = 1; i < argc; ++i) { 145 if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { 146 args.insert(args.begin(), "help"); 147 } else if (strcmp(argv[i], "--log") == 0) { 148 if (i + 1 < argc) { 149 ++i; 150 if (!GetLogSeverity(argv[i], &log_severity)) { 151 LOG(ERROR) << "Unknown log severity: " << argv[i]; 152 return false; 153 } 154 } else { 155 LOG(ERROR) << "Missing argument for --log option.\n"; 156 return false; 157 } 158 #if defined(__ANDROID__) 159 } else if (strcmp(argv[i], "--log-to-android-buffer") == 0) { 160 android::base::SetLogger(android::base::LogdLogger()); 161 log_to_android_buffer = true; 162 #endif 163 } else if (strcmp(argv[i], "--version") == 0) { 164 LOG(INFO) << "Simpleperf version " << GetSimpleperfVersion(); 165 return true; 166 } else { 167 args.push_back(argv[i]); 168 } 169 } 170 android::base::ScopedLogSeverity severity(log_severity); 171 172 if (args.empty()) { 173 args.push_back("help"); 174 } 175 std::unique_ptr<Command> command = CreateCommandInstance(args[0]); 176 if (command == nullptr) { 177 LOG(ERROR) << "malformed command line: unknown command " << args[0]; 178 return false; 179 } 180 std::string command_name = args[0]; 181 args.erase(args.begin()); 182 183 LOG(DEBUG) << "command '" << command_name << "' starts running"; 184 bool result = command->Run(args); 185 LOG(DEBUG) << "command '" << command_name << "' " 186 << (result ? "finished successfully" : "failed"); 187 // Quick exit to avoid the cost of freeing memory and closing files. 188 fflush(stdout); 189 fflush(stderr); 190 _Exit(result ? 0 : 1); 191 return result; 192 } 193