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: ...@@ -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. 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 ### Multiple attachment points
More than one function/tracepoint can be specified for a single probe: 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 ...@@ -104,6 +104,8 @@ std::string AttachPoint::name(const std::string &attach_point) const
n += ":" + target; n += ":" + target;
if (attach_point != "") if (attach_point != "")
n += ":" + attach_point; n += ":" + attach_point;
if (freq != 0)
n += ":" + std::to_string(freq);
return n; return n;
} }
...@@ -117,6 +119,8 @@ std::string Probe::name() const ...@@ -117,6 +119,8 @@ std::string Probe::name() const
n += ":" + attach_point->target; n += ":" + attach_point->target;
if (attach_point->func != "") if (attach_point->func != "")
n += ":" + attach_point->func; n += ":" + attach_point->func;
if (attach_point->freq != 0)
n += ":" + std::to_string(attach_point->freq);
n += ","; n += ",";
} }
return n.substr(0, n.size()-1); return n.substr(0, n.size()-1);
......
...@@ -147,10 +147,15 @@ public: ...@@ -147,10 +147,15 @@ public:
const std::string &target, const std::string &target,
const std::string &func) const std::string &func)
: provider(provider), target(target), func(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 provider;
std::string target; std::string target;
std::string func; std::string func;
int freq = 0;
void accept(Visitor &v) override; void accept(Visitor &v) override;
std::string name(const std::string &attach_point) const; std::string name(const std::string &attach_point) const;
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#include "attached_probe.h" #include "attached_probe.h"
#include "bcc_syms.h" #include "bcc_syms.h"
#include "common.h"
#include "libbpf.h" #include "libbpf.h"
#include "perf_reader.h" #include "perf_reader.h"
#include <linux/perf_event.h>
namespace bpftrace { namespace bpftrace {
...@@ -32,6 +34,7 @@ bpf_prog_type progtype(ProbeType t) ...@@ -32,6 +34,7 @@ bpf_prog_type progtype(ProbeType t)
case ProbeType::uprobe: return BPF_PROG_TYPE_KPROBE; break; case ProbeType::uprobe: return BPF_PROG_TYPE_KPROBE; break;
case ProbeType::uretprobe: 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::tracepoint: return BPF_PROG_TYPE_TRACEPOINT; break;
case ProbeType::profile: return BPF_PROG_TYPE_PERF_EVENT; break;
default: abort(); default: abort();
} }
} }
...@@ -54,6 +57,9 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun ...@@ -54,6 +57,9 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun
case ProbeType::tracepoint: case ProbeType::tracepoint:
attach_tracepoint(); attach_tracepoint();
break; break;
case ProbeType::profile:
attach_profile();
break;
default: default:
abort(); abort();
} }
...@@ -62,6 +68,7 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun ...@@ -62,6 +68,7 @@ AttachedProbe::AttachedProbe(Probe &probe, std::tuple<uint8_t *, uintptr_t> &fun
AttachedProbe::~AttachedProbe() AttachedProbe::~AttachedProbe()
{ {
close(progfd_); close(progfd_);
if (perf_reader_)
perf_reader_free(perf_reader_); perf_reader_free(perf_reader_);
int err = 0; int err = 0;
switch (probe_.type) switch (probe_.type)
...@@ -77,6 +84,9 @@ AttachedProbe::~AttachedProbe() ...@@ -77,6 +84,9 @@ AttachedProbe::~AttachedProbe()
case ProbeType::tracepoint: case ProbeType::tracepoint:
err = bpf_detach_tracepoint(probe_.path.c_str(), eventname().c_str()); err = bpf_detach_tracepoint(probe_.path.c_str(), eventname().c_str());
break; break;
case ProbeType::profile:
err = detach_profile();
break;
default: default:
abort(); abort();
} }
...@@ -206,4 +216,59 @@ void AttachedProbe::attach_tracepoint() ...@@ -206,4 +216,59 @@ void AttachedProbe::attach_tracepoint()
throw std::runtime_error("Error attaching probe: " + probe_.name); 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 } // namespace bpftrace
...@@ -26,10 +26,13 @@ private: ...@@ -26,10 +26,13 @@ private:
void attach_kprobe(); void attach_kprobe();
void attach_uprobe(); void attach_uprobe();
void attach_tracepoint(); void attach_tracepoint();
void attach_profile();
int detach_profile();
Probe &probe_; Probe &probe_;
std::tuple<uint8_t *, uintptr_t> &func_; std::tuple<uint8_t *, uintptr_t> &func_;
void *perf_reader_; std::vector<int> perf_event_fds_;
void *perf_reader_ = nullptr;
int progfd_; int progfd_;
}; };
......
...@@ -78,6 +78,7 @@ int BPFtrace::add_probe(ast::Probe &p) ...@@ -78,6 +78,7 @@ int BPFtrace::add_probe(ast::Probe &p)
probe.type = probetype(attach_point->provider); probe.type = probetype(attach_point->provider);
probe.prog_name = p.name(); probe.prog_name = p.name();
probe.name = attach_point->name(func); probe.name = attach_point->name(func);
probe.freq = attach_point->freq;
probes_.push_back(probe); probes_.push_back(probe);
} }
} }
......
...@@ -121,6 +121,7 @@ attach_points : attach_points "," attach_point { $$ = $1; $1->push_back($3); } ...@@ -121,6 +121,7 @@ attach_points : attach_points "," attach_point { $$ = $1; $1->push_back($3); }
attach_point : IDENT { $$ = new ast::AttachPoint($1); } attach_point : IDENT { $$ = new ast::AttachPoint($1); }
| IDENT ":" wildcard { $$ = new ast::AttachPoint($1, $3); } | IDENT ":" wildcard { $$ = new ast::AttachPoint($1, $3); }
| IDENT PATH wildcard { $$ = new ast::AttachPoint($1, $2.substr(1, $2.size()-2), $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; } wildcard : wildcard IDENT { $$ = $1 + $2; }
......
...@@ -339,6 +339,19 @@ void SemanticAnalyser::visit(AttachPoint &ap) ...@@ -339,6 +339,19 @@ void SemanticAnalyser::visit(AttachPoint &ap)
if (ap.target == "" || ap.func == "") if (ap.target == "" || ap.func == "")
err_ << "tracepoint probe must have a target" << std::endl; 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") { else if (ap.provider == "BEGIN" || ap.provider == "END") {
if (ap.target != "" || ap.func != "") if (ap.target != "" || ap.func != "")
err_ << "BEGIN/END probes should not have a target" << std::endl; err_ << "BEGIN/END probes should not have a target" << std::endl;
......
...@@ -54,7 +54,9 @@ ProbeType probetype(const std::string &type) ...@@ -54,7 +54,9 @@ ProbeType probetype(const std::string &type)
return ProbeType::uprobe; return ProbeType::uprobe;
else if (type == "tracepoint") else if (type == "tracepoint")
return ProbeType::tracepoint; return ProbeType::tracepoint;
return ProbeType::invalid; else if (type == "profile")
return ProbeType::profile;
abort();
} }
} // namespace bpftrace } // namespace bpftrace
...@@ -48,6 +48,7 @@ enum class ProbeType ...@@ -48,6 +48,7 @@ enum class ProbeType
uprobe, uprobe,
uretprobe, uretprobe,
tracepoint, tracepoint,
profile,
}; };
std::string typestr(Type t); std::string typestr(Type t);
...@@ -61,6 +62,7 @@ public: ...@@ -61,6 +62,7 @@ public:
std::string attach_point; std::string attach_point;
std::string prog_name; std::string prog_name;
std::string name; std::string name;
int freq;
}; };
} // namespace bpftrace } // namespace bpftrace
...@@ -51,6 +51,14 @@ void check_tracepoint(Probe &p, const std::string &target, const std::string &fu ...@@ -51,6 +51,14 @@ void check_tracepoint(Probe &p, const std::string &target, const std::string &fu
EXPECT_EQ("tracepoint:" + target + ":" + func, p.name); 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) void check_special_probe(Probe &p, const std::string &attach_point, const std::string &prog_name)
{ {
EXPECT_EQ(ProbeType::uprobe, p.type); EXPECT_EQ(ProbeType::uprobe, p.type);
...@@ -259,6 +267,22 @@ TEST(bpftrace, add_probes_tracepoint_wildcard_no_matches) ...@@ -259,6 +267,22 @@ TEST(bpftrace, add_probes_tracepoint_wildcard_no_matches)
EXPECT_EQ(0, bpftrace.get_special_probes().size()); 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>> key_value_pair_int(std::vector<uint64_t> key, int val)
{ {
std::pair<std::vector<uint8_t>, std::vector<uint8_t>> pair; std::pair<std::vector<uint8_t>, std::vector<uint8_t>> pair;
......
...@@ -220,6 +220,22 @@ TEST(Parser, begin_probe) ...@@ -220,6 +220,22 @@ TEST(Parser, begin_probe)
" int: 1\n"); " 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(Parser, multiple_attach_points_kprobe)
{ {
test("BEGIN,kprobe:sys_open,uprobe:/bin/sh:foo,tracepoint:syscalls:sys_enter_* { 1 }", test("BEGIN,kprobe:sys_open,uprobe:/bin/sh:foo,tracepoint:syscalls:sys_enter_* { 1 }",
......
...@@ -229,6 +229,18 @@ TEST(semantic_analyser, tracepoint) ...@@ -229,6 +229,18 @@ TEST(semantic_analyser, tracepoint)
test("tracepoint { 1 }", 1); 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 semantic_analyser
} // namespace test } // namespace test
} // namespace bpftrace } // 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