diff options
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 112 | ||||
-rw-r--r-- | tools/perf/ui/keysyms.h | 1 |
2 files changed, 112 insertions, 1 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 20ccd57753f7..aa22704047d6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1241,6 +1241,96 @@ static inline bool is_report_browser(void *timer) | |||
1241 | return timer == NULL; | 1241 | return timer == NULL; |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | /* | ||
1245 | * Only runtime switching of perf data file will make "input_name" point | ||
1246 | * to a malloced buffer. So add "is_input_name_malloced" flag to decide | ||
1247 | * whether we need to call free() for current "input_name" during the switch. | ||
1248 | */ | ||
1249 | static bool is_input_name_malloced = false; | ||
1250 | |||
1251 | static int switch_data_file(void) | ||
1252 | { | ||
1253 | char *pwd, *options[32], *abs_path[32], *tmp; | ||
1254 | DIR *pwd_dir; | ||
1255 | int nr_options = 0, choice = -1, ret = -1; | ||
1256 | struct dirent *dent; | ||
1257 | |||
1258 | pwd = getenv("PWD"); | ||
1259 | if (!pwd) | ||
1260 | return ret; | ||
1261 | |||
1262 | pwd_dir = opendir(pwd); | ||
1263 | if (!pwd_dir) | ||
1264 | return ret; | ||
1265 | |||
1266 | memset(options, 0, sizeof(options)); | ||
1267 | memset(options, 0, sizeof(abs_path)); | ||
1268 | |||
1269 | while ((dent = readdir(pwd_dir))) { | ||
1270 | char path[PATH_MAX]; | ||
1271 | u64 magic; | ||
1272 | char *name = dent->d_name; | ||
1273 | FILE *file; | ||
1274 | |||
1275 | if (!(dent->d_type == DT_REG)) | ||
1276 | continue; | ||
1277 | |||
1278 | snprintf(path, sizeof(path), "%s/%s", pwd, name); | ||
1279 | |||
1280 | file = fopen(path, "r"); | ||
1281 | if (!file) | ||
1282 | continue; | ||
1283 | |||
1284 | if (fread(&magic, 1, 8, file) < 8) | ||
1285 | goto close_file_and_continue; | ||
1286 | |||
1287 | if (is_perf_magic(magic)) { | ||
1288 | options[nr_options] = strdup(name); | ||
1289 | if (!options[nr_options]) | ||
1290 | goto close_file_and_continue; | ||
1291 | |||
1292 | abs_path[nr_options] = strdup(path); | ||
1293 | if (!abs_path[nr_options]) { | ||
1294 | free(options[nr_options]); | ||
1295 | ui__warning("Can't search all data files due to memory shortage.\n"); | ||
1296 | fclose(file); | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | nr_options++; | ||
1301 | } | ||
1302 | |||
1303 | close_file_and_continue: | ||
1304 | fclose(file); | ||
1305 | if (nr_options >= 32) { | ||
1306 | ui__warning("Too many perf data files in PWD!\n" | ||
1307 | "Only the first 32 files will be listed.\n"); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
1311 | closedir(pwd_dir); | ||
1312 | |||
1313 | if (nr_options) { | ||
1314 | choice = ui__popup_menu(nr_options, options); | ||
1315 | if (choice < nr_options && choice >= 0) { | ||
1316 | tmp = strdup(abs_path[choice]); | ||
1317 | if (tmp) { | ||
1318 | if (is_input_name_malloced) | ||
1319 | free((void *)input_name); | ||
1320 | input_name = tmp; | ||
1321 | is_input_name_malloced = true; | ||
1322 | ret = 0; | ||
1323 | } else | ||
1324 | ui__warning("Data switch failed due to memory shortage!\n"); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | free_popup_options(options, nr_options); | ||
1329 | free_popup_options(abs_path, nr_options); | ||
1330 | return ret; | ||
1331 | } | ||
1332 | |||
1333 | |||
1244 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | 1334 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
1245 | const char *helpline, const char *ev_name, | 1335 | const char *helpline, const char *ev_name, |
1246 | bool left_exits, | 1336 | bool left_exits, |
@@ -1275,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1275 | int choice = 0, | 1365 | int choice = 0, |
1276 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 1366 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
1277 | annotate_f = -2, annotate_t = -2, browse_map = -2; | 1367 | annotate_f = -2, annotate_t = -2, browse_map = -2; |
1278 | int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; | 1368 | int scripts_comm = -2, scripts_symbol = -2, |
1369 | scripts_all = -2, switch_data = -2; | ||
1279 | 1370 | ||
1280 | nr_options = 0; | 1371 | nr_options = 0; |
1281 | 1372 | ||
@@ -1332,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1332 | if (is_report_browser(hbt)) | 1423 | if (is_report_browser(hbt)) |
1333 | goto do_scripts; | 1424 | goto do_scripts; |
1334 | continue; | 1425 | continue; |
1426 | case 's': | ||
1427 | if (is_report_browser(hbt)) | ||
1428 | goto do_data_switch; | ||
1429 | continue; | ||
1335 | case K_F1: | 1430 | case K_F1: |
1336 | case 'h': | 1431 | case 'h': |
1337 | case '?': | 1432 | case '?': |
@@ -1351,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1351 | "d Zoom into current DSO\n" | 1446 | "d Zoom into current DSO\n" |
1352 | "t Zoom into current Thread\n" | 1447 | "t Zoom into current Thread\n" |
1353 | "r Run available scripts('perf report' only)\n" | 1448 | "r Run available scripts('perf report' only)\n" |
1449 | "s Switch to another data file in PWD ('perf report' only)\n" | ||
1354 | "P Print histograms to perf.hist.N\n" | 1450 | "P Print histograms to perf.hist.N\n" |
1355 | "V Verbose (DSO names in callchains, etc)\n" | 1451 | "V Verbose (DSO names in callchains, etc)\n" |
1356 | "/ Filter symbol by name"); | 1452 | "/ Filter symbol by name"); |
@@ -1458,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1458 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) | 1554 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) |
1459 | scripts_all = nr_options++; | 1555 | scripts_all = nr_options++; |
1460 | 1556 | ||
1557 | if (is_report_browser(hbt) && asprintf(&options[nr_options], | ||
1558 | "Switch to another data file in PWD") > 0) | ||
1559 | switch_data = nr_options++; | ||
1461 | add_exit_option: | 1560 | add_exit_option: |
1462 | options[nr_options++] = (char *)"Exit"; | 1561 | options[nr_options++] = (char *)"Exit"; |
1463 | retry_popup_menu: | 1562 | retry_popup_menu: |
@@ -1568,6 +1667,16 @@ do_scripts: | |||
1568 | 1667 | ||
1569 | script_browse(script_opt); | 1668 | script_browse(script_opt); |
1570 | } | 1669 | } |
1670 | /* Switch to another data file */ | ||
1671 | else if (choice == switch_data) { | ||
1672 | do_data_switch: | ||
1673 | if (!switch_data_file()) { | ||
1674 | key = K_SWITCH_INPUT_DATA; | ||
1675 | break; | ||
1676 | } else | ||
1677 | ui__warning("Won't switch the data files due to\n" | ||
1678 | "no valid data file get selected!\n"); | ||
1679 | } | ||
1571 | } | 1680 | } |
1572 | out_free_stack: | 1681 | out_free_stack: |
1573 | pstack__delete(fstack); | 1682 | pstack__delete(fstack); |
@@ -1694,6 +1803,7 @@ browse_hists: | |||
1694 | "Do you really want to exit?")) | 1803 | "Do you really want to exit?")) |
1695 | continue; | 1804 | continue; |
1696 | /* Fall thru */ | 1805 | /* Fall thru */ |
1806 | case K_SWITCH_INPUT_DATA: | ||
1697 | case 'q': | 1807 | case 'q': |
1698 | case CTRL('c'): | 1808 | case CTRL('c'): |
1699 | goto out; | 1809 | goto out; |
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h index 809eca5707fa..65092d576b4e 100644 --- a/tools/perf/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h | |||
@@ -23,5 +23,6 @@ | |||
23 | #define K_TIMER -1 | 23 | #define K_TIMER -1 |
24 | #define K_ERROR -2 | 24 | #define K_ERROR -2 |
25 | #define K_RESIZE -3 | 25 | #define K_RESIZE -3 |
26 | #define K_SWITCH_INPUT_DATA -4 | ||
26 | 27 | ||
27 | #endif /* _PERF_KEYSYMS_H_ */ | 28 | #endif /* _PERF_KEYSYMS_H_ */ |