Runtime performance analysis for c++ code.
This project was based off of Stabilizer (Github).
Sable aims to get an accurate assessment of a function's runtime in the presence of noise and factors like memory location in both the stack and heap, which can bias a function's performance evaluation.
To do this, multiple samples of the function are taken, with randomized stack and heap paddings created before function execution.
This method aims to approximate the true runtime of the function, regardless of noise and memory location.
Sable works by comparing the runtime of two functions by performing a student's t-test on both functions runtimes. This necessitates three conditions:
- Samples must be random
- The sample must approximate a normal distribution
- Each sample is independent of one another
These are important to keep in mind during usage, especially when setting parameters such as number of trials, which can satistfy condition #2, to be greater than 30, by the Central Limit Theorem
Clone this repository and make using:
$ git clone https://github.com/MaxiBal/sable.git
$ cd sable
$ mkdir build && cd build
$ cmake ..
$ make sable_lib
From this, add the object built into linking and add include/
to targeted include directories.
Finally, add:
#include <sable.hpp>
To compare the runtime of two functions, use sable::compare_runtime
.
sable::TestResult sable::compare_runtime(
void() function1,
void() function2,
float significance_level,
size_t number_of_trials
);
significance_level - determines when null hypothesis should be rejected. Usually 0.01, 0.05 or 0.10.
number_of_trials - should at least be greater than 30
This returns a sable::TestResult
struct, which contains 5 parameters: the runtime data for functions 1 and 2, the probability for the functions to have the same runtime, the student's t-test test statistic, and a summary of the hypotheses.
The hypotheses are summarized by the bitflags in the enum sable::HypothesisTest
, where 0 means a failure to reject the null hypothesis, and a flag is set for the alternate hypotheses: Not Equal, Greater Than, and Less Than.
To print results of a test to stdout, use sable::output_test_result
.
void run_func()
{
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
void run_func2()
{
std::this_thread::sleep_for(std::chrono::microseconds(14));
}
int main()
{
auto test_results = sable::compare_runtime(
run_func,
run_func2,
0.05, // signficance level
100 // # of trials
);
sable::output_test_result(test_results);
return 0;
}
For more examples, see tests:
test/wait.cpp
,test/calc_test.cpp
, andtest/confusion_matrix.cpp
.
Sable watch function compares the functions current runtime, to its previous runtime.
std::optional<TestResult> watch_function(
const std::string& identifier,
void() func,
size_t trials,
float alpha
);
identifier - must be unique for each call
alpha - significance level - determines when null hypothesis should be rejected. Usually 0.01, 0.05 or 0.10.
trials - should at least be greater than 30
Returns - an option of
sable::TestResult
This function saves runtime data to a created file ./sable/[identifier].csv
. This makes it necessary to have a unique identifier for each watch_function
call.
In the event that no data file or sable
directory exists, this function will create the file and path and write headings and runtime data to it.
This function will run a student's t-test (like compare_runtime
) to determine if there is a difference in runtime from the previous execution.
This function returns nullopt
when there is no existing data file (sable/[identifier].csv
), or if it is unable to read from the file. Otherwise, it returns the results of the student's t-test.
void run_func()
{
const size_t duration = 40; // change between compilations
std::this_thread::sleep_for(std::chrono::microseconds(duration));
}
int main()
{
auto test_results = sable::watch_function("WaitFunction", run_func, trials, 0.05);
if (test_results)
sable::output_test_result(test_results.value());
return 0;
}
For further usage examples, see test/
directory.
Make any of the tests using make [TestName]