builtin-trace.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. #include <traceevent/event-parse.h>
  2. #include "builtin.h"
  3. #include "util/color.h"
  4. #include "util/debug.h"
  5. #include "util/evlist.h"
  6. #include "util/machine.h"
  7. #include "util/session.h"
  8. #include "util/thread.h"
  9. #include "util/parse-options.h"
  10. #include "util/strlist.h"
  11. #include "util/intlist.h"
  12. #include "util/thread_map.h"
  13. #include <libaudit.h>
  14. #include <stdlib.h>
  15. #include <sys/mman.h>
  16. #include <linux/futex.h>
  17. static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
  18. unsigned long arg,
  19. u8 arg_idx __maybe_unused,
  20. u8 *arg_mask __maybe_unused)
  21. {
  22. return scnprintf(bf, size, "%#lx", arg);
  23. }
  24. #define SCA_HEX syscall_arg__scnprintf_hex
  25. static size_t syscall_arg__scnprintf_whence(char *bf, size_t size,
  26. unsigned long arg,
  27. u8 arg_idx __maybe_unused,
  28. u8 *arg_mask __maybe_unused)
  29. {
  30. int whence = arg;
  31. switch (whence) {
  32. #define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
  33. P_WHENCE(SET);
  34. P_WHENCE(CUR);
  35. P_WHENCE(END);
  36. #ifdef SEEK_DATA
  37. P_WHENCE(DATA);
  38. #endif
  39. #ifdef SEEK_HOLE
  40. P_WHENCE(HOLE);
  41. #endif
  42. #undef P_WHENCE
  43. default: break;
  44. }
  45. return scnprintf(bf, size, "%#x", whence);
  46. }
  47. #define SCA_WHENCE syscall_arg__scnprintf_whence
  48. static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
  49. unsigned long arg,
  50. u8 arg_idx __maybe_unused,
  51. u8 *arg_mask __maybe_unused)
  52. {
  53. int printed = 0, prot = arg;
  54. if (prot == PROT_NONE)
  55. return scnprintf(bf, size, "NONE");
  56. #define P_MMAP_PROT(n) \
  57. if (prot & PROT_##n) { \
  58. printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
  59. prot &= ~PROT_##n; \
  60. }
  61. P_MMAP_PROT(EXEC);
  62. P_MMAP_PROT(READ);
  63. P_MMAP_PROT(WRITE);
  64. #ifdef PROT_SEM
  65. P_MMAP_PROT(SEM);
  66. #endif
  67. P_MMAP_PROT(GROWSDOWN);
  68. P_MMAP_PROT(GROWSUP);
  69. #undef P_MMAP_PROT
  70. if (prot)
  71. printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
  72. return printed;
  73. }
  74. #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
  75. static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
  76. unsigned long arg, u8 arg_idx __maybe_unused,
  77. u8 *arg_mask __maybe_unused)
  78. {
  79. int printed = 0, flags = arg;
  80. #define P_MMAP_FLAG(n) \
  81. if (flags & MAP_##n) { \
  82. printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
  83. flags &= ~MAP_##n; \
  84. }
  85. P_MMAP_FLAG(SHARED);
  86. P_MMAP_FLAG(PRIVATE);
  87. P_MMAP_FLAG(32BIT);
  88. P_MMAP_FLAG(ANONYMOUS);
  89. P_MMAP_FLAG(DENYWRITE);
  90. P_MMAP_FLAG(EXECUTABLE);
  91. P_MMAP_FLAG(FILE);
  92. P_MMAP_FLAG(FIXED);
  93. P_MMAP_FLAG(GROWSDOWN);
  94. #ifdef MAP_HUGETLB
  95. P_MMAP_FLAG(HUGETLB);
  96. #endif
  97. P_MMAP_FLAG(LOCKED);
  98. P_MMAP_FLAG(NONBLOCK);
  99. P_MMAP_FLAG(NORESERVE);
  100. P_MMAP_FLAG(POPULATE);
  101. P_MMAP_FLAG(STACK);
  102. #ifdef MAP_UNINITIALIZED
  103. P_MMAP_FLAG(UNINITIALIZED);
  104. #endif
  105. #undef P_MMAP_FLAG
  106. if (flags)
  107. printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
  108. return printed;
  109. }
  110. #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
  111. static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
  112. unsigned long arg, u8 arg_idx __maybe_unused,
  113. u8 *arg_mask __maybe_unused)
  114. {
  115. int behavior = arg;
  116. switch (behavior) {
  117. #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
  118. P_MADV_BHV(NORMAL);
  119. P_MADV_BHV(RANDOM);
  120. P_MADV_BHV(SEQUENTIAL);
  121. P_MADV_BHV(WILLNEED);
  122. P_MADV_BHV(DONTNEED);
  123. P_MADV_BHV(REMOVE);
  124. P_MADV_BHV(DONTFORK);
  125. P_MADV_BHV(DOFORK);
  126. P_MADV_BHV(HWPOISON);
  127. #ifdef MADV_SOFT_OFFLINE
  128. P_MADV_BHV(SOFT_OFFLINE);
  129. #endif
  130. P_MADV_BHV(MERGEABLE);
  131. P_MADV_BHV(UNMERGEABLE);
  132. #ifdef MADV_HUGEPAGE
  133. P_MADV_BHV(HUGEPAGE);
  134. #endif
  135. #ifdef MADV_NOHUGEPAGE
  136. P_MADV_BHV(NOHUGEPAGE);
  137. #endif
  138. #ifdef MADV_DONTDUMP
  139. P_MADV_BHV(DONTDUMP);
  140. #endif
  141. #ifdef MADV_DODUMP
  142. P_MADV_BHV(DODUMP);
  143. #endif
  144. #undef P_MADV_PHV
  145. default: break;
  146. }
  147. return scnprintf(bf, size, "%#x", behavior);
  148. }
  149. #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
  150. static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg,
  151. u8 arg_idx __maybe_unused, u8 *arg_mask)
  152. {
  153. enum syscall_futex_args {
  154. SCF_UADDR = (1 << 0),
  155. SCF_OP = (1 << 1),
  156. SCF_VAL = (1 << 2),
  157. SCF_TIMEOUT = (1 << 3),
  158. SCF_UADDR2 = (1 << 4),
  159. SCF_VAL3 = (1 << 5),
  160. };
  161. int op = arg;
  162. int cmd = op & FUTEX_CMD_MASK;
  163. size_t printed = 0;
  164. switch (cmd) {
  165. #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
  166. P_FUTEX_OP(WAIT); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
  167. P_FUTEX_OP(WAKE); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
  168. P_FUTEX_OP(FD); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
  169. P_FUTEX_OP(REQUEUE); *arg_mask |= SCF_VAL3|SCF_TIMEOUT; break;
  170. P_FUTEX_OP(CMP_REQUEUE); *arg_mask |= SCF_TIMEOUT; break;
  171. P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT; break;
  172. P_FUTEX_OP(WAKE_OP); break;
  173. P_FUTEX_OP(LOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
  174. P_FUTEX_OP(UNLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
  175. P_FUTEX_OP(TRYLOCK_PI); *arg_mask |= SCF_VAL3|SCF_UADDR2; break;
  176. P_FUTEX_OP(WAIT_BITSET); *arg_mask |= SCF_UADDR2; break;
  177. P_FUTEX_OP(WAKE_BITSET); *arg_mask |= SCF_UADDR2; break;
  178. P_FUTEX_OP(WAIT_REQUEUE_PI); break;
  179. default: printed = scnprintf(bf, size, "%#x", cmd); break;
  180. }
  181. if (op & FUTEX_PRIVATE_FLAG)
  182. printed += scnprintf(bf + printed, size - printed, "|PRIV");
  183. if (op & FUTEX_CLOCK_REALTIME)
  184. printed += scnprintf(bf + printed, size - printed, "|CLKRT");
  185. return printed;
  186. }
  187. #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
  188. static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
  189. unsigned long arg,
  190. u8 arg_idx, u8 *arg_mask)
  191. {
  192. int printed = 0, flags = arg;
  193. if (!(flags & O_CREAT))
  194. *arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */
  195. if (flags == 0)
  196. return scnprintf(bf, size, "RDONLY");
  197. #define P_FLAG(n) \
  198. if (flags & O_##n) { \
  199. printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
  200. flags &= ~O_##n; \
  201. }
  202. P_FLAG(APPEND);
  203. P_FLAG(ASYNC);
  204. P_FLAG(CLOEXEC);
  205. P_FLAG(CREAT);
  206. P_FLAG(DIRECT);
  207. P_FLAG(DIRECTORY);
  208. P_FLAG(EXCL);
  209. P_FLAG(LARGEFILE);
  210. P_FLAG(NOATIME);
  211. P_FLAG(NOCTTY);
  212. #ifdef O_NONBLOCK
  213. P_FLAG(NONBLOCK);
  214. #elif O_NDELAY
  215. P_FLAG(NDELAY);
  216. #endif
  217. #ifdef O_PATH
  218. P_FLAG(PATH);
  219. #endif
  220. P_FLAG(RDWR);
  221. #ifdef O_DSYNC
  222. if ((flags & O_SYNC) == O_SYNC)
  223. printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
  224. else {
  225. P_FLAG(DSYNC);
  226. }
  227. #else
  228. P_FLAG(SYNC);
  229. #endif
  230. P_FLAG(TRUNC);
  231. P_FLAG(WRONLY);
  232. #undef P_FLAG
  233. if (flags)
  234. printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
  235. return printed;
  236. }
  237. #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
  238. static struct syscall_fmt {
  239. const char *name;
  240. const char *alias;
  241. size_t (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask);
  242. bool errmsg;
  243. bool timeout;
  244. bool hexret;
  245. } syscall_fmts[] = {
  246. { .name = "access", .errmsg = true, },
  247. { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
  248. { .name = "brk", .hexret = true,
  249. .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
  250. { .name = "mmap", .hexret = true, },
  251. { .name = "connect", .errmsg = true, },
  252. { .name = "fstat", .errmsg = true, .alias = "newfstat", },
  253. { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
  254. { .name = "futex", .errmsg = true,
  255. .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
  256. { .name = "ioctl", .errmsg = true,
  257. .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
  258. { .name = "lseek", .errmsg = true,
  259. .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, },
  260. { .name = "lstat", .errmsg = true, .alias = "newlstat", },
  261. { .name = "madvise", .errmsg = true,
  262. .arg_scnprintf = { [0] = SCA_HEX, /* start */
  263. [2] = SCA_MADV_BHV, /* behavior */ }, },
  264. { .name = "mmap", .hexret = true,
  265. .arg_scnprintf = { [0] = SCA_HEX, /* addr */
  266. [2] = SCA_MMAP_PROT, /* prot */
  267. [3] = SCA_MMAP_FLAGS, /* flags */ }, },
  268. { .name = "mprotect", .errmsg = true,
  269. .arg_scnprintf = { [0] = SCA_HEX, /* start */
  270. [2] = SCA_MMAP_PROT, /* prot */ }, },
  271. { .name = "mremap", .hexret = true,
  272. .arg_scnprintf = { [0] = SCA_HEX, /* addr */
  273. [4] = SCA_HEX, /* new_addr */ }, },
  274. { .name = "munmap", .errmsg = true,
  275. .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
  276. { .name = "open", .errmsg = true,
  277. .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
  278. { .name = "open_by_handle_at", .errmsg = true,
  279. .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
  280. { .name = "openat", .errmsg = true,
  281. .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
  282. { .name = "poll", .errmsg = true, .timeout = true, },
  283. { .name = "ppoll", .errmsg = true, .timeout = true, },
  284. { .name = "pread", .errmsg = true, .alias = "pread64", },
  285. { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
  286. { .name = "read", .errmsg = true, },
  287. { .name = "recvfrom", .errmsg = true, },
  288. { .name = "select", .errmsg = true, .timeout = true, },
  289. { .name = "socket", .errmsg = true, },
  290. { .name = "stat", .errmsg = true, .alias = "newstat", },
  291. { .name = "uname", .errmsg = true, .alias = "newuname", },
  292. };
  293. static int syscall_fmt__cmp(const void *name, const void *fmtp)
  294. {
  295. const struct syscall_fmt *fmt = fmtp;
  296. return strcmp(name, fmt->name);
  297. }
  298. static struct syscall_fmt *syscall_fmt__find(const char *name)
  299. {
  300. const int nmemb = ARRAY_SIZE(syscall_fmts);
  301. return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
  302. }
  303. struct syscall {
  304. struct event_format *tp_format;
  305. const char *name;
  306. bool filtered;
  307. struct syscall_fmt *fmt;
  308. size_t (**arg_scnprintf)(char *bf, size_t size,
  309. unsigned long arg, u8 arg_idx, u8 *args_mask);
  310. };
  311. static size_t fprintf_duration(unsigned long t, FILE *fp)
  312. {
  313. double duration = (double)t / NSEC_PER_MSEC;
  314. size_t printed = fprintf(fp, "(");
  315. if (duration >= 1.0)
  316. printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
  317. else if (duration >= 0.01)
  318. printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
  319. else
  320. printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
  321. return printed + fprintf(fp, "): ");
  322. }
  323. struct thread_trace {
  324. u64 entry_time;
  325. u64 exit_time;
  326. bool entry_pending;
  327. unsigned long nr_events;
  328. char *entry_str;
  329. double runtime_ms;
  330. };
  331. static struct thread_trace *thread_trace__new(void)
  332. {
  333. return zalloc(sizeof(struct thread_trace));
  334. }
  335. static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
  336. {
  337. struct thread_trace *ttrace;
  338. if (thread == NULL)
  339. goto fail;
  340. if (thread->priv == NULL)
  341. thread->priv = thread_trace__new();
  342. if (thread->priv == NULL)
  343. goto fail;
  344. ttrace = thread->priv;
  345. ++ttrace->nr_events;
  346. return ttrace;
  347. fail:
  348. color_fprintf(fp, PERF_COLOR_RED,
  349. "WARNING: not enough memory, dropping samples!\n");
  350. return NULL;
  351. }
  352. struct trace {
  353. struct perf_tool tool;
  354. int audit_machine;
  355. struct {
  356. int max;
  357. struct syscall *table;
  358. } syscalls;
  359. struct perf_record_opts opts;
  360. struct machine host;
  361. u64 base_time;
  362. FILE *output;
  363. unsigned long nr_events;
  364. struct strlist *ev_qualifier;
  365. bool not_ev_qualifier;
  366. struct intlist *tid_list;
  367. struct intlist *pid_list;
  368. bool sched;
  369. bool multiple_threads;
  370. double duration_filter;
  371. double runtime_ms;
  372. };
  373. static bool trace__filter_duration(struct trace *trace, double t)
  374. {
  375. return t < (trace->duration_filter * NSEC_PER_MSEC);
  376. }
  377. static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
  378. {
  379. double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
  380. return fprintf(fp, "%10.3f ", ts);
  381. }
  382. static bool done = false;
  383. static void sig_handler(int sig __maybe_unused)
  384. {
  385. done = true;
  386. }
  387. static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
  388. u64 duration, u64 tstamp, FILE *fp)
  389. {
  390. size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
  391. printed += fprintf_duration(duration, fp);
  392. if (trace->multiple_threads)
  393. printed += fprintf(fp, "%d ", thread->tid);
  394. return printed;
  395. }
  396. static int trace__process_event(struct trace *trace, struct machine *machine,
  397. union perf_event *event)
  398. {
  399. int ret = 0;
  400. switch (event->header.type) {
  401. case PERF_RECORD_LOST:
  402. color_fprintf(trace->output, PERF_COLOR_RED,
  403. "LOST %" PRIu64 " events!\n", event->lost.lost);
  404. ret = machine__process_lost_event(machine, event);
  405. default:
  406. ret = machine__process_event(machine, event);
  407. break;
  408. }
  409. return ret;
  410. }
  411. static int trace__tool_process(struct perf_tool *tool,
  412. union perf_event *event,
  413. struct perf_sample *sample __maybe_unused,
  414. struct machine *machine)
  415. {
  416. struct trace *trace = container_of(tool, struct trace, tool);
  417. return trace__process_event(trace, machine, event);
  418. }
  419. static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
  420. {
  421. int err = symbol__init();
  422. if (err)
  423. return err;
  424. machine__init(&trace->host, "", HOST_KERNEL_ID);
  425. machine__create_kernel_maps(&trace->host);
  426. if (perf_target__has_task(&trace->opts.target)) {
  427. err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
  428. trace__tool_process,
  429. &trace->host);
  430. } else {
  431. err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
  432. &trace->host);
  433. }
  434. if (err)
  435. symbol__exit();
  436. return err;
  437. }
  438. static int syscall__set_arg_fmts(struct syscall *sc)
  439. {
  440. struct format_field *field;
  441. int idx = 0;
  442. sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
  443. if (sc->arg_scnprintf == NULL)
  444. return -1;
  445. for (field = sc->tp_format->format.fields->next; field; field = field->next) {
  446. if (sc->fmt && sc->fmt->arg_scnprintf[idx])
  447. sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
  448. else if (field->flags & FIELD_IS_POINTER)
  449. sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
  450. ++idx;
  451. }
  452. return 0;
  453. }
  454. static int trace__read_syscall_info(struct trace *trace, int id)
  455. {
  456. char tp_name[128];
  457. struct syscall *sc;
  458. const char *name = audit_syscall_to_name(id, trace->audit_machine);
  459. if (name == NULL)
  460. return -1;
  461. if (id > trace->syscalls.max) {
  462. struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
  463. if (nsyscalls == NULL)
  464. return -1;
  465. if (trace->syscalls.max != -1) {
  466. memset(nsyscalls + trace->syscalls.max + 1, 0,
  467. (id - trace->syscalls.max) * sizeof(*sc));
  468. } else {
  469. memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
  470. }
  471. trace->syscalls.table = nsyscalls;
  472. trace->syscalls.max = id;
  473. }
  474. sc = trace->syscalls.table + id;
  475. sc->name = name;
  476. if (trace->ev_qualifier) {
  477. bool in = strlist__find(trace->ev_qualifier, name) != NULL;
  478. if (!(in ^ trace->not_ev_qualifier)) {
  479. sc->filtered = true;
  480. /*
  481. * No need to do read tracepoint information since this will be
  482. * filtered out.
  483. */
  484. return 0;
  485. }
  486. }
  487. sc->fmt = syscall_fmt__find(sc->name);
  488. snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
  489. sc->tp_format = event_format__new("syscalls", tp_name);
  490. if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
  491. snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
  492. sc->tp_format = event_format__new("syscalls", tp_name);
  493. }
  494. if (sc->tp_format == NULL)
  495. return -1;
  496. return syscall__set_arg_fmts(sc);
  497. }
  498. static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
  499. unsigned long *args)
  500. {
  501. int i = 0;
  502. size_t printed = 0;
  503. if (sc->tp_format != NULL) {
  504. struct format_field *field;
  505. u8 mask = 0, bit = 1;
  506. for (field = sc->tp_format->format.fields->next; field;
  507. field = field->next, ++i, bit <<= 1) {
  508. if (mask & bit)
  509. continue;
  510. printed += scnprintf(bf + printed, size - printed,
  511. "%s%s: ", printed ? ", " : "", field->name);
  512. if (sc->arg_scnprintf && sc->arg_scnprintf[i]) {
  513. printed += sc->arg_scnprintf[i](bf + printed, size - printed,
  514. args[i], i, &mask);
  515. } else {
  516. printed += scnprintf(bf + printed, size - printed,
  517. "%ld", args[i]);
  518. }
  519. }
  520. } else {
  521. while (i < 6) {
  522. printed += scnprintf(bf + printed, size - printed,
  523. "%sarg%d: %ld",
  524. printed ? ", " : "", i, args[i]);
  525. ++i;
  526. }
  527. }
  528. return printed;
  529. }
  530. typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
  531. struct perf_sample *sample);
  532. static struct syscall *trace__syscall_info(struct trace *trace,
  533. struct perf_evsel *evsel,
  534. struct perf_sample *sample)
  535. {
  536. int id = perf_evsel__intval(evsel, sample, "id");
  537. if (id < 0) {
  538. /*
  539. * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
  540. * before that, leaving at a higher verbosity level till that is
  541. * explained. Reproduced with plain ftrace with:
  542. *
  543. * echo 1 > /t/events/raw_syscalls/sys_exit/enable
  544. * grep "NR -1 " /t/trace_pipe
  545. *
  546. * After generating some load on the machine.
  547. */
  548. if (verbose > 1) {
  549. static u64 n;
  550. fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
  551. id, perf_evsel__name(evsel), ++n);
  552. }
  553. return NULL;
  554. }
  555. if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
  556. trace__read_syscall_info(trace, id))
  557. goto out_cant_read;
  558. if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
  559. goto out_cant_read;
  560. return &trace->syscalls.table[id];
  561. out_cant_read:
  562. if (verbose) {
  563. fprintf(trace->output, "Problems reading syscall %d", id);
  564. if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
  565. fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
  566. fputs(" information\n", trace->output);
  567. }
  568. return NULL;
  569. }
  570. static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
  571. struct perf_sample *sample)
  572. {
  573. char *msg;
  574. void *args;
  575. size_t printed = 0;
  576. struct thread *thread;
  577. struct syscall *sc = trace__syscall_info(trace, evsel, sample);
  578. struct thread_trace *ttrace;
  579. if (sc == NULL)
  580. return -1;
  581. if (sc->filtered)
  582. return 0;
  583. thread = machine__findnew_thread(&trace->host, sample->pid,
  584. sample->tid);
  585. ttrace = thread__trace(thread, trace->output);
  586. if (ttrace == NULL)
  587. return -1;
  588. args = perf_evsel__rawptr(evsel, sample, "args");
  589. if (args == NULL) {
  590. fprintf(trace->output, "Problems reading syscall arguments\n");
  591. return -1;
  592. }
  593. ttrace = thread->priv;
  594. if (ttrace->entry_str == NULL) {
  595. ttrace->entry_str = malloc(1024);
  596. if (!ttrace->entry_str)
  597. return -1;
  598. }
  599. ttrace->entry_time = sample->time;
  600. msg = ttrace->entry_str;
  601. printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
  602. printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
  603. if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
  604. if (!trace->duration_filter) {
  605. trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
  606. fprintf(trace->output, "%-70s\n", ttrace->entry_str);
  607. }
  608. } else
  609. ttrace->entry_pending = true;
  610. return 0;
  611. }
  612. static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
  613. struct perf_sample *sample)
  614. {
  615. int ret;
  616. u64 duration = 0;
  617. struct thread *thread;
  618. struct syscall *sc = trace__syscall_info(trace, evsel, sample);
  619. struct thread_trace *ttrace;
  620. if (sc == NULL)
  621. return -1;
  622. if (sc->filtered)
  623. return 0;
  624. thread = machine__findnew_thread(&trace->host, sample->pid,
  625. sample->tid);
  626. ttrace = thread__trace(thread, trace->output);
  627. if (ttrace == NULL)
  628. return -1;
  629. ret = perf_evsel__intval(evsel, sample, "ret");
  630. ttrace = thread->priv;
  631. ttrace->exit_time = sample->time;
  632. if (ttrace->entry_time) {
  633. duration = sample->time - ttrace->entry_time;
  634. if (trace__filter_duration(trace, duration))
  635. goto out;
  636. } else if (trace->duration_filter)
  637. goto out;
  638. trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
  639. if (ttrace->entry_pending) {
  640. fprintf(trace->output, "%-70s", ttrace->entry_str);
  641. } else {
  642. fprintf(trace->output, " ... [");
  643. color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
  644. fprintf(trace->output, "]: %s()", sc->name);
  645. }
  646. if (sc->fmt == NULL) {
  647. signed_print:
  648. fprintf(trace->output, ") = %d", ret);
  649. } else if (ret < 0 && sc->fmt->errmsg) {
  650. char bf[256];
  651. const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
  652. *e = audit_errno_to_name(-ret);
  653. fprintf(trace->output, ") = -1 %s %s", e, emsg);
  654. } else if (ret == 0 && sc->fmt->timeout)
  655. fprintf(trace->output, ") = 0 Timeout");
  656. else if (sc->fmt->hexret)
  657. fprintf(trace->output, ") = %#x", ret);
  658. else
  659. goto signed_print;
  660. fputc('\n', trace->output);
  661. out:
  662. ttrace->entry_pending = false;
  663. return 0;
  664. }
  665. static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
  666. struct perf_sample *sample)
  667. {
  668. u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
  669. double runtime_ms = (double)runtime / NSEC_PER_MSEC;
  670. struct thread *thread = machine__findnew_thread(&trace->host,
  671. sample->pid,
  672. sample->tid);
  673. struct thread_trace *ttrace = thread__trace(thread, trace->output);
  674. if (ttrace == NULL)
  675. goto out_dump;
  676. ttrace->runtime_ms += runtime_ms;
  677. trace->runtime_ms += runtime_ms;
  678. return 0;
  679. out_dump:
  680. fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
  681. evsel->name,
  682. perf_evsel__strval(evsel, sample, "comm"),
  683. (pid_t)perf_evsel__intval(evsel, sample, "pid"),
  684. runtime,
  685. perf_evsel__intval(evsel, sample, "vruntime"));
  686. return 0;
  687. }
  688. static bool skip_sample(struct trace *trace, struct perf_sample *sample)
  689. {
  690. if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
  691. (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
  692. return false;
  693. if (trace->pid_list || trace->tid_list)
  694. return true;
  695. return false;
  696. }
  697. static int trace__process_sample(struct perf_tool *tool,
  698. union perf_event *event __maybe_unused,
  699. struct perf_sample *sample,
  700. struct perf_evsel *evsel,
  701. struct machine *machine __maybe_unused)
  702. {
  703. struct trace *trace = container_of(tool, struct trace, tool);
  704. int err = 0;
  705. tracepoint_handler handler = evsel->handler.func;
  706. if (skip_sample(trace, sample))
  707. return 0;
  708. if (trace->base_time == 0)
  709. trace->base_time = sample->time;
  710. if (handler)
  711. handler(trace, evsel, sample);
  712. return err;
  713. }
  714. static bool
  715. perf_session__has_tp(struct perf_session *session, const char *name)
  716. {
  717. struct perf_evsel *evsel;
  718. evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
  719. return evsel != NULL;
  720. }
  721. static int parse_target_str(struct trace *trace)
  722. {
  723. if (trace->opts.target.pid) {
  724. trace->pid_list = intlist__new(trace->opts.target.pid);
  725. if (trace->pid_list == NULL) {
  726. pr_err("Error parsing process id string\n");
  727. return -EINVAL;
  728. }
  729. }
  730. if (trace->opts.target.tid) {
  731. trace->tid_list = intlist__new(trace->opts.target.tid);
  732. if (trace->tid_list == NULL) {
  733. pr_err("Error parsing thread id string\n");
  734. return -EINVAL;
  735. }
  736. }
  737. return 0;
  738. }
  739. static int trace__run(struct trace *trace, int argc, const char **argv)
  740. {
  741. struct perf_evlist *evlist = perf_evlist__new();
  742. struct perf_evsel *evsel;
  743. int err = -1, i;
  744. unsigned long before;
  745. const bool forks = argc > 0;
  746. if (evlist == NULL) {
  747. fprintf(trace->output, "Not enough memory to run!\n");
  748. goto out;
  749. }
  750. if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
  751. perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
  752. fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
  753. goto out_delete_evlist;
  754. }
  755. if (trace->sched &&
  756. perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
  757. trace__sched_stat_runtime)) {
  758. fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
  759. goto out_delete_evlist;
  760. }
  761. err = perf_evlist__create_maps(evlist, &trace->opts.target);
  762. if (err < 0) {
  763. fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
  764. goto out_delete_evlist;
  765. }
  766. err = trace__symbols_init(trace, evlist);
  767. if (err < 0) {
  768. fprintf(trace->output, "Problems initializing symbol libraries!\n");
  769. goto out_delete_maps;
  770. }
  771. perf_evlist__config(evlist, &trace->opts);
  772. signal(SIGCHLD, sig_handler);
  773. signal(SIGINT, sig_handler);
  774. if (forks) {
  775. err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
  776. argv, false, false);
  777. if (err < 0) {
  778. fprintf(trace->output, "Couldn't run the workload!\n");
  779. goto out_delete_maps;
  780. }
  781. }
  782. err = perf_evlist__open(evlist);
  783. if (err < 0) {
  784. fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
  785. goto out_delete_maps;
  786. }
  787. err = perf_evlist__mmap(evlist, UINT_MAX, false);
  788. if (err < 0) {
  789. fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
  790. goto out_close_evlist;
  791. }
  792. perf_evlist__enable(evlist);
  793. if (forks)
  794. perf_evlist__start_workload(evlist);
  795. trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
  796. again:
  797. before = trace->nr_events;
  798. for (i = 0; i < evlist->nr_mmaps; i++) {
  799. union perf_event *event;
  800. while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
  801. const u32 type = event->header.type;
  802. tracepoint_handler handler;
  803. struct perf_sample sample;
  804. ++trace->nr_events;
  805. err = perf_evlist__parse_sample(evlist, event, &sample);
  806. if (err) {
  807. fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
  808. continue;
  809. }
  810. if (trace->base_time == 0)
  811. trace->base_time = sample.time;
  812. if (type != PERF_RECORD_SAMPLE) {
  813. trace__process_event(trace, &trace->host, event);
  814. continue;
  815. }
  816. evsel = perf_evlist__id2evsel(evlist, sample.id);
  817. if (evsel == NULL) {
  818. fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
  819. continue;
  820. }
  821. if (sample.raw_data == NULL) {
  822. fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
  823. perf_evsel__name(evsel), sample.tid,
  824. sample.cpu, sample.raw_size);
  825. continue;
  826. }
  827. handler = evsel->handler.func;
  828. handler(trace, evsel, &sample);
  829. }
  830. }
  831. if (trace->nr_events == before) {
  832. if (done)
  833. goto out_unmap_evlist;
  834. poll(evlist->pollfd, evlist->nr_fds, -1);
  835. }
  836. if (done)
  837. perf_evlist__disable(evlist);
  838. goto again;
  839. out_unmap_evlist:
  840. perf_evlist__munmap(evlist);
  841. out_close_evlist:
  842. perf_evlist__close(evlist);
  843. out_delete_maps:
  844. perf_evlist__delete_maps(evlist);
  845. out_delete_evlist:
  846. perf_evlist__delete(evlist);
  847. out:
  848. return err;
  849. }
  850. static int trace__replay(struct trace *trace)
  851. {
  852. const struct perf_evsel_str_handler handlers[] = {
  853. { "raw_syscalls:sys_enter", trace__sys_enter, },
  854. { "raw_syscalls:sys_exit", trace__sys_exit, },
  855. };
  856. struct perf_session *session;
  857. int err = -1;
  858. trace->tool.sample = trace__process_sample;
  859. trace->tool.mmap = perf_event__process_mmap;
  860. trace->tool.comm = perf_event__process_comm;
  861. trace->tool.exit = perf_event__process_exit;
  862. trace->tool.fork = perf_event__process_fork;
  863. trace->tool.attr = perf_event__process_attr;
  864. trace->tool.tracing_data = perf_event__process_tracing_data;
  865. trace->tool.build_id = perf_event__process_build_id;
  866. trace->tool.ordered_samples = true;
  867. trace->tool.ordering_requires_timestamps = true;
  868. /* add tid to output */
  869. trace->multiple_threads = true;
  870. if (symbol__init() < 0)
  871. return -1;
  872. session = perf_session__new(input_name, O_RDONLY, 0, false,
  873. &trace->tool);
  874. if (session == NULL)
  875. return -ENOMEM;
  876. err = perf_session__set_tracepoints_handlers(session, handlers);
  877. if (err)
  878. goto out;
  879. if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
  880. pr_err("Data file does not have raw_syscalls:sys_enter events\n");
  881. goto out;
  882. }
  883. if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
  884. pr_err("Data file does not have raw_syscalls:sys_exit events\n");
  885. goto out;
  886. }
  887. err = parse_target_str(trace);
  888. if (err != 0)
  889. goto out;
  890. setup_pager();
  891. err = perf_session__process_events(session, &trace->tool);
  892. if (err)
  893. pr_err("Failed to process events, error %d", err);
  894. out:
  895. perf_session__delete(session);
  896. return err;
  897. }
  898. static size_t trace__fprintf_threads_header(FILE *fp)
  899. {
  900. size_t printed;
  901. printed = fprintf(fp, "\n _____________________________________________________________________\n");
  902. printed += fprintf(fp," __) Summary of events (__\n\n");
  903. printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
  904. printed += fprintf(fp," _____________________________________________________________________\n\n");
  905. return printed;
  906. }
  907. static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
  908. {
  909. size_t printed = trace__fprintf_threads_header(fp);
  910. struct rb_node *nd;
  911. for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
  912. struct thread *thread = rb_entry(nd, struct thread, rb_node);
  913. struct thread_trace *ttrace = thread->priv;
  914. const char *color;
  915. double ratio;
  916. if (ttrace == NULL)
  917. continue;
  918. ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
  919. color = PERF_COLOR_NORMAL;
  920. if (ratio > 50.0)
  921. color = PERF_COLOR_RED;
  922. else if (ratio > 25.0)
  923. color = PERF_COLOR_GREEN;
  924. else if (ratio > 5.0)
  925. color = PERF_COLOR_YELLOW;
  926. printed += color_fprintf(fp, color, "%20s", thread->comm);
  927. printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
  928. printed += color_fprintf(fp, color, "%5.1f%%", ratio);
  929. printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
  930. }
  931. return printed;
  932. }
  933. static int trace__set_duration(const struct option *opt, const char *str,
  934. int unset __maybe_unused)
  935. {
  936. struct trace *trace = opt->value;
  937. trace->duration_filter = atof(str);
  938. return 0;
  939. }
  940. static int trace__open_output(struct trace *trace, const char *filename)
  941. {
  942. struct stat st;
  943. if (!stat(filename, &st) && st.st_size) {
  944. char oldname[PATH_MAX];
  945. scnprintf(oldname, sizeof(oldname), "%s.old", filename);
  946. unlink(oldname);
  947. rename(filename, oldname);
  948. }
  949. trace->output = fopen(filename, "w");
  950. return trace->output == NULL ? -errno : 0;
  951. }
  952. int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
  953. {
  954. const char * const trace_usage[] = {
  955. "perf trace [<options>] [<command>]",
  956. "perf trace [<options>] -- <command> [<options>]",
  957. NULL
  958. };
  959. struct trace trace = {
  960. .audit_machine = audit_detect_machine(),
  961. .syscalls = {
  962. . max = -1,
  963. },
  964. .opts = {
  965. .target = {
  966. .uid = UINT_MAX,
  967. .uses_mmap = true,
  968. },
  969. .user_freq = UINT_MAX,
  970. .user_interval = ULLONG_MAX,
  971. .no_delay = true,
  972. .mmap_pages = 1024,
  973. },
  974. .output = stdout,
  975. };
  976. const char *output_name = NULL;
  977. const char *ev_qualifier_str = NULL;
  978. const struct option trace_options[] = {
  979. OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
  980. "list of events to trace"),
  981. OPT_STRING('o', "output", &output_name, "file", "output file name"),
  982. OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
  983. OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
  984. "trace events on existing process id"),
  985. OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
  986. "trace events on existing thread id"),
  987. OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
  988. "system-wide collection from all CPUs"),
  989. OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
  990. "list of cpus to monitor"),
  991. OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
  992. "child tasks do not inherit counters"),
  993. OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
  994. "number of mmap data pages"),
  995. OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
  996. "user to profile"),
  997. OPT_CALLBACK(0, "duration", &trace, "float",
  998. "show only events with duration > N.M ms",
  999. trace__set_duration),
  1000. OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
  1001. OPT_INCR('v', "verbose", &verbose, "be more verbose"),
  1002. OPT_END()
  1003. };
  1004. int err;
  1005. char bf[BUFSIZ];
  1006. argc = parse_options(argc, argv, trace_options, trace_usage, 0);
  1007. if (output_name != NULL) {
  1008. err = trace__open_output(&trace, output_name);
  1009. if (err < 0) {
  1010. perror("failed to create output file");
  1011. goto out;
  1012. }
  1013. }
  1014. if (ev_qualifier_str != NULL) {
  1015. const char *s = ev_qualifier_str;
  1016. trace.not_ev_qualifier = *s == '!';
  1017. if (trace.not_ev_qualifier)
  1018. ++s;
  1019. trace.ev_qualifier = strlist__new(true, s);
  1020. if (trace.ev_qualifier == NULL) {
  1021. fputs("Not enough memory to parse event qualifier",
  1022. trace.output);
  1023. err = -ENOMEM;
  1024. goto out_close;
  1025. }
  1026. }
  1027. err = perf_target__validate(&trace.opts.target);
  1028. if (err) {
  1029. perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
  1030. fprintf(trace.output, "%s", bf);
  1031. goto out_close;
  1032. }
  1033. err = perf_target__parse_uid(&trace.opts.target);
  1034. if (err) {
  1035. perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
  1036. fprintf(trace.output, "%s", bf);
  1037. goto out_close;
  1038. }
  1039. if (!argc && perf_target__none(&trace.opts.target))
  1040. trace.opts.target.system_wide = true;
  1041. if (input_name)
  1042. err = trace__replay(&trace);
  1043. else
  1044. err = trace__run(&trace, argc, argv);
  1045. if (trace.sched && !err)
  1046. trace__fprintf_thread_summary(&trace, trace.output);
  1047. out_close:
  1048. if (output_name != NULL)
  1049. fclose(trace.output);
  1050. out:
  1051. return err;
  1052. }