blob: 8fa73ae301a95c8300acc3f968d3ac598e6c0ea8 [file] [log] [blame]
Ashwin Chaugule4eaee1a2013-03-14 18:37:49 -04001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <asm/thread_notify.h>
Sheetal Sahasrabudhe711300e2013-07-10 12:18:59 -040013#include <linux/uaccess.h>
14#include <linux/debugfs.h>
Ashwin Chaugule4eaee1a2013-03-14 18:37:49 -040015#define CREATE_TRACE_POINTS
16#include "perf_trace_counters.h"
17
Sheetal Sahasrabudhe711300e2013-07-10 12:18:59 -040018static unsigned int tp_pid_state;
19
Ashwin Chaugule4eaee1a2013-03-14 18:37:49 -040020static int tracectr_notifier(struct notifier_block *self, unsigned long cmd,
21 void *v)
22{
23 static int old_pid = -1;
24 struct thread_info *thread = v;
25 int current_pid;
26
27 if (cmd != THREAD_NOTIFY_SWITCH)
28 return old_pid;
29
30 current_pid = thread->task->pid;
31 if (old_pid != -1)
32 trace_sched_switch_with_ctrs(old_pid, current_pid);
33 old_pid = current_pid;
34 return old_pid;
35}
36
37static struct notifier_block tracectr_notifier_block = {
38 .notifier_call = tracectr_notifier,
39};
40
Sheetal Sahasrabudhe711300e2013-07-10 12:18:59 -040041static void enable_tp_pid(void)
42{
43 if (tp_pid_state == 0) {
44 tp_pid_state = 1;
45 thread_register_notifier(&tracectr_notifier_block);
46 }
47}
48
49static void disable_tp_pid(void)
50{
51 if (tp_pid_state == 1) {
52 tp_pid_state = 0;
53 thread_unregister_notifier(&tracectr_notifier_block);
54 }
55}
56
57static ssize_t read_enabled_perftp_file_bool(struct file *file,
58 char __user *user_buf, size_t count, loff_t *ppos)
59{
60 char buf[2];
61 buf[1] = '\n';
62 if (tp_pid_state == 0)
63 buf[0] = '0';
64 else
65 buf[0] = '1';
66 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
67}
68
69static ssize_t write_enabled_perftp_file_bool(struct file *file,
70 const char __user *user_buf, size_t count, loff_t *ppos)
71{
72 char buf[32];
73 size_t buf_size;
74
75 buf_size = min(count, (sizeof(buf)-1));
76 if (copy_from_user(buf, user_buf, buf_size))
77 return -EFAULT;
78 switch (buf[0]) {
79 case 'y':
80 case 'Y':
81 case '1':
82 enable_tp_pid();
83 break;
84 case 'n':
85 case 'N':
86 case '0':
87 disable_tp_pid();
88 break;
89 }
90
91 return count;
92}
93
94static const struct file_operations fops_perftp = {
95 .read = read_enabled_perftp_file_bool,
96 .write = write_enabled_perftp_file_bool,
97 .llseek = default_llseek,
98};
99
Ashwin Chaugule4eaee1a2013-03-14 18:37:49 -0400100int __init init_tracecounters(void)
101{
Sheetal Sahasrabudhe711300e2013-07-10 12:18:59 -0400102 struct dentry *dir;
103 struct dentry *file;
104 unsigned int value = 1;
105
106 dir = debugfs_create_dir("perf_debug_tp", NULL);
107 if (!dir)
108 return -ENOMEM;
Sheetal Sahasrabudhebf3e69b2013-08-12 13:53:59 -0400109 file = debugfs_create_file("enabled", 0660, dir,
Sheetal Sahasrabudhe711300e2013-07-10 12:18:59 -0400110 &value, &fops_perftp);
111 if (!file) {
112 debugfs_remove(dir);
113 return -ENOMEM;
114 }
Ashwin Chaugule4eaee1a2013-03-14 18:37:49 -0400115 return 0;
116}
117late_initcall(init_tracecounters);