Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
las3_pub
/
predictable_parallel_patterns
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
a5bb074c
authored
Jun 10, 2019
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor: Use perfect forwarding instead of copy constructor.
parent
0228aa92
Pipeline
#1260
failed with stages
in 43 seconds
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
70 additions
and
70 deletions
+70
-70
lib/pls/CMakeLists.txt
+3
-1
lib/pls/include/pls/algorithms/invoke_parallel_impl.h
+12
-12
lib/pls/include/pls/algorithms/parallel_for_impl.h
+7
-8
lib/pls/include/pls/internal/data_structures/aligned_stack.h
+2
-2
lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h
+4
-4
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
+4
-4
lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h
+8
-6
lib/pls/include/pls/internal/scheduling/scheduler.h
+8
-6
lib/pls/include/pls/internal/scheduling/scheduler_impl.h
+6
-6
lib/pls/include/pls/internal/scheduling/task.h
+16
-16
lib/pls/src/internal/scheduling/task.cpp
+0
-5
No files found.
lib/pls/CMakeLists.txt
View file @
a5bb074c
...
@@ -34,8 +34,10 @@ add_library(pls STATIC
...
@@ -34,8 +34,10 @@ add_library(pls STATIC
include/pls/internal/scheduling/scheduler_impl.h
include/pls/internal/scheduling/scheduler_impl.h
include/pls/internal/scheduling/task.h src/internal/scheduling/task.cpp
include/pls/internal/scheduling/task.h src/internal/scheduling/task.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
include/pls/internal/scheduling/lambda_task.h include/pls/internal/data_structures/deque.h
)
include/pls/internal/scheduling/lambda_task.h include/pls/internal/data_structures/deque.h
# include/pls/algorithms/parallel_scan.h include/pls/algorithms/parallel_scan_impl.h)
)
# Add everything in `./include` to be in the include path of this project
# Add everything in `./include` to be in the include path of this project
target_include_directories
(
pls
target_include_directories
(
pls
PUBLIC
PUBLIC
...
...
lib/pls/include/pls/algorithms/invoke_parallel_impl.h
View file @
a5bb074c
...
@@ -11,27 +11,27 @@ namespace pls {
...
@@ -11,27 +11,27 @@ namespace pls {
namespace
algorithm
{
namespace
algorithm
{
template
<
typename
Function1
,
typename
Function2
>
template
<
typename
Function1
,
typename
Function2
>
void
invoke_parallel
(
const
Function1
&
function1
,
const
Function2
&
function2
)
{
void
invoke_parallel
(
Function1
&&
function1
,
Function2
&
&
function2
)
{
using
namespace
::
pls
::
internal
::
scheduling
;
using
namespace
::
pls
::
internal
::
scheduling
;
auto
sub_task_1
=
lambda_task_by_reference
<
Function1
>
(
function1
)
;
using
task_1_t
=
lambda_task_by_value
<
Function1
>
;
auto
sub_task_2
=
lambda_task_by_reference
<
Function2
>
(
function2
)
;
using
task_2_t
=
lambda_task_by_value
<
Function2
>
;
scheduler
::
spawn_child
(
sub_task_2
);
scheduler
::
spawn_child
<
task_2_t
>
(
std
::
forward
<
Function2
>
(
function2
)
);
scheduler
::
spawn_child_and_wait
(
sub_task_1
);
scheduler
::
spawn_child_and_wait
<
task_1_t
>
(
std
::
forward
<
Function1
>
(
function1
)
);
}
}
template
<
typename
Function1
,
typename
Function2
,
typename
Function3
>
template
<
typename
Function1
,
typename
Function2
,
typename
Function3
>
void
invoke_parallel
(
const
Function1
&
function1
,
const
Function2
&
function2
,
const
Function3
&
function3
)
{
void
invoke_parallel
(
Function1
&&
function1
,
Function2
&&
function2
,
Function3
&
&
function3
)
{
using
namespace
::
pls
::
internal
::
scheduling
;
using
namespace
::
pls
::
internal
::
scheduling
;
auto
sub_task_1
=
lambda_task_by_reference
<
Function1
>
(
function1
)
;
using
task_1_t
=
lambda_task_by_value
<
Function1
>
;
auto
sub_task_2
=
lambda_task_by_reference
<
Function2
>
(
function2
)
;
using
task_2_t
=
lambda_task_by_value
<
Function2
>
;
auto
sub_task_3
=
lambda_task_by_reference
<
Function3
>
(
function3
)
;
using
task_3_t
=
lambda_task_by_value
<
Function3
>
;
scheduler
::
spawn_child
(
sub_task_3
);
scheduler
::
spawn_child
<
task_3_t
>
(
std
::
forward
<
Function3
>
(
function3
)
);
scheduler
::
spawn_child
(
sub_task_2
);
scheduler
::
spawn_child
<
task_2_t
>
(
std
::
forward
<
Function2
>
(
function2
)
);
scheduler
::
spawn_child_and_wait
(
sub_task_1
);
scheduler
::
spawn_child_and_wait
<
task_1_t
>
(
std
::
forward
<
Function1
>
(
function1
)
);
}
}
}
}
...
...
lib/pls/include/pls/algorithms/parallel_for_impl.h
View file @
a5bb074c
...
@@ -25,14 +25,13 @@ void parallel_for(RandomIt first, RandomIt last, const Function &function) {
...
@@ -25,14 +25,13 @@ void parallel_for(RandomIt first, RandomIt last, const Function &function) {
// Cut in half recursively
// Cut in half recursively
long
middle_index
=
num_elements
/
2
;
long
middle_index
=
num_elements
/
2
;
auto
body2
=
[
=
]
{
parallel_for
(
first
+
middle_index
,
last
,
function
);
};
auto
second_half_body
=
[
=
]
{
parallel_for
(
first
+
middle_index
,
last
,
function
);
};
lambda_task_by_reference
<
decltype
(
body2
)
>
second_half_task
(
body2
);
using
second_half_t
=
lambda_task_by_reference
<
decltype
(
second_half_body
)
>
;
scheduler
::
spawn_child
(
second_half_task
);
scheduler
::
spawn_child
<
second_half_t
>
(
std
::
move
(
second_half_body
));
auto
body1
=
[
=
]
{
parallel_for
(
first
,
first
+
middle_index
,
function
);
};
auto
first_half_body
=
[
=
]
{
parallel_for
(
first
,
first
+
middle_index
,
function
);
};
lambda_task_by_reference
<
decltype
(
body1
)
>
first_half_task
(
body1
);
using
first_half_t
=
lambda_task_by_reference
<
decltype
(
first_half_body
)
>
;
scheduler
::
spawn_child
(
first_half_task
);
scheduler
::
spawn_child_and_wait
<
first_half_t
>
(
std
::
move
(
first_half_body
));
scheduler
::
wait_for_all
();
}
}
}
}
...
...
lib/pls/include/pls/internal/data_structures/aligned_stack.h
View file @
a5bb074c
...
@@ -40,8 +40,8 @@ class aligned_stack {
...
@@ -40,8 +40,8 @@ class aligned_stack {
aligned_stack
(
pointer_t
memory_region
,
std
::
size_t
size
);
aligned_stack
(
pointer_t
memory_region
,
std
::
size_t
size
);
aligned_stack
(
char
*
memory_region
,
std
::
size_t
size
);
aligned_stack
(
char
*
memory_region
,
std
::
size_t
size
);
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
T
*
push
(
const
T
&
object
);
T
*
push
(
ARGS
&&
...
args
);
template
<
typename
T
>
template
<
typename
T
>
void
*
push
();
void
*
push
();
template
<
typename
T
>
template
<
typename
T
>
...
...
lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h
View file @
a5bb074c
...
@@ -6,10 +6,10 @@ namespace pls {
...
@@ -6,10 +6,10 @@ namespace pls {
namespace
internal
{
namespace
internal
{
namespace
data_structures
{
namespace
data_structures
{
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
T
*
aligned_stack
::
push
(
const
T
&
object
)
{
T
*
aligned_stack
::
push
(
ARGS
&&
...
args
)
{
//
Copy-C
onstruct
//
Perfect-Forward c
onstruct
return
new
(
push
<
T
>
())
T
(
object
);
return
new
(
push
<
T
>
())
T
(
std
::
forward
<
ARGS
>
(
args
)...
);
}
}
template
<
typename
T
>
template
<
typename
T
>
...
...
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
View file @
a5bb074c
...
@@ -81,8 +81,8 @@ class work_stealing_deque {
...
@@ -81,8 +81,8 @@ class work_stealing_deque {
tail_
{
other
.
tail_
.
load
()},
tail_
{
other
.
tail_
.
load
()},
previous_tail_
{
other
.
previous_tail_
}
{}
previous_tail_
{
other
.
previous_tail_
}
{}
template
<
typename
T
>
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
T
*
push_tail
(
const
T
&
new_item
);
T
*
push_tail
(
const
Function
&
after_creation
,
ARGS
&&
...
args
);
Item
*
pop_tail
();
Item
*
pop_tail
();
Item
*
pop_head
();
Item
*
pop_head
();
...
@@ -94,8 +94,8 @@ class work_stealing_deque {
...
@@ -94,8 +94,8 @@ class work_stealing_deque {
work_stealing_deque_item
*
item_at
(
offset_t
offset
);
work_stealing_deque_item
*
item_at
(
offset_t
offset
);
offset_t
current_stack_offset
();
offset_t
current_stack_offset
();
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
std
::
pair
<
work_stealing_deque_item
,
T
>
*
allocate_item
(
const
T
&
new_item
);
std
::
pair
<
work_stealing_deque_item
,
T
>
*
allocate_item
(
ARGS
&&
...
args
);
};
};
}
}
...
...
lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h
View file @
a5bb074c
...
@@ -23,28 +23,30 @@ offset_t work_stealing_deque<Item>::current_stack_offset() {
...
@@ -23,28 +23,30 @@ offset_t work_stealing_deque<Item>::current_stack_offset() {
}
}
template
<
typename
Item
>
template
<
typename
Item
>
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
std
::
pair
<
work_stealing_deque_item
,
T
>
*
work_stealing_deque
<
Item
>::
allocate_item
(
const
T
&
new_item
)
{
std
::
pair
<
work_stealing_deque_item
,
T
>
*
work_stealing_deque
<
Item
>::
allocate_item
(
ARGS
&&
...
args
)
{
// 'Union' type to push both on stack
// 'Union' type to push both on stack
using
pair_t
=
std
::
pair
<
work_stealing_deque_item
,
T
>
;
using
pair_t
=
std
::
pair
<
work_stealing_deque_item
,
T
>
;
// Allocate space on stack
// Allocate space on stack
auto
new_pair
=
reinterpret_cast
<
pair_t
*>
(
stack_
->
push
<
pair_t
>
());
auto
new_pair
=
reinterpret_cast
<
pair_t
*>
(
stack_
->
push
<
pair_t
>
());
// Initialize memory on stack
// Initialize memory on stack
new
((
void
*
)
&
(
new_pair
->
first
))
work_stealing_deque_item
();
new
((
void
*
)
&
(
new_pair
->
first
))
work_stealing_deque_item
();
new
((
void
*
)
&
(
new_pair
->
second
))
T
(
new_item
);
new
((
void
*
)
&
(
new_pair
->
second
))
T
(
std
::
forward
<
ARGS
>
(
args
)...
);
return
new_pair
;
return
new_pair
;
}
}
template
<
typename
Item
>
template
<
typename
Item
>
template
<
typename
T
>
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
T
*
work_stealing_deque
<
Item
>::
push_tail
(
const
T
&
new_item
)
{
T
*
work_stealing_deque
<
Item
>::
push_tail
(
const
Function
&
after_creation
,
ARGS
&&
...
args
)
{
static_assert
(
std
::
is_same
<
Item
,
T
>::
value
||
std
::
is_base_of
<
Item
,
T
>::
value
,
static_assert
(
std
::
is_same
<
Item
,
T
>::
value
||
std
::
is_base_of
<
Item
,
T
>::
value
,
"Must only push types of <Item> onto work_stealing_deque<Item>"
);
"Must only push types of <Item> onto work_stealing_deque<Item>"
);
offset_t
local_tail
=
tail_
;
offset_t
local_tail
=
tail_
;
auto
new_pair
=
allocate_item
(
new_item
);
auto
new_pair
=
allocate_item
<
T
>
(
std
::
forward
<
ARGS
>
(
args
)...);
after_creation
(
&
(
new_pair
->
second
));
// callback for time after creation but before being visible to others
// Prepare current tail to point to correct next items
// Prepare current tail to point to correct next items
auto
tail_deque_item
=
item_at
(
local_tail
);
auto
tail_deque_item
=
item_at
(
local_tail
);
tail_deque_item
->
set_data
(
&
(
new_pair
->
second
));
tail_deque_item
->
set_data
(
&
(
new_pair
->
second
));
...
...
lib/pls/include/pls/internal/scheduling/scheduler.h
View file @
a5bb074c
...
@@ -79,19 +79,21 @@ class scheduler {
...
@@ -79,19 +79,21 @@ class scheduler {
* Helper to spawn a child on the currently running task.
* Helper to spawn a child on the currently running task.
*
*
* @tparam T type of the new task
* @tparam T type of the new task
* @param sub_task the new task to be spawned
* @tparam ARGS Constructor argument types
* @param args constructor arguments
*/
*/
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
static
void
spawn_child
(
T
&
sub_task
);
static
void
spawn_child
(
ARGS
&&
...
args
);
/**
/**
* Helper to spawn a child on the currently running task and waiting for it (skipping over the task-deque).
* Helper to spawn a child on the currently running task and waiting for it (skipping over the task-deque).
*
*
* @tparam T type of the new task
* @tparam T type of the new task
* @param sub_task the new task to be spawned
* @tparam ARGS Constructor argument types
* @param args constructor arguments
*/
*/
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
static
void
spawn_child_and_wait
(
T
&
sub_task
);
static
void
spawn_child_and_wait
(
ARGS
&&
...
args
);
/**
/**
* Helper to wait for all children of the currently executing task.
* Helper to wait for all children of the currently executing task.
...
...
lib/pls/include/pls/internal/scheduling/scheduler_impl.h
View file @
a5bb074c
...
@@ -40,14 +40,14 @@ void scheduler::perform_work(Function work_section) {
...
@@ -40,14 +40,14 @@ void scheduler::perform_work(Function work_section) {
}
}
}
}
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
scheduler
::
spawn_child
(
T
&
sub_task
)
{
void
scheduler
::
spawn_child
(
ARGS
&&
...
args
)
{
thread_state
::
get
()
->
current_task_
->
spawn_child
(
sub_task
);
thread_state
::
get
()
->
current_task_
->
spawn_child
<
T
>
(
std
::
forward
<
ARGS
>
(
args
)...
);
}
}
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
scheduler
::
spawn_child_and_wait
(
T
&
sub_task
)
{
void
scheduler
::
spawn_child_and_wait
(
ARGS
&&
...
args
)
{
thread_state
::
get
()
->
current_task_
->
spawn_child_and_wait
(
sub_task
);
thread_state
::
get
()
->
current_task_
->
spawn_child_and_wait
<
T
>
(
std
::
forward
<
ARGS
>
(
args
)...
);
}
}
}
}
...
...
lib/pls/include/pls/internal/scheduling/task.h
View file @
a5bb074c
...
@@ -24,48 +24,48 @@ class task {
...
@@ -24,48 +24,48 @@ class task {
data_structures
::
deque
<
task
>::
state
deque_state_
;
data_structures
::
deque
<
task
>::
state
deque_state_
;
protected
:
protected
:
// TODO: Double Check with copy and move constructors, try to minimize overhead while keeping a clean API.
explicit
task
();
explicit
task
();
task
(
const
task
&
other
);
/**
/**
* Overwrite this with the actual behaviour of concrete tasks.
* Overwrite this with the actual behaviour of concrete tasks.
*/
*/
virtual
void
execute_internal
()
=
0
;
virtual
void
execute_internal
()
=
0
;
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
spawn_child
(
T
&&
sub_task
);
void
spawn_child
(
ARGS
&&
...
args
);
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
spawn_child_and_wait
(
T
&&
sub_task
);
void
spawn_child_and_wait
(
ARGS
&&
...
args
);
void
wait_for_all
();
void
wait_for_all
();
private
:
private
:
void
execute
();
void
execute
();
};
};
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
task
::
spawn_child
(
T
&&
sub_task
)
{
void
task
::
spawn_child
(
ARGS
&&
...
args
)
{
PROFILE_FORK_JOIN_STEALING
(
"spawn_child"
)
PROFILE_FORK_JOIN_STEALING
(
"spawn_child"
)
static_assert
(
std
::
is_base_of
<
task
,
typename
std
::
remove_reference
<
T
>::
type
>::
value
,
"Only pass task subclasses!"
);
static_assert
(
std
::
is_base_of
<
task
,
typename
std
::
remove_reference
<
T
>::
type
>::
value
,
"Only pass task subclasses!"
);
// Keep our refcount up to date
// Keep our refcount up to date
ref_count_
++
;
ref_count_
++
;
// Assign forced values (for stack and parent management)
sub_task
.
parent_
=
this
;
sub_task
.
deque_state_
=
thread_state
::
get
()
->
deque_
.
save_state
();
// Push on our deque
// Push on our deque
const
T
const_task
=
sub_task
;
auto
deque_state
=
thread_state
::
get
()
->
deque_
.
save_state
();
thread_state
::
get
()
->
deque_
.
push_tail
(
const_task
);
thread_state
::
get
()
->
deque_
.
push_tail
<
T
>
([
this
,
deque_state
](
T
*
item
)
{
// Assign forced values (for stack and parent management)
item
->
parent_
=
this
;
item
->
deque_state_
=
deque_state
;
},
std
::
forward
<
ARGS
>
(
args
)...);
}
}
template
<
typename
T
>
template
<
typename
T
,
typename
...
ARGS
>
void
task
::
spawn_child_and_wait
(
T
&&
sub_task
)
{
void
task
::
spawn_child_and_wait
(
ARGS
&&
...
args
)
{
PROFILE_FORK_JOIN_STEALING
(
"spawn_child_wait"
)
PROFILE_FORK_JOIN_STEALING
(
"spawn_child_wait"
)
static_assert
(
std
::
is_base_of
<
task
,
typename
std
::
remove_reference
<
T
>::
type
>::
value
,
"Only pass task subclasses!"
);
static_assert
(
std
::
is_base_of
<
task
,
typename
std
::
remove_reference
<
T
>::
type
>::
value
,
"Only pass task subclasses!"
);
// Assign forced values (for stack and parent management)
// Assign forced values (for stack and parent management)
// TODO: Move this after construction
T
sub_task
{
std
::
forward
<
ARGS
>
(
args
)...};
sub_task
.
parent_
=
nullptr
;
sub_task
.
parent_
=
nullptr
;
sub_task
.
deque_state_
=
thread_state
::
get
()
->
deque_
.
save_state
();
sub_task
.
deque_state_
=
thread_state
::
get
()
->
deque_
.
save_state
();
PROFILE_END_BLOCK
PROFILE_END_BLOCK
...
...
lib/pls/src/internal/scheduling/task.cpp
View file @
a5bb074c
...
@@ -13,11 +13,6 @@ task::task() :
...
@@ -13,11 +13,6 @@ task::task() :
parent_
{
nullptr
},
parent_
{
nullptr
},
deque_state_
{
0
}
{}
deque_state_
{
0
}
{}
task
::
task
(
const
task
&
other
)
:
ref_count_
{
0
},
parent_
{
other
.
parent_
},
deque_state_
{
other
.
deque_state_
}
{}
void
task
::
execute
()
{
void
task
::
execute
()
{
PROFILE_WORK_BLOCK
(
"execute task"
)
PROFILE_WORK_BLOCK
(
"execute task"
)
auto
last_executing
=
thread_state
::
get
()
->
current_task_
;
auto
last_executing
=
thread_state
::
get
()
->
current_task_
;
...
...
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