Add kernel module sources from stability-monitor
[platform/core/system/stability-monitor-kmod-rpi3.git] / kernel / proc-tsm.c
1 /*
2  * This file is part of stability-monitor-kmod-rpi3
3  *
4  * Copyright © 2019 Samsung Electronics
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/kernel.h>
22
23 #include <linux/fs.h>
24 #include <linux/proc_fs.h>
25 #include <linux/seq_file.h>
26 #include <linux/sched.h>
27 #include <linux/sched/signal.h>
28 #include <linux/sched/cputime.h>
29 #include <linux/mm.h>
30 #include <linux/pid_namespace.h>
31 #include <asm/uaccess.h>
32 #include <linux/time.h>
33 #include <linux/posix-timers.h>
34 #include <linux/kernel_stat.h>
35 #include <linux/fdtable.h>
36 #include <linux/math64.h>
37 #include <linux/task_io_accounting_ops.h>
38
39 #define DEBUG 0
40 #define PAGE_TO_KB(x) ((x) << (PAGE_SHIFT - 10))
41
42 static struct proc_dir_entry* proc_file;
43
44
45 static u64 time_now(void)
46 {
47     return div64_ul(ktime_get_boot_ns(), NSEC_PER_USEC);
48 }
49
50 static inline u64 cputime_to_usecs(const u64 cputime)
51 {
52     // return cputime >> 12;
53     return div64_ul(cputime, NSEC_PER_USEC);
54 }
55
56 static unsigned int count_open_files(struct files_struct *files)
57 {
58     unsigned int open_files = 0;
59     int i;
60     struct fdtable *fdt;
61
62     if (!files)
63         return 0;
64
65     spin_lock(&files->file_lock);
66     fdt = files_fdtable(files);
67
68     /* Find the last non zero cell in open fds array */
69     for (i = fdt->max_fds / BITS_PER_LONG - 1; i >= 0; i--) {
70         if (fdt->open_fds[i])
71             break;
72     }
73
74     /* Count set bits */
75     for (i = (i + 1) * BITS_PER_LONG - 1; i >= 0; i--) {
76         if(test_bit(i, fdt->open_fds))
77             open_files++;
78     }
79
80     spin_unlock(&files->file_lock);
81     return open_files;
82 }
83
84 static int stability_monitor_show(struct seq_file *m, void *v)
85 {
86     struct sysinfo info;
87     struct task_struct *task, *t;
88     struct pid *pid = NULL;
89     pid_t ppid = 0;
90     u64 uptime, utime, stime, ut, st;
91     unsigned long long vm_rss, total_ram;
92     struct task_io_accounting task_ioac;
93     unsigned int open_fds;
94
95     rcu_read_lock();
96
97     /* Uptime in us */
98     uptime = time_now();
99
100     /* Memory info */
101     si_meminfo(&info);
102     total_ram = PAGE_TO_KB(info.totalram);
103
104     seq_put_decimal_ull(m, "", uptime);
105     seq_put_decimal_ull(m, " ", total_ram);
106     seq_printf(m, "\n");
107
108     for_each_process(task) {
109         ppid = task->real_parent->pid;
110         pid = task_pgrp(task);
111         if (!pid)
112             continue;
113
114         task_lock(task);
115
116         if (!task->mm) {
117             task_unlock(task);
118             continue;
119         }
120
121         if (task->flags & (PF_DUMPCORE|PF_SIGNALED|PF_EXITING)) {
122             task_unlock(task);
123             continue;
124         }
125
126
127         /* Memory */
128         vm_rss = get_mm_rss(task->mm);
129
130         /* Open FDs */
131         open_fds = count_open_files(task->files);
132
133         /* CPU time + IO accounting */
134         task_cputime_adjusted(task, &utime, &stime);
135         task_ioac = task->ioac;
136         t = task;
137         while_each_thread(task, t) {
138             task_cputime_adjusted(t, &ut, &st);
139             utime += ut;
140             stime += st;
141             task_io_accounting_add(&task_ioac, &t->ioac);
142         }
143
144         task_unlock(task);
145
146         seq_put_decimal_ll(m, "", task->pid);
147         seq_put_decimal_ll(m, " ", ppid);
148         seq_put_decimal_ull(m, " ", cputime_to_usecs(utime + stime));
149         seq_put_decimal_ull(m, " ", PAGE_TO_KB(vm_rss));
150         seq_put_decimal_ll(m, " ", open_fds);
151         seq_put_decimal_ull(m, " ", task_ioac.read_bytes + task_ioac.write_bytes);
152         seq_printf(m, "\n");
153     }
154
155     rcu_read_unlock();
156
157 #if DEBUG
158     printk(KERN_DEBUG "stability_monitor_show() took %llu us\n", time_now() - uptime);
159 #endif
160
161     return 0;
162 }
163
164 static int stability_monitor_open(struct inode *inode, struct file *file)
165 {
166     return single_open_size(file, stability_monitor_show, NULL, 8192);
167 }
168
169 static const struct file_operations stability_monitor_fops = {
170     .owner      = THIS_MODULE,
171     .open       = stability_monitor_open,
172     .read       = seq_read,
173     .llseek  = seq_lseek,
174     .release = single_release,
175 };
176
177 static int __init stability_monitor_init(void)
178 {
179     proc_file = proc_create("tsm", 0, NULL, &stability_monitor_fops);
180     if (!proc_file)
181         return -ENOMEM;
182
183     return 0;
184 }
185
186 static void __exit stability_monitor_exit(void)
187 {
188     remove_proc_entry("tsm", NULL);
189 }
190
191 module_init(stability_monitor_init);
192 module_exit(stability_monitor_exit);
193
194 MODULE_LICENSE("GPL");