]> sourceware.org Git - systemtap.git/blob - tapset-perfmon.cxx
PR14179: Start the runtime shuffle
[systemtap.git] / tapset-perfmon.cxx
1 // tapset for HW performance monitoring
2 // Copyright (C) 2005-2010 Red Hat Inc.
3 // Copyright (C) 2005-2007 Intel Corporation.
4 // Copyright (C) 2008 James.Bottomley@HansenPartnership.com
5 //
6 // This file is part of systemtap, and is free software. You can
7 // redistribute it and/or modify it under the terms of the GNU General
8 // Public License (GPL); either version 2, or (at your option) any
9 // later version.
10
11 #include "session.h"
12 #include "tapsets.h"
13 #include "translate.h"
14 #include "util.h"
15
16 #include <string>
17
18 extern "C" {
19 #define __STDC_FORMAT_MACROS
20 #include <inttypes.h>
21 }
22
23 using namespace std;
24 using namespace __gnu_cxx;
25
26
27 static const string TOK_PERF("perf");
28 static const string TOK_TYPE("type");
29 static const string TOK_CONFIG("config");
30 static const string TOK_SAMPLE("sample");
31
32
33 // ------------------------------------------------------------------------
34 // perf event derived probes
35 // ------------------------------------------------------------------------
36 // This is a new interface to the perfmon hw.
37 //
38
39 struct perf_derived_probe: public derived_probe
40 {
41 int64_t event_type;
42 int64_t event_config;
43 int64_t interval;
44 perf_derived_probe (probe* p, probe_point* l, int64_t type, int64_t config, int64_t i);
45 virtual void join_group (systemtap_session& s);
46 };
47
48
49 struct perf_derived_probe_group: public generic_dpg<perf_derived_probe>
50 {
51 void emit_module_decls (systemtap_session& s);
52 void emit_module_init (systemtap_session& s);
53 void emit_module_exit (systemtap_session& s);
54 };
55
56
57 perf_derived_probe::perf_derived_probe (probe* p, probe_point* l,
58 int64_t type,
59 int64_t config,
60 int64_t i):
61 derived_probe (p, l, true /* .components soon rewritten */),
62 event_type (type), event_config (config), interval (i)
63 {
64 vector<probe_point::component*>& comps = this->sole_location()->components;
65 comps.clear();
66 comps.push_back (new probe_point::component (TOK_PERF));
67 comps.push_back (new probe_point::component (TOK_TYPE, new literal_number(type)));
68 comps.push_back (new probe_point::component (TOK_CONFIG, new literal_number (config)));
69 comps.push_back (new probe_point::component (TOK_SAMPLE, new literal_number (interval)));
70 }
71
72
73 void
74 perf_derived_probe::join_group (systemtap_session& s)
75 {
76 if (! s.perf_derived_probes)
77 s.perf_derived_probes = new perf_derived_probe_group ();
78 s.perf_derived_probes->enroll (this);
79 }
80
81
82 void
83 perf_derived_probe_group::emit_module_decls (systemtap_session& s)
84 {
85 if (probes.empty()) return;
86
87 s.op->newline() << "/* ---- perf probes ---- */";
88 s.op->newline() << "#include \"linux/perf.c\"";
89 s.op->newline();
90
91 /* declarations */
92 s.op->newline() << "static void handle_perf_probe (unsigned i, struct pt_regs *regs);";
93 for (unsigned i=0; i < probes.size(); i++)
94 {
95 s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
96 s.op->newline() << "static void enter_perf_probe_" << i
97 << " (struct perf_event *e, int nmi, "
98 << "struct perf_sample_data *data, "
99 << "struct pt_regs *regs);";
100 s.op->newline() << "#else";
101 s.op->newline() << "static void enter_perf_probe_" << i
102 << " (struct perf_event *e, "
103 << "struct perf_sample_data *data, "
104 << "struct pt_regs *regs);";
105 s.op->newline() << "#endif";
106 }
107 s.op->newline();
108
109 /* data structures */
110 s.op->newline() << "static struct stap_perf_probe stap_perf_probes ["
111 << probes.size() << "] = {";
112 s.op->indent(1);
113 for (unsigned i=0; i < probes.size(); i++)
114 {
115 s.op->newline() << "{";
116 s.op->newline(1) << ".attr={ "
117 << ".type=" << probes[i]->event_type << "ULL, "
118 << ".config=" << probes[i]->event_config << "ULL, "
119 << "{ .sample_period=" << probes[i]->interval << "ULL }},";
120 s.op->newline() << ".callback=enter_perf_probe_" << i << ", ";
121 s.op->newline() << ".probe=" << common_probe_init (probes[i]) << ", ";
122 s.op->newline(-1) << "},";
123 }
124 s.op->newline(-1) << "};";
125 s.op->newline();
126
127 /* wrapper functions */
128 for (unsigned i=0; i < probes.size(); i++)
129 {
130 s.op->newline() << "#ifdef STAPCONF_PERF_HANDLER_NMI";
131 s.op->newline() << "static void enter_perf_probe_" << i
132 << " (struct perf_event *e, int nmi, "
133 << "struct perf_sample_data *data, "
134 << "struct pt_regs *regs)";
135 s.op->newline() << "#else";
136 s.op->newline() << "static void enter_perf_probe_" << i
137 << " (struct perf_event *e, "
138 << "struct perf_sample_data *data, "
139 << "struct pt_regs *regs)";
140 s.op->newline() << "#endif";
141 s.op->newline() << "{";
142 s.op->newline(1) << "handle_perf_probe(" << i << ", regs);";
143 s.op->newline(-1) << "}";
144 }
145 s.op->newline();
146
147 s.op->newline() << "static void handle_perf_probe (unsigned i, struct pt_regs *regs)";
148 s.op->newline() << "{";
149 s.op->newline(1) << "struct stap_perf_probe* stp = & stap_perf_probes [i];";
150 common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->probe",
151 "_STP_PROBE_HANDLER_PERF");
152 s.op->newline() << "if (user_mode(regs)) {";
153 s.op->newline(1)<< "c->probe_flags |= _STP_PROBE_STATE_USER_MODE;";
154 s.op->newline() << "c->uregs = regs;";
155 s.op->newline(-1) << "} else {";
156 s.op->newline(1) << "c->kregs = regs;";
157 s.op->newline(-1) << "}";
158
159 s.op->newline() << "(*stp->probe->ph) (c);";
160 common_probe_entryfn_epilogue (s.op, true, s.suppress_handler_errors);
161 s.op->newline(-1) << "}";
162 }
163
164
165 void
166 perf_derived_probe_group::emit_module_init (systemtap_session& s)
167 {
168 if (probes.empty()) return;
169
170 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
171 s.op->newline(1) << "struct stap_perf_probe* stp = & stap_perf_probes [i];";
172 s.op->newline() << "rc = _stp_perf_init(stp);";
173 s.op->newline() << "if (rc) {";
174 s.op->newline(1) << "probe_point = stp->probe->pp;";
175 s.op->newline() << "for (j=0; j<i; j++) {";
176 s.op->newline(1) << "_stp_perf_del(& stap_perf_probes [j]);";
177 s.op->newline(-1) << "}"; // for unwind loop
178 s.op->newline(-1) << "}"; // if-error
179 s.op->newline() << "break;";
180 s.op->newline(-1) << "}"; // for loop
181 }
182
183
184 void
185 perf_derived_probe_group::emit_module_exit (systemtap_session& s)
186 {
187 if (probes.empty()) return;
188
189 s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
190 s.op->newline(1) << "_stp_perf_del(& stap_perf_probes [i]);";
191 s.op->newline(-1) << "}"; // for loop
192 }
193
194
195 struct perf_builder: public derived_probe_builder
196 {
197 virtual void build(systemtap_session & sess,
198 probe * base, probe_point * location,
199 literal_map_t const & parameters,
200 vector<derived_probe *> & finished_results);
201
202 static void register_patterns(systemtap_session& s);
203 };
204
205
206 void
207 perf_builder::build(systemtap_session & sess,
208 probe * base,
209 probe_point * location,
210 literal_map_t const & parameters,
211 vector<derived_probe *> & finished_results)
212 {
213 // XXX need additional version checks too?
214 // --- perhaps look for export of perf_event_create_kernel_counter
215 if (sess.kernel_exports.find("perf_event_create_kernel_counter") == sess.kernel_exports.end())
216 throw semantic_error (_("perf probes not available without exported perf_event_create_kernel_counter"));
217 if (sess.kernel_config["CONFIG_PERF_EVENTS"] != "y")
218 throw semantic_error (_("perf probes not available without CONFIG_PERF_EVENTS"));
219
220 int64_t type;
221 bool has_type = get_param(parameters, TOK_TYPE, type);
222 assert(has_type);
223
224 int64_t config;
225 bool has_config = get_param(parameters, TOK_CONFIG, config);
226 assert(has_config);
227
228 int64_t period;
229 bool has_period = get_param(parameters, TOK_SAMPLE, period);
230 if (!has_period)
231 period = 1000000; // XXX: better parametrize this default
232 else if (period < 1)
233 throw semantic_error(_("invalid perf sample period ") + lex_cast(period),
234 parameters.find(TOK_SAMPLE)->second->tok);
235
236 if (sess.verbose > 1)
237 clog << _F("perf probe type=%" PRId64 " config=%" PRId64 " period=%" PRId64, type, config, period) << endl;
238
239 finished_results.push_back
240 (new perf_derived_probe(base, location, type, config, period));
241 }
242
243
244 void
245 register_tapset_perf(systemtap_session& s)
246 {
247 // NB: at this point, the binding is *not* unprivileged.
248
249 derived_probe_builder *builder = new perf_builder();
250 match_node* perf = s.pattern_root->bind(TOK_PERF);
251
252 match_node* event = perf->bind_num(TOK_TYPE)->bind_num(TOK_CONFIG);
253 event->bind(builder);
254 event->bind_num(TOK_SAMPLE)->bind(builder);
255 }
256
257 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.055659 seconds and 6 git commands to generate.