update TimingsDatabase to support csv format and incremental updating
This commit is contained in:
parent
0a1eaf26f9
commit
236e5d4623
|
@ -12,9 +12,10 @@ TimingsDatabase::TimingsDatabase()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingsDatabase::TimingsDatabase(const std::string &filename):
|
TimingsDatabase::TimingsDatabase(const std::string &filename, const bool load_previous /*=false*/):
|
||||||
filename(filename)
|
filename(filename)
|
||||||
{
|
{
|
||||||
|
if (load_previous)
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,53 +74,96 @@ bool TimingsDatabase::load()
|
||||||
{
|
{
|
||||||
i.deciles.push_back(atoi(fields[idx++].c_str()));
|
i.deciles.push_back(atoi(fields[idx++].c_str()));
|
||||||
}
|
}
|
||||||
instances.insert(std::make_pair(name, i));
|
instances.emplace_back(name, i);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TimingsDatabase::save()
|
bool TimingsDatabase::save(const bool save_current_time /*=true*/)
|
||||||
{
|
{
|
||||||
if (filename.empty())
|
if (filename.empty() || instances.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
FILE *f = fopen(filename.c_str(), "w");
|
FILE *f = fopen(filename.c_str(), "a"); // append
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
MERROR("Failed to write to file " << filename << ": " << strerror(errno));
|
MERROR("Failed to write to file " << filename << ": " << strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const auto &i: instances)
|
|
||||||
|
if (save_current_time)
|
||||||
{
|
{
|
||||||
fprintf(f, "%s", i.first.c_str());
|
// save current time in readable format (UTC)
|
||||||
fprintf(f, "\t%lu", (unsigned long)i.second.t);
|
std::time_t sys_time{std::time(nullptr)};
|
||||||
fprintf(f, " %zu", i.second.npoints);
|
std::tm *utc_time = std::gmtime(&sys_time); //GMT is equivalent to UTC
|
||||||
fprintf(f, " %f", i.second.min);
|
|
||||||
fprintf(f, " %f", i.second.max);
|
// format: year-month-day : hour:minute:second
|
||||||
fprintf(f, " %f", i.second.mean);
|
std::string current_time{};
|
||||||
fprintf(f, " %f", i.second.median);
|
if (utc_time && sys_time != (std::time_t)(-1))
|
||||||
fprintf(f, " %f", i.second.stddev);
|
{
|
||||||
fprintf(f, " %f", i.second.npskew);
|
char timeString[22]; //length = std::size("yyyy-mm-dd : hh:mm:ss") (constexpr std::size is C++17)
|
||||||
for (uint64_t v: i.second.deciles)
|
std::strftime(timeString, 22, "%F : %T", utc_time);
|
||||||
fprintf(f, " %lu", (unsigned long)v);
|
current_time += timeString;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_time += "TIME_ERROR_";
|
||||||
|
}
|
||||||
|
fputc('\n', f); // add an extra line before each 'print time'
|
||||||
|
fprintf(f, "%s", current_time.c_str());
|
||||||
fputc('\n', f);
|
fputc('\n', f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &i: instances)
|
||||||
|
{
|
||||||
|
fprintf(f, "%s,", i.first.c_str());
|
||||||
|
|
||||||
|
if (i.second.npoints > 0)
|
||||||
|
{
|
||||||
|
fprintf(f, "%lu,", (unsigned long)i.second.t);
|
||||||
|
fprintf(f, "%zu,", i.second.npoints);
|
||||||
|
fprintf(f, "%f,", i.second.min);
|
||||||
|
fprintf(f, "%f,", i.second.max);
|
||||||
|
fprintf(f, "%f,", i.second.mean);
|
||||||
|
fprintf(f, "%f,", i.second.median);
|
||||||
|
fprintf(f, "%f,", i.second.stddev);
|
||||||
|
fprintf(f, "%f,", i.second.npskew);
|
||||||
|
for (uint64_t v: i.second.deciles)
|
||||||
|
fprintf(f, "%lu,", (unsigned long)v);
|
||||||
|
|
||||||
|
// note: only add a new line if there are points; assume that 'no points' means i.first is a message meant to be
|
||||||
|
// prepended to the next save operation
|
||||||
|
fputc('\n', f);
|
||||||
|
}
|
||||||
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
// after saving, clear so next save does not append the same stuff over again
|
||||||
|
instances.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TimingsDatabase::instance> TimingsDatabase::get(const char *name) const
|
const TimingsDatabase::instance* TimingsDatabase::get_most_recent(const char *name) const
|
||||||
{
|
{
|
||||||
std::vector<instance> ret;
|
time_t latest_time = 0;
|
||||||
auto range = instances.equal_range(name);
|
const TimingsDatabase::instance *instance_ptr = nullptr;
|
||||||
for (auto i = range.first; i != range.second; ++i)
|
|
||||||
ret.push_back(i->second);
|
for (const auto &i: instances)
|
||||||
std::sort(ret.begin(), ret.end(), [](const instance &e0, const instance &e1){ return e0.t < e1.t; });
|
{
|
||||||
return ret;
|
if (i.first != name)
|
||||||
|
continue;
|
||||||
|
if (i.second.t < latest_time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
latest_time = i.second.t;
|
||||||
|
instance_ptr = &i.second;
|
||||||
|
}
|
||||||
|
return instance_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimingsDatabase::add(const char *name, const instance &i)
|
void TimingsDatabase::add(const char *name, const instance &i)
|
||||||
{
|
{
|
||||||
instances.insert(std::make_pair(name, i));
|
instances.emplace_back(name, i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class TimingsDatabase
|
class TimingsDatabase
|
||||||
{
|
{
|
||||||
|
@ -18,17 +18,17 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TimingsDatabase();
|
TimingsDatabase();
|
||||||
TimingsDatabase(const std::string &filename);
|
TimingsDatabase(const std::string &filename, const bool load_previous = false);
|
||||||
~TimingsDatabase();
|
~TimingsDatabase();
|
||||||
|
|
||||||
std::vector<instance> get(const char *name) const;
|
const instance* get_most_recent(const char *name) const;
|
||||||
void add(const char *name, const instance &data);
|
void add(const char *name, const instance &data);
|
||||||
|
bool save(const bool print_current_time = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool load();
|
bool load();
|
||||||
bool save();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::multimap<std::string, instance> instances;
|
std::vector<std::pair<std::string, instance>> instances;
|
||||||
};
|
};
|
||||||
|
|
|
@ -249,7 +249,7 @@ bool run_test(const std::string &filter, ParamsT ¶ms_shuttle, const char* te
|
||||||
double stddev = runner.get_stddev();
|
double stddev = runner.get_stddev();
|
||||||
double npskew = runner.get_non_parametric_skew();
|
double npskew = runner.get_non_parametric_skew();
|
||||||
|
|
||||||
std::vector<TimingsDatabase::instance> prev_instances = params.td.get(test_name);
|
const TimingsDatabase::instance* prev_instance = params.td.get_most_recent(test_name);
|
||||||
params.td.add(test_name, {time(NULL), runner.get_size(), min, max, mean, med, stddev, npskew, quantiles});
|
params.td.add(test_name, {time(NULL), runner.get_size(), min, max, mean, med, stddev, npskew, quantiles});
|
||||||
|
|
||||||
std::cout << (params.verbose ? " time per call: " : " ") << time_per_call << " " << unit << "/call" << (params.verbose ? "\n" : "");
|
std::cout << (params.verbose ? " time per call: " : " ") << time_per_call << " " << unit << "/call" << (params.verbose ? "\n" : "");
|
||||||
|
@ -260,15 +260,14 @@ bool run_test(const std::string &filter, ParamsT ¶ms_shuttle, const char* te
|
||||||
uint64_t p95s = quantiles[9] / scale;
|
uint64_t p95s = quantiles[9] / scale;
|
||||||
uint64_t stddevs = stddev / scale;
|
uint64_t stddevs = stddev / scale;
|
||||||
std::string cmp;
|
std::string cmp;
|
||||||
if (!prev_instances.empty())
|
if (prev_instance)
|
||||||
{
|
{
|
||||||
const TimingsDatabase::instance &prev_instance = prev_instances.back();
|
if (!runner.is_same_distribution(prev_instance->npoints, prev_instance->mean, prev_instance->stddev))
|
||||||
if (!runner.is_same_distribution(prev_instance.npoints, prev_instance.mean, prev_instance.stddev))
|
|
||||||
{
|
{
|
||||||
double pc = fabs(100. * (prev_instance.mean - runner.get_mean()) / prev_instance.mean);
|
double pc = fabs(100. * (prev_instance->mean - runner.get_mean()) / prev_instance->mean);
|
||||||
cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance.mean ? "slower" : "faster");
|
cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance->mean ? "slower" : "faster");
|
||||||
}
|
}
|
||||||
cmp += " -- " + std::to_string(prev_instance.mean);
|
cmp += " -- " + std::to_string(prev_instance->mean);
|
||||||
}
|
}
|
||||||
std::cout << " (min " << mins << " " << unit << ", 90th " << p95s << " " << unit << ", median " << meds << " " << unit << ", std dev " << stddevs << " " << unit << ")" << cmp;
|
std::cout << " (min " << mins << " " << unit << ", 90th " << p95s << " " << unit << ", median " << meds << " " << unit << ", std dev " << stddevs << " " << unit << ")" << cmp;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue