This adds the capability for a task to read a perf counter. usage syntax: perf.type(0).config(0).counter("a") ... probe process("name")... {... x = @perf("name") } translation data structures tapsets.cxx dwarf_var_expanding_visitor std::vector perf_counter_refs; A vector of derived probes corresponding to @perf ops used by this probe. session.h std::map perf_counters; A mapping from the counter name to the associated probe runtime data structures stap_inode_uprobe_consumers perf_counters is a list of indices into stap_perf_probes corresponding to the perf counters that a process probe uses. e.g. {0, 2} AND static struct stap_perf_probe stap_perf_probes [3] = {...} uprobes-inode.c::stapiu_target_reg calls _stp_perf_read_init to setup a counter corresponding to each @perf using the index to stap_perf_probes _stp_perf_read is passed the same index to read the counter EXAMPLE for the script: global perm_begin global perm_end global tower_begin global tower_end probe perf.type(0).config(0).counter("a") { } probe perf.type(0).config(0).counter("b") { } probe perf.type(0).config(1).counter("c") { } probe process ("/work/scox/stap/perf/bench.x").statement("*@bench.c:1131") { perm_begin <<< @perf("a") perm_begin <<< @perf("c") } probe process ("/work/scox/stap/perf/bench.x").statement("tower@bench.c") {} probe process ("/work/scox/stap/perf/bench.x").statement("*@bench.c:1131") { perm_end <<< @perf("a") perm_begin <<< @perf("c") } probe process ("/work/scox/stap/perf/bench.x").statement("*@bench.c:1135") { tower_begin <<< @perf("b") } probe process ("/work/scox/stap/perf/bench.x").statement("*@bench.c:1136") { tower_end <<< @perf("b") } long perf_counters_0[] = {0, 2}; long perf_counters_1[] = {}; long perf_counters_2[] = {0, 2}; long perf_counters_3[] = {1}; long perf_counters_4[] = {1}; static struct stapiu_consumer stap_inode_uprobe_consumers[] = { { .target=&stap_inode_uprobe_targets[0], .offset=(loff_t)0x31f1ULL, .perf_counters_dim=ARRAY_SIZE(perf_counters_0), .perf_counters=&perf_counters_0, .probe=(&stap_probes[3]), }, { .target=&stap_inode_uprobe_targets[0], .offset=(loff_t)0xa7aULL, .perf_counters_dim=ARRAY_SIZE(perf_counters_1), .perf_counters=&perf_counters_1, .probe=(&stap_probes[4]), }, ... static struct stap_perf_probe stap_perf_probes [3] = { { .attr={ .type=0ULL, .config=0ULL, { .sample_period=0ULL }}, .callback=enter_perf_probe_0, .probe=(&stap_probes[0]), .per_thread=1, }, { .attr={ .type=0ULL, .config=0ULL, { .sample_period=0ULL }}, .callback=enter_perf_probe_1, .probe=(&stap_probes[1]), .per_thread=1, }, { .attr={ .type=0ULL, .config=1ULL, { .sample_period=0ULL }}, .callback=enter_perf_probe_2, .probe=(&stap_probes[2]), .per_thread=1, }, }; ... and a read is done with: l->l___perf_read_b = (((int64_t) (_stp_perf_read(smp_processor_id(),1)))); # where 1 is the index into stap_perf_probes corresponding to counter("b")