diff --git a/ServerBench.cpp b/ServerBench.cpp index b1ac88d..5860286 100644 --- a/ServerBench.cpp +++ b/ServerBench.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "ConflictSet.h" #include "third_party/nadeau.h" @@ -175,25 +177,22 @@ double toSeconds(timeval t) { #ifdef __linux__ struct PerfCounter { - PerfCounter(int type, int event) { + PerfCounter(int type, int config, const std::string &labels = {}) + : labels(labels) { struct perf_event_attr pe; memset(&pe, 0, sizeof(pe)); - pe.type = PERF_TYPE_HARDWARE; + pe.type = type; pe.size = sizeof(pe); - pe.config = event; + pe.config = config; pe.inherit = 1; pe.exclude_kernel = 1; pe.exclude_hv = 1; fd = perf_event_open(&pe, 0, -1, -1, 0); - if (fd == -1) { - fprintf(stderr, "Error opening leader %llx\n", pe.config); - exit(EXIT_FAILURE); - } } - int64_t total() { + int64_t total() const { int64_t count; if (read(fd, &count, sizeof(count)) != sizeof(count)) { perror("read instructions from perf"); @@ -202,10 +201,26 @@ struct PerfCounter { return count; } - ~PerfCounter() { close(fd); } + PerfCounter(PerfCounter &&other) + : fd(std::exchange(other.fd, -1)), labels(std::move(other.labels)) {} + PerfCounter &operator=(PerfCounter &&other) { + fd = std::exchange(other.fd, -1); + labels = std::move(other.labels); + return *this; + } + + ~PerfCounter() { + if (fd >= 0) { + close(fd); + } + } + + bool ok() const { return fd >= 0; } + const std::string &getLabels() const { return labels; } private: int fd; + std::string labels; static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { int ret; @@ -235,10 +250,41 @@ int main(int argc, char **argv) { PerfCounter instructions{PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS}; PerfCounter cycles{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES}; - PerfCounter cacheRef{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES}; - PerfCounter cacheMiss{PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES}; - PerfCounter branch{PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS}; - PerfCounter branchMiss{PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES}; + + std::vector cacheCounters; + for (auto [id, idStr] : std::initializer_list>{ + {PERF_COUNT_HW_CACHE_L1D, "l1d"}, + {PERF_COUNT_HW_CACHE_L1I, "l1i"}, + {PERF_COUNT_HW_CACHE_LL, "ll"}, + {PERF_COUNT_HW_CACHE_DTLB, "dtlb"}, + // Somehow was showing a miss rate > 1 /shrug + // {PERF_COUNT_HW_CACHE_ITLB, "itlb"}, + {PERF_COUNT_HW_CACHE_BPU, "bpu"}, + {PERF_COUNT_HW_CACHE_NODE, "node"}, + }) { + for (auto [op, opStr] : + std::initializer_list>{ + {PERF_COUNT_HW_CACHE_OP_READ, "read"}, + {PERF_COUNT_HW_CACHE_OP_WRITE, "write"}, + {PERF_COUNT_HW_CACHE_OP_PREFETCH, "prefetch"}, + }) { + for (auto [result, resultStr] : + std::initializer_list>{ + {PERF_COUNT_HW_CACHE_RESULT_MISS, "miss"}, + {PERF_COUNT_HW_CACHE_RESULT_ACCESS, "access"}, + }) { + auto labels = "{id=\"" + idStr + "\", op=\"" + opStr + + "\", result=\"" + resultStr + "\"}"; + cacheCounters.emplace_back(PERF_TYPE_HW_CACHE, + id | (op << 8) | (result << 16), labels); + if (!cacheCounters.back().ok()) { + fprintf(stderr, "Could not open cache event: %s\n", labels.c_str()); + cacheCounters.pop_back(); + } + } + } + } + auto w = std::thread{workload, &cs}; for (;;) { @@ -276,26 +322,12 @@ int main(int argc, char **argv) { "cycles_total "; body += std::to_string(cycles.total()); body += "\n"; - body += "# HELP cache_references_total Total number of cache references\n" - "# TYPE cache_references_total counter\n" - "cache_references_total "; - body += std::to_string(cacheRef.total()); - body += "\n"; - body += "# HELP cache_misses_total Total number of cache misses\n" - "# TYPE cache_misses_total counter\n" - "cache_misses_total "; - body += std::to_string(cacheMiss.total()); - body += "\n"; - body += "# HELP branch_instructions_total Total number of branch " - "instructions\n" - "# TYPE branch_instructions_total counter\n" - "branch_instructions_total "; - body += std::to_string(branch.total()); - body += "\n"; - body += "# HELP branch_misses_total Total number of branch misses\n" - "# TYPE branch_misses_total counter\n" - "branch_misses_total "; - body += std::to_string(branchMiss.total()); + body += "# HELP cache_event_total Total number of cache events\n" + "# TYPE cache_event_total counter\n"; + for (const auto &counter : cacheCounters) { + body += "cache_event_total" + counter.getLabels() + " " + + std::to_string(counter.total()) + "\n"; + } for (int i = 0; i < metricsCount; ++i) { body += "# HELP ";