Commit | Line | Data |
---|---|---|
f3f47a67 AV |
1 | /* |
2 | * ring buffer based C-state tracer | |
3 | * | |
4 | * Arjan van de Ven <arjan@linux.intel.com> | |
5 | * Copyright (C) 2008 Intel Corporation | |
6 | * | |
7 | * Much is borrowed from trace_boot.c which is | |
8 | * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com> | |
9 | * | |
10 | */ | |
11 | ||
12 | #include <linux/init.h> | |
13 | #include <linux/debugfs.h> | |
12922110 | 14 | #include <trace/power.h> |
f3f47a67 AV |
15 | #include <linux/kallsyms.h> |
16 | #include <linux/module.h> | |
17 | ||
18 | #include "trace.h" | |
f0868d1e | 19 | #include "trace_output.h" |
f3f47a67 AV |
20 | |
21 | static struct trace_array *power_trace; | |
22 | static int __read_mostly trace_power_enabled; | |
23 | ||
b5f9fd0f JB |
24 | static void probe_power_start(struct power_trace *it, unsigned int type, |
25 | unsigned int level) | |
26 | { | |
27 | if (!trace_power_enabled) | |
28 | return; | |
29 | ||
30 | memset(it, 0, sizeof(struct power_trace)); | |
31 | it->state = level; | |
32 | it->type = type; | |
33 | it->stamp = ktime_get(); | |
34 | } | |
35 | ||
36 | ||
37 | static void probe_power_end(struct power_trace *it) | |
38 | { | |
e1112b4d | 39 | struct ftrace_event_call *call = &event_power; |
b5f9fd0f JB |
40 | struct ring_buffer_event *event; |
41 | struct trace_power *entry; | |
42 | struct trace_array_cpu *data; | |
43 | struct trace_array *tr = power_trace; | |
44 | ||
45 | if (!trace_power_enabled) | |
46 | return; | |
47 | ||
48 | preempt_disable(); | |
49 | it->end = ktime_get(); | |
50 | data = tr->data[smp_processor_id()]; | |
51 | ||
52 | event = trace_buffer_lock_reserve(tr, TRACE_POWER, | |
53 | sizeof(*entry), 0, 0); | |
54 | if (!event) | |
55 | goto out; | |
56 | entry = ring_buffer_event_data(event); | |
57 | entry->state_data = *it; | |
eb02ce01 TZ |
58 | if (!filter_check_discard(call, entry, tr->buffer, event)) |
59 | trace_buffer_unlock_commit(tr, event, 0, 0); | |
b5f9fd0f JB |
60 | out: |
61 | preempt_enable(); | |
62 | } | |
63 | ||
64 | static void probe_power_mark(struct power_trace *it, unsigned int type, | |
65 | unsigned int level) | |
66 | { | |
e1112b4d | 67 | struct ftrace_event_call *call = &event_power; |
b5f9fd0f JB |
68 | struct ring_buffer_event *event; |
69 | struct trace_power *entry; | |
70 | struct trace_array_cpu *data; | |
71 | struct trace_array *tr = power_trace; | |
72 | ||
73 | if (!trace_power_enabled) | |
74 | return; | |
75 | ||
76 | memset(it, 0, sizeof(struct power_trace)); | |
77 | it->state = level; | |
78 | it->type = type; | |
79 | it->stamp = ktime_get(); | |
80 | preempt_disable(); | |
81 | it->end = it->stamp; | |
82 | data = tr->data[smp_processor_id()]; | |
83 | ||
84 | event = trace_buffer_lock_reserve(tr, TRACE_POWER, | |
85 | sizeof(*entry), 0, 0); | |
86 | if (!event) | |
87 | goto out; | |
88 | entry = ring_buffer_event_data(event); | |
89 | entry->state_data = *it; | |
eb02ce01 TZ |
90 | if (!filter_check_discard(call, entry, tr->buffer, event)) |
91 | trace_buffer_unlock_commit(tr, event, 0, 0); | |
b5f9fd0f JB |
92 | out: |
93 | preempt_enable(); | |
94 | } | |
95 | ||
96 | static int tracing_power_register(void) | |
97 | { | |
98 | int ret; | |
99 | ||
100 | ret = register_trace_power_start(probe_power_start); | |
101 | if (ret) { | |
102 | pr_info("power trace: Couldn't activate tracepoint" | |
103 | " probe to trace_power_start\n"); | |
104 | return ret; | |
105 | } | |
106 | ret = register_trace_power_end(probe_power_end); | |
107 | if (ret) { | |
108 | pr_info("power trace: Couldn't activate tracepoint" | |
109 | " probe to trace_power_end\n"); | |
110 | goto fail_start; | |
111 | } | |
112 | ret = register_trace_power_mark(probe_power_mark); | |
113 | if (ret) { | |
114 | pr_info("power trace: Couldn't activate tracepoint" | |
115 | " probe to trace_power_mark\n"); | |
116 | goto fail_end; | |
117 | } | |
118 | return ret; | |
119 | fail_end: | |
120 | unregister_trace_power_end(probe_power_end); | |
121 | fail_start: | |
122 | unregister_trace_power_start(probe_power_start); | |
123 | return ret; | |
124 | } | |
f3f47a67 AV |
125 | |
126 | static void start_power_trace(struct trace_array *tr) | |
127 | { | |
128 | trace_power_enabled = 1; | |
129 | } | |
130 | ||
131 | static void stop_power_trace(struct trace_array *tr) | |
62524d55 SR |
132 | { |
133 | trace_power_enabled = 0; | |
134 | } | |
135 | ||
136 | static void power_trace_reset(struct trace_array *tr) | |
f3f47a67 AV |
137 | { |
138 | trace_power_enabled = 0; | |
b5f9fd0f JB |
139 | unregister_trace_power_start(probe_power_start); |
140 | unregister_trace_power_end(probe_power_end); | |
141 | unregister_trace_power_mark(probe_power_mark); | |
f3f47a67 AV |
142 | } |
143 | ||
144 | ||
145 | static int power_trace_init(struct trace_array *tr) | |
146 | { | |
147 | int cpu; | |
148 | power_trace = tr; | |
149 | ||
150 | trace_power_enabled = 1; | |
b5f9fd0f | 151 | tracing_power_register(); |
f3f47a67 | 152 | |
4462344e | 153 | for_each_cpu(cpu, cpu_possible_mask) |
f3f47a67 AV |
154 | tracing_reset(tr, cpu); |
155 | return 0; | |
156 | } | |
157 | ||
158 | static enum print_line_t power_print_line(struct trace_iterator *iter) | |
159 | { | |
160 | int ret = 0; | |
161 | struct trace_entry *entry = iter->ent; | |
162 | struct trace_power *field ; | |
163 | struct power_trace *it; | |
164 | struct trace_seq *s = &iter->seq; | |
165 | struct timespec stamp; | |
166 | struct timespec duration; | |
167 | ||
168 | trace_assign_type(field, entry); | |
169 | it = &field->state_data; | |
170 | stamp = ktime_to_timespec(it->stamp); | |
171 | duration = ktime_to_timespec(ktime_sub(it->end, it->stamp)); | |
172 | ||
173 | if (entry->type == TRACE_POWER) { | |
174 | if (it->type == POWER_CSTATE) | |
175 | ret = trace_seq_printf(s, "[%5ld.%09ld] CSTATE: Going to C%i on cpu %i for %ld.%09ld\n", | |
176 | stamp.tv_sec, | |
177 | stamp.tv_nsec, | |
178 | it->state, iter->cpu, | |
179 | duration.tv_sec, | |
180 | duration.tv_nsec); | |
181 | if (it->type == POWER_PSTATE) | |
182 | ret = trace_seq_printf(s, "[%5ld.%09ld] PSTATE: Going to P%i on cpu %i\n", | |
183 | stamp.tv_sec, | |
184 | stamp.tv_nsec, | |
185 | it->state, iter->cpu); | |
186 | if (!ret) | |
187 | return TRACE_TYPE_PARTIAL_LINE; | |
188 | return TRACE_TYPE_HANDLED; | |
189 | } | |
190 | return TRACE_TYPE_UNHANDLED; | |
191 | } | |
192 | ||
193 | static struct tracer power_tracer __read_mostly = | |
194 | { | |
195 | .name = "power", | |
196 | .init = power_trace_init, | |
197 | .start = start_power_trace, | |
198 | .stop = stop_power_trace, | |
62524d55 | 199 | .reset = power_trace_reset, |
f3f47a67 AV |
200 | .print_line = power_print_line, |
201 | }; | |
202 | ||
203 | static int init_power_trace(void) | |
204 | { | |
205 | return register_tracer(&power_tracer); | |
206 | } | |
207 | device_initcall(init_power_trace); |