]>
sourceware.org Git - systemtap.git/blob - 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
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
13 #include "translate.h"
19 #define __STDC_FORMAT_MACROS
24 using namespace __gnu_cxx
;
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");
33 // ------------------------------------------------------------------------
34 // perf event derived probes
35 // ------------------------------------------------------------------------
36 // This is a new interface to the perfmon hw.
39 struct perf_derived_probe
: public derived_probe
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
);
49 struct perf_derived_probe_group
: public generic_dpg
<perf_derived_probe
>
51 void emit_module_decls (systemtap_session
& s
);
52 void emit_module_init (systemtap_session
& s
);
53 void emit_module_exit (systemtap_session
& s
);
57 perf_derived_probe::perf_derived_probe (probe
* p
, probe_point
* l
,
61 derived_probe (p
, l
, true /* .components soon rewritten */),
62 event_type (type
), event_config (config
), interval (i
)
64 vector
<probe_point::component
*>& comps
= this->sole_location()->components
;
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
)));
74 perf_derived_probe::join_group (systemtap_session
& s
)
76 if (! s
.perf_derived_probes
)
77 s
.perf_derived_probes
= new perf_derived_probe_group ();
78 s
.perf_derived_probes
->enroll (this);
83 perf_derived_probe_group::emit_module_decls (systemtap_session
& s
)
85 if (probes
.empty()) return;
87 s
.op
->newline() << "/* ---- perf probes ---- */";
88 s
.op
->newline() << "#include \"perf.c\"";
92 s
.op
->newline() << "static void handle_perf_probe (unsigned i, struct pt_regs *regs);";
93 for (unsigned i
=0; i
< probes
.size(); i
++)
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";
109 /* data structures */
110 s
.op
->newline() << "static struct stap_perf_probe stap_perf_probes ["
111 << probes
.size() << "] = {";
113 for (unsigned i
=0; i
< probes
.size(); i
++)
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) << "},";
124 s
.op
->newline(-1) << "};";
127 /* wrapper functions */
128 for (unsigned i
=0; i
< probes
.size(); i
++)
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) << "}";
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) << "}";
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) << "}";
166 perf_derived_probe_group::emit_module_init (systemtap_session
& s
)
168 if (probes
.empty()) return;
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
185 perf_derived_probe_group::emit_module_exit (systemtap_session
& s
)
187 if (probes
.empty()) return;
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
195 struct perf_builder
: public derived_probe_builder
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
);
202 static void register_patterns(systemtap_session
& s
);
207 perf_builder::build(systemtap_session
& sess
,
209 probe_point
* location
,
210 literal_map_t
const & parameters
,
211 vector
<derived_probe
*> & finished_results
)
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"));
221 bool has_type
= get_param(parameters
, TOK_TYPE
, type
);
225 bool has_config
= get_param(parameters
, TOK_CONFIG
, config
);
229 bool has_period
= get_param(parameters
, TOK_SAMPLE
, period
);
231 period
= 1000000; // XXX: better parametrize this default
233 throw semantic_error(_("invalid perf sample period ") + lex_cast(period
),
234 parameters
.find(TOK_SAMPLE
)->second
->tok
);
236 if (sess
.verbose
> 1)
237 clog
<< _F("perf probe type=%" PRId64
" config=%" PRId64
" period=%" PRId64
, type
, config
, period
) << endl
;
239 finished_results
.push_back
240 (new perf_derived_probe(base
, location
, type
, config
, period
));
245 register_tapset_perf(systemtap_session
& s
)
247 // NB: at this point, the binding is *not* unprivileged.
249 derived_probe_builder
*builder
= new perf_builder();
250 match_node
* perf
= s
.pattern_root
->bind(TOK_PERF
);
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
);
257 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.052977 seconds and 6 git commands to generate.