University of Duisburg-Essen, House of Energy Markets and Finance
2024-07-01
$$ %mathbb alphabet
%mathcal alphabet
%boldsymbols
%greeks
% Transpose like you want to have it % %%\newcommand{}[1]{#1’
%general short cuts$$
I searched a benchmarking tool for my (R)cpp code
I found RcppClock
RcppClock was slow, so I started accelerating it
But why is it so cool?
It’s simple:
class Clock {
private:
std::vector<std::chrono::steady_clock::time_point> tick_times, tock_times;
std::vector<std::string> tick_names, tock_names;
public:
// start a timer
void tick(std::string name) {
tick_names.push_back(name);
tick_times.push_back(std::chrono::steady_clock::now());
}
// stop a timer
void tock(std::string name) {
tock_names.push_back(name);
tock_times.push_back(std::chrono::steady_clock::now());
}
}
Incomplete section for illustration purposes. The complete source is available on GitHub
void stop() {
// Fill `timers` and `tickers` with the results
for (unsigned int i = 0; i < tick_names.size(); ++i) {
for (unsigned int j = 0; j < tock_names.size(); ++j) {
if (tick_names[i] == tock_names[j]) {
timers.push_back(duration(tock_times[j] - tick_times[i]));
tickers.push_back(tick_names[i]);
tock_times.erase(tock_times.begin() + j);
tock_names.erase(tock_names.begin() + j);
break;
}
}
}
// Pass data to R
DataFrame df = DataFrame::create(Named("ticker") = tickers, Named("timer") = timers);
df.attr("class") = "RcppClock";
Environment::global_env()["times"] = df;
}
Incomplete section for illustration purposes. The complete source is available on GitHub
.tock
method..tock
Using std::map
to match .tick()
and .tock()
calls is efficient:
std::map<std::string, tp> tickmap;
// Start timer: write name + time into tickmap
void tick(std::string name)
{
tickmap.insert(std::pair<std::string, tp>(name, sc::high_resolution_clock::now()));
}
// Stop timer: write duration into timers, save key
void tock(std::string name)
{
timers.push_back(
sc::duration_cast<sc::nanoseconds>(
sc::high_resolution_clock::now() - tickmap[name]
).count()
);
keys.push_back(name);
}
At this stage, RcppTimer can’t handle OpenMP parralelism as it can’t distinguish between threads.
Simple solution: Add Threadnumber to the Key of the tickmap
.
At this stage, RcppTimer can’t handle OpenMP parralelism as it can’t distinguish between threads.
Simple solution: Add Threadnumber to the Key of the tickmap
.
Parallelism can cause memory access problems
But we can “lock” objects in OMP threads, before accessing them
Parallelism can cause memory access problems
But we can “lock” objects in OMP threads, before accessing them
The Timer::ScopedTimer
calls
tic
at instantiation andtoc
as it goes out of scopeThe Timer::ScopedTimer
calls
tic
at instantiation andtoc
as it goes out of scopeReturning whole timers
and names
vectors is unnecessary
New aggregate()
method
names
vector, Iterates over all timers
Destructor calls aggregate()
:
~clock()
stop()
{ aggregate()
Return results }
rcpptimer
Includes cpptimer as submodule
R-Specific Code
stop()
cpptimer
Shared C++ core
Header only
Contains aggregate
method
cppytimer
Includes cpptimer as submodule
Python specific code
stop()
Simple
Powefull
ISF 2024