adc6c0342d42d74134f8323ae719b05cf32302f4
[linux-3.10.git] / drivers / misc / tegra-profiler / ma.c
1 /*
2  * drivers/misc/tegra-profiler/ma.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/module.h>
20 #include <linux/mm.h>
21 #include <linux/timer.h>
22 #include <linux/sched.h>
23
24 #include <linux/tegra_profiler.h>
25
26 #include "ma.h"
27 #include "quadd.h"
28 #include "hrt.h"
29 #include "comm.h"
30 #include "debug.h"
31
32 static void make_sample(struct quadd_hrt_ctx *hrt_ctx,
33                         pid_t pid, unsigned long vm_size,
34                         unsigned long rss_size)
35 {
36         struct quadd_record_data record;
37         struct quadd_ma_data *ma = &record.ma;
38         struct quadd_comm_data_interface *comm = hrt_ctx->quadd_ctx->comm;
39
40         record.magic = QUADD_RECORD_MAGIC;
41         record.record_type = QUADD_RECORD_TYPE_MA;
42
43         ma->pid = pid;
44         ma->time = quadd_get_time();
45
46         ma->vm_size = vm_size << (PAGE_SHIFT-10);
47         ma->rss_size = rss_size << (PAGE_SHIFT-10);
48
49         comm->put_sample(&record, NULL, 0);
50 }
51
52 static void check_ma(struct quadd_hrt_ctx *hrt_ctx)
53 {
54         pid_t pid;
55         struct pid *pid_s;
56         struct task_struct *task = NULL;
57         struct mm_struct *mm;
58         struct quadd_ctx *quadd_ctx = hrt_ctx->quadd_ctx;
59         unsigned long vm_size, rss_size;
60
61         pid = quadd_ctx->param.pids[0];
62
63         rcu_read_lock();
64         pid_s = find_vpid(pid);
65         if (pid_s)
66                 task = pid_task(pid_s, PIDTYPE_PID);
67         rcu_read_unlock();
68         if (!task)
69                 return;
70
71         mm = task->mm;
72         if (!mm)
73                 return;
74
75         vm_size = mm->total_vm;
76         rss_size = get_mm_rss(mm);
77
78         if (vm_size != hrt_ctx->vm_size_prev ||
79             rss_size != hrt_ctx->rss_size_prev) {
80                 make_sample(hrt_ctx, pid, vm_size, rss_size);
81                 hrt_ctx->vm_size_prev = vm_size;
82                 hrt_ctx->rss_size_prev = rss_size;
83         }
84 }
85
86 static void timer_interrupt(unsigned long data)
87 {
88         struct quadd_hrt_ctx *hrt_ctx = (struct quadd_hrt_ctx *)data;
89         struct timer_list *timer = &hrt_ctx->ma_timer;
90
91         if (hrt_ctx->active == 0)
92                 return;
93
94         check_ma(hrt_ctx);
95
96         timer->expires = jiffies + msecs_to_jiffies(hrt_ctx->ma_period);
97         add_timer(timer);
98 }
99
100 void quadd_ma_start(struct quadd_hrt_ctx *hrt_ctx)
101 {
102         struct timer_list *timer = &hrt_ctx->ma_timer;
103
104         if (hrt_ctx->ma_period == 0) {
105                 pr_info("QuadD MA is disabled\n");
106                 return;
107         }
108         pr_info("QuadD MA is started, interval: %u msec\n",
109                 hrt_ctx->ma_period);
110
111         hrt_ctx->vm_size_prev = 0;
112         hrt_ctx->rss_size_prev = 0;
113
114         init_timer(timer);
115         timer->function = timer_interrupt;
116         timer->expires = jiffies + msecs_to_jiffies(hrt_ctx->ma_period);
117         timer->data = (unsigned long)hrt_ctx;
118         add_timer(timer);
119 }
120
121 void quadd_ma_stop(struct quadd_hrt_ctx *hrt_ctx)
122 {
123         if (hrt_ctx->ma_period > 0) {
124                 pr_info("QuadD MA is stopped\n");
125                 del_timer_sync(&hrt_ctx->ma_timer);
126         }
127 }