]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/misc/tegra-profiler/hrt.c
c25384429cfdbff54d52851709d8c654b92a9112
[sojka/nv-tegra/linux-3.10.git] / drivers / misc / tegra-profiler / hrt.c
1 /*
2  * drivers/misc/tegra-profiler/hrt.c
3  *
4  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/sched.h>
20 #include <linux/hrtimer.h>
21 #include <linux/slab.h>
22 #include <linux/cpu.h>
23 #include <linux/ptrace.h>
24 #include <linux/interrupt.h>
25 #include <linux/err.h>
26 #include <linux/nsproxy.h>
27
28 #include <asm/cputype.h>
29 #include <asm/irq_regs.h>
30
31 #include <linux/tegra_profiler.h>
32
33 #include "quadd.h"
34 #include "hrt.h"
35 #include "comm.h"
36 #include "mmap.h"
37 #include "ma.h"
38 #include "power_clk.h"
39 #include "tegra.h"
40 #include "debug.h"
41
42 static struct quadd_hrt_ctx hrt;
43
44 static void
45 read_all_sources(struct pt_regs *regs, struct task_struct *task);
46
47 struct hrt_event_value {
48         int event_id;
49         u32 value;
50 };
51
52 static enum hrtimer_restart hrtimer_handler(struct hrtimer *hrtimer)
53 {
54         struct pt_regs *regs;
55
56         regs = get_irq_regs();
57
58         if (!hrt.active)
59                 return HRTIMER_NORESTART;
60
61         qm_debug_handler_sample(regs);
62
63         if (regs)
64                 read_all_sources(regs, NULL);
65
66         hrtimer_forward_now(hrtimer, ns_to_ktime(hrt.sample_period));
67         qm_debug_timer_forward(regs, hrt.sample_period);
68
69         return HRTIMER_RESTART;
70 }
71
72 static void start_hrtimer(struct quadd_cpu_context *cpu_ctx)
73 {
74         u64 period = hrt.sample_period;
75
76         __hrtimer_start_range_ns(&cpu_ctx->hrtimer,
77                                  ns_to_ktime(period), 0,
78                                  HRTIMER_MODE_REL_PINNED, 0);
79         qm_debug_timer_start(NULL, period);
80 }
81
82 static void cancel_hrtimer(struct quadd_cpu_context *cpu_ctx)
83 {
84         hrtimer_cancel(&cpu_ctx->hrtimer);
85         qm_debug_timer_cancel();
86 }
87
88 static void init_hrtimer(struct quadd_cpu_context *cpu_ctx)
89 {
90         hrtimer_init(&cpu_ctx->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
91         cpu_ctx->hrtimer.function = hrtimer_handler;
92 }
93
94 u64 quadd_get_time(void)
95 {
96         struct timespec ts;
97
98         do_posix_clock_monotonic_gettime(&ts);
99         return timespec_to_ns(&ts);
100 }
101
102 static void put_header(void)
103 {
104         int nr_events = 0, max_events = QUADD_MAX_COUNTERS;
105         int events[QUADD_MAX_COUNTERS];
106         struct quadd_record_data record;
107         struct quadd_header_data *hdr = &record.hdr;
108         struct quadd_parameters *param = &hrt.quadd_ctx->param;
109         unsigned int extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
110         struct quadd_iovec vec;
111         struct quadd_ctx *ctx = hrt.quadd_ctx;
112         struct quadd_event_source_interface *pmu = ctx->pmu;
113         struct quadd_event_source_interface *pl310 = ctx->pl310;
114
115         record.record_type = QUADD_RECORD_TYPE_HEADER;
116
117         hdr->magic = QUADD_HEADER_MAGIC;
118         hdr->version = QUADD_SAMPLES_VERSION;
119
120         hdr->backtrace = param->backtrace;
121         hdr->use_freq = param->use_freq;
122         hdr->system_wide = param->system_wide;
123
124         /* TODO: dynamically */
125 #ifdef QM_DEBUG_SAMPLES_ENABLE
126         hdr->debug_samples = 1;
127 #else
128         hdr->debug_samples = 0;
129 #endif
130
131         hdr->freq = param->freq;
132         hdr->ma_freq = param->ma_freq;
133         hdr->power_rate_freq = param->power_rate_freq;
134
135         hdr->power_rate = hdr->power_rate_freq > 0 ? 1 : 0;
136         hdr->get_mmap = (extra & QUADD_PARAM_EXTRA_GET_MMAP) ? 1 : 0;
137
138         hdr->reserved = 0;
139         hdr->extra_length = 0;
140
141         if (pmu)
142                 nr_events += pmu->get_current_events(events, max_events);
143
144         if (pl310)
145                 nr_events += pl310->get_current_events(events + nr_events,
146                                                        max_events - nr_events);
147
148         hdr->nr_events = nr_events;
149
150         vec.base = events;
151         vec.len = nr_events * sizeof(events[0]);
152
153         quadd_put_sample(&record, &vec, 1);
154 }
155
156 void quadd_put_sample(struct quadd_record_data *data,
157                       struct quadd_iovec *vec, int vec_count)
158 {
159         struct quadd_comm_data_interface *comm = hrt.quadd_ctx->comm;
160
161         comm->put_sample(data, vec, vec_count);
162         atomic64_inc(&hrt.counter_samples);
163 }
164
165 static int get_sample_data(struct quadd_sample_data *sample,
166                            struct pt_regs *regs,
167                            struct task_struct *task)
168 {
169         unsigned int cpu, flags;
170         struct quadd_ctx *quadd_ctx = hrt.quadd_ctx;
171
172         cpu = quadd_get_processor_id(regs, &flags);
173         sample->cpu = cpu;
174
175         sample->lp_mode =
176                 (flags & QUADD_CPUMODE_TEGRA_POWER_CLUSTER_LP) ? 1 : 0;
177         sample->thumb_mode = (flags & QUADD_CPUMODE_THUMB) ? 1 : 0;
178         sample->user_mode = user_mode(regs) ? 1 : 0;
179
180         /* For security reasons, hide IPs from the kernel space. */
181         if (!sample->user_mode && !quadd_ctx->collect_kernel_ips)
182                 sample->ip = 0;
183         else
184                 sample->ip = instruction_pointer(regs);
185
186         sample->time = quadd_get_time();
187         sample->reserved = 0;
188         sample->pid = task->pid;
189         sample->in_interrupt = in_interrupt() ? 1 : 0;
190
191         return 0;
192 }
193
194 static int read_source(struct quadd_event_source_interface *source,
195                        struct pt_regs *regs,
196                        struct hrt_event_value *events_vals,
197                        int max_events)
198 {
199         int nr_events, i;
200         u32 prev_val, val, res_val;
201         struct event_data events[QUADD_MAX_COUNTERS];
202
203         if (!source)
204                 return 0;
205
206         max_events = min_t(int, max_events, QUADD_MAX_COUNTERS);
207         nr_events = source->read(events, max_events);
208
209         for (i = 0; i < nr_events; i++) {
210                 struct event_data *s = &events[i];
211
212                 prev_val = s->prev_val;
213                 val = s->val;
214
215                 if (prev_val <= val)
216                         res_val = val - prev_val;
217                 else
218                         res_val = QUADD_U32_MAX - prev_val + val;
219
220                 if (s->event_source == QUADD_EVENT_SOURCE_PL310) {
221                         int nr_active = atomic_read(&hrt.nr_active_all_core);
222                         if (nr_active > 1)
223                                 res_val /= nr_active;
224                 }
225
226                 events_vals[i].event_id = s->event_id;
227                 events_vals[i].value = res_val;
228         }
229
230         return nr_events;
231 }
232
233 static void
234 read_all_sources(struct pt_regs *regs, struct task_struct *task)
235 {
236         u32 state, extra_data = 0;
237         int i, vec_idx = 0, bt_size = 0;
238         int nr_events = 0, nr_positive_events = 0;
239         struct pt_regs *user_regs;
240         struct quadd_iovec vec[4];
241         struct hrt_event_value events[QUADD_MAX_COUNTERS];
242         u32 events_extra[QUADD_MAX_COUNTERS];
243
244         struct quadd_record_data record_data;
245         struct quadd_sample_data *s = &record_data.sample;
246
247         struct quadd_ctx *ctx = hrt.quadd_ctx;
248         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
249         struct quadd_callchain *cc = &cpu_ctx->cc;
250
251         if (!regs)
252                 return;
253
254         if (atomic_read(&cpu_ctx->nr_active) == 0)
255                 return;
256
257         if (!task)
258                 task = current;
259
260         rcu_read_lock();
261         if (!task_nsproxy(task)) {
262                 rcu_read_unlock();
263                 return;
264         }
265         rcu_read_unlock();
266
267         if (ctx->pmu && ctx->pmu_info.active)
268                 nr_events += read_source(ctx->pmu, regs,
269                                          events, QUADD_MAX_COUNTERS);
270
271         if (ctx->pl310 && ctx->pl310_info.active)
272                 nr_events += read_source(ctx->pl310, regs,
273                                          events + nr_events,
274                                          QUADD_MAX_COUNTERS - nr_events);
275
276         if (!nr_events)
277                 return;
278
279         if (user_mode(regs))
280                 user_regs = regs;
281         else
282                 user_regs = current_pt_regs();
283
284         if (get_sample_data(s, regs, task))
285                 return;
286
287         if (cc->cs_64)
288                 extra_data |= QUADD_SED_IP64;
289
290         vec[vec_idx].base = &extra_data;
291         vec[vec_idx].len = sizeof(extra_data);
292         vec_idx++;
293
294         s->reserved = 0;
295
296         if (ctx->param.backtrace) {
297                 bt_size = quadd_get_user_callchain(user_regs, cc, ctx, task);
298
299                 if (!bt_size && !user_mode(regs)) {
300                         unsigned long pc = instruction_pointer(user_regs);
301
302                         cc->nr = 0;
303 #ifdef CONFIG_ARM64
304                         cc->cs_64 = compat_user_mode(user_regs) ? 0 : 1;
305 #else
306                         cc->cs_64 = 0;
307 #endif
308                         bt_size += quadd_callchain_store(cc, pc);
309                 }
310
311                 if (bt_size > 0) {
312                         int ip_size = cc->cs_64 ? sizeof(u64) : sizeof(u32);
313
314                         vec[vec_idx].base = cc->cs_64 ?
315                                 (void *)cc->ip_64 : (void *)cc->ip_32;
316                         vec[vec_idx].len = bt_size * ip_size;
317                         vec_idx++;
318                 }
319
320                 extra_data |= cc->unw_method << QUADD_SED_UNW_METHOD_SHIFT;
321
322                 if (cc->unw_method == QUADD_UNW_METHOD_EHT ||
323                     cc->unw_method == QUADD_UNW_METHOD_MIXED)
324                         s->reserved |= cc->unw_rc << QUADD_SAMPLE_URC_SHIFT;
325         }
326         s->callchain_nr = bt_size;
327
328         record_data.record_type = QUADD_RECORD_TYPE_SAMPLE;
329
330         s->events_flags = 0;
331         for (i = 0; i < nr_events; i++) {
332                 u32 value = events[i].value;
333                 if (value > 0) {
334                         s->events_flags |= 1 << i;
335                         events_extra[nr_positive_events++] = value;
336                 }
337         }
338
339         if (nr_positive_events == 0)
340                 return;
341
342         vec[vec_idx].base = events_extra;
343         vec[vec_idx].len = nr_positive_events * sizeof(events_extra[0]);
344         vec_idx++;
345
346         state = task->state;
347         if (state) {
348                 s->state = 1;
349                 vec[vec_idx].base = &state;
350                 vec[vec_idx].len = sizeof(state);
351                 vec_idx++;
352         } else {
353                 s->state = 0;
354         }
355
356         quadd_put_sample(&record_data, vec, vec_idx);
357 }
358
359 static inline int
360 is_profile_process(struct task_struct *task)
361 {
362         int i;
363         pid_t pid, profile_pid;
364         struct quadd_ctx *ctx = hrt.quadd_ctx;
365
366         if (!task)
367                 return 0;
368
369         pid = task->tgid;
370
371         for (i = 0; i < ctx->param.nr_pids; i++) {
372                 profile_pid = ctx->param.pids[i];
373                 if (profile_pid == pid)
374                         return 1;
375         }
376         return 0;
377 }
378
379 static int
380 add_active_thread(struct quadd_cpu_context *cpu_ctx, pid_t pid, pid_t tgid)
381 {
382         struct quadd_thread_data *t_data = &cpu_ctx->active_thread;
383
384         if (t_data->pid > 0 ||
385                 atomic_read(&cpu_ctx->nr_active) > 0) {
386                 pr_warn_once("Warning for thread: %d\n", (int)pid);
387                 return 0;
388         }
389
390         t_data->pid = pid;
391         t_data->tgid = tgid;
392         return 1;
393 }
394
395 static int remove_active_thread(struct quadd_cpu_context *cpu_ctx, pid_t pid)
396 {
397         struct quadd_thread_data *t_data = &cpu_ctx->active_thread;
398
399         if (t_data->pid < 0)
400                 return 0;
401
402         if (t_data->pid == pid) {
403                 t_data->pid = -1;
404                 t_data->tgid = -1;
405                 return 1;
406         }
407
408         pr_warn_once("Warning for thread: %d\n", (int)pid);
409         return 0;
410 }
411
412 void __quadd_task_sched_in(struct task_struct *prev,
413                            struct task_struct *task)
414 {
415         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
416         struct quadd_ctx *ctx = hrt.quadd_ctx;
417         struct event_data events[QUADD_MAX_COUNTERS];
418         /* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
419
420         if (likely(!hrt.active))
421                 return;
422 /*
423         if (__ratelimit(&ratelimit_state))
424                 pr_info("sch_in, cpu: %d, prev: %u (%u) \t--> curr: %u (%u)\n",
425                         smp_processor_id(), (unsigned int)prev->pid,
426                         (unsigned int)prev->tgid, (unsigned int)task->pid,
427                         (unsigned int)task->tgid);
428 */
429
430         if (is_profile_process(task)) {
431                 add_active_thread(cpu_ctx, task->pid, task->tgid);
432                 atomic_inc(&cpu_ctx->nr_active);
433
434                 if (atomic_read(&cpu_ctx->nr_active) == 1) {
435                         if (ctx->pmu)
436                                 ctx->pmu->start();
437
438                         if (ctx->pl310)
439                                 ctx->pl310->read(events, 1);
440
441                         start_hrtimer(cpu_ctx);
442                         atomic_inc(&hrt.nr_active_all_core);
443                 }
444         }
445 }
446
447 void __quadd_task_sched_out(struct task_struct *prev,
448                             struct task_struct *next)
449 {
450         int n;
451         struct pt_regs *user_regs;
452         struct quadd_cpu_context *cpu_ctx = this_cpu_ptr(hrt.cpu_ctx);
453         struct quadd_ctx *ctx = hrt.quadd_ctx;
454         /* static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 2); */
455
456         if (likely(!hrt.active))
457                 return;
458 /*
459         if (__ratelimit(&ratelimit_state))
460                 pr_info("sch_out: cpu: %d, prev: %u (%u) \t--> next: %u (%u)\n",
461                         smp_processor_id(), (unsigned int)prev->pid,
462                         (unsigned int)prev->tgid, (unsigned int)next->pid,
463                         (unsigned int)next->tgid);
464 */
465
466         if (is_profile_process(prev)) {
467                 user_regs = task_pt_regs(prev);
468                 if (user_regs)
469                         read_all_sources(user_regs, prev);
470
471                 n = remove_active_thread(cpu_ctx, prev->pid);
472                 atomic_sub(n, &cpu_ctx->nr_active);
473
474                 if (n && atomic_read(&cpu_ctx->nr_active) == 0) {
475                         cancel_hrtimer(cpu_ctx);
476                         atomic_dec(&hrt.nr_active_all_core);
477
478                         if (ctx->pmu)
479                                 ctx->pmu->stop();
480                 }
481         }
482 }
483
484 void __quadd_event_mmap(struct vm_area_struct *vma)
485 {
486         struct quadd_parameters *param;
487
488         if (likely(!hrt.active))
489                 return;
490
491         if (!is_profile_process(current))
492                 return;
493
494         param = &hrt.quadd_ctx->param;
495         quadd_process_mmap(vma, param->pids[0]);
496 }
497
498 static void reset_cpu_ctx(void)
499 {
500         int cpu_id;
501         struct quadd_cpu_context *cpu_ctx;
502         struct quadd_thread_data *t_data;
503
504         for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
505                 cpu_ctx = per_cpu_ptr(hrt.cpu_ctx, cpu_id);
506                 t_data = &cpu_ctx->active_thread;
507
508                 atomic_set(&cpu_ctx->nr_active, 0);
509
510                 t_data->pid = -1;
511                 t_data->tgid = -1;
512         }
513 }
514
515 int quadd_hrt_start(void)
516 {
517         int err;
518         u64 period;
519         long freq;
520         unsigned int extra;
521         struct quadd_ctx *ctx = hrt.quadd_ctx;
522         struct quadd_parameters *param = &ctx->param;
523
524         freq = ctx->param.freq;
525         freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
526         period = NSEC_PER_SEC / freq;
527         hrt.sample_period = period;
528
529         if (ctx->param.ma_freq > 0)
530                 hrt.ma_period = MSEC_PER_SEC / ctx->param.ma_freq;
531         else
532                 hrt.ma_period = 0;
533
534         atomic64_set(&hrt.counter_samples, 0);
535
536         reset_cpu_ctx();
537
538         put_header();
539
540         extra = param->reserved[QUADD_PARAM_IDX_EXTRA];
541
542         if (extra & QUADD_PARAM_EXTRA_GET_MMAP) {
543                 err = quadd_get_current_mmap(param->pids[0]);
544                 if (err) {
545                         pr_err("error: quadd_get_current_mmap\n");
546                         return err;
547                 }
548         }
549
550         if (ctx->pl310)
551                 ctx->pl310->start();
552
553         quadd_ma_start(&hrt);
554
555         hrt.active = 1;
556
557         pr_info("Start hrt: freq/period: %ld/%llu\n", freq, period);
558         return 0;
559 }
560
561 void quadd_hrt_stop(void)
562 {
563         struct quadd_ctx *ctx = hrt.quadd_ctx;
564
565         pr_info("Stop hrt, number of samples: %llu\n",
566                 atomic64_read(&hrt.counter_samples));
567
568         if (ctx->pl310)
569                 ctx->pl310->stop();
570
571         quadd_ma_stop(&hrt);
572
573         hrt.active = 0;
574
575         atomic64_set(&hrt.counter_samples, 0);
576
577         /* reset_cpu_ctx(); */
578 }
579
580 void quadd_hrt_deinit(void)
581 {
582         if (hrt.active)
583                 quadd_hrt_stop();
584
585         free_percpu(hrt.cpu_ctx);
586 }
587
588 void quadd_hrt_get_state(struct quadd_module_state *state)
589 {
590         state->nr_all_samples = atomic64_read(&hrt.counter_samples);
591         state->nr_skipped_samples = 0;
592 }
593
594 struct quadd_hrt_ctx *quadd_hrt_init(struct quadd_ctx *ctx)
595 {
596         int cpu_id;
597         u64 period;
598         long freq;
599         struct quadd_cpu_context *cpu_ctx;
600
601         hrt.quadd_ctx = ctx;
602         hrt.active = 0;
603
604         freq = ctx->param.freq;
605         freq = max_t(long, QUADD_HRT_MIN_FREQ, freq);
606         period = NSEC_PER_SEC / freq;
607         hrt.sample_period = period;
608
609         if (ctx->param.ma_freq > 0)
610                 hrt.ma_period = MSEC_PER_SEC / ctx->param.ma_freq;
611         else
612                 hrt.ma_period = 0;
613
614         atomic64_set(&hrt.counter_samples, 0);
615
616         hrt.cpu_ctx = alloc_percpu(struct quadd_cpu_context);
617         if (!hrt.cpu_ctx)
618                 return ERR_PTR(-ENOMEM);
619
620         for (cpu_id = 0; cpu_id < nr_cpu_ids; cpu_id++) {
621                 cpu_ctx = per_cpu_ptr(hrt.cpu_ctx, cpu_id);
622
623                 atomic_set(&cpu_ctx->nr_active, 0);
624
625                 cpu_ctx->active_thread.pid = -1;
626                 cpu_ctx->active_thread.tgid = -1;
627
628                 init_hrtimer(cpu_ctx);
629         }
630
631         return &hrt;
632 }