Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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 | |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 17 | #include <aio.h> |
| 18 | #include <fcntl.h> |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 19 | #include <inttypes.h> |
Lalit Maganti | 26f69bd | 2019-04-29 18:23:47 +0100 | [diff] [blame] | 20 | #include <stdio.h> |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 21 | #include <sys/stat.h> |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 22 | #include <unistd.h> |
| 23 | |
| 24 | #include <functional> |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 25 | #include <iostream> |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 26 | #include <vector> |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 27 | |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 28 | #include "perfetto/base/build_config.h" |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 29 | #include "perfetto/base/file_utils.h" |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 30 | #include "perfetto/base/logging.h" |
Ioannis Ilkos | eff38f5 | 2018-10-29 10:37:55 +0000 | [diff] [blame] | 31 | #include "perfetto/base/scoped_file.h" |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 32 | #include "perfetto/base/string_splitter.h" |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 33 | #include "perfetto/base/time.h" |
Ioannis Ilkos | eff38f5 | 2018-10-29 10:37:55 +0000 | [diff] [blame] | 34 | #include "perfetto/trace_processor/trace_processor.h" |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 35 | |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 36 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
| 37 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ |
| 38 | PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) |
| 39 | #define PERFETTO_HAS_SIGNAL_H() 1 |
| 40 | #else |
| 41 | #define PERFETTO_HAS_SIGNAL_H() 0 |
| 42 | #endif |
| 43 | |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 44 | #if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) |
| 45 | #include <linenoise.h> |
Hector Dearman | 36adc82 | 2018-10-02 11:35:08 +0100 | [diff] [blame] | 46 | #include <pwd.h> |
| 47 | #include <sys/types.h> |
Primiano Tucci | 00da64a | 2019-02-22 14:51:10 +0000 | [diff] [blame] | 48 | #include "perfetto_version.gen.h" |
| 49 | #else |
| 50 | #define PERFETTO_GET_GIT_REVISION() "unknown" |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 51 | #endif |
| 52 | |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 53 | #if PERFETTO_HAS_SIGNAL_H() |
| 54 | #include <signal.h> |
| 55 | #endif |
| 56 | |
Lalit Maganti | 1ebebf1 | 2018-10-15 17:24:04 +0100 | [diff] [blame] | 57 | namespace perfetto { |
| 58 | namespace trace_processor { |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 59 | |
| 60 | namespace { |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 61 | TraceProcessor* g_tp; |
| 62 | |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 63 | #if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) |
| 64 | |
Hector Dearman | 36adc82 | 2018-10-02 11:35:08 +0100 | [diff] [blame] | 65 | bool EnsureDir(const std::string& path) { |
| 66 | return mkdir(path.c_str(), 0755) != -1 || errno == EEXIST; |
| 67 | } |
| 68 | |
| 69 | bool EnsureFile(const std::string& path) { |
Primiano Tucci | f675dc2 | 2018-10-18 00:17:26 +0200 | [diff] [blame] | 70 | return base::OpenFile(path, O_RDONLY | O_CREAT, 0644).get() != -1; |
Hector Dearman | 36adc82 | 2018-10-02 11:35:08 +0100 | [diff] [blame] | 71 | } |
| 72 | |
| 73 | std::string GetConfigPath() { |
| 74 | const char* homedir = getenv("HOME"); |
| 75 | if (homedir == nullptr) |
| 76 | homedir = getpwuid(getuid())->pw_dir; |
| 77 | if (homedir == nullptr) |
| 78 | return ""; |
| 79 | return std::string(homedir) + "/.config"; |
| 80 | } |
| 81 | |
| 82 | std::string GetPerfettoPath() { |
| 83 | std::string config = GetConfigPath(); |
| 84 | if (config == "") |
| 85 | return ""; |
| 86 | return config + "/perfetto"; |
| 87 | } |
| 88 | |
| 89 | std::string GetHistoryPath() { |
| 90 | std::string perfetto = GetPerfettoPath(); |
| 91 | if (perfetto == "") |
| 92 | return ""; |
| 93 | return perfetto + "/.trace_processor_shell_history"; |
| 94 | } |
| 95 | |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 96 | void SetupLineEditor() { |
| 97 | linenoiseSetMultiLine(true); |
| 98 | linenoiseHistorySetMaxLen(1000); |
Hector Dearman | 36adc82 | 2018-10-02 11:35:08 +0100 | [diff] [blame] | 99 | |
| 100 | bool success = GetHistoryPath() != ""; |
| 101 | success = success && EnsureDir(GetConfigPath()); |
| 102 | success = success && EnsureDir(GetPerfettoPath()); |
| 103 | success = success && EnsureFile(GetHistoryPath()); |
| 104 | success = success && linenoiseHistoryLoad(GetHistoryPath().c_str()) != -1; |
| 105 | if (!success) { |
| 106 | PERFETTO_PLOG("Could not load history from %s", GetHistoryPath().c_str()); |
| 107 | } |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 108 | } |
| 109 | |
Hector Dearman | 6935644 | 2018-09-21 14:10:57 +0100 | [diff] [blame] | 110 | void FreeLine(char* line) { |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 111 | linenoiseHistoryAdd(line); |
Hector Dearman | 36adc82 | 2018-10-02 11:35:08 +0100 | [diff] [blame] | 112 | linenoiseHistorySave(GetHistoryPath().c_str()); |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 113 | linenoiseFree(line); |
| 114 | } |
| 115 | |
| 116 | char* GetLine(const char* prompt) { |
| 117 | return linenoise(prompt); |
| 118 | } |
| 119 | |
| 120 | #else |
| 121 | |
| 122 | void SetupLineEditor() {} |
| 123 | |
| 124 | void FreeLine(char* line) { |
Greg Kaiser | bc635a5 | 2018-09-24 06:12:09 -0700 | [diff] [blame] | 125 | delete[] line; |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | char* GetLine(const char* prompt) { |
| 129 | printf("\r%80s\r%s", "", prompt); |
| 130 | fflush(stdout); |
| 131 | char* line = new char[1024]; |
| 132 | if (!fgets(line, 1024 - 1, stdin)) { |
| 133 | FreeLine(line); |
| 134 | return nullptr; |
| 135 | } |
| 136 | if (strlen(line) > 0) |
| 137 | line[strlen(line) - 1] = 0; |
| 138 | return line; |
| 139 | } |
| 140 | |
| 141 | #endif |
| 142 | |
Lalit Maganti | 49ae901 | 2019-04-03 16:10:39 +0100 | [diff] [blame] | 143 | bool PrintStats() { |
| 144 | auto it = g_tp->ExecuteQuery( |
| 145 | "SELECT name, idx, source, value from stats " |
| 146 | "where severity = 'error' and value > 0"); |
| 147 | |
| 148 | bool first = true; |
| 149 | for (uint32_t rows = 0; it.Next(); rows++) { |
| 150 | if (first) { |
| 151 | fprintf(stderr, "Error stats for this trace:\n"); |
| 152 | |
| 153 | for (uint32_t i = 0; i < it.ColumnCount(); i++) |
| 154 | fprintf(stderr, "%40s ", it.GetColumName(i).c_str()); |
| 155 | fprintf(stderr, "\n"); |
| 156 | |
| 157 | for (uint32_t i = 0; i < it.ColumnCount(); i++) |
| 158 | fprintf(stderr, "%40s ", "----------------------------------------"); |
| 159 | fprintf(stderr, "\n"); |
| 160 | |
| 161 | first = false; |
| 162 | } |
| 163 | |
| 164 | for (uint32_t c = 0; c < it.ColumnCount(); c++) { |
| 165 | auto value = it.Get(c); |
| 166 | switch (value.type) { |
| 167 | case SqlValue::Type::kNull: |
| 168 | fprintf(stderr, "%-40.40s", "[NULL]"); |
| 169 | break; |
| 170 | case SqlValue::Type::kDouble: |
| 171 | fprintf(stderr, "%40f", value.double_value); |
| 172 | break; |
| 173 | case SqlValue::Type::kLong: |
| 174 | fprintf(stderr, "%40" PRIi64, value.long_value); |
| 175 | break; |
| 176 | case SqlValue::Type::kString: |
| 177 | fprintf(stderr, "%-40.40s", value.string_value); |
| 178 | break; |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame^] | 179 | case SqlValue::Type::kBytes: |
| 180 | printf("%-40.40s", "<raw bytes>"); |
| 181 | break; |
Lalit Maganti | 49ae901 | 2019-04-03 16:10:39 +0100 | [diff] [blame] | 182 | } |
| 183 | fprintf(stderr, " "); |
| 184 | } |
| 185 | fprintf(stderr, "\n"); |
| 186 | } |
| 187 | |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 188 | util::Status status = it.Status(); |
| 189 | if (!status.ok()) { |
| 190 | PERFETTO_ELOG("Error while iterating stats %s", status.c_message()); |
Lalit Maganti | 49ae901 | 2019-04-03 16:10:39 +0100 | [diff] [blame] | 191 | return false; |
| 192 | } |
| 193 | return true; |
| 194 | } |
| 195 | |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 196 | int ExportTraceToDatabase(const std::string& output_name) { |
| 197 | PERFETTO_CHECK(output_name.find("'") == std::string::npos); |
| 198 | { |
| 199 | base::ScopedFile fd(base::OpenFile(output_name, O_CREAT | O_RDWR, 0600)); |
| 200 | if (!fd) { |
| 201 | PERFETTO_PLOG("Failed to create file: %s", output_name.c_str()); |
| 202 | return 1; |
| 203 | } |
| 204 | int res = ftruncate(fd.get(), 0); |
| 205 | PERFETTO_CHECK(res == 0); |
| 206 | } |
| 207 | |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 208 | std::string attach_sql = |
| 209 | "ATTACH DATABASE '" + output_name + "' AS perfetto_export"; |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 210 | auto attach_it = g_tp->ExecuteQuery(attach_sql); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 211 | bool attach_has_more = attach_it.Next(); |
| 212 | PERFETTO_DCHECK(!attach_has_more); |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 213 | |
| 214 | util::Status status = attach_it.Status(); |
| 215 | if (!status.ok()) { |
| 216 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 217 | return 1; |
| 218 | } |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 219 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 220 | auto tables_it = g_tp->ExecuteQuery( |
| 221 | "SELECT name FROM perfetto_tables UNION " |
| 222 | "SELECT name FROM sqlite_master WHERE type='table'"); |
| 223 | for (uint32_t rows = 0; tables_it.Next(); rows++) { |
| 224 | std::string table_name = tables_it.Get(0).string_value; |
| 225 | PERFETTO_CHECK(table_name.find("'") == std::string::npos); |
| 226 | std::string export_sql = "CREATE TABLE perfetto_export." + table_name + |
| 227 | " AS SELECT * FROM " + table_name; |
| 228 | |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 229 | auto export_it = g_tp->ExecuteQuery(export_sql); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 230 | bool export_has_more = export_it.Next(); |
| 231 | PERFETTO_DCHECK(!export_has_more); |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 232 | |
| 233 | status = export_it.Status(); |
| 234 | if (!status.ok()) { |
| 235 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 236 | return 1; |
| 237 | } |
| 238 | } |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 239 | status = tables_it.Status(); |
| 240 | if (!status.ok()) { |
| 241 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 242 | return 1; |
| 243 | } |
| 244 | |
| 245 | auto detach_it = g_tp->ExecuteQuery("DETACH DATABASE perfetto_export"); |
| 246 | bool detach_has_more = attach_it.Next(); |
| 247 | PERFETTO_DCHECK(!detach_has_more); |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 248 | status = detach_it.Status(); |
| 249 | if (!status.ok()) { |
| 250 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 251 | return 1; |
| 252 | } |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 253 | return 0; |
| 254 | } |
| 255 | |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 256 | int RunMetrics(const std::vector<std::string>& metric_names) { |
Lalit Maganti | d9f86b6 | 2019-04-08 11:11:51 +0100 | [diff] [blame] | 257 | std::vector<uint8_t> metric_result; |
Lalit Maganti | d71a945 | 2019-05-09 15:13:24 +0100 | [diff] [blame] | 258 | util::Status status = g_tp->ComputeMetric(metric_names, &metric_result); |
| 259 | if (!status.ok()) { |
| 260 | PERFETTO_ELOG("Error when computing metrics: %s", status.c_message()); |
Lalit Maganti | d9f86b6 | 2019-04-08 11:11:51 +0100 | [diff] [blame] | 261 | return 1; |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 262 | } |
Lalit Maganti | 26f69bd | 2019-04-29 18:23:47 +0100 | [diff] [blame] | 263 | fwrite(metric_result.data(), sizeof(uint8_t), metric_result.size(), stdout); |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 264 | return 0; |
| 265 | } |
| 266 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 267 | void PrintQueryResultInteractively(TraceProcessor::Iterator* it, |
| 268 | base::TimeNanos t_start) { |
| 269 | base::TimeNanos t_end = t_start; |
| 270 | for (uint32_t rows = 0; it->Next(); rows++) { |
| 271 | if (rows % 32 == 0) { |
| 272 | if (rows > 0) { |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 273 | fprintf(stderr, "...\nType 'q' to stop, Enter for more records: "); |
| 274 | fflush(stderr); |
| 275 | char input[32]; |
| 276 | if (!fgets(input, sizeof(input) - 1, stdin)) |
| 277 | exit(0); |
| 278 | if (input[0] == 'q') |
| 279 | break; |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 280 | } else { |
Lalit Maganti | aac2f65 | 2019-04-30 12:16:21 +0100 | [diff] [blame] | 281 | t_end = base::GetWallTimeNs(); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 282 | } |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 283 | for (uint32_t i = 0; i < it->ColumnCount(); i++) |
| 284 | printf("%20s ", it->GetColumName(i).c_str()); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 285 | printf("\n"); |
| 286 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 287 | for (uint32_t i = 0; i < it->ColumnCount(); i++) |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 288 | printf("%20s ", "--------------------"); |
| 289 | printf("\n"); |
| 290 | } |
| 291 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 292 | for (uint32_t c = 0; c < it->ColumnCount(); c++) { |
| 293 | auto value = it->Get(c); |
| 294 | switch (value.type) { |
| 295 | case SqlValue::Type::kNull: |
| 296 | printf("%-20.20s", "[NULL]"); |
| 297 | break; |
| 298 | case SqlValue::Type::kDouble: |
| 299 | printf("%20f", value.double_value); |
| 300 | break; |
| 301 | case SqlValue::Type::kLong: |
| 302 | printf("%20" PRIi64, value.long_value); |
| 303 | break; |
| 304 | case SqlValue::Type::kString: |
| 305 | printf("%-20.20s", value.string_value); |
| 306 | break; |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame^] | 307 | case SqlValue::Type::kBytes: |
| 308 | printf("%-20.20s", "<raw bytes>"); |
| 309 | break; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 310 | } |
| 311 | printf(" "); |
| 312 | } |
| 313 | printf("\n"); |
| 314 | } |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 315 | |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 316 | util::Status status = it->Status(); |
| 317 | if (!status.ok()) { |
| 318 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 319 | } |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 320 | printf("\nQuery executed in %.3f ms\n\n", (t_end - t_start).count() / 1E6); |
| 321 | } |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 322 | |
| 323 | void PrintShellUsage() { |
| 324 | PERFETTO_ELOG( |
| 325 | "Available commands:\n" |
| 326 | ".quit, .q Exit the shell.\n" |
| 327 | ".help This text.\n" |
| 328 | ".dump FILE Export the trace as a sqlite database.\n"); |
| 329 | } |
| 330 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 331 | int StartInteractiveShell() { |
| 332 | SetupLineEditor(); |
Primiano Tucci | b75dcee | 2018-08-08 12:21:36 +0100 | [diff] [blame] | 333 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 334 | for (;;) { |
| 335 | char* line = GetLine("> "); |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 336 | if (!line) |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 337 | break; |
| 338 | if (strcmp(line, "") == 0) |
| 339 | continue; |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 340 | if (line[0] == '.') { |
| 341 | char command[32] = {}; |
| 342 | char arg[1024] = {}; |
| 343 | sscanf(line + 1, "%31s %1023s", command, arg); |
| 344 | if (strcmp(command, "quit") == 0 || strcmp(command, "q") == 0) { |
| 345 | break; |
| 346 | } else if (strcmp(command, "help") == 0) { |
| 347 | PrintShellUsage(); |
| 348 | } else if (strcmp(command, "dump") == 0 && strlen(arg)) { |
| 349 | if (ExportTraceToDatabase(arg) != 0) |
| 350 | PERFETTO_ELOG("Database export failed"); |
| 351 | } else { |
| 352 | PrintShellUsage(); |
| 353 | } |
| 354 | continue; |
| 355 | } |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 356 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 357 | base::TimeNanos t_start = base::GetWallTimeNs(); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 358 | auto it = g_tp->ExecuteQuery(line); |
| 359 | PrintQueryResultInteractively(&it, t_start); |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 360 | |
| 361 | FreeLine(line); |
| 362 | } |
| 363 | return 0; |
| 364 | } |
| 365 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 366 | void PrintQueryResultAsCsv(TraceProcessor::Iterator* it, FILE* output) { |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 367 | for (uint32_t c = 0; c < it->ColumnCount(); c++) { |
| 368 | if (c > 0) |
| 369 | fprintf(output, ","); |
| 370 | fprintf(output, "\"%s\"", it->GetColumName(c).c_str()); |
| 371 | } |
| 372 | fprintf(output, "\n"); |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 373 | |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 374 | for (uint32_t rows = 0; it->Next(); rows++) { |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 375 | for (uint32_t c = 0; c < it->ColumnCount(); c++) { |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 376 | if (c > 0) |
| 377 | fprintf(output, ","); |
Lalit Maganti | b55c884 | 2018-12-13 14:26:08 +0000 | [diff] [blame] | 378 | |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 379 | auto value = it->Get(c); |
| 380 | switch (value.type) { |
| 381 | case SqlValue::Type::kNull: |
| 382 | fprintf(output, "\"%s\"", "[NULL]"); |
| 383 | break; |
| 384 | case SqlValue::Type::kDouble: |
| 385 | fprintf(output, "%f", value.double_value); |
| 386 | break; |
| 387 | case SqlValue::Type::kLong: |
| 388 | fprintf(output, "%" PRIi64, value.long_value); |
| 389 | break; |
| 390 | case SqlValue::Type::kString: |
| 391 | fprintf(output, "\"%s\"", value.string_value); |
| 392 | break; |
Lalit Maganti | 6221107 | 2019-05-10 14:09:58 +0100 | [diff] [blame^] | 393 | case SqlValue::Type::kBytes: |
| 394 | fprintf(output, "\"%s\"", "<raw bytes>"); |
| 395 | break; |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 396 | } |
| 397 | } |
Lalit Maganti | b55c884 | 2018-12-13 14:26:08 +0000 | [diff] [blame] | 398 | fprintf(output, "\n"); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 399 | } |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 400 | } |
| 401 | |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 402 | bool LoadQueries(FILE* input, std::vector<std::string>* output) { |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 403 | char buffer[4096]; |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 404 | while (!feof(input) && !ferror(input)) { |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 405 | std::string sql_query; |
| 406 | while (fgets(buffer, sizeof(buffer), input)) { |
| 407 | if (strncmp(buffer, "\n", sizeof(buffer)) == 0) |
| 408 | break; |
| 409 | sql_query.append(buffer); |
| 410 | } |
| 411 | if (sql_query.back() == '\n') |
| 412 | sql_query.resize(sql_query.size() - 1); |
Lalit Maganti | cbccb0a | 2018-12-04 20:14:42 +0000 | [diff] [blame] | 413 | |
| 414 | // If we have a new line at the end of the file or an extra new line |
| 415 | // somewhere in the file, we'll end up with an empty query which we should |
| 416 | // just ignore. |
| 417 | if (sql_query.empty()) |
| 418 | continue; |
| 419 | |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 420 | output->push_back(sql_query); |
| 421 | } |
| 422 | if (ferror(input)) { |
| 423 | PERFETTO_ELOG("Error reading query file"); |
| 424 | return false; |
| 425 | } |
| 426 | return true; |
| 427 | } |
| 428 | |
| 429 | bool RunQueryAndPrintResult(const std::vector<std::string> queries, |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 430 | FILE* output) { |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 431 | bool is_first_query = true; |
| 432 | bool is_query_error = false; |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 433 | bool has_output = false; |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 434 | for (const auto& sql_query : queries) { |
| 435 | // Add an extra newline separator between query results. |
| 436 | if (!is_first_query) |
| 437 | fprintf(output, "\n"); |
| 438 | is_first_query = false; |
| 439 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 440 | PERFETTO_ILOG("Executing query: %s", sql_query.c_str()); |
| 441 | |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 442 | auto it = g_tp->ExecuteQuery(sql_query); |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 443 | util::Status status = it.Status(); |
| 444 | if (!status.ok()) { |
| 445 | PERFETTO_ELOG("SQLite error: %s", status.c_message()); |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 446 | is_query_error = true; |
| 447 | break; |
| 448 | } |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 449 | if (it.ColumnCount() == 0) { |
| 450 | bool it_has_more = it.Next(); |
| 451 | PERFETTO_DCHECK(!it_has_more); |
| 452 | continue; |
| 453 | } |
| 454 | |
| 455 | if (has_output) { |
Lalit Maganti | c72cea2 | 2019-04-08 12:29:15 +0100 | [diff] [blame] | 456 | PERFETTO_ELOG( |
| 457 | "More than one query generated result rows. This is " |
| 458 | "unsupported."); |
| 459 | is_query_error = true; |
| 460 | break; |
| 461 | } |
| 462 | PrintQueryResultAsCsv(&it, output); |
Lalit Maganti | 73b1a0a | 2019-04-08 13:51:14 +0100 | [diff] [blame] | 463 | has_output = true; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 464 | } |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 465 | return !is_query_error; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 466 | } |
| 467 | |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 468 | int MaybePrintPerfFile(const char* perf_file_path, |
| 469 | base::TimeNanos t_load, |
| 470 | base::TimeNanos t_run) { |
| 471 | if (!perf_file_path) |
| 472 | return 0; |
| 473 | |
| 474 | char buf[128]; |
| 475 | int count = snprintf(buf, sizeof(buf), "%" PRId64 ",%" PRId64, |
| 476 | static_cast<int64_t>(t_load.count()), |
| 477 | static_cast<int64_t>(t_run.count())); |
| 478 | if (count < 0) { |
| 479 | PERFETTO_ELOG("Failed to write perf data"); |
| 480 | return 1; |
| 481 | } |
| 482 | |
| 483 | auto fd(base::OpenFile(perf_file_path, O_WRONLY | O_CREAT | O_TRUNC, 066)); |
| 484 | if (!fd) { |
| 485 | PERFETTO_ELOG("Failed to open perf file"); |
| 486 | return 1; |
| 487 | } |
| 488 | base::WriteAll(fd.get(), buf, static_cast<size_t>(count)); |
| 489 | return 0; |
| 490 | } |
| 491 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 492 | void PrintUsage(char** argv) { |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 493 | PERFETTO_ELOG( |
| 494 | "Interactive trace processor shell.\n" |
| 495 | "Usage: %s [OPTIONS] trace_file.pb\n\n" |
| 496 | "Options:\n" |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 497 | " -d Enable virtual table debugging.\n" |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 498 | " -p FILE Writes the time taken to ingest the trace and" |
| 499 | "execute the queries to the given file. Only valid with -q or " |
| 500 | "--run-metrics and the file will only be written if the execution is " |
| 501 | "successful\n" |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 502 | " -s FILE Read and execute contents of file before " |
| 503 | "launching an interactive shell.\n" |
| 504 | " -q FILE Read and execute an SQL query from a file.\n" |
| 505 | " -e FILE Export the trace into a SQLite database.\n" |
| 506 | " --run-metrics x,y,z Runs a comma separated list of metrics and " |
| 507 | "prints the result as a TraceMetrics proto to stdout.\n", |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 508 | argv[0]); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 509 | } |
| 510 | |
Lalit Maganti | 1ebebf1 | 2018-10-15 17:24:04 +0100 | [diff] [blame] | 511 | int TraceProcessorMain(int argc, char** argv) { |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 512 | if (argc < 2) { |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 513 | PrintUsage(argv); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 514 | return 1; |
| 515 | } |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 516 | const char* perf_file_path = nullptr; |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 517 | const char* trace_file_path = nullptr; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 518 | const char* query_file_path = nullptr; |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 519 | const char* sqlite_file_path = nullptr; |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 520 | const char* metric_names = nullptr; |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 521 | bool launch_shell = true; |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 522 | for (int i = 1; i < argc; i++) { |
Primiano Tucci | 00da64a | 2019-02-22 14:51:10 +0000 | [diff] [blame] | 523 | if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { |
| 524 | printf("%s\n", PERFETTO_GET_GIT_REVISION()); |
| 525 | exit(0); |
| 526 | } |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 527 | if (strcmp(argv[i], "-d") == 0) { |
| 528 | EnableSQLiteVtableDebugging(); |
| 529 | continue; |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 530 | } else if (strcmp(argv[i], "-p") == 0) { |
| 531 | if (++i == argc) { |
| 532 | PrintUsage(argv); |
| 533 | return 1; |
| 534 | } |
| 535 | perf_file_path = argv[i]; |
| 536 | continue; |
| 537 | } else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "-s") == 0) { |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 538 | launch_shell = strcmp(argv[i], "-s") == 0; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 539 | if (++i == argc) { |
| 540 | PrintUsage(argv); |
| 541 | return 1; |
| 542 | } |
| 543 | query_file_path = argv[i]; |
| 544 | continue; |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 545 | } else if (strcmp(argv[i], "-e") == 0) { |
| 546 | if (++i == argc) { |
| 547 | PrintUsage(argv); |
| 548 | return 1; |
| 549 | } |
| 550 | sqlite_file_path = argv[i]; |
| 551 | continue; |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 552 | } else if (strcmp(argv[i], "--run-metrics") == 0) { |
| 553 | if (++i == argc) { |
| 554 | PrintUsage(argv); |
| 555 | return 1; |
| 556 | } |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 557 | launch_shell = false; |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 558 | metric_names = argv[i]; |
| 559 | continue; |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 560 | } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { |
| 561 | PrintUsage(argv); |
| 562 | return 0; |
| 563 | } else if (argv[i][0] == '-') { |
| 564 | PERFETTO_ELOG("Unknown option: %s", argv[i]); |
| 565 | return 1; |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 566 | } |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 567 | trace_file_path = argv[i]; |
| 568 | } |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 569 | |
Lalit Maganti | 21160e8 | 2018-10-16 09:40:29 +0100 | [diff] [blame] | 570 | if (trace_file_path == nullptr) { |
| 571 | PrintUsage(argv); |
| 572 | return 1; |
| 573 | } |
| 574 | |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 575 | // Only allow non-interactive queries to emit perf data. |
| 576 | if (perf_file_path && launch_shell) { |
| 577 | PrintUsage(argv); |
| 578 | return 1; |
| 579 | } |
| 580 | |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 581 | // Load the trace file into the trace processor. |
Ioannis Ilkos | eff38f5 | 2018-10-29 10:37:55 +0000 | [diff] [blame] | 582 | Config config; |
Ioannis Ilkos | f837129 | 2018-11-05 16:47:35 +0000 | [diff] [blame] | 583 | std::unique_ptr<TraceProcessor> tp = TraceProcessor::CreateInstance(config); |
Florian Mayer | b03fd28 | 2018-10-03 16:05:16 +0100 | [diff] [blame] | 584 | base::ScopedFile fd(base::OpenFile(trace_file_path, O_RDONLY)); |
Lalit Maganti | 22a1e0c | 2018-12-04 20:28:18 +0000 | [diff] [blame] | 585 | if (!fd) { |
| 586 | PERFETTO_ELOG("Could not open trace file (path: %s)", trace_file_path); |
| 587 | return 1; |
| 588 | } |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 589 | |
| 590 | // Load the trace in chunks using async IO. We create a simple pipeline where, |
| 591 | // at each iteration, we parse the current chunk and asynchronously start |
| 592 | // reading the next chunk. |
| 593 | |
| 594 | // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz. |
| 595 | constexpr size_t kChunkSize = 1024 * 1024; |
| 596 | struct aiocb cb {}; |
| 597 | cb.aio_nbytes = kChunkSize; |
| 598 | cb.aio_fildes = *fd; |
| 599 | |
Florian Mayer | e37c620 | 2018-10-18 12:07:59 +0100 | [diff] [blame] | 600 | std::unique_ptr<uint8_t[]> aio_buf(new uint8_t[kChunkSize]); |
Lalit Maganti | 9e6616e | 2019-04-03 13:19:44 +0100 | [diff] [blame] | 601 | #if defined(MEMORY_SANITIZER) |
| 602 | // Just initialize the memory to make the memory sanitizer happy as it |
| 603 | // cannot track aio calls below. |
| 604 | memset(aio_buf.get(), 0, kChunkSize); |
| 605 | #endif |
Florian Mayer | e37c620 | 2018-10-18 12:07:59 +0100 | [diff] [blame] | 606 | cb.aio_buf = aio_buf.get(); |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 607 | |
| 608 | PERFETTO_CHECK(aio_read(&cb) == 0); |
| 609 | struct aiocb* aio_list[1] = {&cb}; |
| 610 | |
| 611 | uint64_t file_size = 0; |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 612 | auto t_load_start = base::GetWallTimeNs(); |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 613 | for (int i = 0;; i++) { |
| 614 | if (i % 128 == 0) |
| 615 | fprintf(stderr, "\rLoading trace: %.2f MB\r", file_size / 1E6); |
| 616 | |
| 617 | // Block waiting for the pending read to complete. |
| 618 | PERFETTO_CHECK(aio_suspend(aio_list, 1, nullptr) == 0); |
| 619 | auto rsize = aio_return(&cb); |
| 620 | if (rsize <= 0) |
| 621 | break; |
| 622 | file_size += static_cast<uint64_t>(rsize); |
| 623 | |
| 624 | // Take ownership of the completed buffer and enqueue a new async read |
| 625 | // with a fresh buffer. |
Florian Mayer | e37c620 | 2018-10-18 12:07:59 +0100 | [diff] [blame] | 626 | std::unique_ptr<uint8_t[]> buf(std::move(aio_buf)); |
| 627 | aio_buf.reset(new uint8_t[kChunkSize]); |
Lalit Maganti | 9e6616e | 2019-04-03 13:19:44 +0100 | [diff] [blame] | 628 | #if defined(MEMORY_SANITIZER) |
| 629 | // Just initialize the memory to make the memory sanitizer happy as it |
| 630 | // cannot track aio calls below. |
| 631 | memset(aio_buf.get(), 0, kChunkSize); |
| 632 | #endif |
Florian Mayer | e37c620 | 2018-10-18 12:07:59 +0100 | [diff] [blame] | 633 | cb.aio_buf = aio_buf.get(); |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 634 | cb.aio_offset += rsize; |
| 635 | PERFETTO_CHECK(aio_read(&cb) == 0); |
| 636 | |
| 637 | // Parse the completed buffer while the async read is in-flight. |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 638 | util::Status status = tp->Parse(std::move(buf), static_cast<size_t>(rsize)); |
| 639 | if (PERFETTO_UNLIKELY(!status.ok())) { |
| 640 | PERFETTO_ELOG("Fatal error while parsing trace: %s", status.c_message()); |
Lalit Maganti | 4b2b253 | 2019-05-09 11:03:23 +0100 | [diff] [blame] | 641 | return 1; |
Lalit Maganti | 1f06718 | 2019-05-09 14:50:05 +0100 | [diff] [blame] | 642 | } |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 643 | } |
Ioannis Ilkos | f837129 | 2018-11-05 16:47:35 +0000 | [diff] [blame] | 644 | tp->NotifyEndOfFile(); |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 645 | |
| 646 | auto t_load = base::GetWallTimeNs() - t_load_start; |
| 647 | double t_load_s = t_load.count() / 1E9; |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 648 | double size_mb = file_size / 1E6; |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 649 | PERFETTO_ILOG("Trace loaded: %.2f MB (%.1f MB/s)", size_mb, |
| 650 | size_mb / t_load_s); |
Ioannis Ilkos | f837129 | 2018-11-05 16:47:35 +0000 | [diff] [blame] | 651 | g_tp = tp.get(); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 652 | |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 653 | #if PERFETTO_HAS_SIGNAL_H() |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 654 | signal(SIGINT, [](int) { g_tp->InterruptQuery(); }); |
Primiano Tucci | 2464714 | 2018-08-13 21:18:24 +0200 | [diff] [blame] | 655 | #endif |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 656 | |
Lalit Maganti | 49ae901 | 2019-04-03 16:10:39 +0100 | [diff] [blame] | 657 | // Print out the stats to stderr for the trace. |
| 658 | if (!PrintStats()) { |
| 659 | return 1; |
| 660 | } |
| 661 | |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 662 | auto t_run_start = base::GetWallTimeNs(); |
| 663 | |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 664 | // First, see if we have some metrics to run. If we do, just run them and |
| 665 | // return. |
| 666 | if (metric_names) { |
| 667 | std::vector<std::string> metrics; |
| 668 | for (base::StringSplitter ss(metric_names, ','); ss.Next();) { |
| 669 | metrics.emplace_back(ss.cur_token()); |
| 670 | } |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 671 | int ret = RunMetrics(std::move(metrics)); |
| 672 | if (!ret) { |
| 673 | auto t_query = base::GetWallTimeNs() - t_run_start; |
| 674 | ret = MaybePrintPerfFile(perf_file_path, t_load, t_query); |
| 675 | } |
| 676 | return ret; |
Lalit Maganti | 7c95978 | 2019-04-02 16:54:12 +0100 | [diff] [blame] | 677 | } |
| 678 | |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 679 | // If we were given a query file, load contents |
| 680 | std::vector<std::string> queries; |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 681 | if (query_file_path) { |
| 682 | base::ScopedFstream file(fopen(query_file_path, "r")); |
Lalit Maganti | 22a1e0c | 2018-12-04 20:28:18 +0000 | [diff] [blame] | 683 | if (!file) { |
| 684 | PERFETTO_ELOG("Could not open query file (path: %s)", query_file_path); |
| 685 | return 1; |
| 686 | } |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 687 | if (!LoadQueries(file.get(), &queries)) { |
| 688 | return 1; |
| 689 | } |
| 690 | } |
| 691 | |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 692 | if (!RunQueryAndPrintResult(queries, stdout)) { |
Lalit Maganti | 77f1dbe | 2019-02-27 12:58:01 +0000 | [diff] [blame] | 693 | return 1; |
Primiano Tucci | 7e33029 | 2018-08-24 19:10:52 +0200 | [diff] [blame] | 694 | } |
Hector Dearman | e44ad45 | 2018-09-21 11:51:57 +0100 | [diff] [blame] | 695 | |
Ioannis Ilkos | 42dafcc | 2019-02-08 17:35:27 +0000 | [diff] [blame] | 696 | if (sqlite_file_path) { |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 697 | return ExportTraceToDatabase(sqlite_file_path); |
| 698 | } |
| 699 | |
Ioannis Ilkos | 433c8e5 | 2019-02-11 12:52:35 +0000 | [diff] [blame] | 700 | if (!launch_shell) { |
Lalit Maganti | 260e04d | 2019-05-03 13:17:01 +0100 | [diff] [blame] | 701 | auto t_query = base::GetWallTimeNs() - t_run_start; |
| 702 | return MaybePrintPerfFile(perf_file_path, t_load, t_query); |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 703 | } |
| 704 | |
Sami Kyostila | 3366894 | 2018-11-13 16:33:32 +0000 | [diff] [blame] | 705 | return StartInteractiveShell(); |
Primiano Tucci | 5968caf | 2018-08-06 10:31:46 +0100 | [diff] [blame] | 706 | } |
Lalit Maganti | 1ebebf1 | 2018-10-15 17:24:04 +0100 | [diff] [blame] | 707 | |
| 708 | } // namespace |
| 709 | |
| 710 | } // namespace trace_processor |
| 711 | } // namespace perfetto |
| 712 | |
| 713 | int main(int argc, char** argv) { |
| 714 | return perfetto::trace_processor::TraceProcessorMain(argc, argv); |
| 715 | } |