aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-12-04 04:17:17 -0500
committerIngo Molnar <mingo@kernel.org>2013-12-04 04:17:17 -0500
commit89e3bbd58a6186b832fe2b9419ac2f9ab90e9089 (patch)
tree01acb821aaa8660ce072613f0c986314727e72a4
parent0ed1e0bee0b2c6b4cc6d7a63787739a9d3ac8aa8 (diff)
parentf885037ef6400ce4a4c122a88845dea2c9bca256 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/tools improvements and fixes from Arnaldo Carvalho de Melo: * Honour -m option in 'trace', the tool was offering the option to set the mmap size, but wasn't using it when doing the actual mmap on the events file descriptors, fix from Jiri Olsa. * Correct the message in feature-libnuma checking, swowing the right devel package names for various distros, from Dongsheng Yang. * Polish 'readn' function and introduce its counterpart, 'writen', from Jiri Olsa. * Start moving timechart state from global variables to a 'perf_tool' derived 'timechart' struct. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/builtin-record.c20
-rw-r--r--tools/perf/builtin-timechart.c364
-rw-r--r--tools/perf/builtin-trace.c2
-rw-r--r--tools/perf/config/Makefile2
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/util/data.c6
-rw-r--r--tools/perf/util/data.h14
-rw-r--r--tools/perf/util/header.c18
-rw-r--r--tools/perf/util/session.c2
-rw-r--r--tools/perf/util/util.c32
-rw-r--r--tools/perf/util/util.h3
11 files changed, 256 insertions, 212 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 65615a8bc25e..d93e2eef0979 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -76,7 +76,7 @@ struct perf_record {
76 long samples; 76 long samples;
77}; 77};
78 78
79static int do_write_output(struct perf_record *rec, void *buf, size_t size) 79static int perf_record__write(struct perf_record *rec, void *buf, size_t size)
80{ 80{
81 struct perf_data_file *file = &rec->file; 81 struct perf_data_file *file = &rec->file;
82 82
@@ -97,21 +97,13 @@ static int do_write_output(struct perf_record *rec, void *buf, size_t size)
97 return 0; 97 return 0;
98} 98}
99 99
100static int write_output(struct perf_record *rec, void *buf, size_t size)
101{
102 return do_write_output(rec, buf, size);
103}
104
105static int process_synthesized_event(struct perf_tool *tool, 100static int process_synthesized_event(struct perf_tool *tool,
106 union perf_event *event, 101 union perf_event *event,
107 struct perf_sample *sample __maybe_unused, 102 struct perf_sample *sample __maybe_unused,
108 struct machine *machine __maybe_unused) 103 struct machine *machine __maybe_unused)
109{ 104{
110 struct perf_record *rec = container_of(tool, struct perf_record, tool); 105 struct perf_record *rec = container_of(tool, struct perf_record, tool);
111 if (write_output(rec, event, event->header.size) < 0) 106 return perf_record__write(rec, event, event->header.size);
112 return -1;
113
114 return 0;
115} 107}
116 108
117static int perf_record__mmap_read(struct perf_record *rec, 109static int perf_record__mmap_read(struct perf_record *rec,
@@ -136,7 +128,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
136 size = md->mask + 1 - (old & md->mask); 128 size = md->mask + 1 - (old & md->mask);
137 old += size; 129 old += size;
138 130
139 if (write_output(rec, buf, size) < 0) { 131 if (perf_record__write(rec, buf, size) < 0) {
140 rc = -1; 132 rc = -1;
141 goto out; 133 goto out;
142 } 134 }
@@ -146,7 +138,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
146 size = head - old; 138 size = head - old;
147 old += size; 139 old += size;
148 140
149 if (write_output(rec, buf, size) < 0) { 141 if (perf_record__write(rec, buf, size) < 0) {
150 rc = -1; 142 rc = -1;
151 goto out; 143 goto out;
152 } 144 }
@@ -335,8 +327,8 @@ static int perf_record__mmap_read_all(struct perf_record *rec)
335 } 327 }
336 328
337 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 329 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
338 rc = write_output(rec, &finished_round_event, 330 rc = perf_record__write(rec, &finished_round_event,
339 sizeof(finished_round_event)); 331 sizeof(finished_round_event));
340 332
341out: 333out:
342 return rc; 334 return rc;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 680632d7e26a..0bda620a717d 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -41,19 +41,25 @@
41#define SUPPORT_OLD_POWER_EVENTS 1 41#define SUPPORT_OLD_POWER_EVENTS 1
42#define PWR_EVENT_EXIT -1 42#define PWR_EVENT_EXIT -1
43 43
44static int proc_num = 15; 44struct per_pid;
45 45struct power_event;
46static unsigned int numcpus; 46struct wake_event;
47static u64 min_freq; /* Lowest CPU frequency seen */ 47
48static u64 max_freq; /* Highest CPU frequency seen */ 48struct timechart {
49static u64 turbo_frequency; 49 struct perf_tool tool;
50 50 struct per_pid *all_data;
51static u64 first_time, last_time; 51 struct power_event *power_events;
52 52 struct wake_event *wake_events;
53static bool power_only; 53 int proc_num;
54static bool tasks_only; 54 unsigned int numcpus;
55static bool with_backtrace; 55 u64 min_freq, /* Lowest CPU frequency seen */
56 56 max_freq, /* Highest CPU frequency seen */
57 turbo_frequency,
58 first_time, last_time;
59 bool power_only,
60 tasks_only,
61 with_backtrace;
62};
57 63
58struct per_pidcomm; 64struct per_pidcomm;
59struct cpu_sample; 65struct cpu_sample;
@@ -124,8 +130,6 @@ struct cpu_sample {
124 const char *backtrace; 130 const char *backtrace;
125}; 131};
126 132
127static struct per_pid *all_data;
128
129#define CSTATE 1 133#define CSTATE 1
130#define PSTATE 2 134#define PSTATE 2
131 135
@@ -146,9 +150,6 @@ struct wake_event {
146 const char *backtrace; 150 const char *backtrace;
147}; 151};
148 152
149static struct power_event *power_events;
150static struct wake_event *wake_events;
151
152struct process_filter { 153struct process_filter {
153 char *name; 154 char *name;
154 int pid; 155 int pid;
@@ -158,9 +159,9 @@ struct process_filter {
158static struct process_filter *process_filter; 159static struct process_filter *process_filter;
159 160
160 161
161static struct per_pid *find_create_pid(int pid) 162static struct per_pid *find_create_pid(struct timechart *tchart, int pid)
162{ 163{
163 struct per_pid *cursor = all_data; 164 struct per_pid *cursor = tchart->all_data;
164 165
165 while (cursor) { 166 while (cursor) {
166 if (cursor->pid == pid) 167 if (cursor->pid == pid)
@@ -170,16 +171,16 @@ static struct per_pid *find_create_pid(int pid)
170 cursor = zalloc(sizeof(*cursor)); 171 cursor = zalloc(sizeof(*cursor));
171 assert(cursor != NULL); 172 assert(cursor != NULL);
172 cursor->pid = pid; 173 cursor->pid = pid;
173 cursor->next = all_data; 174 cursor->next = tchart->all_data;
174 all_data = cursor; 175 tchart->all_data = cursor;
175 return cursor; 176 return cursor;
176} 177}
177 178
178static void pid_set_comm(int pid, char *comm) 179static void pid_set_comm(struct timechart *tchart, int pid, char *comm)
179{ 180{
180 struct per_pid *p; 181 struct per_pid *p;
181 struct per_pidcomm *c; 182 struct per_pidcomm *c;
182 p = find_create_pid(pid); 183 p = find_create_pid(tchart, pid);
183 c = p->all; 184 c = p->all;
184 while (c) { 185 while (c) {
185 if (c->comm && strcmp(c->comm, comm) == 0) { 186 if (c->comm && strcmp(c->comm, comm) == 0) {
@@ -201,14 +202,14 @@ static void pid_set_comm(int pid, char *comm)
201 p->all = c; 202 p->all = c;
202} 203}
203 204
204static void pid_fork(int pid, int ppid, u64 timestamp) 205static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
205{ 206{
206 struct per_pid *p, *pp; 207 struct per_pid *p, *pp;
207 p = find_create_pid(pid); 208 p = find_create_pid(tchart, pid);
208 pp = find_create_pid(ppid); 209 pp = find_create_pid(tchart, ppid);
209 p->ppid = ppid; 210 p->ppid = ppid;
210 if (pp->current && pp->current->comm && !p->current) 211 if (pp->current && pp->current->comm && !p->current)
211 pid_set_comm(pid, pp->current->comm); 212 pid_set_comm(tchart, pid, pp->current->comm);
212 213
213 p->start_time = timestamp; 214 p->start_time = timestamp;
214 if (p->current) { 215 if (p->current) {
@@ -217,24 +218,24 @@ static void pid_fork(int pid, int ppid, u64 timestamp)
217 } 218 }
218} 219}
219 220
220static void pid_exit(int pid, u64 timestamp) 221static void pid_exit(struct timechart *tchart, int pid, u64 timestamp)
221{ 222{
222 struct per_pid *p; 223 struct per_pid *p;
223 p = find_create_pid(pid); 224 p = find_create_pid(tchart, pid);
224 p->end_time = timestamp; 225 p->end_time = timestamp;
225 if (p->current) 226 if (p->current)
226 p->current->end_time = timestamp; 227 p->current->end_time = timestamp;
227} 228}
228 229
229static void 230static void pid_put_sample(struct timechart *tchart, int pid, int type,
230pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end, 231 unsigned int cpu, u64 start, u64 end,
231 const char *backtrace) 232 const char *backtrace)
232{ 233{
233 struct per_pid *p; 234 struct per_pid *p;
234 struct per_pidcomm *c; 235 struct per_pidcomm *c;
235 struct cpu_sample *sample; 236 struct cpu_sample *sample;
236 237
237 p = find_create_pid(pid); 238 p = find_create_pid(tchart, pid);
238 c = p->current; 239 c = p->current;
239 if (!c) { 240 if (!c) {
240 c = zalloc(sizeof(*c)); 241 c = zalloc(sizeof(*c));
@@ -272,30 +273,33 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
274 275
275static int process_comm_event(struct perf_tool *tool __maybe_unused, 276static int process_comm_event(struct perf_tool *tool,
276 union perf_event *event, 277 union perf_event *event,
277 struct perf_sample *sample __maybe_unused, 278 struct perf_sample *sample __maybe_unused,
278 struct machine *machine __maybe_unused) 279 struct machine *machine __maybe_unused)
279{ 280{
280 pid_set_comm(event->comm.tid, event->comm.comm); 281 struct timechart *tchart = container_of(tool, struct timechart, tool);
282 pid_set_comm(tchart, event->comm.tid, event->comm.comm);
281 return 0; 283 return 0;
282} 284}
283 285
284static int process_fork_event(struct perf_tool *tool __maybe_unused, 286static int process_fork_event(struct perf_tool *tool,
285 union perf_event *event, 287 union perf_event *event,
286 struct perf_sample *sample __maybe_unused, 288 struct perf_sample *sample __maybe_unused,
287 struct machine *machine __maybe_unused) 289 struct machine *machine __maybe_unused)
288{ 290{
289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 291 struct timechart *tchart = container_of(tool, struct timechart, tool);
292 pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time);
290 return 0; 293 return 0;
291} 294}
292 295
293static int process_exit_event(struct perf_tool *tool __maybe_unused, 296static int process_exit_event(struct perf_tool *tool,
294 union perf_event *event, 297 union perf_event *event,
295 struct perf_sample *sample __maybe_unused, 298 struct perf_sample *sample __maybe_unused,
296 struct machine *machine __maybe_unused) 299 struct machine *machine __maybe_unused)
297{ 300{
298 pid_exit(event->fork.pid, event->fork.time); 301 struct timechart *tchart = container_of(tool, struct timechart, tool);
302 pid_exit(tchart, event->fork.pid, event->fork.time);
299 return 0; 303 return 0;
300} 304}
301 305
@@ -309,7 +313,7 @@ static void c_state_start(int cpu, u64 timestamp, int state)
309 cpus_cstate_state[cpu] = state; 313 cpus_cstate_state[cpu] = state;
310} 314}
311 315
312static void c_state_end(int cpu, u64 timestamp) 316static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp)
313{ 317{
314 struct power_event *pwr = zalloc(sizeof(*pwr)); 318 struct power_event *pwr = zalloc(sizeof(*pwr));
315 319
@@ -321,12 +325,12 @@ static void c_state_end(int cpu, u64 timestamp)
321 pwr->end_time = timestamp; 325 pwr->end_time = timestamp;
322 pwr->cpu = cpu; 326 pwr->cpu = cpu;
323 pwr->type = CSTATE; 327 pwr->type = CSTATE;
324 pwr->next = power_events; 328 pwr->next = tchart->power_events;
325 329
326 power_events = pwr; 330 tchart->power_events = pwr;
327} 331}
328 332
329static void p_state_change(int cpu, u64 timestamp, u64 new_freq) 333static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
330{ 334{
331 struct power_event *pwr; 335 struct power_event *pwr;
332 336
@@ -342,28 +346,28 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
342 pwr->end_time = timestamp; 346 pwr->end_time = timestamp;
343 pwr->cpu = cpu; 347 pwr->cpu = cpu;
344 pwr->type = PSTATE; 348 pwr->type = PSTATE;
345 pwr->next = power_events; 349 pwr->next = tchart->power_events;
346 350
347 if (!pwr->start_time) 351 if (!pwr->start_time)
348 pwr->start_time = first_time; 352 pwr->start_time = tchart->first_time;
349 353
350 power_events = pwr; 354 tchart->power_events = pwr;
351 355
352 cpus_pstate_state[cpu] = new_freq; 356 cpus_pstate_state[cpu] = new_freq;
353 cpus_pstate_start_times[cpu] = timestamp; 357 cpus_pstate_start_times[cpu] = timestamp;
354 358
355 if ((u64)new_freq > max_freq) 359 if ((u64)new_freq > tchart->max_freq)
356 max_freq = new_freq; 360 tchart->max_freq = new_freq;
357 361
358 if (new_freq < min_freq || min_freq == 0) 362 if (new_freq < tchart->min_freq || tchart->min_freq == 0)
359 min_freq = new_freq; 363 tchart->min_freq = new_freq;
360 364
361 if (new_freq == max_freq - 1000) 365 if (new_freq == tchart->max_freq - 1000)
362 turbo_frequency = max_freq; 366 tchart->turbo_frequency = tchart->max_freq;
363} 367}
364 368
365static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee, 369static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
366 u8 flags, const char *backtrace) 370 int waker, int wakee, u8 flags, const char *backtrace)
367{ 371{
368 struct per_pid *p; 372 struct per_pid *p;
369 struct wake_event *we = zalloc(sizeof(*we)); 373 struct wake_event *we = zalloc(sizeof(*we));
@@ -379,38 +383,39 @@ static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee,
379 we->waker = -1; 383 we->waker = -1;
380 384
381 we->wakee = wakee; 385 we->wakee = wakee;
382 we->next = wake_events; 386 we->next = tchart->wake_events;
383 wake_events = we; 387 tchart->wake_events = we;
384 p = find_create_pid(we->wakee); 388 p = find_create_pid(tchart, we->wakee);
385 389
386 if (p && p->current && p->current->state == TYPE_NONE) { 390 if (p && p->current && p->current->state == TYPE_NONE) {
387 p->current->state_since = timestamp; 391 p->current->state_since = timestamp;
388 p->current->state = TYPE_WAITING; 392 p->current->state = TYPE_WAITING;
389 } 393 }
390 if (p && p->current && p->current->state == TYPE_BLOCKED) { 394 if (p && p->current && p->current->state == TYPE_BLOCKED) {
391 pid_put_sample(p->pid, p->current->state, cpu, 395 pid_put_sample(tchart, p->pid, p->current->state, cpu,
392 p->current->state_since, timestamp, NULL); 396 p->current->state_since, timestamp, NULL);
393 p->current->state_since = timestamp; 397 p->current->state_since = timestamp;
394 p->current->state = TYPE_WAITING; 398 p->current->state = TYPE_WAITING;
395 } 399 }
396} 400}
397 401
398static void sched_switch(int cpu, u64 timestamp, int prev_pid, int next_pid, 402static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
399 u64 prev_state, const char *backtrace) 403 int prev_pid, int next_pid, u64 prev_state,
404 const char *backtrace)
400{ 405{
401 struct per_pid *p = NULL, *prev_p; 406 struct per_pid *p = NULL, *prev_p;
402 407
403 prev_p = find_create_pid(prev_pid); 408 prev_p = find_create_pid(tchart, prev_pid);
404 409
405 p = find_create_pid(next_pid); 410 p = find_create_pid(tchart, next_pid);
406 411
407 if (prev_p->current && prev_p->current->state != TYPE_NONE) 412 if (prev_p->current && prev_p->current->state != TYPE_NONE)
408 pid_put_sample(prev_pid, TYPE_RUNNING, cpu, 413 pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
409 prev_p->current->state_since, timestamp, 414 prev_p->current->state_since, timestamp,
410 backtrace); 415 backtrace);
411 if (p && p->current) { 416 if (p && p->current) {
412 if (p->current->state != TYPE_NONE) 417 if (p->current->state != TYPE_NONE)
413 pid_put_sample(next_pid, p->current->state, cpu, 418 pid_put_sample(tchart, next_pid, p->current->state, cpu,
414 p->current->state_since, timestamp, 419 p->current->state_since, timestamp,
415 backtrace); 420 backtrace);
416 421
@@ -506,36 +511,40 @@ exit:
506 return p; 511 return p;
507} 512}
508 513
509typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 514typedef int (*tracepoint_handler)(struct timechart *tchart,
515 struct perf_evsel *evsel,
510 struct perf_sample *sample, 516 struct perf_sample *sample,
511 const char *backtrace); 517 const char *backtrace);
512 518
513static int process_sample_event(struct perf_tool *tool __maybe_unused, 519static int process_sample_event(struct perf_tool *tool,
514 union perf_event *event, 520 union perf_event *event,
515 struct perf_sample *sample, 521 struct perf_sample *sample,
516 struct perf_evsel *evsel, 522 struct perf_evsel *evsel,
517 struct machine *machine __maybe_unused) 523 struct machine *machine)
518{ 524{
525 struct timechart *tchart = container_of(tool, struct timechart, tool);
526
519 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 527 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
520 if (!first_time || first_time > sample->time) 528 if (!tchart->first_time || tchart->first_time > sample->time)
521 first_time = sample->time; 529 tchart->first_time = sample->time;
522 if (last_time < sample->time) 530 if (tchart->last_time < sample->time)
523 last_time = sample->time; 531 tchart->last_time = sample->time;
524 } 532 }
525 533
526 if (sample->cpu > numcpus) 534 if (sample->cpu > tchart->numcpus)
527 numcpus = sample->cpu; 535 tchart->numcpus = sample->cpu;
528 536
529 if (evsel->handler != NULL) { 537 if (evsel->handler != NULL) {
530 tracepoint_handler f = evsel->handler; 538 tracepoint_handler f = evsel->handler;
531 return f(evsel, sample, cat_backtrace(event, sample, machine)); 539 return f(tchart, evsel, sample, cat_backtrace(event, sample, machine));
532 } 540 }
533 541
534 return 0; 542 return 0;
535} 543}
536 544
537static int 545static int
538process_sample_cpu_idle(struct perf_evsel *evsel, 546process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
547 struct perf_evsel *evsel,
539 struct perf_sample *sample, 548 struct perf_sample *sample,
540 const char *backtrace __maybe_unused) 549 const char *backtrace __maybe_unused)
541{ 550{
@@ -543,26 +552,28 @@ process_sample_cpu_idle(struct perf_evsel *evsel,
543 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); 552 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
544 553
545 if (state == (u32)PWR_EVENT_EXIT) 554 if (state == (u32)PWR_EVENT_EXIT)
546 c_state_end(cpu_id, sample->time); 555 c_state_end(tchart, cpu_id, sample->time);
547 else 556 else
548 c_state_start(cpu_id, sample->time, state); 557 c_state_start(cpu_id, sample->time, state);
549 return 0; 558 return 0;
550} 559}
551 560
552static int 561static int
553process_sample_cpu_frequency(struct perf_evsel *evsel, 562process_sample_cpu_frequency(struct timechart *tchart,
563 struct perf_evsel *evsel,
554 struct perf_sample *sample, 564 struct perf_sample *sample,
555 const char *backtrace __maybe_unused) 565 const char *backtrace __maybe_unused)
556{ 566{
557 u32 state = perf_evsel__intval(evsel, sample, "state"); 567 u32 state = perf_evsel__intval(evsel, sample, "state");
558 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); 568 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
559 569
560 p_state_change(cpu_id, sample->time, state); 570 p_state_change(tchart, cpu_id, sample->time, state);
561 return 0; 571 return 0;
562} 572}
563 573
564static int 574static int
565process_sample_sched_wakeup(struct perf_evsel *evsel, 575process_sample_sched_wakeup(struct timechart *tchart,
576 struct perf_evsel *evsel,
566 struct perf_sample *sample, 577 struct perf_sample *sample,
567 const char *backtrace) 578 const char *backtrace)
568{ 579{
@@ -570,12 +581,13 @@ process_sample_sched_wakeup(struct perf_evsel *evsel,
570 int waker = perf_evsel__intval(evsel, sample, "common_pid"); 581 int waker = perf_evsel__intval(evsel, sample, "common_pid");
571 int wakee = perf_evsel__intval(evsel, sample, "pid"); 582 int wakee = perf_evsel__intval(evsel, sample, "pid");
572 583
573 sched_wakeup(sample->cpu, sample->time, waker, wakee, flags, backtrace); 584 sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
574 return 0; 585 return 0;
575} 586}
576 587
577static int 588static int
578process_sample_sched_switch(struct perf_evsel *evsel, 589process_sample_sched_switch(struct timechart *tchart,
590 struct perf_evsel *evsel,
579 struct perf_sample *sample, 591 struct perf_sample *sample,
580 const char *backtrace) 592 const char *backtrace)
581{ 593{
@@ -583,14 +595,15 @@ process_sample_sched_switch(struct perf_evsel *evsel,
583 int next_pid = perf_evsel__intval(evsel, sample, "next_pid"); 595 int next_pid = perf_evsel__intval(evsel, sample, "next_pid");
584 u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state"); 596 u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
585 597
586 sched_switch(sample->cpu, sample->time, prev_pid, next_pid, prev_state, 598 sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
587 backtrace); 599 prev_state, backtrace);
588 return 0; 600 return 0;
589} 601}
590 602
591#ifdef SUPPORT_OLD_POWER_EVENTS 603#ifdef SUPPORT_OLD_POWER_EVENTS
592static int 604static int
593process_sample_power_start(struct perf_evsel *evsel, 605process_sample_power_start(struct timechart *tchart __maybe_unused,
606 struct perf_evsel *evsel,
594 struct perf_sample *sample, 607 struct perf_sample *sample,
595 const char *backtrace __maybe_unused) 608 const char *backtrace __maybe_unused)
596{ 609{
@@ -602,23 +615,25 @@ process_sample_power_start(struct perf_evsel *evsel,
602} 615}
603 616
604static int 617static int
605process_sample_power_end(struct perf_evsel *evsel __maybe_unused, 618process_sample_power_end(struct timechart *tchart,
619 struct perf_evsel *evsel __maybe_unused,
606 struct perf_sample *sample, 620 struct perf_sample *sample,
607 const char *backtrace __maybe_unused) 621 const char *backtrace __maybe_unused)
608{ 622{
609 c_state_end(sample->cpu, sample->time); 623 c_state_end(tchart, sample->cpu, sample->time);
610 return 0; 624 return 0;
611} 625}
612 626
613static int 627static int
614process_sample_power_frequency(struct perf_evsel *evsel, 628process_sample_power_frequency(struct timechart *tchart,
629 struct perf_evsel *evsel,
615 struct perf_sample *sample, 630 struct perf_sample *sample,
616 const char *backtrace __maybe_unused) 631 const char *backtrace __maybe_unused)
617{ 632{
618 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); 633 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
619 u64 value = perf_evsel__intval(evsel, sample, "value"); 634 u64 value = perf_evsel__intval(evsel, sample, "value");
620 635
621 p_state_change(cpu_id, sample->time, value); 636 p_state_change(tchart, cpu_id, sample->time, value);
622 return 0; 637 return 0;
623} 638}
624#endif /* SUPPORT_OLD_POWER_EVENTS */ 639#endif /* SUPPORT_OLD_POWER_EVENTS */
@@ -627,12 +642,12 @@ process_sample_power_frequency(struct perf_evsel *evsel,
627 * After the last sample we need to wrap up the current C/P state 642 * After the last sample we need to wrap up the current C/P state
628 * and close out each CPU for these. 643 * and close out each CPU for these.
629 */ 644 */
630static void end_sample_processing(void) 645static void end_sample_processing(struct timechart *tchart)
631{ 646{
632 u64 cpu; 647 u64 cpu;
633 struct power_event *pwr; 648 struct power_event *pwr;
634 649
635 for (cpu = 0; cpu <= numcpus; cpu++) { 650 for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
636 /* C state */ 651 /* C state */
637#if 0 652#if 0
638 pwr = zalloc(sizeof(*pwr)); 653 pwr = zalloc(sizeof(*pwr));
@@ -641,12 +656,12 @@ static void end_sample_processing(void)
641 656
642 pwr->state = cpus_cstate_state[cpu]; 657 pwr->state = cpus_cstate_state[cpu];
643 pwr->start_time = cpus_cstate_start_times[cpu]; 658 pwr->start_time = cpus_cstate_start_times[cpu];
644 pwr->end_time = last_time; 659 pwr->end_time = tchart->last_time;
645 pwr->cpu = cpu; 660 pwr->cpu = cpu;
646 pwr->type = CSTATE; 661 pwr->type = CSTATE;
647 pwr->next = power_events; 662 pwr->next = tchart->power_events;
648 663
649 power_events = pwr; 664 tchart->power_events = pwr;
650#endif 665#endif
651 /* P state */ 666 /* P state */
652 667
@@ -656,32 +671,32 @@ static void end_sample_processing(void)
656 671
657 pwr->state = cpus_pstate_state[cpu]; 672 pwr->state = cpus_pstate_state[cpu];
658 pwr->start_time = cpus_pstate_start_times[cpu]; 673 pwr->start_time = cpus_pstate_start_times[cpu];
659 pwr->end_time = last_time; 674 pwr->end_time = tchart->last_time;
660 pwr->cpu = cpu; 675 pwr->cpu = cpu;
661 pwr->type = PSTATE; 676 pwr->type = PSTATE;
662 pwr->next = power_events; 677 pwr->next = tchart->power_events;
663 678
664 if (!pwr->start_time) 679 if (!pwr->start_time)
665 pwr->start_time = first_time; 680 pwr->start_time = tchart->first_time;
666 if (!pwr->state) 681 if (!pwr->state)
667 pwr->state = min_freq; 682 pwr->state = tchart->min_freq;
668 power_events = pwr; 683 tchart->power_events = pwr;
669 } 684 }
670} 685}
671 686
672/* 687/*
673 * Sort the pid datastructure 688 * Sort the pid datastructure
674 */ 689 */
675static void sort_pids(void) 690static void sort_pids(struct timechart *tchart)
676{ 691{
677 struct per_pid *new_list, *p, *cursor, *prev; 692 struct per_pid *new_list, *p, *cursor, *prev;
678 /* sort by ppid first, then by pid, lowest to highest */ 693 /* sort by ppid first, then by pid, lowest to highest */
679 694
680 new_list = NULL; 695 new_list = NULL;
681 696
682 while (all_data) { 697 while (tchart->all_data) {
683 p = all_data; 698 p = tchart->all_data;
684 all_data = p->next; 699 tchart->all_data = p->next;
685 p->next = NULL; 700 p->next = NULL;
686 701
687 if (new_list == NULL) { 702 if (new_list == NULL) {
@@ -714,14 +729,14 @@ static void sort_pids(void)
714 prev->next = p; 729 prev->next = p;
715 } 730 }
716 } 731 }
717 all_data = new_list; 732 tchart->all_data = new_list;
718} 733}
719 734
720 735
721static void draw_c_p_states(void) 736static void draw_c_p_states(struct timechart *tchart)
722{ 737{
723 struct power_event *pwr; 738 struct power_event *pwr;
724 pwr = power_events; 739 pwr = tchart->power_events;
725 740
726 /* 741 /*
727 * two pass drawing so that the P state bars are on top of the C state blocks 742 * two pass drawing so that the P state bars are on top of the C state blocks
@@ -732,30 +747,30 @@ static void draw_c_p_states(void)
732 pwr = pwr->next; 747 pwr = pwr->next;
733 } 748 }
734 749
735 pwr = power_events; 750 pwr = tchart->power_events;
736 while (pwr) { 751 while (pwr) {
737 if (pwr->type == PSTATE) { 752 if (pwr->type == PSTATE) {
738 if (!pwr->state) 753 if (!pwr->state)
739 pwr->state = min_freq; 754 pwr->state = tchart->min_freq;
740 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); 755 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
741 } 756 }
742 pwr = pwr->next; 757 pwr = pwr->next;
743 } 758 }
744} 759}
745 760
746static void draw_wakeups(void) 761static void draw_wakeups(struct timechart *tchart)
747{ 762{
748 struct wake_event *we; 763 struct wake_event *we;
749 struct per_pid *p; 764 struct per_pid *p;
750 struct per_pidcomm *c; 765 struct per_pidcomm *c;
751 766
752 we = wake_events; 767 we = tchart->wake_events;
753 while (we) { 768 while (we) {
754 int from = 0, to = 0; 769 int from = 0, to = 0;
755 char *task_from = NULL, *task_to = NULL; 770 char *task_from = NULL, *task_to = NULL;
756 771
757 /* locate the column of the waker and wakee */ 772 /* locate the column of the waker and wakee */
758 p = all_data; 773 p = tchart->all_data;
759 while (p) { 774 while (p) {
760 if (p->pid == we->waker || p->pid == we->wakee) { 775 if (p->pid == we->waker || p->pid == we->wakee) {
761 c = p->all; 776 c = p->all;
@@ -811,12 +826,12 @@ static void draw_wakeups(void)
811 } 826 }
812} 827}
813 828
814static void draw_cpu_usage(void) 829static void draw_cpu_usage(struct timechart *tchart)
815{ 830{
816 struct per_pid *p; 831 struct per_pid *p;
817 struct per_pidcomm *c; 832 struct per_pidcomm *c;
818 struct cpu_sample *sample; 833 struct cpu_sample *sample;
819 p = all_data; 834 p = tchart->all_data;
820 while (p) { 835 while (p) {
821 c = p->all; 836 c = p->all;
822 while (c) { 837 while (c) {
@@ -833,16 +848,16 @@ static void draw_cpu_usage(void)
833 } 848 }
834} 849}
835 850
836static void draw_process_bars(void) 851static void draw_process_bars(struct timechart *tchart)
837{ 852{
838 struct per_pid *p; 853 struct per_pid *p;
839 struct per_pidcomm *c; 854 struct per_pidcomm *c;
840 struct cpu_sample *sample; 855 struct cpu_sample *sample;
841 int Y = 0; 856 int Y = 0;
842 857
843 Y = 2 * numcpus + 2; 858 Y = 2 * tchart->numcpus + 2;
844 859
845 p = all_data; 860 p = tchart->all_data;
846 while (p) { 861 while (p) {
847 c = p->all; 862 c = p->all;
848 while (c) { 863 while (c) {
@@ -922,21 +937,21 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
922 return 0; 937 return 0;
923} 938}
924 939
925static int determine_display_tasks_filtered(void) 940static int determine_display_tasks_filtered(struct timechart *tchart)
926{ 941{
927 struct per_pid *p; 942 struct per_pid *p;
928 struct per_pidcomm *c; 943 struct per_pidcomm *c;
929 int count = 0; 944 int count = 0;
930 945
931 p = all_data; 946 p = tchart->all_data;
932 while (p) { 947 while (p) {
933 p->display = 0; 948 p->display = 0;
934 if (p->start_time == 1) 949 if (p->start_time == 1)
935 p->start_time = first_time; 950 p->start_time = tchart->first_time;
936 951
937 /* no exit marker, task kept running to the end */ 952 /* no exit marker, task kept running to the end */
938 if (p->end_time == 0) 953 if (p->end_time == 0)
939 p->end_time = last_time; 954 p->end_time = tchart->last_time;
940 955
941 c = p->all; 956 c = p->all;
942 957
@@ -944,7 +959,7 @@ static int determine_display_tasks_filtered(void)
944 c->display = 0; 959 c->display = 0;
945 960
946 if (c->start_time == 1) 961 if (c->start_time == 1)
947 c->start_time = first_time; 962 c->start_time = tchart->first_time;
948 963
949 if (passes_filter(p, c)) { 964 if (passes_filter(p, c)) {
950 c->display = 1; 965 c->display = 1;
@@ -953,7 +968,7 @@ static int determine_display_tasks_filtered(void)
953 } 968 }
954 969
955 if (c->end_time == 0) 970 if (c->end_time == 0)
956 c->end_time = last_time; 971 c->end_time = tchart->last_time;
957 972
958 c = c->next; 973 c = c->next;
959 } 974 }
@@ -962,24 +977,24 @@ static int determine_display_tasks_filtered(void)
962 return count; 977 return count;
963} 978}
964 979
965static int determine_display_tasks(u64 threshold) 980static int determine_display_tasks(struct timechart *tchart, u64 threshold)
966{ 981{
967 struct per_pid *p; 982 struct per_pid *p;
968 struct per_pidcomm *c; 983 struct per_pidcomm *c;
969 int count = 0; 984 int count = 0;
970 985
971 if (process_filter) 986 if (process_filter)
972 return determine_display_tasks_filtered(); 987 return determine_display_tasks_filtered(tchart);
973 988
974 p = all_data; 989 p = tchart->all_data;
975 while (p) { 990 while (p) {
976 p->display = 0; 991 p->display = 0;
977 if (p->start_time == 1) 992 if (p->start_time == 1)
978 p->start_time = first_time; 993 p->start_time = tchart->first_time;
979 994
980 /* no exit marker, task kept running to the end */ 995 /* no exit marker, task kept running to the end */
981 if (p->end_time == 0) 996 if (p->end_time == 0)
982 p->end_time = last_time; 997 p->end_time = tchart->last_time;
983 if (p->total_time >= threshold) 998 if (p->total_time >= threshold)
984 p->display = 1; 999 p->display = 1;
985 1000
@@ -989,7 +1004,7 @@ static int determine_display_tasks(u64 threshold)
989 c->display = 0; 1004 c->display = 0;
990 1005
991 if (c->start_time == 1) 1006 if (c->start_time == 1)
992 c->start_time = first_time; 1007 c->start_time = tchart->first_time;
993 1008
994 if (c->total_time >= threshold) { 1009 if (c->total_time >= threshold) {
995 c->display = 1; 1010 c->display = 1;
@@ -997,7 +1012,7 @@ static int determine_display_tasks(u64 threshold)
997 } 1012 }
998 1013
999 if (c->end_time == 0) 1014 if (c->end_time == 0)
1000 c->end_time = last_time; 1015 c->end_time = tchart->last_time;
1001 1016
1002 c = c->next; 1017 c = c->next;
1003 } 1018 }
@@ -1010,52 +1025,45 @@ static int determine_display_tasks(u64 threshold)
1010 1025
1011#define TIME_THRESH 10000000 1026#define TIME_THRESH 10000000
1012 1027
1013static void write_svg_file(const char *filename) 1028static void write_svg_file(struct timechart *tchart, const char *filename)
1014{ 1029{
1015 u64 i; 1030 u64 i;
1016 int count; 1031 int count;
1017 int thresh = TIME_THRESH; 1032 int thresh = TIME_THRESH;
1018 1033
1019 numcpus++; 1034 tchart->numcpus++;
1020 1035
1021 if (power_only) 1036 if (tchart->power_only)
1022 proc_num = 0; 1037 tchart->proc_num = 0;
1023 1038
1024 /* We'd like to show at least proc_num tasks; 1039 /* We'd like to show at least proc_num tasks;
1025 * be less picky if we have fewer */ 1040 * be less picky if we have fewer */
1026 do { 1041 do {
1027 count = determine_display_tasks(thresh); 1042 count = determine_display_tasks(tchart, thresh);
1028 thresh /= 10; 1043 thresh /= 10;
1029 } while (!process_filter && thresh && count < proc_num); 1044 } while (!process_filter && thresh && count < tchart->proc_num);
1030 1045
1031 open_svg(filename, numcpus, count, first_time, last_time); 1046 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
1032 1047
1033 svg_time_grid(); 1048 svg_time_grid();
1034 svg_legenda(); 1049 svg_legenda();
1035 1050
1036 for (i = 0; i < numcpus; i++) 1051 for (i = 0; i < tchart->numcpus; i++)
1037 svg_cpu_box(i, max_freq, turbo_frequency); 1052 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
1038 1053
1039 draw_cpu_usage(); 1054 draw_cpu_usage(tchart);
1040 if (proc_num) 1055 if (tchart->proc_num)
1041 draw_process_bars(); 1056 draw_process_bars(tchart);
1042 if (!tasks_only) 1057 if (!tchart->tasks_only)
1043 draw_c_p_states(); 1058 draw_c_p_states(tchart);
1044 if (proc_num) 1059 if (tchart->proc_num)
1045 draw_wakeups(); 1060 draw_wakeups(tchart);
1046 1061
1047 svg_close(); 1062 svg_close();
1048} 1063}
1049 1064
1050static int __cmd_timechart(const char *output_name) 1065static int __cmd_timechart(struct timechart *tchart, const char *output_name)
1051{ 1066{
1052 struct perf_tool perf_timechart = {
1053 .comm = process_comm_event,
1054 .fork = process_fork_event,
1055 .exit = process_exit_event,
1056 .sample = process_sample_event,
1057 .ordered_samples = true,
1058 };
1059 const struct perf_evsel_str_handler power_tracepoints[] = { 1067 const struct perf_evsel_str_handler power_tracepoints[] = {
1060 { "power:cpu_idle", process_sample_cpu_idle }, 1068 { "power:cpu_idle", process_sample_cpu_idle },
1061 { "power:cpu_frequency", process_sample_cpu_frequency }, 1069 { "power:cpu_frequency", process_sample_cpu_frequency },
@@ -1073,7 +1081,7 @@ static int __cmd_timechart(const char *output_name)
1073 }; 1081 };
1074 1082
1075 struct perf_session *session = perf_session__new(&file, false, 1083 struct perf_session *session = perf_session__new(&file, false,
1076 &perf_timechart); 1084 &tchart->tool);
1077 int ret = -EINVAL; 1085 int ret = -EINVAL;
1078 1086
1079 if (session == NULL) 1087 if (session == NULL)
@@ -1088,24 +1096,24 @@ static int __cmd_timechart(const char *output_name)
1088 goto out_delete; 1096 goto out_delete;
1089 } 1097 }
1090 1098
1091 ret = perf_session__process_events(session, &perf_timechart); 1099 ret = perf_session__process_events(session, &tchart->tool);
1092 if (ret) 1100 if (ret)
1093 goto out_delete; 1101 goto out_delete;
1094 1102
1095 end_sample_processing(); 1103 end_sample_processing(tchart);
1096 1104
1097 sort_pids(); 1105 sort_pids(tchart);
1098 1106
1099 write_svg_file(output_name); 1107 write_svg_file(tchart, output_name);
1100 1108
1101 pr_info("Written %2.1f seconds of trace to %s.\n", 1109 pr_info("Written %2.1f seconds of trace to %s.\n",
1102 (last_time - first_time) / 1000000000.0, output_name); 1110 (tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
1103out_delete: 1111out_delete:
1104 perf_session__delete(session); 1112 perf_session__delete(session);
1105 return ret; 1113 return ret;
1106} 1114}
1107 1115
1108static int __cmd_record(int argc, const char **argv) 1116static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1109{ 1117{
1110 unsigned int rec_argc, i, j; 1118 unsigned int rec_argc, i, j;
1111 const char **rec_argv; 1119 const char **rec_argv;
@@ -1153,15 +1161,15 @@ static int __cmd_record(int argc, const char **argv)
1153 } 1161 }
1154#endif 1162#endif
1155 1163
1156 if (power_only) 1164 if (tchart->power_only)
1157 tasks_args_nr = 0; 1165 tasks_args_nr = 0;
1158 1166
1159 if (tasks_only) { 1167 if (tchart->tasks_only) {
1160 power_args_nr = 0; 1168 power_args_nr = 0;
1161 old_power_args_nr = 0; 1169 old_power_args_nr = 0;
1162 } 1170 }
1163 1171
1164 if (!with_backtrace) 1172 if (!tchart->with_backtrace)
1165 backtrace_args_no = 0; 1173 backtrace_args_no = 0;
1166 1174
1167 record_elems = common_args_nr + tasks_args_nr + 1175 record_elems = common_args_nr + tasks_args_nr +
@@ -1207,20 +1215,30 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
1207int cmd_timechart(int argc, const char **argv, 1215int cmd_timechart(int argc, const char **argv,
1208 const char *prefix __maybe_unused) 1216 const char *prefix __maybe_unused)
1209{ 1217{
1218 struct timechart tchart = {
1219 .tool = {
1220 .comm = process_comm_event,
1221 .fork = process_fork_event,
1222 .exit = process_exit_event,
1223 .sample = process_sample_event,
1224 .ordered_samples = true,
1225 },
1226 .proc_num = 15,
1227 };
1210 const char *output_name = "output.svg"; 1228 const char *output_name = "output.svg";
1211 const struct option timechart_options[] = { 1229 const struct option timechart_options[] = {
1212 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1230 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1213 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1231 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1214 OPT_INTEGER('w', "width", &svg_page_width, "page width"), 1232 OPT_INTEGER('w', "width", &svg_page_width, "page width"),
1215 OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), 1233 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1216 OPT_BOOLEAN('T', "tasks-only", &tasks_only, 1234 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1217 "output processes data only"), 1235 "output processes data only"),
1218 OPT_CALLBACK('p', "process", NULL, "process", 1236 OPT_CALLBACK('p', "process", NULL, "process",
1219 "process selector. Pass a pid or process name.", 1237 "process selector. Pass a pid or process name.",
1220 parse_process), 1238 parse_process),
1221 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1239 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1222 "Look for files with symbols relative to this directory"), 1240 "Look for files with symbols relative to this directory"),
1223 OPT_INTEGER('n', "proc-num", &proc_num, 1241 OPT_INTEGER('n', "proc-num", &tchart.proc_num,
1224 "min. number of tasks to print"), 1242 "min. number of tasks to print"),
1225 OPT_END() 1243 OPT_END()
1226 }; 1244 };
@@ -1230,10 +1248,10 @@ int cmd_timechart(int argc, const char **argv,
1230 }; 1248 };
1231 1249
1232 const struct option record_options[] = { 1250 const struct option record_options[] = {
1233 OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), 1251 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1234 OPT_BOOLEAN('T', "tasks-only", &tasks_only, 1252 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1235 "output processes data only"), 1253 "output processes data only"),
1236 OPT_BOOLEAN('g', "callchain", &with_backtrace, "record callchain"), 1254 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1237 OPT_END() 1255 OPT_END()
1238 }; 1256 };
1239 const char * const record_usage[] = { 1257 const char * const record_usage[] = {
@@ -1243,7 +1261,7 @@ int cmd_timechart(int argc, const char **argv,
1243 argc = parse_options(argc, argv, timechart_options, timechart_usage, 1261 argc = parse_options(argc, argv, timechart_options, timechart_usage,
1244 PARSE_OPT_STOP_AT_NON_OPTION); 1262 PARSE_OPT_STOP_AT_NON_OPTION);
1245 1263
1246 if (power_only && tasks_only) { 1264 if (tchart.power_only && tchart.tasks_only) {
1247 pr_err("-P and -T options cannot be used at the same time.\n"); 1265 pr_err("-P and -T options cannot be used at the same time.\n");
1248 return -1; 1266 return -1;
1249 } 1267 }
@@ -1254,16 +1272,16 @@ int cmd_timechart(int argc, const char **argv,
1254 argc = parse_options(argc, argv, record_options, record_usage, 1272 argc = parse_options(argc, argv, record_options, record_usage,
1255 PARSE_OPT_STOP_AT_NON_OPTION); 1273 PARSE_OPT_STOP_AT_NON_OPTION);
1256 1274
1257 if (power_only && tasks_only) { 1275 if (tchart.power_only && tchart.tasks_only) {
1258 pr_err("-P and -T options cannot be used at the same time.\n"); 1276 pr_err("-P and -T options cannot be used at the same time.\n");
1259 return -1; 1277 return -1;
1260 } 1278 }
1261 1279
1262 return __cmd_record(argc, argv); 1280 return timechart__record(&tchart, argc, argv);
1263 } else if (argc) 1281 } else if (argc)
1264 usage_with_options(timechart_usage, timechart_options); 1282 usage_with_options(timechart_usage, timechart_options);
1265 1283
1266 setup_pager(); 1284 setup_pager();
1267 1285
1268 return __cmd_timechart(output_name); 1286 return __cmd_timechart(&tchart, output_name);
1269} 1287}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e9f345e2551a..9f2a242fa79c 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1890,7 +1890,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1890 if (err < 0) 1890 if (err < 0)
1891 goto out_error_open; 1891 goto out_error_open;
1892 1892
1893 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1893 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
1894 if (err < 0) { 1894 if (err < 0) {
1895 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); 1895 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1896 goto out_close_evlist; 1896 goto out_close_evlist;
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f7d11a811c74..36e66ac40abc 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -533,7 +533,7 @@ endif
533 533
534ifndef NO_LIBNUMA 534ifndef NO_LIBNUMA
535 ifeq ($(feature-libnuma), 0) 535 ifeq ($(feature-libnuma), 0)
536 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); 536 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev);
537 NO_LIBNUMA := 1 537 NO_LIBNUMA := 1
538 else 538 else
539 CFLAGS += -DHAVE_LIBNUMA_SUPPORT 539 CFLAGS += -DHAVE_LIBNUMA_SUPPORT
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 59e7a705e146..9b8a544155bb 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -85,6 +85,10 @@
85# include "test-timerfd.c" 85# include "test-timerfd.c"
86#undef main 86#undef main
87 87
88#define main main_test_stackprotector_all
89# include "test-stackprotector-all.c"
90#undef main
91
88int main(int argc, char *argv[]) 92int main(int argc, char *argv[])
89{ 93{
90 main_test_libpython(); 94 main_test_libpython();
@@ -106,6 +110,7 @@ int main(int argc, char *argv[])
106 main_test_backtrace(); 110 main_test_backtrace();
107 main_test_libnuma(); 111 main_test_libnuma();
108 main_test_timerfd(); 112 main_test_timerfd();
113 main_test_stackprotector_all();
109 114
110 return 0; 115 return 0;
111} 116}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 7d09faf85cf1..1fbcd8bdc11b 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -118,3 +118,9 @@ void perf_data_file__close(struct perf_data_file *file)
118{ 118{
119 close(file->fd); 119 close(file->fd);
120} 120}
121
122ssize_t perf_data_file__write(struct perf_data_file *file,
123 void *buf, size_t size)
124{
125 return writen(file->fd, buf, size);
126}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 8c2df80152a5..2b15d0c95c7f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -9,12 +9,12 @@ enum perf_data_mode {
9}; 9};
10 10
11struct perf_data_file { 11struct perf_data_file {
12 const char *path; 12 const char *path;
13 int fd; 13 int fd;
14 bool is_pipe; 14 bool is_pipe;
15 bool force; 15 bool force;
16 unsigned long size; 16 unsigned long size;
17 enum perf_data_mode mode; 17 enum perf_data_mode mode;
18}; 18};
19 19
20static inline bool perf_data_file__is_read(struct perf_data_file *file) 20static inline bool perf_data_file__is_read(struct perf_data_file *file)
@@ -44,5 +44,7 @@ static inline unsigned long perf_data_file__size(struct perf_data_file *file)
44 44
45int perf_data_file__open(struct perf_data_file *file); 45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file); 46void perf_data_file__close(struct perf_data_file *file);
47ssize_t perf_data_file__write(struct perf_data_file *file,
48 void *buf, size_t size);
47 49
48#endif /* __PERF_DATA_H */ 50#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1cd035708931..3e755f2bfe8f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1709,7 +1709,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1709 struct perf_header *ph, int fd, 1709 struct perf_header *ph, int fd,
1710 void *data __maybe_unused) 1710 void *data __maybe_unused)
1711{ 1711{
1712 size_t ret; 1712 ssize_t ret;
1713 u32 nr; 1713 u32 nr;
1714 1714
1715 ret = readn(fd, &nr, sizeof(nr)); 1715 ret = readn(fd, &nr, sizeof(nr));
@@ -1753,7 +1753,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1753 void *data __maybe_unused) 1753 void *data __maybe_unused)
1754{ 1754{
1755 uint64_t mem; 1755 uint64_t mem;
1756 size_t ret; 1756 ssize_t ret;
1757 1757
1758 ret = readn(fd, &mem, sizeof(mem)); 1758 ret = readn(fd, &mem, sizeof(mem));
1759 if (ret != sizeof(mem)) 1759 if (ret != sizeof(mem))
@@ -1822,7 +1822,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1822 struct perf_header *ph, int fd, 1822 struct perf_header *ph, int fd,
1823 void *data __maybe_unused) 1823 void *data __maybe_unused)
1824{ 1824{
1825 size_t ret; 1825 ssize_t ret;
1826 char *str; 1826 char *str;
1827 u32 nr, i; 1827 u32 nr, i;
1828 struct strbuf sb; 1828 struct strbuf sb;
@@ -1858,7 +1858,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1858 struct perf_header *ph, int fd, 1858 struct perf_header *ph, int fd,
1859 void *data __maybe_unused) 1859 void *data __maybe_unused)
1860{ 1860{
1861 size_t ret; 1861 ssize_t ret;
1862 u32 nr, i; 1862 u32 nr, i;
1863 char *str; 1863 char *str;
1864 struct strbuf sb; 1864 struct strbuf sb;
@@ -1914,7 +1914,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1914 struct perf_header *ph, int fd, 1914 struct perf_header *ph, int fd,
1915 void *data __maybe_unused) 1915 void *data __maybe_unused)
1916{ 1916{
1917 size_t ret; 1917 ssize_t ret;
1918 u32 nr, node, i; 1918 u32 nr, node, i;
1919 char *str; 1919 char *str;
1920 uint64_t mem_total, mem_free; 1920 uint64_t mem_total, mem_free;
@@ -1974,7 +1974,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1974 struct perf_header *ph, int fd, 1974 struct perf_header *ph, int fd,
1975 void *data __maybe_unused) 1975 void *data __maybe_unused)
1976{ 1976{
1977 size_t ret; 1977 ssize_t ret;
1978 char *name; 1978 char *name;
1979 u32 pmu_num; 1979 u32 pmu_num;
1980 u32 type; 1980 u32 type;
@@ -2534,7 +2534,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2534int perf_file_header__read(struct perf_file_header *header, 2534int perf_file_header__read(struct perf_file_header *header,
2535 struct perf_header *ph, int fd) 2535 struct perf_header *ph, int fd)
2536{ 2536{
2537 int ret; 2537 ssize_t ret;
2538 2538
2539 lseek(fd, 0, SEEK_SET); 2539 lseek(fd, 0, SEEK_SET);
2540 2540
@@ -2628,7 +2628,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2628 struct perf_header *ph, int fd, 2628 struct perf_header *ph, int fd,
2629 bool repipe) 2629 bool repipe)
2630{ 2630{
2631 int ret; 2631 ssize_t ret;
2632 2632
2633 ret = readn(fd, header, sizeof(*header)); 2633 ret = readn(fd, header, sizeof(*header));
2634 if (ret <= 0) 2634 if (ret <= 0)
@@ -2669,7 +2669,7 @@ static int read_attr(int fd, struct perf_header *ph,
2669 struct perf_event_attr *attr = &f_attr->attr; 2669 struct perf_event_attr *attr = &f_attr->attr;
2670 size_t sz, left; 2670 size_t sz, left;
2671 size_t our_sz = sizeof(f_attr->attr); 2671 size_t our_sz = sizeof(f_attr->attr);
2672 int ret; 2672 ssize_t ret;
2673 2673
2674 memset(f_attr, 0, sizeof(*f_attr)); 2674 memset(f_attr, 0, sizeof(*f_attr));
2675 2675
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b0b15e213df5..4ce146bae552 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1158,7 +1158,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1158 void *buf = NULL; 1158 void *buf = NULL;
1159 int skip = 0; 1159 int skip = 0;
1160 u64 head; 1160 u64 head;
1161 int err; 1161 ssize_t err;
1162 void *p; 1162 void *p;
1163 1163
1164 perf_tool__fill_defaults(tool); 1164 perf_tool__fill_defaults(tool);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 28a0a89c1f73..b1d5376b9dd9 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -6,6 +6,7 @@
6#endif 6#endif
7#include <stdio.h> 7#include <stdio.h>
8#include <stdlib.h> 8#include <stdlib.h>
9#include <linux/kernel.h>
9 10
10/* 11/*
11 * XXX We need to find a better place for these things... 12 * XXX We need to find a better place for these things...
@@ -151,21 +152,40 @@ unsigned long convert_unit(unsigned long value, char *unit)
151 return value; 152 return value;
152} 153}
153 154
154int readn(int fd, void *buf, size_t n) 155static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
155{ 156{
156 void *buf_start = buf; 157 void *buf_start = buf;
158 size_t left = n;
157 159
158 while (n) { 160 while (left) {
159 int ret = read(fd, buf, n); 161 ssize_t ret = is_read ? read(fd, buf, left) :
162 write(fd, buf, left);
160 163
161 if (ret <= 0) 164 if (ret <= 0)
162 return ret; 165 return ret;
163 166
164 n -= ret; 167 left -= ret;
165 buf += ret; 168 buf += ret;
166 } 169 }
167 170
168 return buf - buf_start; 171 BUG_ON((size_t)(buf - buf_start) != n);
172 return n;
173}
174
175/*
176 * Read exactly 'n' bytes or return an error.
177 */
178ssize_t readn(int fd, void *buf, size_t n)
179{
180 return ion(true, fd, buf, n);
181}
182
183/*
184 * Write exactly 'n' bytes or return an error.
185 */
186ssize_t writen(int fd, void *buf, size_t n)
187{
188 return ion(false, fd, buf, n);
169} 189}
170 190
171size_t hex_width(u64 v) 191size_t hex_width(u64 v)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c8f362daba87..ce0f73d4d91f 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -253,7 +253,8 @@ bool strlazymatch(const char *str, const char *pat);
253int strtailcmp(const char *s1, const char *s2); 253int strtailcmp(const char *s1, const char *s2);
254char *strxfrchar(char *s, char from, char to); 254char *strxfrchar(char *s, char from, char to);
255unsigned long convert_unit(unsigned long value, char *unit); 255unsigned long convert_unit(unsigned long value, char *unit);
256int readn(int fd, void *buf, size_t size); 256ssize_t readn(int fd, void *buf, size_t n);
257ssize_t writen(int fd, void *buf, size_t n);
257 258
258struct perf_event_attr; 259struct perf_event_attr;
259 260