Add BoolProfiler and IntProfiler clases (using StackTraceProfiler)
A BoolProfiler uses two StackTraceProfilers to take profiled samples of a boolean value. At shutdown it prints the %false, %true, and a profile for each case. An IntProfiler is similar, but profiles buckets of 0, 1, 2, 4, and 5+.
Esse commit está contido em:
@@ -21,9 +21,13 @@
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
const bool enable = getenv("STACKTRACE_PROFILER") != nullptr;
|
||||
const bool enabled = getenv("STACKTRACE_PROFILER") != nullptr;
|
||||
const int kMaxDepth = 10;
|
||||
|
||||
StackTraceProfiler::StackTraceProfiler(std::string name, int skip) :
|
||||
m_name(name), finishing(false), m_root(nullptr), m_skip(skip) {
|
||||
}
|
||||
|
||||
// Make a new caller node and link it into n's caller list.
|
||||
StackTraceProfiler::Node* StackTraceProfiler::makeCaller(Node* n, void* addr) {
|
||||
Node* caller = new (m_arena) Node(addr);
|
||||
@@ -54,7 +58,7 @@ StackTraceProfiler::Node* StackTraceProfiler::findCaller(Node* n, void* addr) {
|
||||
}
|
||||
|
||||
void StackTraceProfiler::count() {
|
||||
if (!enable) return;
|
||||
if (!enabled || finishing) return;
|
||||
void* addrs[kMaxDepth];
|
||||
auto count = backtrace(addrs, kMaxDepth);
|
||||
if (count <= 0) return;
|
||||
@@ -80,12 +84,12 @@ int StackTraceProfiler::numLeaves(Node* n) {
|
||||
}
|
||||
|
||||
void StackTraceProfiler::print(Node* n, std::string indent) {
|
||||
fprintf(stderr, "%s%d ", indent.c_str(), n->hits);
|
||||
fprintf(stderr, "%s%lu ", indent.c_str(), n->hits);
|
||||
if (n->addr) {
|
||||
std::string s = StackTrace::Translate(n->addr)->toString();
|
||||
fprintf(stderr, "%s\n", s.c_str());
|
||||
} else {
|
||||
fprintf(stderr, "%s\n", m_name);
|
||||
fprintf(stderr, "%s\n", m_name.c_str());
|
||||
}
|
||||
if (numLeaves(n) <= 1) return;
|
||||
indent += " ";
|
||||
@@ -100,8 +104,76 @@ void StackTraceProfiler::print(Node* n, std::string indent) {
|
||||
}
|
||||
|
||||
StackTraceProfiler::~StackTraceProfiler() {
|
||||
if (!enable) return;
|
||||
if (!enabled) return;
|
||||
finishing = true;
|
||||
print(&m_root, "");
|
||||
}
|
||||
|
||||
BoolProfiler::BoolProfiler(std::string name)
|
||||
: name(name)
|
||||
, p1(name + "=true", 2)
|
||||
, p0(name + "=false", 2)
|
||||
{}
|
||||
|
||||
BoolProfiler::~BoolProfiler() {
|
||||
if (!enabled) return;
|
||||
auto total = p0.hits() + p1.hits();
|
||||
if (total) {
|
||||
fprintf(stderr, "%s: total=%lu false=%.1f%% true=%.1f%%\n", name.c_str(),
|
||||
total,
|
||||
100.0 * p0.hits() / total,
|
||||
100.0 * p1.hits() / total);
|
||||
}
|
||||
}
|
||||
|
||||
bool BoolProfiler::operator()(bool b) {
|
||||
(b ? &p1 : &p0)->count();
|
||||
return b;
|
||||
}
|
||||
|
||||
IntProfiler::IntProfiler(std::string name)
|
||||
: name(name)
|
||||
, pN(name + ">=65", 2)
|
||||
, p64(name + "=33-64", 2)
|
||||
, p32(name + "=17-32", 2)
|
||||
, p16(name + "=9-16", 2)
|
||||
, p8(name + "=5-8", 2)
|
||||
, p4(name + "=3-4", 2)
|
||||
, p2(name + "=2", 2)
|
||||
, p1(name + "=1", 2)
|
||||
, p0(name + "=0", 2)
|
||||
{}
|
||||
|
||||
IntProfiler::~IntProfiler() {
|
||||
if (!enabled) return;
|
||||
auto total = p0.hits() + p1.hits() + p2.hits() + p4.hits() + p8.hits() +
|
||||
p16.hits() + p32.hits() + p64.hits() + pN.hits();
|
||||
if (total) {
|
||||
fprintf(stderr, "%s: total=%lu 0=%.1f%% 1=%.1f%% 2=%.1f%% "
|
||||
"3-4=%.1f%% 5-8=%.1f%% 9-16=%.1f%% 17-32=%.1f%% 33-64=%.1f%% "
|
||||
"65+=%.1f%%\n", name.c_str(), total,
|
||||
100.0 * p0.hits() / total,
|
||||
100.0 * p1.hits() / total,
|
||||
100.0 * p2.hits() / total,
|
||||
100.0 * p4.hits() / total,
|
||||
100.0 * p8.hits() / total,
|
||||
100.0 * p16.hits() / total,
|
||||
100.0 * p32.hits() / total,
|
||||
100.0 * p64.hits() / total,
|
||||
100.0 * pN.hits() / total);
|
||||
}
|
||||
}
|
||||
|
||||
void IntProfiler::operator()(unsigned i) {
|
||||
(i == 0 ? &p0 :
|
||||
i == 1 ? &p1 :
|
||||
i == 2 ? &p2 :
|
||||
i <= 4 ? &p4 :
|
||||
i <= 8 ? &p8 :
|
||||
i <= 16 ? &p16 :
|
||||
i <= 32 ? &p32 :
|
||||
i <= 64 ? &p64 :
|
||||
&pN)->count();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,19 +47,18 @@ class StackTraceProfiler {
|
||||
void* const addr;
|
||||
Node* callers;
|
||||
Node* next;
|
||||
int hits;
|
||||
size_t hits;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit StackTraceProfiler(const char* name, int skip = 1) :
|
||||
m_name(name), m_root(nullptr), m_skip(skip) {
|
||||
}
|
||||
explicit StackTraceProfiler(std::string name, int skip = 1);
|
||||
~StackTraceProfiler();
|
||||
StackTraceProfiler(const StackTraceProfiler& other) = delete;
|
||||
StackTraceProfiler& operator=(const StackTraceProfiler& other) = delete;
|
||||
|
||||
// count one call in this probe.
|
||||
void count();
|
||||
size_t hits() const { return m_root.hits; }
|
||||
|
||||
private:
|
||||
static bool compareNodes(Node* a, Node* b);
|
||||
@@ -70,12 +69,38 @@ private:
|
||||
|
||||
private:
|
||||
Arena m_arena;
|
||||
const char* m_name;
|
||||
const std::string m_name;
|
||||
std::mutex m_mutex;
|
||||
std::atomic<bool> finishing;
|
||||
Node m_root;
|
||||
int m_skip;
|
||||
};
|
||||
|
||||
/*
|
||||
* BoolProfiler is used to collect profiled samples of a bool variable.
|
||||
*/
|
||||
struct BoolProfiler {
|
||||
explicit BoolProfiler(std::string name);
|
||||
~BoolProfiler();
|
||||
bool operator()(bool b);
|
||||
private:
|
||||
const std::string name;
|
||||
StackTraceProfiler p1, p0;
|
||||
};
|
||||
|
||||
/*
|
||||
* IntProfiler is used to collect profiled samples of an unsiged variable.
|
||||
* A histogram of samples are collected in power-of-2 buckets up to 64.
|
||||
*/
|
||||
struct IntProfiler {
|
||||
explicit IntProfiler(std::string name);
|
||||
~IntProfiler();
|
||||
void operator()(unsigned i);
|
||||
private:
|
||||
const std::string name;
|
||||
StackTraceProfiler pN, p64, p32, p16, p8, p4, p2, p1, p0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário