Add benchlib
This commit is contained in:
parent
f872119189
commit
11a218b6ab
5 changed files with 195 additions and 0 deletions
103
benching/benchlib/DwBenchmark.cpp
Normal file
103
benching/benchlib/DwBenchmark.cpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
#include "DwBenchmark.hpp"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#ifdef UNWIND_EH_ELF
|
||||||
|
#include "../../stack_walker/stack_walker.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef UNWIND_LIBUNWIND
|
||||||
|
#include <libunwind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
unique_ptr<DwBenchmark> DwBenchmark::instance = nullptr;
|
||||||
|
|
||||||
|
DwBenchmark::DwBenchmark() {
|
||||||
|
#ifdef UNWIND_EH_ELF
|
||||||
|
stack_walker_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DwBenchmark& DwBenchmark::get_instance() {
|
||||||
|
if(!DwBenchmark::instance)
|
||||||
|
instance = unique_ptr<DwBenchmark>(new DwBenchmark);
|
||||||
|
return *instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwBenchmark::unwind_measure() {
|
||||||
|
#ifdef UNWIND_EH_ELF
|
||||||
|
unwind_context_t context = get_context();
|
||||||
|
SingleUnwind this_measure;
|
||||||
|
this_measure.nb_frames = 0;
|
||||||
|
|
||||||
|
auto start_time = chrono::high_resolution_clock::now();
|
||||||
|
while(unwind_context(context)) {
|
||||||
|
this_measure.nb_frames++;
|
||||||
|
}
|
||||||
|
auto end_time = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
this_measure.nanoseconds = chrono::duration_cast<chrono::nanoseconds>(
|
||||||
|
end_time - start_time).count();
|
||||||
|
|
||||||
|
add_measure(this_measure);
|
||||||
|
#elif UNWIND_LIBUNWIND
|
||||||
|
unw_context_t context;
|
||||||
|
int rc = unw_getcontext(&context);
|
||||||
|
if(rc < 0)
|
||||||
|
assert(false);
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
rc = unw_init_local(&cursor, &context);
|
||||||
|
if(rc < 0)
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
SingleUnwind this_measure;
|
||||||
|
this_measure.nb_frames = 0;
|
||||||
|
|
||||||
|
auto start_time = chrono::high_resolution_clock::now();
|
||||||
|
while(unw_step(&cursor) > 0) {
|
||||||
|
this_measure.nb_frames++;
|
||||||
|
}
|
||||||
|
auto end_time = chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
this_measure.nanoseconds = chrono::duration_cast<chrono::nanoseconds>(
|
||||||
|
end_time - start_time).count();
|
||||||
|
|
||||||
|
add_measure(this_measure);
|
||||||
|
#else
|
||||||
|
assert(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwBenchmark::add_measure(const SingleUnwind& measure) {
|
||||||
|
measures.push_back(measure);
|
||||||
|
}
|
||||||
|
void DwBenchmark::add_measure(int nb_frames, size_t microseconds) {
|
||||||
|
add_measure(SingleUnwind({nb_frames, microseconds}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DwBenchmark::format_output(std::ostream& os) const {
|
||||||
|
size_t nb_unwind_frames = 0;
|
||||||
|
size_t total_nanoseconds = 0;
|
||||||
|
|
||||||
|
for(const auto& measure: measures) {
|
||||||
|
nb_unwind_frames += measure.nb_frames;
|
||||||
|
total_nanoseconds += measure.nanoseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
double clock_precision_ns =
|
||||||
|
((double)
|
||||||
|
(1000*1000*1000 * std::chrono::high_resolution_clock::period::num))
|
||||||
|
/ ((double) std::chrono::high_resolution_clock::period::den);
|
||||||
|
|
||||||
|
os << "Total time: " << total_nanoseconds << "ns" << endl
|
||||||
|
<< "Total frames: " << nb_unwind_frames << endl
|
||||||
|
<< "Avg frames/unwind: "
|
||||||
|
<< (double)nb_unwind_frames / (double)measures.size() << endl
|
||||||
|
<< "Avg time/frame: "
|
||||||
|
<< (double)total_nanoseconds / nb_unwind_frames << "ns" << endl
|
||||||
|
<< "Clock precision: " << clock_precision_ns << "ns" << endl;
|
||||||
|
}
|
32
benching/benchlib/DwBenchmark.hpp
Normal file
32
benching/benchlib/DwBenchmark.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class DwBenchmark {
|
||||||
|
/** Singleton class - keeps track of benchmarks performed during a run */
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct SingleUnwind {
|
||||||
|
int nb_frames;
|
||||||
|
size_t nanoseconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
static DwBenchmark& get_instance();
|
||||||
|
|
||||||
|
void unwind_measure(); ///< Unwind from here, and add the measure
|
||||||
|
|
||||||
|
void add_measure(const SingleUnwind& measure); ///< Add this measure
|
||||||
|
void add_measure(int nb_frames, size_t microseconds);
|
||||||
|
|
||||||
|
/** Dump formatted output on `os` displaying stats about this benchmark
|
||||||
|
* run */
|
||||||
|
void format_output(std::ostream& os) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DwBenchmark();
|
||||||
|
|
||||||
|
static std::unique_ptr<DwBenchmark> instance;
|
||||||
|
|
||||||
|
std::vector<SingleUnwind> measures;
|
||||||
|
};
|
32
benching/benchlib/Makefile
Normal file
32
benching/benchlib/Makefile
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
TARGETS=libbench.eh_elf.so libbench.unwind.so
|
||||||
|
COMMON_OBJS=bench.o
|
||||||
|
EH_ELF_OBJS=DwBenchmark.eh_elf.o
|
||||||
|
UNWIND_OBJS=DwBenchmark.unwind.o
|
||||||
|
CXX=g++
|
||||||
|
CXXFLAGS=-Wall -Wextra -O2 -std=c++14
|
||||||
|
CXXLIBS=
|
||||||
|
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
libbench.eh_elf.so: $(EH_ELF_OBJS) $(COMMON_OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) -shared -o $@ $^ $(CXXLIBS) \
|
||||||
|
-L../../stack_walker -lstack_walker.global
|
||||||
|
|
||||||
|
libbench.unwind.so: $(UNWIND_OBJS) $(COMMON_OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) -shared -o $@ $^ $(CXXLIBS) \
|
||||||
|
-lunwind -lunwind-x86_64
|
||||||
|
|
||||||
|
%.eh_elf.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -fPIC -DUNWIND_EH_ELF -o $@ -c $<
|
||||||
|
|
||||||
|
%.unwind.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -fPIC -DUNWIND_LIBUNWIND -o $@ -c $<
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -fPIC -o $@ -c $<
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm *.o $(TARGETS)
|
12
benching/benchlib/bench.cpp
Normal file
12
benching/benchlib/bench.cpp
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#include "bench.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "DwBenchmark.hpp"
|
||||||
|
|
||||||
|
void bench_unwinding() {
|
||||||
|
DwBenchmark::get_instance().unwind_measure();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bench_dump_data() {
|
||||||
|
DwBenchmark::get_instance().format_output(std::cout);
|
||||||
|
}
|
16
benching/benchlib/bench.h
Normal file
16
benching/benchlib/bench.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/** Benchmarking library: a collection of functions that can be called to
|
||||||
|
* benchmark dwarf-assembly
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void bench_unwinding();
|
||||||
|
void bench_dump_data();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // END extern "C"
|
||||||
|
#endif
|
Loading…
Reference in a new issue