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
Show 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
include/pls/internal/scheduling/scheduler_impl.h
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/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
target_include_directories
(
pls
PUBLIC
...
...
lib/pls/include/pls/algorithms/invoke_parallel_impl.h
View file @
a5bb074c
...
...
@@ -11,27 +11,27 @@ namespace pls {
namespace
algorithm
{
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
;
auto
sub_task_1
=
lambda_task_by_reference
<
Function1
>
(
function1
)
;
auto
sub_task_2
=
lambda_task_by_reference
<
Function2
>
(
function2
)
;
using
task_1_t
=
lambda_task_by_value
<
Function1
>
;
using
task_2_t
=
lambda_task_by_value
<
Function2
>
;
scheduler
::
spawn_child
(
sub_task_2
);
scheduler
::
spawn_child_and_wait
(
sub_task_1
);
scheduler
::
spawn_child
<
task_2_t
>
(
std
::
forward
<
Function2
>
(
function2
)
);
scheduler
::
spawn_child_and_wait
<
task_1_t
>
(
std
::
forward
<
Function1
>
(
function1
)
);
}
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
;
auto
sub_task_1
=
lambda_task_by_reference
<
Function1
>
(
function1
)
;
auto
sub_task_2
=
lambda_task_by_reference
<
Function2
>
(
function2
)
;
auto
sub_task_3
=
lambda_task_by_reference
<
Function3
>
(
function3
)
;
using
task_1_t
=
lambda_task_by_value
<
Function1
>
;
using
task_2_t
=
lambda_task_by_value
<
Function2
>
;
using
task_3_t
=
lambda_task_by_value
<
Function3
>
;
scheduler
::
spawn_child
(
sub_task_3
);
scheduler
::
spawn_child
(
sub_task_2
);
scheduler
::
spawn_child_and_wait
(
sub_task_1
);
scheduler
::
spawn_child
<
task_3_t
>
(
std
::
forward
<
Function3
>
(
function3
)
);
scheduler
::
spawn_child
<
task_2_t
>
(
std
::
forward
<
Function2
>
(
function2
)
);
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) {
// Cut in half recursively
long
middle_index
=
num_elements
/
2
;
auto
body2
=
[
=
]
{
parallel_for
(
first
+
middle_index
,
last
,
function
);
};
lambda_task_by_reference
<
decltype
(
body2
)
>
second_half_task
(
body2
);
scheduler
::
spawn_child
(
second_half_task
);
auto
body1
=
[
=
]
{
parallel_for
(
first
,
first
+
middle_index
,
function
);
};
lambda_task_by_reference
<
decltype
(
body1
)
>
first_half_task
(
body1
);
scheduler
::
spawn_child
(
first_half_task
);
scheduler
::
wait_for_all
();
auto
second_half_body
=
[
=
]
{
parallel_for
(
first
+
middle_index
,
last
,
function
);
};
using
second_half_t
=
lambda_task_by_reference
<
decltype
(
second_half_body
)
>
;
scheduler
::
spawn_child
<
second_half_t
>
(
std
::
move
(
second_half_body
));
auto
first_half_body
=
[
=
]
{
parallel_for
(
first
,
first
+
middle_index
,
function
);
};
using
first_half_t
=
lambda_task_by_reference
<
decltype
(
first_half_body
)
>
;
scheduler
::
spawn_child_and_wait
<
first_half_t
>
(
std
::
move
(
first_half_body
));
}
}
...
...
lib/pls/include/pls/internal/data_structures/aligned_stack.h
View file @
a5bb074c
...
...
@@ -40,8 +40,8 @@ class aligned_stack {
aligned_stack
(
pointer_t
memory_region
,
std
::
size_t
size
);
aligned_stack
(
char
*
memory_region
,
std
::
size_t
size
);
template
<
typename
T
>
T
*
push
(
const
T
&
object
);
template
<
typename
T
,
typename
...
ARGS
>
T
*
push
(
ARGS
&&
...
args
);
template
<
typename
T
>
void
*
push
();
template
<
typename
T
>
...
...
lib/pls/include/pls/internal/data_structures/aligned_stack_impl.h
View file @
a5bb074c
...
...
@@ -6,10 +6,10 @@ namespace pls {
namespace
internal
{
namespace
data_structures
{
template
<
typename
T
>
T
*
aligned_stack
::
push
(
const
T
&
object
)
{
//
Copy-C
onstruct
return
new
(
push
<
T
>
())
T
(
object
);
template
<
typename
T
,
typename
...
ARGS
>
T
*
aligned_stack
::
push
(
ARGS
&&
...
args
)
{
//
Perfect-Forward c
onstruct
return
new
(
push
<
T
>
())
T
(
std
::
forward
<
ARGS
>
(
args
)...
);
}
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 {
tail_
{
other
.
tail_
.
load
()},
previous_tail_
{
other
.
previous_tail_
}
{}
template
<
typename
T
>
T
*
push_tail
(
const
T
&
new_item
);
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
T
*
push_tail
(
const
Function
&
after_creation
,
ARGS
&&
...
args
);
Item
*
pop_tail
();
Item
*
pop_head
();
...
...
@@ -94,8 +94,8 @@ class work_stealing_deque {
work_stealing_deque_item
*
item_at
(
offset_t
offset
);
offset_t
current_stack_offset
();
template
<
typename
T
>
std
::
pair
<
work_stealing_deque_item
,
T
>
*
allocate_item
(
const
T
&
new_item
);
template
<
typename
T
,
typename
...
ARGS
>
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() {
}
template
<
typename
Item
>
template
<
typename
T
>
std
::
pair
<
work_stealing_deque_item
,
T
>
*
work_stealing_deque
<
Item
>::
allocate_item
(
const
T
&
new_item
)
{
template
<
typename
T
,
typename
...
ARGS
>
std
::
pair
<
work_stealing_deque_item
,
T
>
*
work_stealing_deque
<
Item
>::
allocate_item
(
ARGS
&&
...
args
)
{
// 'Union' type to push both on stack
using
pair_t
=
std
::
pair
<
work_stealing_deque_item
,
T
>
;
// Allocate space on stack
auto
new_pair
=
reinterpret_cast
<
pair_t
*>
(
stack_
->
push
<
pair_t
>
());
// Initialize memory on stack
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
;
}
template
<
typename
Item
>
template
<
typename
T
>
T
*
work_stealing_deque
<
Item
>::
push_tail
(
const
T
&
new_item
)
{
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
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
,
"Must only push types of <Item> onto work_stealing_deque<Item>"
);
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
auto
tail_deque_item
=
item_at
(
local_tail
);
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 {
* Helper to spawn a child on the currently running 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
>
static
void
spawn_child
(
T
&
sub_task
);
template
<
typename
T
,
typename
...
ARGS
>
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).
*
* @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
>
static
void
spawn_child_and_wait
(
T
&
sub_task
);
template
<
typename
T
,
typename
...
ARGS
>
static
void
spawn_child_and_wait
(
ARGS
&&
...
args
);
/**
* 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) {
}
}
template
<
typename
T
>
void
scheduler
::
spawn_child
(
T
&
sub_task
)
{
thread_state
::
get
()
->
current_task_
->
spawn_child
(
sub_task
);
template
<
typename
T
,
typename
...
ARGS
>
void
scheduler
::
spawn_child
(
ARGS
&&
...
args
)
{
thread_state
::
get
()
->
current_task_
->
spawn_child
<
T
>
(
std
::
forward
<
ARGS
>
(
args
)...
);
}
template
<
typename
T
>
void
scheduler
::
spawn_child_and_wait
(
T
&
sub_task
)
{
thread_state
::
get
()
->
current_task_
->
spawn_child_and_wait
(
sub_task
);
template
<
typename
T
,
typename
...
ARGS
>
void
scheduler
::
spawn_child_and_wait
(
ARGS
&&
...
args
)
{
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 {
data_structures
::
deque
<
task
>::
state
deque_state_
;
protected
:
// TODO: Double Check with copy and move constructors, try to minimize overhead while keeping a clean API.
explicit
task
();
task
(
const
task
&
other
);
/**
* Overwrite this with the actual behaviour of concrete tasks.
*/
virtual
void
execute_internal
()
=
0
;
template
<
typename
T
>
void
spawn_child
(
T
&&
sub_task
);
template
<
typename
T
>
void
spawn_child_and_wait
(
T
&&
sub_task
);
template
<
typename
T
,
typename
...
ARGS
>
void
spawn_child
(
ARGS
&&
...
args
);
template
<
typename
T
,
typename
...
ARGS
>
void
spawn_child_and_wait
(
ARGS
&&
...
args
);
void
wait_for_all
();
private
:
void
execute
();
};
template
<
typename
T
>
void
task
::
spawn_child
(
T
&&
sub_task
)
{
template
<
typename
T
,
typename
...
ARGS
>
void
task
::
spawn_child
(
ARGS
&&
...
args
)
{
PROFILE_FORK_JOIN_STEALING
(
"spawn_child"
)
static_assert
(
std
::
is_base_of
<
task
,
typename
std
::
remove_reference
<
T
>::
type
>::
value
,
"Only pass task subclasses!"
);
// Keep our refcount up to date
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
const
T
const_task
=
sub_task
;
thread_state
::
get
()
->
deque_
.
push_tail
(
const_task
);
auto
deque_state
=
thread_state
::
get
()
->
deque_
.
save_state
();
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
>
void
task
::
spawn_child_and_wait
(
T
&&
sub_task
)
{
template
<
typename
T
,
typename
...
ARGS
>
void
task
::
spawn_child_and_wait
(
ARGS
&&
...
args
)
{
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!"
);
// 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
.
deque_state_
=
thread_state
::
get
()
->
deque_
.
save_state
();
PROFILE_END_BLOCK
...
...
lib/pls/src/internal/scheduling/task.cpp
View file @
a5bb074c
...
...
@@ -13,11 +13,6 @@ task::task() :
parent_
{
nullptr
},
deque_state_
{
0
}
{}
task
::
task
(
const
task
&
other
)
:
ref_count_
{
0
},
parent_
{
other
.
parent_
},
deque_state_
{
other
.
deque_state_
}
{}
void
task
::
execute
()
{
PROFILE_WORK_BLOCK
(
"execute 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