command.cpp 5.7 KB

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