Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
49f80aa9
Commit
49f80aa9
authored
Sep 09, 2019
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make credit computation configurable
parent
c05c1e0e
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
474 additions
and
118 deletions
+474
-118
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+3
-0
libcaf_core/caf/credit_controller.hpp
libcaf_core/caf/credit_controller.hpp
+93
-0
libcaf_core/caf/defaults.hpp
libcaf_core/caf/defaults.hpp
+1
-0
libcaf_core/caf/detail/complexity_based_credit_controller.hpp
...af_core/caf/detail/complexity_based_credit_controller.hpp
+68
-0
libcaf_core/caf/detail/test_credit_controller.hpp
libcaf_core/caf/detail/test_credit_controller.hpp
+55
-0
libcaf_core/caf/inbound_path.hpp
libcaf_core/caf/inbound_path.hpp
+8
-47
libcaf_core/src/actor_system_config.cpp
libcaf_core/src/actor_system_config.cpp
+4
-1
libcaf_core/src/complexity_based_credit_controller.cpp
libcaf_core/src/complexity_based_credit_controller.cpp
+83
-0
libcaf_core/src/credit_controller.cpp
libcaf_core/src/credit_controller.cpp
+39
-0
libcaf_core/src/defaults.cpp
libcaf_core/src/defaults.cpp
+1
-0
libcaf_core/src/inbound_path.cpp
libcaf_core/src/inbound_path.cpp
+37
-60
libcaf_core/src/scheduled_actor.cpp
libcaf_core/src/scheduled_actor.cpp
+2
-3
libcaf_core/src/stream_manager.cpp
libcaf_core/src/stream_manager.cpp
+2
-3
libcaf_core/src/test_credit_controller.cpp
libcaf_core/src/test_credit_controller.cpp
+75
-0
libcaf_core/test/native_streaming_classes.cpp
libcaf_core/test/native_streaming_classes.cpp
+2
-4
libcaf_test/caf/test/dsl.hpp
libcaf_test/caf/test/dsl.hpp
+1
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
49f80aa9
...
...
@@ -46,10 +46,12 @@ set(LIBCAF_CORE_SRCS
src/binary_deserializer.cpp
src/binary_serializer.cpp
src/blocking_actor.cpp
src/complexity_based_credit_controller.cpp
src/config_option.cpp
src/config_option_adder.cpp
src/config_option_set.cpp
src/config_value.cpp
src/credit_controller.cpp
src/decorator/sequencer.cpp
src/default_attachable.cpp
src/defaults.cpp
...
...
@@ -144,6 +146,7 @@ set(LIBCAF_CORE_SRCS
src/string_algorithms.cpp
src/string_view.cpp
src/term.cpp
src/test_credit_controller.cpp
src/thread_hook.cpp
src/timestamp.cpp
src/tracing_data.cpp
...
...
libcaf_core/caf/credit_controller.hpp
0 → 100644
View file @
49f80aa9
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstdint>
#include "caf/downstream_msg.hpp"
#include "caf/fwd.hpp"
namespace
caf
{
/// Computes credit for an attached source.
class
credit_controller
{
public:
// -- member types -----------------------------------------------------------
/// Wraps an assignment of the controller to its source.
struct
assignment
{
/// Store how much credit we assign to the source.
int32_t
credit
;
/// Store how many elements we demand per batch.
int32_t
batch_size
;
};
// -- constructors, destructors, and assignment operators --------------------
explicit
credit_controller
(
scheduled_actor
*
self
);
virtual
~
credit_controller
();
// -- properties -------------------------------------------------------------
scheduled_actor
*
self
()
noexcept
{
return
self_
;
}
// -- pure virtual functions -------------------------------------------------
/// Called before processing the batch `x` in order to allow the controller
/// to keep statistics on incoming batches.
virtual
void
before_processing
(
downstream_msg
::
batch
&
x
)
=
0
;
/// Called after processing the batch `x` in order to allow the controller to
/// keep statistics on incoming batches.
/// @note The consumer may alter the batch while processing it, for example
/// by moving each element of the batch downstream.
virtual
void
after_processing
(
downstream_msg
::
batch
&
x
)
=
0
;
/// Assigns initial credit during the stream handshake.
/// @returns The initial credit for the new sources.
virtual
assignment
compute_initial
()
=
0
;
/// Computes a credit assignment to the source after a cycle ends.
virtual
assignment
compute
(
timespan
cycle
)
=
0
;
// -- virtual functions ------------------------------------------------------
/// Computes a credit assignment to the source after crossing the
/// low-threshold. May assign zero credit.
virtual
assignment
compute_bridge
();
/// Returns the threshold for when we may give extra credit to a source
/// during a cycle.
/// @returns A negative value if the controller never grants bridge credit,
/// otherwise the threshold for calling `compute_bridge` to generate
/// additional credit.
virtual
int32_t
low_threshold
()
const
noexcept
;
private:
// -- member variables -------------------------------------------------------
/// Points to the parent system.
scheduled_actor
*
self_
;
};
}
// namespace caf
libcaf_core/caf/defaults.hpp
View file @
49f80aa9
...
...
@@ -36,6 +36,7 @@ namespace stream {
extern
const
timespan
desired_batch_complexity
;
extern
const
timespan
max_batch_delay
;
extern
const
timespan
credit_round_interval
;
extern
const
atom_value
credit_policy
;
}
// namespace streaming
...
...
libcaf_core/
test/inbound_path.c
pp
→
libcaf_core/
caf/detail/complexity_based_credit_controller.h
pp
View file @
49f80aa9
...
...
@@ -5,7 +5,7 @@
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-201
8
Dominik Charousset *
* Copyright 2011-201
9
Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
...
...
@@ -16,75 +16,53 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE inbound_path
#include "caf/test/unit_test.hpp"
#include <string>
#include "caf/inbound_path.hpp"
using
namespace
std
;
using
namespace
caf
;
namespace
{
#define PRINT(format, ...) \
{ \
char buf[200]; \
snprintf(buf, 200, format, __VA_ARGS__); \
CAF_MESSAGE(buf); \
}
struct
fixture
{
inbound_path
::
stats_t
x
;
void
calculate
(
int32_t
total_items
,
int32_t
total_time
)
{
int32_t
c
=
1000
;
int32_t
d
=
100
;
int32_t
n
=
total_items
;
int32_t
t
=
total_time
;
int32_t
m
=
t
>
0
?
std
::
max
((
c
*
n
)
/
t
,
1
)
:
1
;
int32_t
b
=
t
>
0
?
std
::
max
((
d
*
n
)
/
t
,
1
)
:
1
;
PRINT
(
"with a cycle C = %dns, desied complexity D = %d,"
,
c
,
d
);
PRINT
(
"number of items N = %d, and time delta t = %d:"
,
n
,
t
);
PRINT
(
"- throughput M = max(C * N / t, 1) = max(%d * %d / %d, 1) = %d"
,
c
,
n
,
t
,
m
);
PRINT
(
"- items/batch B = max(D * N / t, 1) = max(%d * %d / %d, 1) = %d"
,
d
,
n
,
t
,
b
);
auto
cr
=
x
.
calculate
(
timespan
(
c
),
timespan
(
d
));
CAF_CHECK_EQUAL
(
cr
.
items_per_batch
,
b
);
CAF_CHECK_EQUAL
(
cr
.
max_throughput
,
m
);
}
void
store
(
int32_t
batch_size
,
int32_t
calculation_time_ns
)
{
inbound_path
::
stats_t
::
measurement
m
{
batch_size
,
timespan
{
calculation_time_ns
}};
x
.
store
(
m
);
}
};
#pragma once
#include "caf/credit_controller.hpp"
namespace
caf
{
namespace
detail
{
/// Computes credit for an attached source based on measuring the complexity of
/// incoming batches.
class
complexity_based_credit_controller
:
public
credit_controller
{
public:
// -- member types -----------------------------------------------------------
using
super
=
credit_controller
;
// -- constructors, destructors, and assignment operators --------------------
explicit
complexity_based_credit_controller
(
scheduled_actor
*
self
);
}
// namespace
~
complexity_based_credit_controller
()
override
;
CAF_TEST_FIXTURE_SCOPE
(
inbound_path_tests
,
fixture
)
// -- implementation of virtual functions ------------------------------------
CAF_TEST
(
default_constructed
)
{
calculate
(
0
,
0
);
}
void
before_processing
(
downstream_msg
::
batch
&
x
)
override
;
CAF_TEST
(
one_store
)
{
CAF_MESSAGE
(
"store a measurement for 500ns with batch size of 50"
);
store
(
50
,
500
);
calculate
(
50
,
500
);
}
void
after_processing
(
downstream_msg
::
batch
&
x
)
override
;
CAF_TEST
(
multiple_stores
)
{
CAF_MESSAGE
(
"store measurements: (50, 500ns), (60, 400ns), (40, 600ns)"
);
store
(
50
,
500
);
store
(
40
,
600
);
store
(
60
,
400
);
calculate
(
150
,
1500
);
}
assignment
compute_initial
()
override
;
assignment
compute
(
timespan
cycle
)
override
;
private:
// -- member variables -------------------------------------------------------
/// Total number of elements in all processed batches in the current cycle.
int64_t
num_elements_
=
0
;
/// Elapsed time for processing all elements of all batches in the current
/// cycle.
timespan
processing_time_
;
/// Timestamp of the last call to `before_processing`.
timestamp
processing_begin_
;
/// Stores the desired per-batch complexity.
timespan
complexity_
;
};
CAF_TEST_FIXTURE_SCOPE_END
()
}
// namespace detail
}
// namespace caf
libcaf_core/caf/detail/test_credit_controller.hpp
0 → 100644
View file @
49f80aa9
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/credit_controller.hpp"
namespace
caf
{
namespace
detail
{
/// Computes predictable credit in unit tests.
class
test_credit_controller
:
public
credit_controller
{
public:
// -- member types -----------------------------------------------------------
using
super
=
credit_controller
;
// -- constructors, destructors, and assignment operators --------------------
using
super
::
super
;
~
test_credit_controller
()
override
;
// -- implementation of virtual functions ------------------------------------
void
before_processing
(
downstream_msg
::
batch
&
x
)
override
;
void
after_processing
(
downstream_msg
::
batch
&
x
)
override
;
assignment
compute_initial
()
override
;
assignment
compute
(
timespan
cycle
)
override
;
private:
/// Total number of elements in all processed batches in the current cycle.
int64_t
num_elements_
=
0
;
};
}
// namespace detail
}
// namespace caf
libcaf_core/caf/inbound_path.hpp
View file @
49f80aa9
...
...
@@ -23,6 +23,7 @@
#include "caf/actor_clock.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/credit_controller.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/rtti_pair.hpp"
...
...
@@ -68,49 +69,8 @@ public:
/// ID of the last received batch.
int64_t
last_batch_id
;
/// Amount of credit we assign sources after receiving `open`.
static
constexpr
int
initial_credit
=
50
;
/// Stores statistics for measuring complexity of incoming batches.
struct
stats_t
{
/// Wraps a time measurement for a single processed batch.
struct
measurement
{
/// Number of items in the batch.
int32_t
batch_size
;
/// Elapsed time for processing all elements of the batch.
timespan
calculation_time
;
};
/// Wraps the resulf of `stats_t::calculate()`.
struct
calculation_result
{
/// Number of items per credit cycle.
int32_t
max_throughput
;
/// Number of items per batch to reach the desired batch complexity.
int32_t
items_per_batch
;
};
/// Total number of elements in all processed batches.
int64_t
num_elements
;
/// Elapsed time for processing all elements of all batches.
timespan
processing_time
;
stats_t
();
/// Returns the maximum number of items this actor could handle for given
/// cycle length with a minimum of 1.
calculation_result
calculate
(
timespan
cycle
,
timespan
desired_complexity
);
/// Adds a measurement to this statistic.
void
store
(
measurement
x
);
/// Resets this statistic.
void
reset
();
};
/// Summarizes how many elements we processed during the last cycle and how
/// much time we spent processing those elements.
stats_t
stats
;
/// Controller for assigning credit to the source.
std
::
unique_ptr
<
credit_controller
>
controller_
;
/// Stores the time point of the last credit decision for this source.
actor_clock
::
time_point
last_credit_decision
;
...
...
@@ -146,10 +106,8 @@ public:
/// waiting in the mailbox.
/// @param now Current timestamp.
/// @param cycle Time between credit rounds.
/// @param desired_batch_complexity Desired processing time per batch.
void
emit_ack_batch
(
local_actor
*
self
,
int32_t
queued_items
,
actor_clock
::
time_point
now
,
timespan
cycle
,
timespan
desired_batch_complexity
);
actor_clock
::
time_point
now
,
timespan
cycle
);
/// Returns whether the path received no input since last emitting
/// `ack_batch`, i.e., `last_acked_batch_id == last_batch_id`.
...
...
@@ -167,6 +125,10 @@ public:
error
reason
);
private:
scheduled_actor
*
self
();
actor_system
&
system
();
actor_clock
&
clock
();
};
...
...
@@ -178,4 +140,3 @@ typename Inspector::return_type inspect(Inspector& f, inbound_path& x) {
}
}
// namespace caf
libcaf_core/src/actor_system_config.cpp
View file @
49f80aa9
...
...
@@ -82,7 +82,9 @@ actor_system_config::actor_system_config()
.
add
<
timespan
>
(
stream_max_batch_delay
,
"max-batch-delay"
,
"maximum delay for partial batches"
)
.
add
<
timespan
>
(
stream_credit_round_interval
,
"credit-round-interval"
,
"time between emitting credit"
);
"time between emitting credit"
)
.
add
<
atom_value
>
(
"credit-policy"
,
"selects an algorithm for credit computation"
);
opt_group
{
custom_options_
,
"scheduler"
}
.
add
<
atom_value
>
(
"policy"
,
"'stealing' (default) or 'sharing'"
)
.
add
<
size_t
>
(
"max-threads"
,
"maximum number of worker threads"
)
...
...
@@ -158,6 +160,7 @@ settings actor_system_config::dump_content() const {
defaults
::
stream
::
max_batch_delay
);
put_missing
(
stream_group
,
"credit-round-interval"
,
defaults
::
stream
::
credit_round_interval
);
put_missing
(
stream_group
,
"credit-policy"
,
defaults
::
stream
::
credit_policy
);
// -- scheduler parameters
auto
&
scheduler_group
=
result
[
"scheduler"
].
as_dictionary
();
put_missing
(
scheduler_group
,
"policy"
,
defaults
::
scheduler
::
policy
);
...
...
libcaf_core/src/complexity_based_credit_controller.cpp
0 → 100644
View file @
49f80aa9
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/complexity_based_credit_controller.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/scheduled_actor.hpp"
// Safe us some typing and very ugly formatting.
#define impl complexity_based_credit_controller
namespace
caf
{
namespace
detail
{
impl
::
impl
(
scheduled_actor
*
self
)
:
super
(
self
)
{
auto
&
cfg
=
self
->
system
().
config
();
complexity_
=
cfg
.
stream_desired_batch_complexity
;
}
impl
::~
impl
()
{
// nop
}
void
impl
::
before_processing
(
downstream_msg
::
batch
&
x
)
{
num_elements_
+=
x
.
xs_size
;
processing_begin_
=
make_timestamp
();
}
void
impl
::
after_processing
(
downstream_msg
::
batch
&
)
{
processing_time_
+=
make_timestamp
()
-
processing_begin_
;
}
credit_controller
::
assignment
impl
::
compute_initial
()
{
return
{
50
,
10
};
}
credit_controller
::
assignment
impl
::
compute
(
timespan
cycle
)
{
// Max throughput = C * (N / t), where C = cycle length, N = measured items,
// and t = measured time. Desired batch size is the same formula with D
// (desired complexity) instead of C. We compute our values in 64-bit for
// more precision before truncating to a 32-bit integer type at the end.
int64_t
total_ns
=
processing_time_
.
count
();
if
(
total_ns
==
0
)
return
{
1
,
1
};
// Helper for truncating a 64-bit integer to a 32-bit integer with a minimum
// value of 1.
auto
clamp
=
[](
int64_t
x
)
->
int32_t
{
static
constexpr
auto
upper_bound
=
std
::
numeric_limits
<
int32_t
>::
max
();
if
(
x
>
upper_bound
)
return
upper_bound
;
if
(
x
<=
0
)
return
1
;
return
static_cast
<
int32_t
>
(
x
);
};
// Instead of C * (N / t) we calculate (C * N) / t to avoid double conversion
// and rounding errors.
assignment
result
;
result
.
credit
=
clamp
((
cycle
.
count
()
*
num_elements_
)
/
total_ns
);
result
.
batch_size
=
clamp
((
complexity_
.
count
()
*
num_elements_
)
/
total_ns
);
// Reset state and return.
num_elements_
=
0
;
processing_time_
=
timespan
{
0
};
return
result
;
}
}
// namespace detail
}
// namespace caf
libcaf_core/src/credit_controller.cpp
0 → 100644
View file @
49f80aa9
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/credit_controller.hpp"
namespace
caf
{
credit_controller
::
credit_controller
(
scheduled_actor
*
self
)
:
self_
(
self
)
{
// nop
}
credit_controller
::~
credit_controller
()
{
// nop
}
credit_controller
::
assignment
credit_controller
::
compute_bridge
()
{
return
{
0
,
0
};
}
int32_t
credit_controller
::
low_threshold
()
const
noexcept
{
return
-
1
;
}
}
// namespace caf
libcaf_core/src/defaults.cpp
View file @
49f80aa9
...
...
@@ -49,6 +49,7 @@ namespace stream {
const
timespan
desired_batch_complexity
=
us
(
50
);
const
timespan
max_batch_delay
=
ms
(
5
);
const
timespan
credit_round_interval
=
ms
(
10
);
const
atom_value
credit_policy
=
atom
(
"complexity"
);
}
// namespace stream
...
...
libcaf_core/src/inbound_path.cpp
View file @
49f80aa9
...
...
@@ -18,59 +18,23 @@
#include "caf/inbound_path.hpp"
#include "caf/send.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/defaults.hpp"
#include "caf/detail/complexity_based_credit_controller.hpp"
#include "caf/detail/test_credit_controller.hpp"
#include "caf/logger.hpp"
#include "caf/no_stages.hpp"
#include "caf/scheduled_actor.hpp"
#include "caf/send.hpp"
#include "caf/settings.hpp"
namespace
caf
{
inbound_path
::
stats_t
::
stats_t
()
:
num_elements
(
0
),
processing_time
(
0
)
{
// nop
}
auto
inbound_path
::
stats_t
::
calculate
(
timespan
c
,
timespan
d
)
->
calculation_result
{
// Max throughput = C * (N / t), where C = cycle length, N = measured items,
// and t = measured time. Desired batch size is the same formula with D
// instead of C.
// We compute our values in 64-bit for more precision before truncating to a
// 32-bit integer type at the end.
int64_t
total_ns
=
processing_time
.
count
();
if
(
total_ns
==
0
)
return
{
1
,
1
};
/// Helper for truncating a 64-bit integer to a 32-bit integer with a minimum
/// value of 1.
auto
clamp
=
[](
int64_t
x
)
->
int32_t
{
static
constexpr
auto
upper_bound
=
std
::
numeric_limits
<
int32_t
>::
max
();
if
(
x
>
upper_bound
)
return
upper_bound
;
if
(
x
<=
0
)
return
1
;
return
static_cast
<
int32_t
>
(
x
);
};
// Instead of C * (N / t) we calculate (C * N) / t to avoid double conversion
// and rounding errors.
return
{
clamp
((
c
.
count
()
*
num_elements
)
/
total_ns
),
clamp
((
d
.
count
()
*
num_elements
)
/
total_ns
)};
}
void
inbound_path
::
stats_t
::
store
(
measurement
x
)
{
num_elements
+=
x
.
batch_size
;
processing_time
+=
x
.
calculation_time
;
}
void
inbound_path
::
stats_t
::
reset
()
{
num_elements
=
0
;
processing_time
=
timespan
{
0
};
}
inbound_path
::
inbound_path
(
stream_manager_ptr
mgr_ptr
,
stream_slots
id
,
strong_actor_ptr
ptr
,
rtti_pair
in_type
)
:
mgr
(
std
::
move
(
mgr_ptr
)),
hdl
(
std
::
move
(
ptr
)),
slots
(
id
),
desired_batch_size
(
initial_credit
),
assigned_credit
(
0
),
prio
(
stream_priority
::
normal
),
last_acked_batch_id
(
0
),
...
...
@@ -81,6 +45,13 @@ inbound_path::inbound_path(stream_manager_ptr mgr_ptr, stream_slots id,
<<
"opens input stream with element type"
<<
mgr
->
self
()
->
system
().
types
().
portable_name
(
in_type
)
<<
"at slot"
<<
id
.
receiver
<<
"from"
<<
hdl
);
switch
(
atom_uint
(
get_or
(
system
().
config
(),
"stream.credit-policy"
,
defaults
::
stream
::
credit_policy
)))
{
case
atom_uint
(
"testing"
):
controller_
.
reset
(
new
detail
::
test_credit_controller
(
self
()));
default:
controller_
.
reset
(
new
detail
::
complexity_based_credit_controller
(
self
()));
}
}
inbound_path
::~
inbound_path
()
{
...
...
@@ -89,10 +60,8 @@ inbound_path::~inbound_path() {
void
inbound_path
::
handle
(
downstream_msg
::
batch
&
x
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
slots
)
<<
CAF_ARG
(
x
));
auto
&
clk
=
clock
();
auto
batch_size
=
x
.
xs_size
;
last_batch_id
=
x
.
id
;
auto
t0
=
clk
.
now
();
CAF_STREAM_LOG_DEBUG
(
mgr
->
self
()
->
name
()
<<
"handles batch of size"
<<
batch_size
<<
"on slot"
<<
slots
.
receiver
<<
"with"
<<
assigned_credit
<<
"assigned credit"
);
...
...
@@ -109,32 +78,33 @@ void inbound_path::handle(downstream_msg::batch& x) {
assigned_credit
-=
batch_size
;
CAF_ASSERT
(
assigned_credit
>=
0
);
}
controller_
->
before_processing
(
x
);
mgr
->
handle
(
this
,
x
);
auto
t1
=
clk
.
now
();
auto
dt
=
clk
.
difference
(
atom
(
"batch"
),
batch_size
,
t0
,
t1
);
stats
.
store
({
batch_size
,
dt
});
controller_
->
after_processing
(
x
);
mgr
->
push
();
}
void
inbound_path
::
emit_ack_open
(
local_actor
*
self
,
actor_addr
rebind_from
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
slots
)
<<
CAF_ARG
(
rebind_from
));
// Update state.
assigned_credit
=
mgr
->
acquire_credit
(
this
,
initial_credit
);
auto
initial
=
controller_
->
compute_initial
();
assigned_credit
=
mgr
->
acquire_credit
(
this
,
initial
.
credit
);
CAF_ASSERT
(
assigned_credit
>=
0
);
desired_batch_size
=
std
::
min
(
initial
.
batch_size
,
assigned_credit
);
// Make sure we receive errors from this point on.
stream_aborter
::
add
(
hdl
,
self
->
address
(),
slots
.
receiver
,
stream_aborter
::
source_aborter
);
// Send message.
unsafe_send_as
(
self
,
hdl
,
make
<
upstream_msg
::
ack_open
>
(
slots
.
invert
(),
self
->
address
(),
std
::
move
(
rebind_from
),
self
->
ctrl
(),
assigned_credit
,
desired_batch_size
));
make
<
upstream_msg
::
ack_open
>
(
slots
.
invert
(),
self
->
address
(),
std
::
move
(
rebind_from
),
self
->
ctrl
(),
assigned_credit
,
desired_batch_size
));
last_credit_decision
=
clock
().
now
();
}
void
inbound_path
::
emit_ack_batch
(
local_actor
*
self
,
int32_t
queued_items
,
actor_clock
::
time_point
now
,
timespan
cycle
,
timespan
complexity
)
{
actor_clock
::
time_point
now
,
timespan
cycle
)
{
CAF_LOG_TRACE
(
CAF_ARG
(
slots
)
<<
CAF_ARG
(
queued_items
)
<<
CAF_ARG
(
cycle
)
<<
CAF_ARG
(
complexity
));
CAF_IGNORE_UNUSED
(
queued_items
);
...
...
@@ -143,10 +113,9 @@ void inbound_path::emit_ack_batch(local_actor* self, int32_t queued_items,
next_credit_decision
=
now
+
cycle
;
// Hand out enough credit to fill our queue for 2 cycles but never exceed
// the downstream capacity.
auto
x
=
stats
.
calculate
(
cycle
,
complexity
);
auto
stats_guard
=
detail
::
make_scope_guard
([
&
]
{
stats
.
reset
();
});
auto
&
out
=
mgr
->
out
();
auto
max_capacity
=
std
::
min
(
x
.
max_throughput
*
2
,
out
.
max_capacity
());
auto
x
=
controller_
->
compute
(
cycle
);
auto
max_capacity
=
std
::
min
(
x
.
credit
*
2
,
out
.
max_capacity
());
CAF_ASSERT
(
max_capacity
>
0
);
// Protect against overflow on `assigned_credit`.
auto
max_new_credit
=
std
::
numeric_limits
<
int32_t
>::
max
()
-
assigned_credit
;
...
...
@@ -170,12 +139,12 @@ void inbound_path::emit_ack_batch(local_actor* self, int32_t queued_items,
<<
CAF_ARG
(
assigned_credit
));
if
(
credit
==
0
&&
up_to_date
())
return
;
CAF_LOG_DEBUG
(
CAF_ARG
(
assigned_credit
)
<<
CAF_ARG
(
max_capacity
)
<<
CAF_ARG
(
queued_items
)
<<
CAF_ARG
(
credit
)
<<
CAF_ARG
(
desired_
batch_size
));
CAF_LOG_DEBUG
(
CAF_ARG
(
assigned_credit
)
<<
CAF_ARG
(
max_capacity
)
<<
CAF_ARG
(
queued_items
)
<<
CAF_ARG
(
credit
)
<<
CAF_ARG
(
x
.
batch_size
));
assigned_credit
+=
credit
;
CAF_ASSERT
(
assigned_credit
>=
0
);
desired_batch_size
=
static_cast
<
int32_t
>
(
x
.
items_per_batch
)
;
desired_batch_size
=
x
.
batch_size
;
unsafe_send_as
(
self
,
hdl
,
make
<
upstream_msg
::
ack_batch
>
(
slots
.
invert
(),
self
->
address
(),
static_cast
<
int32_t
>
(
credit
),
...
...
@@ -216,6 +185,14 @@ void inbound_path::emit_irregular_shutdown(local_actor* self,
std
::
move
(
reason
)));
}
scheduled_actor
*
inbound_path
::
self
()
{
return
mgr
->
self
();
}
actor_system
&
inbound_path
::
system
()
{
return
mgr
->
self
()
->
system
();
}
actor_clock
&
inbound_path
::
clock
()
{
return
mgr
->
self
()
->
clock
();
}
...
...
libcaf_core/src/scheduled_actor.cpp
View file @
49f80aa9
...
...
@@ -1158,12 +1158,11 @@ scheduled_actor::advance_streams(actor_clock::time_point now) {
CAF_LOG_DEBUG
(
"new credit round"
);
auto
cycle
=
stream_ticks_
.
interval
();
cycle
*=
static_cast
<
decltype
(
cycle
)
::
rep
>
(
credit_round_ticks_
);
auto
bc
=
home_system
().
config
().
stream_desired_batch_complexity
;
auto
&
qs
=
get_downstream_queue
().
queues
();
for
(
auto
&
kvp
:
qs
)
{
auto
inptr
=
kvp
.
second
.
policy
().
handler
.
get
();
auto
b
s
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
this
,
bs
,
now
,
cycle
,
bc
);
auto
tt
s
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
this
,
tts
,
now
,
cycle
);
}
}
return
stream_ticks_
.
next_timeout
(
now
,
{
max_batch_delay_ticks_
,
...
...
libcaf_core/src/stream_manager.cpp
View file @
49f80aa9
...
...
@@ -155,7 +155,6 @@ void stream_manager::advance() {
if
(
!
inbound_paths_
.
empty
())
{
auto
now
=
self_
->
clock
().
now
();
auto
&
cfg
=
self_
->
system
().
config
();
auto
bc
=
cfg
.
stream_desired_batch_complexity
;
auto
interval
=
cfg
.
stream_credit_round_interval
;
auto
&
qs
=
self_
->
get_downstream_queue
().
queues
();
// Iterate all queues for inbound traffic.
...
...
@@ -163,8 +162,8 @@ void stream_manager::advance() {
auto
inptr
=
kvp
.
second
.
policy
().
handler
.
get
();
// Ignore inbound paths of other managers.
if
(
inptr
->
mgr
.
get
()
==
this
)
{
auto
b
s
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
self_
,
bs
,
now
,
interval
,
bc
);
auto
tt
s
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
self_
,
tts
,
now
,
interval
);
}
}
}
...
...
libcaf_core/src/test_credit_controller.cpp
0 → 100644
View file @
49f80aa9
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/detail/test_credit_controller.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_system_config.hpp"
#include "caf/scheduled_actor.hpp"
namespace
caf
{
namespace
detail
{
test_credit_controller
::~
test_credit_controller
()
{
// nop
}
void
test_credit_controller
::
before_processing
(
downstream_msg
::
batch
&
x
)
{
num_elements_
+=
x
.
xs_size
;
}
void
test_credit_controller
::
after_processing
(
downstream_msg
::
batch
&
)
{
// nop
}
credit_controller
::
assignment
test_credit_controller
::
compute_initial
()
{
return
{
50
,
50
};
}
credit_controller
::
assignment
test_credit_controller
::
compute
(
timespan
cycle
)
{
auto
&
cfg
=
self
()
->
system
().
config
();
auto
complexity
=
cfg
.
stream_desired_batch_complexity
;
// Max throughput = C * (N / t), where C = cycle length, N = measured items,
// and t = measured time. Desired batch size is the same formula with D
// (desired complexity) instead of C. We compute our values in 64-bit for
// more precision before truncating to a 32-bit integer type at the end.
int64_t
total_ns
=
num_elements_
*
1000
;
// calculate with 1us per element
if
(
total_ns
==
0
)
return
{
1
,
1
};
// Helper for truncating a 64-bit integer to a 32-bit integer with a minimum
// value of 1.
auto
clamp
=
[](
int64_t
x
)
->
int32_t
{
static
constexpr
auto
upper_bound
=
std
::
numeric_limits
<
int32_t
>::
max
();
if
(
x
>
upper_bound
)
return
upper_bound
;
if
(
x
<=
0
)
return
1
;
return
static_cast
<
int32_t
>
(
x
);
};
// Instead of C * (N / t) we calculate (C * N) / t to avoid double conversion
// and rounding errors.
assignment
result
;
result
.
credit
=
clamp
((
cycle
.
count
()
*
num_elements_
)
/
total_ns
);
result
.
batch_size
=
clamp
((
complexity
.
count
()
*
num_elements_
)
/
total_ns
);
// Reset state and return.
num_elements_
=
0
;
return
result
;
}
}
// namespace detail
}
// namespace caf
libcaf_core/test/native_streaming_classes.cpp
View file @
49f80aa9
...
...
@@ -329,7 +329,6 @@ public:
void
advance_time
()
{
auto
cycle
=
std
::
chrono
::
milliseconds
(
100
);
auto
desired_batch_complexity
=
std
::
chrono
::
microseconds
(
50
);
auto
f
=
[
&
](
tick_type
x
)
{
if
(
x
%
ticks_per_force_batches_interval
==
0
)
{
// Force batches on all output paths.
...
...
@@ -341,9 +340,8 @@ public:
auto
&
qs
=
get
<
dmsg_id
::
value
>
(
mbox
.
queues
()).
queues
();
for
(
auto
&
kvp
:
qs
)
{
auto
inptr
=
kvp
.
second
.
policy
().
handler
.
get
();
auto
bs
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
this
,
bs
,
now
(),
cycle
,
desired_batch_complexity
);
auto
tts
=
static_cast
<
int32_t
>
(
kvp
.
second
.
total_task_size
());
inptr
->
emit_ack_batch
(
this
,
tts
,
now
(),
cycle
);
}
}
};
...
...
libcaf_test/caf/test/dsl.hpp
View file @
49f80aa9
...
...
@@ -693,6 +693,7 @@ public:
cfg
.
set
(
"middleman.network-backend"
,
caf
::
atom
(
"testing"
));
cfg
.
set
(
"middleman.manual-multiplexing"
,
true
);
cfg
.
set
(
"middleman.workers"
,
size_t
{
0
});
cfg
.
set
(
"stream.credit-policy"
,
caf
::
atom
(
"testing"
));
return
cfg
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment