Commit ba038b23 authored by Alastair Robertson's avatar Alastair Robertson

Add profile probe provider

parent b67f5598
......@@ -110,6 +110,12 @@ Attach script to a statically defined tracepoint in the kernel:
Tracepoints are guaranteed to be stable between kernel versions, unlike kprobes.
### timers
Run the script at specified time intervals:
`profile:hz:99 { ... }`
`profile:ms:10 { ... }`
### Multiple attachment points
More than one function/tracepoint can be specified for a single probe:
......
......@@ -104,6 +104,8 @@ std::string AttachPoint::name(const std::string &attach_point) const
n += ":" + target;
if (attach_point != "")
n += ":" + attach_point;
if (freq != 0)
n += ":" + std::to_string(freq);
return n;
}
......@@ -117,6 +119,8 @@ std::string Probe::name() const
n += ":" + attach_point->target;
if (attach_point->func != "")
n += ":" + attach_point->func;
if (attach_point->freq != 0)
n += ":" + std::to_string(attach_point->freq);
n += ",";
}
return n.substr(0, n.size()-1);
......
......@@ -147,10 +147,15 @@ public:
const std::string &target,
const std::string &func)
: provider(provider), target(target), func(func) { }
AttachPoint(const std::string &provider,
const std::string &target,
int freq)
: provider(provider), target(target), freq(freq) { }
std::string provider;
std::string target;
std::string func;
int freq = 0;
void accept(Visitor &v) override;
std::string name(const std::string &attach_point) const;
......
......@@ -6,8 +6,10 @@
#include "attached_probe.h"
#include "bcc_syms.h"
#include "common.h"
#include "libbpf.h"
#include "perf_reader.h"
#include <linux/perf_event.h>
namespace bpftrace {
......@@ -32,6 +34,7 @@ bpf_prog_type progtype(ProbeType t)
case ProbeType::uprobe: return BPF_PROG_TYPE_KPROBE; break;
case ProbeType::uretprobe: return BPF_PROG_TYPE_KPROBE; break;
case ProbeType::tracepoint: return BPF_PROG_TYPE_TRACEPOINT; break;
case ProbeType::profile: return BPF_PROG_TYPE_PERF_EVENT; break;
default: abort();
}
}
......@@ -54,6 +57,9 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun
case ProbeType::tracepoint:
attach_tracepoint();
break;
case ProbeType::profile:
attach_profile();
break;
default:
abort();
}
......@@ -62,6 +68,7 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun
AttachedProbe::~AttachedProbe()
{
close(progfd_);
if (perf_reader_)
perf_reader_free(perf_reader_);
int err = 0;
switch (probe_.type)
......@@ -77,6 +84,9 @@ AttachedProbe::~AttachedProbe()
case ProbeType::tracepoint:
err = bpf_detach_tracepoint(probe_.path.c_str(), eventname().c_str());
break;
case ProbeType::profile:
err = detach_profile();
break;
default:
abort();
}
......@@ -206,4 +216,59 @@ void AttachedProbe::attach_tracepoint()
throw std::runtime_error("Error attaching probe: " + probe_.name);
}
void AttachedProbe::attach_profile()
{
int pid = -1;
int group_fd = -1;
uint64_t period, freq;
if (probe_.path == "hz")
{
period = 0;
freq = probe_.freq;
}
else if (probe_.path == "s")
{
period = probe_.freq * 1e9;
freq = 0;
}
else if (probe_.path == "ms")
{
period = probe_.freq * 1e6;
freq = 0;
}
else if (probe_.path == "us")
{
period = probe_.freq * 1e3;
freq = 0;
}
else
{
abort();
}
std::vector<int> cpus = ebpf::get_online_cpus();
for (int cpu : cpus)
{
int perf_event_fd = bpf_attach_perf_event(progfd_, PERF_TYPE_SOFTWARE,
PERF_COUNT_SW_CPU_CLOCK, period, freq, pid, cpu, group_fd);
if (perf_event_fd < 0)
throw std::runtime_error("Error attaching probe: " + probe_.name);
perf_event_fds_.push_back(perf_event_fd);
}
}
int AttachedProbe::detach_profile()
{
for (int perf_event_fd : perf_event_fds_)
{
int err = bpf_close_perf_event_fd(perf_event_fd);
if (err)
return err;
}
return 0;
}
} // namespace bpftrace
......@@ -26,10 +26,13 @@ private:
void attach_kprobe();
void attach_uprobe();
void attach_tracepoint();
void attach_profile();
int detach_profile();
Probe &probe_;
std::tuple<uint8_t *, uintptr_t> &func_;
void *perf_reader_;
std::vector<int> perf_event_fds_;
void *perf_reader_ = nullptr;
int progfd_;
};
......
......@@ -78,6 +78,7 @@ int BPFtrace::add_probe(ast::Probe &p)
probe.type = probetype(attach_point->provider);
probe.prog_name = p.name();
probe.name = attach_point->name(func);
probe.freq = attach_point->freq;
probes_.push_back(probe);
}
}
......
......@@ -121,6 +121,7 @@ attach_points : attach_points "," attach_point { $$ = $1; $1->push_back($3); }
attach_point : IDENT { $$ = new ast::AttachPoint($1); }
| IDENT ":" wildcard { $$ = new ast::AttachPoint($1, $3); }
| IDENT PATH wildcard { $$ = new ast::AttachPoint($1, $2.substr(1, $2.size()-2), $3); }
| IDENT PATH INT { $$ = new ast::AttachPoint($1, $2.substr(1, $2.size()-2), $3); }
;
wildcard : wildcard IDENT { $$ = $1 + $2; }
......
......@@ -339,6 +339,19 @@ void SemanticAnalyser::visit(AttachPoint &ap)
if (ap.target == "" || ap.func == "")
err_ << "tracepoint probe must have a target" << std::endl;
}
else if (ap.provider == "profile") {
if (ap.target == "")
err_ << "profile probe must have unit of time" << std::endl;
else if (ap.target != "hz" &&
ap.target != "us" &&
ap.target != "ms" &&
ap.target != "s")
err_ << ap.target << " is not an accepted unit of time" << std::endl;
if (ap.func != "")
err_ << "profile probe must have an integer frequency" << std::endl;
else if (ap.freq <= 0)
err_ << "profile frequency should be a positive integer" << std::endl;
}
else if (ap.provider == "BEGIN" || ap.provider == "END") {
if (ap.target != "" || ap.func != "")
err_ << "BEGIN/END probes should not have a target" << std::endl;
......
......@@ -54,7 +54,9 @@ ProbeType probetype(const std::string &type)
return ProbeType::uprobe;
else if (type == "tracepoint")
return ProbeType::tracepoint;
return ProbeType::invalid;
else if (type == "profile")
return ProbeType::profile;
abort();
}
} // namespace bpftrace
......@@ -48,6 +48,7 @@ enum class ProbeType
uprobe,
uretprobe,
tracepoint,
profile,
};
std::string typestr(Type t);
......@@ -61,6 +62,7 @@ public:
std::string attach_point;
std::string prog_name;
std::string name;
int freq;
};
} // namespace bpftrace
......@@ -51,6 +51,14 @@ void check_tracepoint(Probe &p, const std::string &target, const std::string &fu
EXPECT_EQ("tracepoint:" + target + ":" + func, p.name);
}
void check_profile(Probe &p, const std::string &unit, int freq, const std::string &prog_name)
{
EXPECT_EQ(ProbeType::profile, p.type);
EXPECT_EQ(freq, p.freq);
EXPECT_EQ(prog_name, p.prog_name);
EXPECT_EQ("profile:" + unit + ":" + std::to_string(freq), p.name);
}
void check_special_probe(Probe &p, const std::string &attach_point, const std::string &prog_name)
{
EXPECT_EQ(ProbeType::uprobe, p.type);
......@@ -259,6 +267,22 @@ TEST(bpftrace, add_probes_tracepoint_wildcard_no_matches)
EXPECT_EQ(0, bpftrace.get_special_probes().size());
}
TEST(bpftrace, add_probes_profile)
{
ast::AttachPoint a("profile", "ms", 997);
ast::AttachPointList attach_points = { &a };
ast::Probe probe(&attach_points, nullptr, nullptr);
StrictMock<MockBPFtrace> bpftrace;
EXPECT_EQ(0, bpftrace.add_probe(probe));
EXPECT_EQ(1, bpftrace.get_probes().size());
EXPECT_EQ(0, bpftrace.get_special_probes().size());
std::string probe_prog_name = "profile:ms:997";
check_profile(bpftrace.get_probes().at(0), "ms", 997, probe_prog_name);
}
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> key_value_pair_int(std::vector<uint64_t> key, int val)
{
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> pair;
......
......@@ -220,6 +220,22 @@ TEST(Parser, begin_probe)
" int: 1\n");
}
TEST(Parser, tracepoint_probe)
{
test("tracepoint:sched:sched_switch { 1 }",
"Program\n"
" tracepoint:sched:sched_switch\n"
" int: 1\n");
}
TEST(Parser, profile_probe)
{
test("profile:ms:997 { 1 }",
"Program\n"
" profile:ms:997\n"
" int: 1\n");
}
TEST(Parser, multiple_attach_points_kprobe)
{
test("BEGIN,kprobe:sys_open,uprobe:/bin/sh:foo,tracepoint:syscalls:sys_enter_* { 1 }",
......
......@@ -229,6 +229,18 @@ TEST(semantic_analyser, tracepoint)
test("tracepoint { 1 }", 1);
}
TEST(semantic_analyser, profile)
{
test("profile:hz:997 { 1 }", 0);
test("profile:s:10 { 1 }", 0);
test("profile:ms:100 { 1 }", 0);
test("profile:us:100 { 1 }", 0);
test("profile:ms:nan { 1 }", 1);
test("profile:unit:100 { 1 }", 1);
test("profile:f { 1 }", 1);
test("profile { 1 }", 1);
}
} // namespace semantic_analyser
} // namespace test
} // namespace bpftrace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment