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
3fccabd8
Commit
3fccabd8
authored
Jul 16, 2014
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Streamline implementation of fork join policy
parent
07d4ef49
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
50 additions
and
72 deletions
+50
-72
cppa/policy/fork_join.hpp
cppa/policy/fork_join.hpp
+50
-72
No files found.
cppa/policy/fork_join.hpp
View file @
3fccabd8
...
...
@@ -19,9 +19,10 @@
#ifndef CPPA_POLICY_FORK_JOIN_HPP
#define CPPA_POLICY_FORK_JOIN_HPP
#include <list>
#include <chrono>
#include <vector>
#include <thread>
#include <cstddef>
#include "cppa/resumable.hpp"
...
...
@@ -76,98 +77,76 @@ class fork_join {
/**
* @brief A queue implementation supporting fast push and pop
* operations. Note that we do dequeue from the back of the
* queue.
* operations on both ends of the queue.
*/
using
priv_queue
=
std
::
vector
<
resumable
*>
;
using
priv_queue
=
std
::
list
<
resumable
*>
;
template
<
class
Worker
>
inline
void
external_enqueue
(
Worker
*
,
resumable
*
job
)
{
void
external_enqueue
(
Worker
*
,
resumable
*
job
)
{
m_exposed_queue
.
push_back
(
job
);
}
template
<
class
Worker
>
inline
void
internal_enqueue
(
Worker
*
,
resumable
*
job
)
{
// give others the opportunity to steal from us
if
(
m_exposed_queue
.
empty
())
{
if
(
m_private_queue
.
empty
())
{
void
internal_enqueue
(
Worker
*
ptr
,
resumable
*
job
)
{
m_exposed_queue
.
push_back
(
job
);
}
else
{
m_exposed_queue
.
push_back
(
m_private_queue
.
front
());
m_private_queue
.
erase
(
m_private_queue
.
begin
());
m_private_queue
.
push_back
(
job
);
}
}
else
{
m_private_queue
.
push_back
(
job
);
}
// give others the opportunity to steal from us
assert_stealable
(
ptr
);
}
template
<
class
Worker
>
inline
resumable
*
try_external_dequeue
(
Worker
*
)
{
resumable
*
try_external_dequeue
(
Worker
*
)
{
return
m_exposed_queue
.
try_pop
();
}
template
<
class
Worker
>
inline
resumable
*
internal_dequeue
(
Worker
*
self
)
{
resumable
*
job
;
auto
local_poll
=
[
&
]()
->
bool
{
resumable
*
internal_dequeue
(
Worker
*
self
)
{
// we wait for new jobs by polling our external queue: first, we
// assume an active work load on the machine and perform aggresive
// polling, then we relax our polling a bit and wait 50 us between
// dequeue attempts, finally we assume pretty much nothing is going
// on and poll every 10 ms; this strategy strives to minimize the
// downside of "busy waiting", which still performs much better than a
// "signalizing" implementation based on mutexes and conition variables
struct
poll_strategy
{
size_t
attempts
;
size_t
step_size
;
size_t
raid_interval
;
std
::
chrono
::
microseconds
sleep_duration
;
};
constexpr
poll_strategy
strategies
[
3
]
=
{
// aggressive polling (100x) without sleep interval
{
100
,
1
,
10
,
std
::
chrono
::
microseconds
{
0
}},
// moderate polling (500x) with 50 us sleep interval
{
500
,
1
,
5
,
std
::
chrono
::
microseconds
{
50
}},
// relaxed polling (infinite attempts) with 10 ms sleep interval
{
101
,
0
,
1
,
std
::
chrono
::
microseconds
{
10000
}}
};
resumable
*
job
=
nullptr
;
// local poll
if
(
!
m_private_queue
.
empty
())
{
job
=
m_private_queue
.
back
();
m_private_queue
.
pop_back
();
return
true
;
}
return
false
;
};
auto
aggressive_poll
=
[
&
]()
->
bool
{
for
(
int
i
=
1
;
i
<
101
;
++
i
)
{
job
=
m_exposed_queue
.
try_pop
();
if
(
job
)
{
return
true
;
}
// try to steal every 10 poll attempts
if
((
i
%
10
)
==
0
)
{
job
=
self
->
raid
();
if
(
job
)
{
return
true
;
}
}
std
::
this_thread
::
yield
();
return
job
;
}
return
false
;
};
auto
moderate_poll
=
[
&
]()
->
bool
{
for
(
int
i
=
1
;
i
<
550
;
++
i
)
{
for
(
auto
&
strat
:
strategies
)
{
for
(
size_t
i
=
0
;
i
<
strat
.
attempts
;
i
+=
strat
.
step_size
)
{
job
=
m_exposed_queue
.
try_pop
();
if
(
job
)
{
return
true
;
return
job
;
}
// try to steal every
5
poll attempts
if
((
i
%
5
)
==
0
)
{
// try to steal every
X
poll attempts
if
((
i
%
strat
.
raid_interval
)
==
0
)
{
job
=
self
->
raid
();
if
(
job
)
{
return
true
;
}
}
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
microseconds
(
50
));
return
job
;
}
return
false
;
};
auto
relaxed_poll
=
[
&
]()
->
bool
{
for
(;;)
{
job
=
m_exposed_queue
.
try_pop
();
if
(
job
)
{
return
true
;
}
// always try to steal at this stage
job
=
self
->
raid
();
if
(
job
)
{
return
true
;
std
::
this_thread
::
sleep_for
(
strat
.
sleep_duration
);
}
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
10
));
}
};
local_poll
()
||
aggressive_poll
()
||
moderate_poll
()
||
relaxed_poll
();
return
job
;
// unreachable, because the last strategy loops
// until a job has been dequeued
return
nullptr
;
}
template
<
class
Worker
>
...
...
@@ -184,7 +163,7 @@ class fork_join {
// give others the opportunity to steal from us
if
(
m_private_queue
.
size
()
>
1
&&
m_exposed_queue
.
empty
())
{
m_exposed_queue
.
push_back
(
m_private_queue
.
front
());
m_private_queue
.
erase
(
m_private_queue
.
begin
()
);
m_private_queue
.
pop_front
(
);
}
}
...
...
@@ -202,9 +181,8 @@ class fork_join {
private:
// this queue is exposed to others, i.e., other workers
// may attempt to steal jobs from it and the central scheduling
// unit can push new jobs to the queue
// this queue is exposed to other workers that may attempt to steal jobs
// from it and the central scheduling unit can push new jobs to the queue
sync_queue
m_exposed_queue
;
// internal job queue
...
...
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