Skip to content

Commit

Permalink
Add timeout operator (#287)
Browse files Browse the repository at this point in the history
  • Loading branch information
victimsnino authored Nov 2, 2022
1 parent 2ae50e7 commit 97144f7
Show file tree
Hide file tree
Showing 13 changed files with 387 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/Implementation Status.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
- [x] do_on_next
- [x] do_on_error
- [x] do_on_completed
- [ ] timeout
- [x] timeout

### Connectable

Expand Down
21 changes: 21 additions & 0 deletions src/benchmarks/rpp_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <rpp/observers/specific_observer.hpp>
#include <rpp/operators.hpp>
#include <rpp/subjects.hpp>
#include <rpp/schedulers/run_loop_scheduler.hpp>
#include <rpp/schedulers/trampoline_scheduler.hpp>
#include <rpp/utils/spinlock.hpp>

Expand Down Expand Up @@ -859,6 +860,26 @@ TEST_CASE("skip")
};
}

TEST_CASE("timeout")
{

BENCHMARK_ADVANCED("timeout construction from observable via dot + subscribe with run_loop")(Catch::Benchmark::Chronometer meter)
{
const auto obs = rpp::observable::create<int>([](const auto& sub) { sub.on_next(1); });
auto sub = rpp::specific_subscriber{[](const int&) {}};
rpp::schedulers::run_loop rl{};
meter.measure([&] { return obs.timeout(std::chrono::days{30}, rl).subscribe(sub); });
};

BENCHMARK_ADVANCED("sending of values from observable via timeout to subscriber with unreachable timeout interval with run_loop")(Catch::Benchmark::Chronometer meter)
{
rpp::schedulers::run_loop rl{};
rpp::source::create<int>([&](const auto& sub) { meter.measure([&] { sub.on_next(1); }); })
.timeout(std::chrono::days{30}, rl)
.subscribe([](const auto&) {});
};
}

TEST_CASE("chains creation test")
{
BENCHMARK_ADVANCED("long non-state chain creation + subscribe")(Catch::Benchmark::Chronometer meter)
Expand Down
19 changes: 19 additions & 0 deletions src/benchmarks/rxcpp_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,25 @@ TEST_CASE("skip")
};
}

TEST_CASE("timeout")
{
BENCHMARK_ADVANCED("timeout construction from observable via dot + subscribe with run_loop")(Catch::Benchmark::Chronometer meter)
{
const auto obs = rxcpp::sources::create<int>([](const auto& sub) { sub.on_next(1); });
auto sub = rxcpp::make_subscriber<int>([](const int&) {});
rxcpp::schedulers::run_loop rl{};
meter.measure([&] { return obs.timeout(std::chrono::days{30}, rxcpp::observe_on_run_loop(rl)).subscribe(sub); });
};

BENCHMARK_ADVANCED("sending of values from observable via timeout to subscriber with unreachable timeout interval with run_loop")(Catch::Benchmark::Chronometer meter)
{
rxcpp::schedulers::run_loop rl{};
rxcpp::sources::create<int>([&](const auto& sub) { meter.measure([&] { sub.on_next(1); }); })
.timeout(std::chrono::days{30}, rxcpp::observe_on_run_loop(rl))
.subscribe([](const auto&) {});
};
}

TEST_CASE("chains creation test")
{
BENCHMARK_ADVANCED("long non-state chain creation + subscribe")(Catch::Benchmark::Chronometer meter)
Expand Down
42 changes: 42 additions & 0 deletions src/examples/doxygen/timeout.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <rpp/rpp.hpp>

#include <iostream>

/**
* \example timeout.cpp
**/
int main()
{
//! [timeout]
rpp::subjects::publish_subject<int> subj{};
subj.get_observable()
.timeout(std::chrono::milliseconds{450}, rpp::schedulers::new_thread{})
.subscribe([](int v) { std::cout << "new value " << v << std::endl; },
[](std::exception_ptr err)
{
try
{
std::rethrow_exception(err);
}
catch (const std::exception& exc)
{
std::cout << "ERR: " << exc.what() << std::endl;
}
},
[]() { std::cout << "completed" << std::endl; });
for (int i = 0; i < 10; ++i)
{
std::this_thread::sleep_for(std::chrono::milliseconds{i * 100});
subj.get_subscriber().on_next(i);
}

// Output:
// new value 0
// new value 1
// new value 2
// new value 3
// new value 4
// ERR : Timeout reached
//! [timeout]
return 0;
}
1 change: 1 addition & 0 deletions src/rpp/rpp/observables/interface_observable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct RPP_EMPTY_BASES interface_observable
, details::member_overload<Type, SpecificObservable, details::take_tag>
, details::member_overload<Type, SpecificObservable, details::take_until_tag>
, details::member_overload<Type, SpecificObservable, details::take_while_tag>
, details::member_overload<Type, SpecificObservable, details::timeout_tag>
, details::member_overload<Type, SpecificObservable, details::window_tag>
, details::member_overload<Type, SpecificObservable, details::with_latest_from_tag>
{
Expand Down
1 change: 1 addition & 0 deletions src/rpp/rpp/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include <rpp/operators/observe_on.hpp>
#include <rpp/operators/repeat.hpp>
#include <rpp/operators/subscribe_on.hpp>
#include <rpp/operators/timeout.hpp>

/**
* \defgroup connectable_operators Connectable Operators
Expand Down
1 change: 1 addition & 0 deletions src/rpp/rpp/operators/fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@
#include <rpp/operators/fwd/take_last.hpp>
#include <rpp/operators/fwd/take_until.hpp>
#include <rpp/operators/fwd/take_while.hpp>
#include <rpp/operators/fwd/timeout.hpp>
#include <rpp/operators/fwd/window.hpp>
#include <rpp/operators/fwd/with_latest_from.hpp>
61 changes: 61 additions & 0 deletions src/rpp/rpp/operators/fwd/timeout.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// ReactivePlusPlus library
//
// Copyright Aleksey Loginov 2022 - present.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/victimsnino/ReactivePlusPlus
//

#pragma once

#include <rpp/schedulers/constraints.hpp>

#include <rpp/observables/details/member_overload.hpp>

namespace rpp::details
{
struct timeout_tag;
}

namespace rpp::details
{
template<constraint::decayed_type Type, schedulers::constraint::scheduler TScheduler>
struct timeout_impl;

template<constraint::decayed_type Type, typename SpecificObservable>
struct member_overload<Type, SpecificObservable, timeout_tag>
{
/**
* \brief Forwards emissions from original observable, but emit error if no any events during specified period of time (since last emission)
*
* \marble timeout
{
source observable : +--1-2-3-4------5-|
operator "timeout(4)" : +--1-2-3-4----#
}
* \param period is maximum duration between emitted items before a timeout occurs
* \param scheduler is scheduler used to run timer for timeout
* \return new specific_observable with the timeout operator as most recent operator.
* \warning #include <rpp/operators/timeout.hpp>
*
* \par Example
* \snippet timeout.cpp timeout
*
* \ingroup utility_operators
* \see https://reactivex.io/documentation/operators/timeout.html
*/
template<schedulers::constraint::scheduler TScheduler>
auto timeout(schedulers::duration period, const TScheduler& scheduler = TScheduler{}) const & requires is_header_included<timeout_tag, TScheduler>
{
return static_cast<const SpecificObservable*>(this)->template lift<Type>(timeout_impl<Type, TScheduler>{period, scheduler});
}

template<schedulers::constraint::scheduler TScheduler>
auto timeout(schedulers::duration period, const TScheduler& scheduler = TScheduler{}) && requires is_header_included<timeout_tag, TScheduler>
{
return std::move(*static_cast<SpecificObservable*>(this)).template lift<Type>(timeout_impl<Type, TScheduler>{period, scheduler});
}
};
} // namespace rpp::details
119 changes: 119 additions & 0 deletions src/rpp/rpp/operators/timeout.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// ReactivePlusPlus library
//
// Copyright Aleksey Loginov 2022 - present.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/victimsnino/ReactivePlusPlus
//

#pragma once

#include <rpp/operators/lift.hpp> // required due to operator uses lift
#include <rpp/operators/details/early_unsubscribe.hpp>
#include <rpp/operators/details/serialized_subscriber.hpp>
#include <rpp/operators/details/subscriber_with_state.hpp>
#include <rpp/operators/fwd/timeout.hpp>
#include <rpp/subscribers/constraints.hpp>
#include <rpp/utils/exceptions.hpp>

#include <rpp/utils/spinlock.hpp>

#include <atomic>

IMPLEMENTATION_FILE(timeout_tag);

namespace rpp::details
{
struct timeout_state : early_unsubscribe_state
{
using early_unsubscribe_state::early_unsubscribe_state;

std::atomic<schedulers::time_point> last_emission_time{};

static constexpr schedulers::time_point s_timeout_reached = schedulers::time_point::min();
};

template<typename Worker>
struct timeout_on_next
{
template<typename Value>
void operator()(Value&& v, const auto& subscriber, const std::shared_ptr<timeout_state>& state) const
{
if (state->last_emission_time.exchange(Worker::now(), std::memory_order_acq_rel) != timeout_state::s_timeout_reached)
subscriber.on_next(std::forward<Value>(v));
}
};

using timeout_on_error = early_unsubscribe_on_error;
using timeout_on_completed = early_unsubscribe_on_completed;

struct timeout_state_with_serialized_spinlock : timeout_state
{
using timeout_state::timeout_state;

// spinlock because most part of time there is only one thread would be active
utils::spinlock spinlock{};
};

template<constraint::decayed_type Type, schedulers::constraint::scheduler TScheduler>
struct timeout_impl
{
schedulers::duration period;
TScheduler scheduler;

template<constraint::subscriber_of_type<Type> TSub>
auto operator()(TSub&& in_subscriber) const
{
auto state = std::make_shared<timeout_state_with_serialized_spinlock>(in_subscriber.get_subscription());
// change subscriber to serialized to avoid manual using of mutex
auto subscriber = make_serialized_subscriber(std::forward<TSub>(in_subscriber),
std::shared_ptr<utils::spinlock>{state, &state->spinlock});

const auto worker = scheduler.create_worker(state->children_subscriptions);
state->last_emission_time.store(worker.now(), std::memory_order_relaxed);

const auto last_emission_time = state->last_emission_time.load(std::memory_order_relaxed);
worker.schedule(last_emission_time + period,
[period = period, prev_emission_time = last_emission_time, subscriber, state]() mutable -> schedulers::optional_duration
{
while (true)
{
// last emission time still same value -> timeout reached, else -> prev_emission_time
// would be update to actual emission time
if (state->last_emission_time.compare_exchange_strong(prev_emission_time,
timeout_state::s_timeout_reached,
std::memory_order_acq_rel))
return time_is_out(state, subscriber);

// if we still need to wait a bit more -> let's wait
if (const auto diff_to_schedule = (prev_emission_time + period) - decltype(worker)::now();
diff_to_schedule > rpp::schedulers::duration{0})
return diff_to_schedule;

// okay, we here because:
// 1) last_emission_time was not equal to prev_emission_time
// 2) last_emission_time + period before now -> we are still in timeout state
// 3) prev_emission_time updated to last_emission_time
// So we can return to begin
}
});

return create_subscriber_with_state<Type>(state->children_subscriptions,
timeout_on_next<decltype(worker)>{},
timeout_on_error{},
timeout_on_completed{},
std::move(subscriber),
std::move(state));
}

private:
static schedulers::optional_duration time_is_out(const auto& state, const auto& subscriber)
{
state->children_subscriptions.unsubscribe();
subscriber.on_error(std::make_exception_ptr(utils::timeout{"Timeout reached"}));
return std::nullopt;
}
};
} // namespace rpp::details
2 changes: 2 additions & 0 deletions src/rpp/rpp/schedulers/details/worker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class worker final : public details::worker_tag
m_strategy.defer_at(time_point, std::forward<decltype(fn)>(fn));
}

static time_point now() { return Strategy::now(); }

private:
Strategy m_strategy;
};
Expand Down
5 changes: 4 additions & 1 deletion src/rpp/rpp/utils/exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@

namespace rpp::utils
{

struct not_enough_emissions : std::runtime_error
{
using std::runtime_error::runtime_error;
};

struct timeout : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace rpp::utils
2 changes: 1 addition & 1 deletion src/tests/test_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include <rpp/schedulers.hpp>

static rpp::schedulers::time_point s_current_time{std::chrono::seconds{0}};
static rpp::schedulers::time_point s_current_time{std::chrono::seconds{10}};

class test_scheduler final : public rpp::schedulers::details::scheduler_tag
{
Expand Down
Loading

1 comment on commit 97144f7

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BENCHMARK RESULTS (AUTOGENERATED)

ci-ubuntu-clang

Observable construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable construction 0.34ns 0.32506 1.03 0.34ns
Dynamic observable construction 29.14ns 30.0954 0.97 24.30ns
Specific observable construction + as_dynamic 29.17ns 30.0351 0.97 24.34ns

Observable lift

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable lift specific observer 88.88ns 105.42 0.84 290.46ns
Specific observable lift dynamic observer 112.49ns 133.682 0.84 306.79ns
Dynamic observable lift specific observer 171.97ns 183.376 0.94 333.88ns
Dynamic observable lift dynamic observer 177.31ns 202.233 0.88 322.37ns

Observable subscribe

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe specific observer 57.96ns 74.6762 0.78 290.75ns
Specific observable subscribe dynamic observer 71.52ns 77.0957 0.93 297.50ns
Dynamic observable subscribe specific observer 126.48ns 140.036 0.90 330.79ns
Dynamic observable subscribe dynamic observer 123.94ns 159.015 0.78 316.73ns

Observable subscribe #2

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe lambda 58.03ns 64.6849 0.90 289.75ns
Dynamic observable subscribe lambda 123.95ns 131.859 0.94 329.62ns
Specific observable subscribe lambda without subscription 58.17ns 64.7068 0.90 289.35ns
Dynamic observable subscribe lambda without subscription 124.70ns 134.402 0.93 331.81ns
Specific observable subscribe specific subscriber 27.86ns 32.639 0.85 228.93ns
Dynamic observable subscribe specific subscriber 88.79ns 89.8663 0.99 273.07ns
Specific observable subscribe dynamic observer 27.80ns 33.3988 0.83 237.89ns
Dynamic observable subscribe dynamic observer 77.29ns 92.8311 0.83 261.54ns

Observer construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer construction 0.34ns 0.365854 0.92 0.33ns
Dynamic observer construction 29.20ns 29.7256 0.98 21.81ns
Specific observer construction + as_dynamic 29.20ns 33.0315 0.88 21.37ns

OnNext

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer OnNext 0.67ns 0.710108 0.94 0.67ns
Dynamic observer OnNext 2.01ns 2.09704 0.96 2.35ns

Subscriber construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Make subsriber 34.88ns 35.4824 0.98 64.76ns
Make copy of subscriber 16.75ns 21.2406 0.79 4.71ns
Transform subsriber to dynamic 43.52ns 48.5076 0.90 26.34ns

Subscription

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
composite_subscription create 34.86ns 38.1346 0.91 51.81ns
composite_subscription add 47.43ns 58.793 0.81 94.19ns
composite_subscription unsubscribe 43.41ns 49.3086 0.88 23.36ns

buffer

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
buffer 244.66ns 298.305 0.82 1839.55ns
sending of values from observable via buffer to subscriber 5.36ns 10.8759 0.49 27.40ns

chains creation test

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
long non-state chain creation + subscribe 254.19ns 296.756 0.86 504.35ns
long stateful chain creation + subscribe 375.59ns 430.671 0.87 1542.84ns

combine_latest

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
combine_latest construction from observable via dot + subscribe 858.53ns 987.344 0.87 931.89ns
sending of values from observable via combine_latest to subscriber 27.45ns 33.8351 0.81 1.74ns

concat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
concat 1876.91ns 2186.81 0.86 3333.05ns
concat_with 2160.25ns 2483.61 0.87 3720.72ns

distinct_until_changed

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
distinct_until_changed construction from observable via dot + subscribe 111.00ns 122.782 0.90 247.43ns
sending of values from observable via distinct_until_changed to subscriber 2.68ns 2.9764 0.90 2.35ns

first

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
first construction from observable via dot + subscribe 122.76ns 156.913 0.78 588.71ns
sending of values from observable via first to subscriber 0.67ns 0.579328 1.16 0.67ns

foundamental sources

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
empty 61.82ns 75.3907 0.82 620.03ns
error 111.67ns 121.792 0.92 753.89ns
never 28.78ns 35.5697 0.81 250.21ns

from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
from vector with int 79.60ns 118.186 0.67 657.40ns

immediate scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 1.34ns 0.669103 2.01 111.79ns
re-schedule 10 times 11.46ns 10.6556 1.08 143.49ns

just

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
just send int 64.89ns 74.1443 0.88 630.56ns
just send variadic 94.98ns 158.039 0.60 760.23ns

last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
last construction from observable via dot + subscribe 168.95ns 193.473 0.87 354.81ns
sending of values from observable via last to subscriber 2.09ns 3.42128 0.61 1.68ns

map

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
map construction from observable via dot + subscribe 68.63ns 78.287 0.88 240.11ns
sending of values from observable via map to subscriber 1.34ns 0.912247 1.47 1.51ns

merge

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
merge 1817.20ns 2038.22 0.89 3291.15ns
merge_with 2101.97ns 2418.03 0.87 3499.94ns

observe_on

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
observe_on construction from observable via dot + subscribe 426.45ns 459.829 0.93 2611.64ns
sending of values from observable via observe_on to subscriber 61.36ns 65.137 0.94 200.56ns

on_error_resume_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_error_resume_next construction from observable via dot + subscribe 421.02ns 505.087 0.83 986.50ns

publish_subject callbacks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_next 24.14ns 26.1878 0.92 10.73ns
on_error 0.67ns 0.654009 1.03 19.19ns
on_completed 0.67ns 0.828633 0.81 0.67ns

publish_subject routines

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
construct 196.43ns 208.552 0.94 178.50ns
get_observable 26.50ns 32.1471 0.82 50.65ns
get_subscriber 60.57ns 61.6486 0.98 13.20ns

repeat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
repeat construction from observable via dot + subscribe 3914.68ns 4632.34 0.85 3026.80ns

scan

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
scan construction from observable via dot + subscribe 100.22ns 113.907 0.88 293.37ns
sending of values from observable via scan to subscriber 2.01ns 2.73791 0.73 2.02ns

single-threaded locks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no-lock increment 2.02ns 2.73283 0.74 .
mutex lock increment 18.12ns 22.0746 0.82 .
spin-lock increment 9.04ns 12.3506 0.73 .

skip

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
skip construction from observable via dot + subscribe 98.51ns 115.92 0.85 493.43ns
sending of values from observable via skip to subscriber 2.35ns 4.34633 0.54 1.78ns

switch_on_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
switch_on_next construction from observable via dot + subscribe 2193.68ns 2644.02 0.83 2831.28ns
sending of values from observable via switch_on_next to subscriber 567.58ns 633.807 0.90 644.37ns

take

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take construction from observable via dot + subscribe 168.82ns 210.983 0.80 486.13ns
sending of values from observable via take to subscriber 2.35ns 2.50303 0.94 3.37ns

take_last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_last construction from observable via dot + subscribe 210.84ns 256.682 0.82 523.59ns
sending of values from observable via take_last to subscriber 2.69ns 4.19017 0.64 3.79ns

take_until

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_until construction from observable via dot + subscribe 1024.26ns 1217.89 0.84 1177.90ns
sending of values from observable via take_until to subscriber 9.07ns 12.6961 0.71 1.84ns

timeout

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
timeout construction from observable via dot + subscribe with run_loop 875.55ns None . 19397.80ns
sending of values from observable via timeout to subscriber with unreachable timeout interval with run_loop 55.82ns None . 18898.50ns

trampoline scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 12.28ns 13.2574 0.93 160.91ns
re-schedule 10 times 32.56ns 44.7886 0.73 188.18ns
recursively schedule 10 times 1393.43ns 1596.49 0.87 8018.12ns

window

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
window 1999.22ns 2280.1 0.88 3172.93ns
sending of values from observable via window to subscriber 541.72ns 707.11 0.77 366.42ns

with_latest_from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
with_latest_from construction from observable via dot + subscribe 1016.75ns 1215.27 0.84 1221.81ns
sending of values from observable via with_latest_from to subscriber 27.10ns 30.1597 0.90 3.07ns

ci-ubuntu-gcc

Observable construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable construction 0.40ns 0.405931 0.99 0.40ns
Dynamic observable construction 29.47ns 37.8163 0.78 22.64ns
Specific observable construction + as_dynamic 29.05ns 37.8035 0.77 21.74ns

Observable lift

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable lift specific observer 95.32ns 111.932 0.85 346.82ns
Specific observable lift dynamic observer 128.49ns 147.306 0.87 372.20ns
Dynamic observable lift specific observer 189.54ns 198.419 0.96 460.67ns
Dynamic observable lift dynamic observer 206.04ns 232.343 0.89 389.25ns

Observable subscribe

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe specific observer 59.60ns 74.9256 0.80 346.27ns
Specific observable subscribe dynamic observer 78.64ns 92.9943 0.85 358.57ns
Dynamic observable subscribe specific observer 128.86ns 147.476 0.87 392.86ns
Dynamic observable subscribe dynamic observer 133.17ns 152.463 0.87 368.99ns

Observable subscribe #2

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe lambda 59.55ns 72.4813 0.82 351.72ns
Dynamic observable subscribe lambda 129.60ns 157.321 0.82 385.14ns
Specific observable subscribe lambda without subscription 59.94ns 71.6302 0.84 360.27ns
Dynamic observable subscribe lambda without subscription 128.96ns 156.952 0.82 384.59ns
Specific observable subscribe specific subscriber 26.90ns 34.5288 0.78 280.72ns
Dynamic observable subscribe specific subscriber 96.47ns 117.931 0.82 323.93ns
Specific observable subscribe dynamic observer 27.04ns 36.4824 0.74 288.38ns
Dynamic observable subscribe dynamic observer 91.27ns 99.5 0.92 293.67ns

Observer construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer construction 0.40ns 0.402267 1.00 0.40ns
Dynamic observer construction 30.24ns 37.7961 0.80 18.98ns
Specific observer construction + as_dynamic 28.79ns 37.3725 0.77 18.46ns

OnNext

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer OnNext 0.43ns 0.403304 1.07 0.44ns
Dynamic observer OnNext 2.01ns 2.41763 0.83 1.60ns

Subscriber construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Make subsriber 33.79ns 41.3938 0.82 60.47ns
Make copy of subscriber 23.32ns 20.1755 1.16 5.93ns
Transform subsriber to dynamic 50.61ns 51.2983 0.99 21.55ns

Subscription

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
composite_subscription create 33.91ns 40.9629 0.83 57.84ns
composite_subscription add 54.26ns 57.9825 0.94 97.95ns
composite_subscription unsubscribe 45.18ns 50.2199 0.90 21.23ns

buffer

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
buffer 240.78ns 283.091 0.85 2000.85ns
sending of values from observable via buffer to subscriber 6.39ns 7.62014 0.84 26.50ns

chains creation test

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
long non-state chain creation + subscribe 326.18ns 303.116 1.08 685.37ns
long stateful chain creation + subscribe 469.35ns 489.933 0.96 1441.99ns

combine_latest

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
combine_latest construction from observable via dot + subscribe 944.41ns 1094.75 0.86 1267.24ns
sending of values from observable via combine_latest to subscriber 33.76ns 32.967 1.02 1.61ns

concat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
concat 2011.25ns 2273.5 0.88 3905.35ns
concat_with 2383.83ns 2588.5 0.92 4327.54ns

distinct_until_changed

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
distinct_until_changed construction from observable via dot + subscribe 119.31ns 145.121 0.82 385.14ns
sending of values from observable via distinct_until_changed to subscriber 3.21ns 2.83226 1.13 1.28ns

first

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
first construction from observable via dot + subscribe 148.13ns 166.35 0.89 762.87ns
sending of values from observable via first to subscriber 1.21ns 1.23025 0.98 0.81ns

foundamental sources

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
empty 68.30ns 80.6234 0.85 794.94ns
error 117.47ns 136.018 0.86 847.08ns
never 29.09ns 36.5464 0.80 291.94ns

from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
from vector with int 81.13ns 95.8551 0.85 794.02ns

immediate scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 0.80ns 1.46735 0.55 128.26ns
re-schedule 10 times 19.24ns 24.8876 0.77 164.93ns

just

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
just send int 71.14ns 85.0621 0.84 781.50ns
just send variadic 94.50ns 138.526 0.68 843.54ns

last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
last construction from observable via dot + subscribe 181.54ns 205.173 0.88 459.17ns
sending of values from observable via last to subscriber 1.80ns 2.45554 0.73 1.43ns

map

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
map construction from observable via dot + subscribe 82.80ns 93.538 0.89 348.37ns
sending of values from observable via map to subscriber 0.80ns 1.57908 0.51 1.61ns

merge

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
merge 1971.26ns 2230.19 0.88 4069.60ns
merge_with 2348.68ns 2578.07 0.91 4593.97ns

observe_on

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
observe_on construction from observable via dot + subscribe 481.74ns 535.718 0.90 2717.82ns
sending of values from observable via observe_on to subscriber 72.30ns 85.5063 0.85 230.80ns

on_error_resume_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_error_resume_next construction from observable via dot + subscribe 458.65ns 521.509 0.88 898.12ns

publish_subject callbacks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_next 29.82ns 26.9678 1.11 9.65ns
on_error 0.81ns 0.795785 1.02 16.16ns
on_completed 0.81ns 1.59101 0.51 0.81ns

publish_subject routines

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
construct 209.80ns 262.031 0.80 147.15ns
get_observable 33.62ns 35.373 0.95 45.35ns
get_subscriber 63.93ns 68.8386 0.93 21.48ns

repeat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
repeat construction from observable via dot + subscribe 4319.54ns 5038.5 0.86 3251.68ns

scan

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
scan construction from observable via dot + subscribe 113.86ns 134.609 0.85 401.33ns
sending of values from observable via scan to subscriber 2.01ns 1.77698 1.13 1.74ns

single-threaded locks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no-lock increment 0.80ns 2.32227 0.35 .
mutex lock increment 22.19ns 20.3141 1.09 .
spin-lock increment 10.45ns 11.2293 0.93 .

skip

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
skip construction from observable via dot + subscribe 113.57ns 138.452 0.82 554.57ns
sending of values from observable via skip to subscriber 3.22ns 2.77016 1.16 2.77ns

switch_on_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
switch_on_next construction from observable via dot + subscribe 2460.48ns 2627.3 0.94 4518.14ns
sending of values from observable via switch_on_next to subscriber 647.22ns 729.914 0.89 1207.83ns

take

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take construction from observable via dot + subscribe 172.62ns 189.596 0.91 617.16ns
sending of values from observable via take to subscriber 4.06ns 4.03075 1.01 3.22ns

take_last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_last construction from observable via dot + subscribe 215.88ns 244.242 0.88 682.56ns
sending of values from observable via take_last to subscriber 3.38ns 3.34896 1.01 6.37ns

take_until

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_until construction from observable via dot + subscribe 1121.18ns 1300.01 0.86 1806.81ns
sending of values from observable via take_until to subscriber 10.45ns 12.7327 0.82 2.07ns

timeout

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
timeout construction from observable via dot + subscribe with run_loop 932.43ns None . 15258.70ns
sending of values from observable via timeout to subscriber with unreachable timeout interval with run_loop 68.46ns None . 19029.20ns

trampoline scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 20.10ns 25.1234 0.80 190.47ns
re-schedule 10 times 39.73ns 60.6078 0.66 215.04ns
recursively schedule 10 times 1388.47ns 1601.95 0.87 8481.75ns

window

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
window 2245.37ns 2520.76 0.89 3391.53ns
sending of values from observable via window to subscriber 610.60ns 711.358 0.86 413.46ns

with_latest_from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
with_latest_from construction from observable via dot + subscribe 1112.07ns 1193.21 0.93 1585.99ns
sending of values from observable via with_latest_from to subscriber 31.89ns 34.6258 0.92 3.64ns

ci-windows

Observable construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable construction 1.80ns 1.50355 1.20 0.81ns
Dynamic observable construction 102.24ns 79.6962 1.28 159.34ns
Specific observable construction + as_dynamic 95.85ns 79.8282 1.20 146.56ns

Observable lift

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable lift specific observer 172.41ns 145.204 1.19 1473.91ns
Specific observable lift dynamic observer 216.46ns 180.683 1.20 1558.00ns
Dynamic observable lift specific observer 344.42ns 283.659 1.21 1703.43ns
Dynamic observable lift dynamic observer 283.09ns 237.351 1.19 1588.95ns

Observable subscribe

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe specific observer 132.12ns 110.982 1.19 1412.80ns
Specific observable subscribe dynamic observer 156.60ns 130.351 1.20 1489.10ns
Dynamic observable subscribe specific observer 272.47ns 227.191 1.20 1652.90ns
Dynamic observable subscribe dynamic observer 217.85ns 177.545 1.23 1609.95ns

Observable subscribe #2

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observable subscribe lambda 133.16ns 111.315 1.20 1429.90ns
Dynamic observable subscribe lambda 288.42ns 227.027 1.27 1637.82ns
Specific observable subscribe lambda without subscription 138.75ns 111.319 1.25 1408.04ns
Dynamic observable subscribe lambda without subscription 286.07ns 227.554 1.26 1629.86ns
Specific observable subscribe specific subscriber 39.06ns 30.8 1.27 1014.62ns
Dynamic observable subscribe specific subscriber 174.91ns 146.365 1.20 1231.52ns
Specific observable subscribe dynamic observer 36.52ns 30.7757 1.19 1068.59ns
Dynamic observable subscribe dynamic observer 97.22ns 87.4726 1.11 1111.82ns

Observer construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer construction 1.81ns 1.50572 1.20 1.80ns
Dynamic observer construction 98.55ns 81.4 1.21 136.29ns
Specific observer construction + as_dynamic 98.20ns 81.2336 1.21 136.93ns

OnNext

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Specific observer OnNext 0.80ns 0.670353 1.20 0.81ns
Dynamic observer OnNext 2.21ns 2.0094 1.10 2.71ns

Subscriber construction

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
Make subsriber 121.73ns 84.1242 1.45 444.19ns
Make copy of subscriber 20.77ns 17.2476 1.20 40.53ns
Transform subsriber to dynamic 117.33ns 96.5602 1.22 183.66ns

Subscription

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
composite_subscription create 107.24ns 84.2226 1.27 422.99ns
composite_subscription add 81.85ns 71.131 1.15 264.11ns
composite_subscription unsubscribe 74.71ns 64.8813 1.15 151.90ns

buffer

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
buffer 429.26ns 351.354 1.22 5591.71ns
sending of values from observable via buffer to subscriber 7.83ns 7.09153 1.10 114.25ns

chains creation test

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
long non-state chain creation + subscribe 323.88ns 269.277 1.20 2109.06ns
long stateful chain creation + subscribe 788.53ns 667.333 1.18 4180.56ns

combine_latest

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
combine_latest construction from observable via dot + subscribe 1877.69ns 1644.07 1.14 3605.00ns
sending of values from observable via combine_latest to subscriber 58.77ns 47.2189 1.24 5.36ns

concat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
concat 3260.20ns 3225.33 1.01 12775.70ns
concat_with 4088.25ns 3875.62 1.05 14968.70ns

distinct_until_changed

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
distinct_until_changed construction from observable via dot + subscribe 221.67ns 183.56 1.21 1334.59ns
sending of values from observable via distinct_until_changed to subscriber 4.05ns 3.54878 1.14 4.68ns

first

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
first construction from observable via dot + subscribe 154.85ns 128.461 1.21 3151.50ns
sending of values from observable via first to subscriber 2.81ns 2.36083 1.19 2.11ns

foundamental sources

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
empty 76.61ns 68.1395 1.12 3019.00ns
error 138.97ns 113.196 1.23 3031.42ns
never 37.00ns 30.8386 1.20 1076.79ns

from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
from vector with int 165.77ns 151.013 1.10 3207.42ns

immediate scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 2.28ns 1.76072 1.30 886.60ns
re-schedule 10 times 119.47ns 102.137 1.17 532.41ns

just

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
just send int 90.11ns 68.2901 1.32 2935.75ns
just send variadic 123.03ns 101.849 1.21 3000.58ns

last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
last construction from observable via dot + subscribe 268.43ns 223.04 1.20 1753.22ns
sending of values from observable via last to subscriber 3.87ns 3.19931 1.21 4.02ns

map

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
map construction from observable via dot + subscribe 112.24ns 88.0136 1.28 1211.11ns
sending of values from observable via map to subscriber 4.49ns 4.01559 1.12 8.48ns

merge

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
merge 3096.20ns 3010.5 1.03 13273.30ns
merge_with 3998.44ns 3691.5 1.08 13873.70ns

observe_on

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
observe_on construction from observable via dot + subscribe 745.29ns 642.641 1.16 6707.00ns
sending of values from observable via observe_on to subscriber 84.89ns 63.7732 1.33 960.38ns

on_error_resume_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_error_resume_next construction from observable via dot + subscribe 768.82ns 634.35 1.21 2212.14ns

publish_subject callbacks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
on_next 23.72ns 19.8402 1.20 39.34ns
on_error 3.39ns 2.72319 1.24 22.56ns
on_completed 3.87ns 2.2798 1.70 1.63ns

publish_subject routines

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
construct 444.89ns 353.203 1.26 737.95ns
get_observable 33.57ns 26.0661 1.29 195.38ns
get_subscriber 60.43ns 50.2096 1.20 142.60ns

repeat

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
repeat construction from observable via dot + subscribe 8180.00ns 6824.5 1.20 13889.00ns

scan

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
scan construction from observable via dot + subscribe 220.34ns 182.564 1.21 1513.55ns
sending of values from observable via scan to subscriber 6.51ns 6.15678 1.06 11.30ns

single-threaded locks

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no-lock increment 2.26ns 1.88211 1.20 .
mutex lock increment 31.40ns 25.8806 1.21 .
spin-lock increment 10.84ns 9.03363 1.20 .

skip

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
skip construction from observable via dot + subscribe 230.01ns 177.469 1.30 1936.24ns
sending of values from observable via skip to subscriber 5.10ns 3.47602 1.47 5.15ns

switch_on_next

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
switch_on_next construction from observable via dot + subscribe 4288.12ns 3769.38 1.14 15758.30ns
sending of values from observable via switch_on_next to subscriber 1057.77ns 868.742 1.22 3826.60ns

take

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take construction from observable via dot + subscribe 271.06ns 224.424 1.21 2557.86ns
sending of values from observable via take to subscriber 7.96ns 5.77979 1.38 7.79ns

take_last

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_last construction from observable via dot + subscribe 386.82ns 321.764 1.20 2863.58ns
sending of values from observable via take_last to subscriber 5.08ns 4.2263 1.20 25.28ns

take_until

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
take_until construction from observable via dot + subscribe 1900.41ns 1694.35 1.12 6949.67ns
sending of values from observable via take_until to subscriber 14.54ns 11.5467 1.26 6.53ns

timeout

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
timeout construction from observable via dot + subscribe with run_loop 1735.22ns None . 6675.60ns
sending of values from observable via timeout to subscriber with unreachable timeout interval with run_loop 66.52ns None . 1664.33ns

trampoline scheduler

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
no any re-schedule 22.73ns 20.3858 1.11 758.17ns
re-schedule 10 times 146.48ns 121.569 1.20 793.56ns
recursively schedule 10 times 3159.40ns 2584.45 1.22 24455.00ns

window

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
window 3503.20ns 2931.67 1.19 11960.00ns
sending of values from observable via window to subscriber 986.32ns 840.161 1.17 1986.94ns

with_latest_from

Table
Test Name Current, ns Prev, ns Ratio RxCpp current, ns
with_latest_from construction from observable via dot + subscribe 2393.23ns 1963.38 1.22 4684.57ns
sending of values from observable via with_latest_from to subscriber 45.75ns 42.0955 1.09 8.21ns

Please sign in to comment.