]> sourceware.org Git - systemtap.git/blame - tapset-perfmon.cxx
update copyrights
[systemtap.git] / tapset-perfmon.cxx
CommitLineData
01c2eefe 1// tapset for HW performance monitoring
ef36f781 2// Copyright (C) 2005-2014 Red Hat Inc.
01c2eefe 3// Copyright (C) 2005-2007 Intel Corporation.
01c2eefe
JS
4//
5// This file is part of systemtap, and is free software. You can
6// redistribute it and/or modify it under the terms of the GNU General
7// Public License (GPL); either version 2, or (at your option) any
8// later version.
9
10#include "session.h"
11#include "tapsets.h"
6a8fe809 12#include "task_finder.h"
83ea76b1 13#include "translate.h"
01c2eefe
JS
14#include "util.h"
15
16#include <string>
17
b29e794d
LB
18extern "C" {
19#define __STDC_FORMAT_MACROS
20#include <inttypes.h>
21}
22
01c2eefe
JS
23using namespace std;
24using namespace __gnu_cxx;
25
26
83ea76b1 27static const string TOK_PERF("perf");
95ef3b30
FCE
28static const string TOK_TYPE("type");
29static const string TOK_CONFIG("config");
a3cf75e6 30static const string TOK_SAMPLE("sample");
6a8fe809 31static const string TOK_PROCESS("process");
3689db05 32static const string TOK_COUNTER("counter");
83ea76b1 33
01c2eefe
JS
34
35// ------------------------------------------------------------------------
83ea76b1 36// perf event derived probes
01c2eefe
JS
37// ------------------------------------------------------------------------
38// This is a new interface to the perfmon hw.
39//
40
83ea76b1
WC
41struct perf_derived_probe: public derived_probe
42{
95ef3b30
FCE
43 int64_t event_type;
44 int64_t event_config;
83ea76b1 45 int64_t interval;
6a8fe809 46 bool has_process;
3689db05 47 bool has_counter;
6a8fe809 48 string process_name;
3689db05
SC
49 string counter;
50 perf_derived_probe (probe* p, probe_point* l, int64_t type, int64_t config,
51 int64_t i, bool pp, bool cp, string pn, string cv);
83ea76b1
WC
52 virtual void join_group (systemtap_session& s);
53};
54
55
56struct perf_derived_probe_group: public generic_dpg<perf_derived_probe>
57{
83ea76b1
WC
58 void emit_module_decls (systemtap_session& s);
59 void emit_module_init (systemtap_session& s);
60 void emit_module_exit (systemtap_session& s);
61};
62
63
64perf_derived_probe::perf_derived_probe (probe* p, probe_point* l,
95ef3b30
FCE
65 int64_t type,
66 int64_t config,
6a8fe809
SC
67 int64_t i,
68 bool process_p,
3689db05
SC
69 bool counter_p,
70 string process_n,
71 string counter):
6a8fe809 72
4c5d1300 73 derived_probe (p, l, true /* .components soon rewritten */),
6a8fe809 74 event_type (type), event_config (config), interval (i),
3689db05
SC
75 has_process (process_p), has_counter (counter_p), process_name (process_n),
76 counter (counter)
83ea76b1 77{
a3cf75e6
JS
78 vector<probe_point::component*>& comps = this->sole_location()->components;
79 comps.clear();
80 comps.push_back (new probe_point::component (TOK_PERF));
95ef3b30
FCE
81 comps.push_back (new probe_point::component (TOK_TYPE, new literal_number(type)));
82 comps.push_back (new probe_point::component (TOK_CONFIG, new literal_number (config)));
a3cf75e6 83 comps.push_back (new probe_point::component (TOK_SAMPLE, new literal_number (interval)));
8a1bdec5
JS
84 if (has_process)
85 comps.push_back (new probe_point::component (TOK_PROCESS, new literal_string (process_name)));
86 if (has_counter)
87 comps.push_back (new probe_point::component (TOK_COUNTER, new literal_string (counter)));
83ea76b1
WC
88}
89
90
91void
92perf_derived_probe::join_group (systemtap_session& s)
93{
94 if (! s.perf_derived_probes)
95 s.perf_derived_probes = new perf_derived_probe_group ();
96 s.perf_derived_probes->enroll (this);
6a8fe809 97
3689db05
SC
98 if (has_process && !has_counter)
99 enable_task_finder(s);
83ea76b1
WC
100}
101
102
83ea76b1
WC
103void
104perf_derived_probe_group::emit_module_decls (systemtap_session& s)
105{
3689db05
SC
106 bool have_a_process_tag = false;
107
108 for (unsigned i=0; i < probes.size(); i++)
109 if (probes[i]->has_process && !probes[i]->has_counter)
110 {
111 have_a_process_tag = true;
112 break;
113 }
114
83ea76b1
WC
115 if (probes.empty()) return;
116
117 s.op->newline() << "/* ---- perf probes ---- */";
6a8fe809
SC
118 s.op->newline() << "#include <linux/perf_event.h>";
119 s.op->newline() << "#include \"linux/perf.h\"";
85955320
JS
120 s.op->newline();
121
83ea76b1 122 /* declarations */
06d2888c 123 s.op->newline() << "static void handle_perf_probe (unsigned i, struct pt_regs *regs);";
85955320 124 for (unsigned i=0; i < probes.size(); i++)
2f3df331
MW
125 {
126 s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
127 s.op->newline() << "static void enter_perf_probe_" << i
128 << " (struct perf_event *e, int nmi, "
129 << "struct perf_sample_data *data, "
130 << "struct pt_regs *regs);";
131 s.op->newline() << "#else";
132 s.op->newline() << "static void enter_perf_probe_" << i
133 << " (struct perf_event *e, "
134 << "struct perf_sample_data *data, "
135 << "struct pt_regs *regs);";
136 s.op->newline() << "#endif";
137 }
85955320
JS
138 s.op->newline();
139
3689db05
SC
140 // Output task finder callback routine
141 if (have_a_process_tag)
142 {
143 s.op->newline() << "static int _stp_perf_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
144 s.op->indent(1);
145 s.op->newline() << "int rc = 0;";
4fa83377 146 s.op->newline() << "struct stap_perf_probe *p = container_of(tgt, struct stap_perf_probe, e.t.tgt);";
3689db05
SC
147
148 s.op->newline() << "if (register_p) ";
149 s.op->indent(1);
150
151 s.op->newline() << "rc = _stp_perf_init(p, tsk);";
152 s.op->newline(-1) << "else";
153 s.op->newline(1) << "_stp_perf_del(p);";
154 s.op->newline(-1) << "return rc;";
155 s.op->newline(-1) << "}";
156 }
6a8fe809 157
85955320 158 /* data structures */
34fe8ec4
JS
159 s.op->newline() << "static struct stap_perf_probe stap_perf_probes ["
160 << probes.size() << "] = {";
85955320 161 s.op->indent(1);
83ea76b1
WC
162 for (unsigned i=0; i < probes.size(); i++)
163 {
85955320
JS
164 s.op->newline() << "{";
165 s.op->newline(1) << ".attr={ "
95ef3b30
FCE
166 << ".type=" << probes[i]->event_type << "ULL, "
167 << ".config=" << probes[i]->event_config << "ULL, "
85955320 168 << "{ .sample_period=" << probes[i]->interval << "ULL }},";
34fe8ec4 169 s.op->newline() << ".callback=enter_perf_probe_" << i << ", ";
faea5e16 170 s.op->newline() << ".probe=" << common_probe_init (probes[i]) << ", ";
6a8fe809 171
3689db05 172 if (probes[i]->has_process && !probes[i]->has_counter)
6a8fe809 173 {
4fa83377
SC
174 s.op->line() << " .e={";
175 s.op->line() << " .t={";
6a8fe809 176 s.op->line() << " .tgt={";
3689db05 177 s.op->line() << " .purpose=\"perfctr\",";
48cd804a 178 s.op->line() << " .procname=\"" << probes[i]->process_name << "\",";
6a8fe809
SC
179 s.op->line() << " .pid=0,";
180 s.op->line() << " .callback=&_stp_perf_probe_cb,";
181 s.op->line() << " },";
4fa83377
SC
182 s.op->line() << " },";
183 s.op->line() << " },";
ad6c8f90 184 s.op->newline() << ".task_finder=" << "1, ";
6a8fe809 185 }
3689db05 186 else if (probes[i]->has_counter)
ad6c8f90
JS
187 {
188 // process counters are currently task-found by uprobes
189 // set neither .system_wide nor .task_finder
190 }
6a8fe809 191 else
ad6c8f90 192 s.op->newline() << ".system_wide=" << "1, ";
85955320 193 s.op->newline(-1) << "},";
83ea76b1 194 }
85955320 195 s.op->newline(-1) << "};";
83ea76b1
WC
196 s.op->newline();
197
198 /* wrapper functions */
85955320
JS
199 for (unsigned i=0; i < probes.size(); i++)
200 {
2f3df331 201 s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
85955320
JS
202 s.op->newline() << "static void enter_perf_probe_" << i
203 << " (struct perf_event *e, int nmi, "
204 << "struct perf_sample_data *data, "
205 << "struct pt_regs *regs)";
2f3df331
MW
206 s.op->newline() << "#else";
207 s.op->newline() << "static void enter_perf_probe_" << i
208 << " (struct perf_event *e, "
209 << "struct perf_sample_data *data, "
210 << "struct pt_regs *regs)";
211 s.op->newline() << "#endif";
85955320 212 s.op->newline() << "{";
06d2888c 213 s.op->newline(1) << "handle_perf_probe(" << i << ", regs);";
85955320
JS
214 s.op->newline(-1) << "}";
215 }
216 s.op->newline();
217
06d2888c 218 s.op->newline() << "static void handle_perf_probe (unsigned i, struct pt_regs *regs)";
83ea76b1 219 s.op->newline() << "{";
06d2888c 220 s.op->newline(1) << "struct stap_perf_probe* stp = & stap_perf_probes [i];";
71db462b 221 common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
cda141c2 222 "stp_probe_type_perf");
d9aed31e 223 s.op->newline() << "if (user_mode(regs)) {";
e04b5d74 224 s.op->newline(1)<< "c->user_mode_p = 1;";
d9aed31e
MW
225 s.op->newline() << "c->uregs = regs;";
226 s.op->newline(-1) << "} else {";
227 s.op->newline(1) << "c->kregs = regs;";
228 s.op->newline(-1) << "}";
d3f9f732 229
d9aed31e 230 s.op->newline() << "(*stp->probe->ph) (c);";
f887a8c9 231 common_probe_entryfn_epilogue (s, true);
83ea76b1 232 s.op->newline(-1) << "}";
6a8fe809 233 s.op->newline();
ad6c8f90
JS
234 if (have_a_process_tag)
235 s.op->newline() << "#define STP_PERF_USE_TASK_FINDER 1";
6a8fe809
SC
236 s.op->newline() << "#include \"linux/perf.c\"";
237 s.op->newline();
83ea76b1
WC
238}
239
240
241void
242perf_derived_probe_group::emit_module_init (systemtap_session& s)
243{
244 if (probes.empty()) return;
245
ad6c8f90
JS
246 s.op->newline() << "rc = _stp_perf_init_n (stap_perf_probes, "
247 << probes.size() << ", &probe_point);";
83ea76b1
WC
248}
249
250
251void
252perf_derived_probe_group::emit_module_exit (systemtap_session& s)
253{
254 if (probes.empty()) return;
255
ad6c8f90
JS
256 s.op->newline() << "_stp_perf_del_n (stap_perf_probes, "
257 << probes.size() << ");";
83ea76b1
WC
258}
259
260
261struct perf_builder: public derived_probe_builder
262{
263 virtual void build(systemtap_session & sess,
264 probe * base, probe_point * location,
265 literal_map_t const & parameters,
266 vector<derived_probe *> & finished_results);
267
268 static void register_patterns(systemtap_session& s);
269};
270
271
272void
273perf_builder::build(systemtap_session & sess,
3689db05
SC
274 probe * base,
275 probe_point * location,
276 literal_map_t const & parameters,
277 vector<derived_probe *> & finished_results)
83ea76b1 278{
7acbe856
FCE
279 // XXX need additional version checks too?
280 // --- perhaps look for export of perf_event_create_kernel_counter
70e6d6c9 281 if (sess.kernel_exports.find("perf_event_create_kernel_counter") == sess.kernel_exports.end())
dc09353a 282 throw SEMANTIC_ERROR (_("perf probes not available without exported perf_event_create_kernel_counter"));
7acbe856 283 if (sess.kernel_config["CONFIG_PERF_EVENTS"] != "y")
dc09353a 284 throw SEMANTIC_ERROR (_("perf probes not available without CONFIG_PERF_EVENTS"));
7acbe856 285
95ef3b30
FCE
286 int64_t type;
287 bool has_type = get_param(parameters, TOK_TYPE, type);
288 assert(has_type);
289
290 int64_t config;
291 bool has_config = get_param(parameters, TOK_CONFIG, config);
292 assert(has_config);
a3cf75e6 293
83ea76b1 294 int64_t period;
a3cf75e6
JS
295 bool has_period = get_param(parameters, TOK_SAMPLE, period);
296 if (!has_period)
95ef3b30 297 period = 1000000; // XXX: better parametrize this default
1f1b6bb1 298 else if (period < 1)
dc09353a 299 throw SEMANTIC_ERROR(_("invalid perf sample period ") + lex_cast(period),
1f1b6bb1 300 parameters.find(TOK_SAMPLE)->second->tok);
3689db05
SC
301
302 string var;
303 bool has_counter = get_param(parameters, TOK_COUNTER, var);
304 if (var.find_first_of("*?[") != string::npos)
dc09353a 305 throw SEMANTIC_ERROR(_("wildcard not allowed with perf probe counter component"));
3689db05
SC
306 if (has_counter)
307 {
7c3feb93 308 if (var.empty())
dc09353a 309 throw SEMANTIC_ERROR(_("missing perf probe counter component name"));
7c3feb93 310
3689db05 311 period = 0; // perf_event_attr.sample_freq should be 0
7c3feb93
JS
312 if (sess.perf_counters.count(var) > 0)
313 throw SEMANTIC_ERROR(_("duplicate counter name"));
314
315 // Splice a 'next' into the probe body, and then elaborate.cxx's
316 // dead_stmtexpr_remover() will warn if anything of substance follows.
317 statement* n = new next_statement ();
318 n->tok = base->tok;
319 base->body = new block (n, base->body);
3689db05 320 }
1f1b6bb1 321
48cd804a
JS
322 bool proc_p;
323 string proc_n;
324 if ((proc_p = has_null_param(parameters, TOK_PROCESS)))
325 {
326 proc_n = sess.cmd_file();
327 if (proc_n.empty())
328 throw SEMANTIC_ERROR(_("process probe is invalid without a -c COMMAND"));
329 }
330 else
331 proc_p = get_param(parameters, TOK_PROCESS, proc_n);
332 if (proc_p && !proc_n.empty())
333 proc_n = find_executable (proc_n, sess.sysroot, sess.sysenv);
334
1f1b6bb1 335 if (sess.verbose > 1)
48cd804a
JS
336 clog << _F("perf probe type=%" PRId64 " config=%" PRId64 " period=%" PRId64 " process=%s counter=%s",
337 type, config, period, proc_n.c_str(), var.c_str()) << endl;
a3cf75e6 338
83ea76b1 339 finished_results.push_back
3689db05
SC
340 (new perf_derived_probe(base, location, type, config, period, proc_p,
341 has_counter, proc_n, var));
48cd804a
JS
342 if (!var.empty())
343 sess.perf_counters[var] = make_pair(proc_n,finished_results.back());
1f1b6bb1
JS
344}
345
346
83ea76b1
WC
347void
348register_tapset_perf(systemtap_session& s)
349{
95ef3b30
FCE
350 // NB: at this point, the binding is *not* unprivileged.
351
83ea76b1 352 derived_probe_builder *builder = new perf_builder();
a3cf75e6 353 match_node* perf = s.pattern_root->bind(TOK_PERF);
83ea76b1 354
95ef3b30 355 match_node* event = perf->bind_num(TOK_TYPE)->bind_num(TOK_CONFIG);
a3cf75e6
JS
356 event->bind(builder);
357 event->bind_num(TOK_SAMPLE)->bind(builder);
6a8fe809
SC
358 event->bind_str(TOK_PROCESS)->bind(builder);
359 event->bind(TOK_PROCESS)->bind(builder);
3689db05
SC
360 event->bind_str(TOK_COUNTER)->bind(builder);
361 event->bind_str(TOK_PROCESS)->bind_str(TOK_COUNTER)->bind(builder);
83ea76b1
WC
362}
363
01c2eefe 364/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.162309 seconds and 5 git commands to generate.