Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ project(chron-cpp VERSION ${ORYX_CHRON_VERSION} LANGUAGES CXX)
message(STATUS "Build ${PROJECT_NAME}: ${PROJECT_VERSION}")

option(ORYX_CHRON_BUILD_SHARED_LIBS "Build shared library" ${BUILD_SHARED_LIBS})
option(ORYX_CHRON_BUILD_BENCHMARKS "Build Benchmarks" OFF)
option(ORYX_CHRON_BUILD_TESTS "Build tests" OFF)
option(ORYX_CHRON_INSTALL "Install the project" OFF)
option(ORYX_CHRON_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
Expand Down Expand Up @@ -106,6 +107,22 @@ if(ORYX_CHRON_BUILD_TESTS)
endif()
endif()

if(ORYX_CHRON_BUILD_BENCHMARKS)
set(bench_exe ${PROJECT_NAME}_benchmarks)
include(FetchContent)
FetchContent_Declare(
libcron
GIT_REPOSITORY https://github.com/PerMalmberg/libcron.git
GIT_TAG master
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(libcron)


add_executable(${bench_exe} benchmarks/main.cpp)
target_link_libraries(${bench_exe} PRIVATE ${PROJECT_NAME} libcron)
endif()

if (ORYX_CHRON_INSTALL)
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,25 @@ when using randomization, i.e. mutual exclusiveness and no extra spaces.
| 0 R(45-15) */12 ? * * | A random minute between 45-15, inclusive, every 12 hours.
|0 0 0 ? R(DEC-MAR) R(SAT-SUN)| On the hour, on a random month december to march, on a random weekday saturday to sunday.

## Performance

These are some initial benchmarks on cron-parsing and cron randomization comparing against libcron:

OS: Linux
CPU: AMD Ryzen 9 7950X 16-Core Processor

| relative | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | Parsing randomized Expressions
|---------:|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:-------------------------------
| 100.0% | 102,326.11 | 9,772.68 | 1.2% | 1,013,843.99 | 548,690.22 | 1.848 | 152,240.32 | 0.3% | 23.50 | `ExpressionParser`
| 9.2% | 1,116,211.84 | 895.89 | 40.5% | 16,046,595.84 | 5,985,076.41 | 2.681 | 2,785,616.84 | 0.0% | 247.82 | `CachedExpressionParser<NullMutex>`
| 9.3% | 1,103,677.48 | 906.06 | 40.3% | 16,042,923.93 | 5,952,656.76 | 2.695 | 2,785,005.43 | 0.1% | 245.24 | `CachedExpressionParser<std::mutex>`
| 7.9% | 1,298,631.94 | 770.04 | 0.2% | 13,982,049.29 | 7,033,908.92 | 1.988 | 2,239,027.96 | 0.4% | 285.72 | `libcron::CronData::create`

| relative | ns/op | op/s | err% | ins/op | cyc/op | IPC | bra/op | miss% | total | Randomization
|---------:|--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:--------------
| 100.0% | 85,454.44 | 11,702.14 | 0.5% | 879,301.99 | 463,006.51 | 1.899 | 134,616.91 | 0.3% | 93.98 | `chron-cpp`
| 5.7% | 1,493,531.23 | 669.55 | 0.2% | 16,608,204.87 | 8,084,464.40 | 2.054 | 2,685,597.92 | 0.4% | 1,643.85 | `libcron`

## Adding this library to your project

```cmake
Expand Down
56 changes: 56 additions & 0 deletions benchmarks/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#define ANKERL_NANOBENCH_IMPLEMENT
#include "nanobench.hpp"

#include <oryx/chron/parser.hpp>
#include <oryx/chron/randomization.hpp>

#include <libcron/CronData.h>
#include <libcron/CronRandomization.h>

using namespace oryx::chron;
using namespace ankerl;

const std::string kRandomSchedule = "R(0-59) R(0-59) R(0-23) R(1-31) R(JAN-DEC) ?";

template <typename Parser>
void bench(ankerl::nanobench::Bench* bench, char const* name) {
Parser parser;
Randomization rng;

bench->run(name, [&] { ankerl::nanobench::doNotOptimizeAway(parser(rng.Parse(kRandomSchedule).value()).value()); });
}

void bench(ankerl::nanobench::Bench* bench, char const* name) {
Randomization rng;

bench->run(name, [&] {
ankerl::nanobench::doNotOptimizeAway(libcron::CronData::create(rng.Parse(kRandomSchedule).value()));
});
}

auto main() -> int {
static const auto kCachedParse = CachedExpressionParser();
static const auto kMtx = CachedExpressionParser<std::mutex>();

ankerl::nanobench::Bench b;
b.title("Parsing randomized Expressions").epochIterations(20000).relative(true).performanceCounters(true);

bench<ExpressionParser>(&b, "ExpressionParser");
bench<CachedExpressionParser<>>(&b, "CachedExpressionParser<NullMutex>");
bench<CachedExpressionParser<std::mutex>>(&b, "CachedExpressionParser<std::mutex>");
bench(&b, "libcron::CronData::create");

ankerl::nanobench::Bench b2;
Randomization rng1;
libcron::CronRandomization rng2;

b2.title("Randomization").epochIterations(100000).relative(true).performanceCounters(true);
b2.run("chron-cpp", [&] {
auto r = rng1.Parse(kRandomSchedule);
nanobench::doNotOptimizeAway(r);
});
b2.run("libcron", [&] {
auto r = rng2.parse(kRandomSchedule);
nanobench::doNotOptimizeAway(r);
});
}
Loading