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
82ccdc91
authored
Jun 30, 2020
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update: add spawn_and_sync to final version for benchmarks.
parent
9fa9296a
Pipeline
#1547
canceled with stages
in 32 minutes 33 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
28 additions
and
24 deletions
+28
-24
app/benchmark_fft/main.cpp
+1
-2
app/benchmark_fib/main.cpp
+2
-7
lib/pls/include/pls/algorithms/invoke_impl.h
+2
-4
lib/pls/include/pls/internal/scheduling/scheduler_impl.h
+5
-4
lib/pls/src/internal/scheduling/lock_free/external_trading_deque.cpp
+10
-2
lib/pls/src/internal/scheduling/scheduler.cpp
+8
-5
No files found.
app/benchmark_fft/main.cpp
View file @
82ccdc91
...
@@ -18,10 +18,9 @@ void pls_conquer(fft::complex_vector::iterator data, fft::complex_vector::iterat
...
@@ -18,10 +18,9 @@ void pls_conquer(fft::complex_vector::iterator data, fft::complex_vector::iterat
pls
::
spawn
([
data
,
n
,
swap_array
]()
{
pls
::
spawn
([
data
,
n
,
swap_array
]()
{
pls_conquer
(
data
,
swap_array
,
n
/
2
);
pls_conquer
(
data
,
swap_array
,
n
/
2
);
});
});
pls
::
spawn
([
data
,
n
,
swap_array
]()
{
pls
::
spawn
_and_sync
([
data
,
n
,
swap_array
]()
{
pls_conquer
(
data
+
n
/
2
,
swap_array
+
n
/
2
,
n
/
2
);
pls_conquer
(
data
+
n
/
2
,
swap_array
+
n
/
2
,
n
/
2
);
});
});
pls
::
sync
();
}
}
fft
::
combine
(
data
,
n
);
fft
::
combine
(
data
,
n
);
...
...
app/benchmark_fib/main.cpp
View file @
82ccdc91
#include "pls/pls.h"
#include "pls/pls.h"
#include "benchmark_runner.h"
#include "benchmark_runner.h"
#include "benchmark_base/fib.h"
using
namespace
comparison_benchmarks
::
base
;
constexpr
int
MAX_NUM_TASKS
=
32
;
constexpr
int
MAX_STACK_SIZE
=
4096
*
1
;
constexpr
int
MAX_STACK_SIZE
=
4096
*
1
;
int
pls_fib
(
int
n
)
{
int
pls_fib
(
int
n
)
{
...
@@ -20,10 +16,9 @@ int pls_fib(int n) {
...
@@ -20,10 +16,9 @@ int pls_fib(int n) {
pls
::
spawn
([
n
,
&
a
]()
{
pls
::
spawn
([
n
,
&
a
]()
{
a
=
pls_fib
(
n
-
1
);
a
=
pls_fib
(
n
-
1
);
});
});
pls
::
spawn
([
n
,
&
b
]()
{
pls
::
spawn
_and_sync
([
n
,
&
b
]()
{
b
=
pls_fib
(
n
-
2
);
b
=
pls_fib
(
n
-
2
);
});
});
pls
::
sync
();
return
a
+
b
;
return
a
+
b
;
}
}
...
@@ -35,7 +30,7 @@ int main(int argc, char **argv) {
...
@@ -35,7 +30,7 @@ int main(int argc, char **argv) {
string
full_directory
=
settings
.
output_directory_
+
"/PLS_v3/"
;
string
full_directory
=
settings
.
output_directory_
+
"/PLS_v3/"
;
benchmark_runner
runner
{
full_directory
,
test_name
};
benchmark_runner
runner
{
full_directory
,
test_name
};
pls
::
scheduler
scheduler
{(
unsigned
)
settings
.
num_threads_
,
MAX_NUM_TASKS
,
MAX_STACK_SIZE
};
pls
::
scheduler
scheduler
{(
unsigned
)
settings
.
num_threads_
,
settings
.
size_
+
2
,
MAX_STACK_SIZE
};
volatile
int
res
;
volatile
int
res
;
if
(
settings
.
type_
==
benchmark_runner
::
benchmark_settings
::
ISOLATED
)
{
if
(
settings
.
type_
==
benchmark_runner
::
benchmark_settings
::
ISOLATED
)
{
...
...
lib/pls/include/pls/algorithms/invoke_impl.h
View file @
82ccdc91
...
@@ -11,8 +11,7 @@ void invoke(Function1 &&function1, Function2 &&function2) {
...
@@ -11,8 +11,7 @@ void invoke(Function1 &&function1, Function2 &&function2) {
using
namespace
::
pls
::
internal
::
scheduling
;
using
namespace
::
pls
::
internal
::
scheduling
;
scheduler
::
spawn
(
std
::
forward
<
Function1
>
(
function1
));
scheduler
::
spawn
(
std
::
forward
<
Function1
>
(
function1
));
scheduler
::
spawn
(
std
::
forward
<
Function2
>
(
function2
));
scheduler
::
spawn_and_sync
(
std
::
forward
<
Function2
>
(
function2
));
scheduler
::
sync
();
}
}
template
<
typename
Function1
,
typename
Function2
,
typename
Function3
>
template
<
typename
Function1
,
typename
Function2
,
typename
Function3
>
...
@@ -21,8 +20,7 @@ void invoke(Function1 &&function1, Function2 &&function2, Function3 &&function3)
...
@@ -21,8 +20,7 @@ void invoke(Function1 &&function1, Function2 &&function2, Function3 &&function3)
scheduler
::
spawn
(
std
::
forward
<
Function1
>
(
function1
));
scheduler
::
spawn
(
std
::
forward
<
Function1
>
(
function1
));
scheduler
::
spawn
(
std
::
forward
<
Function2
>
(
function2
));
scheduler
::
spawn
(
std
::
forward
<
Function2
>
(
function2
));
scheduler
::
spawn
(
std
::
forward
<
Function3
>
(
function3
));
scheduler
::
spawn_and_sync
(
std
::
forward
<
Function3
>
(
function3
));
scheduler
::
sync
();
}
}
}
}
...
...
lib/pls/include/pls/internal/scheduling/scheduler_impl.h
View file @
82ccdc91
...
@@ -207,8 +207,8 @@ void scheduler::spawn_internal(Function &&lambda) {
...
@@ -207,8 +207,8 @@ void scheduler::spawn_internal(Function &&lambda) {
spawning_state
.
get_task_manager
().
push_local_task
(
last_task
);
spawning_state
.
get_task_manager
().
push_local_task
(
last_task
);
#if PLS_SLEEP_WORKERS_ON_EMPTY
#if PLS_SLEEP_WORKERS_ON_EMPTY
// TODO: relax atomic operations on empty flag
data_structures
::
stamped_integer
data_structures
::
stamped_integer
queue_empty_flag
=
spawning_state
.
get_queue_empty_flag
().
load
(
);
queue_empty_flag
=
spawning_state
.
get_queue_empty_flag
().
load
(
std
::
memory_order_relaxed
);
switch
(
queue_empty_flag
.
value_
)
{
switch
(
queue_empty_flag
.
value_
)
{
case
EMPTY_QUEUE_STATE
:
:
QUEUE_NON_EMPTY
:
{
case
EMPTY_QUEUE_STATE
:
:
QUEUE_NON_EMPTY
:
{
// The queue was not found empty, ignore it.
// The queue was not found empty, ignore it.
...
@@ -218,7 +218,8 @@ void scheduler::spawn_internal(Function &&lambda) {
...
@@ -218,7 +218,8 @@ void scheduler::spawn_internal(Function &&lambda) {
// Someone tries to mark us empty and might be re-stealing right now.
// Someone tries to mark us empty and might be re-stealing right now.
data_structures
::
stamped_integer
data_structures
::
stamped_integer
queue_non_empty_flag
{
queue_empty_flag
.
stamp_
++
,
EMPTY_QUEUE_STATE
::
QUEUE_NON_EMPTY
};
queue_non_empty_flag
{
queue_empty_flag
.
stamp_
++
,
EMPTY_QUEUE_STATE
::
QUEUE_NON_EMPTY
};
auto
actual_empty_flag
=
spawning_state
.
get_queue_empty_flag
().
exchange
(
queue_non_empty_flag
);
auto
actual_empty_flag
=
spawning_state
.
get_queue_empty_flag
().
exchange
(
queue_non_empty_flag
,
std
::
memory_order_acq_rel
);
if
(
actual_empty_flag
.
value_
==
EMPTY_QUEUE_STATE
::
QUEUE_EMPTY
)
{
if
(
actual_empty_flag
.
value_
==
EMPTY_QUEUE_STATE
::
QUEUE_EMPTY
)
{
spawning_state
.
get_scheduler
().
empty_queue_decrease_counter_and_wake
();
spawning_state
.
get_scheduler
().
empty_queue_decrease_counter_and_wake
();
}
}
...
@@ -228,7 +229,7 @@ void scheduler::spawn_internal(Function &&lambda) {
...
@@ -228,7 +229,7 @@ void scheduler::spawn_internal(Function &&lambda) {
// Someone already marked the queue empty, we must revert its action on the central queue.
// Someone already marked the queue empty, we must revert its action on the central queue.
data_structures
::
stamped_integer
data_structures
::
stamped_integer
queue_non_empty_flag
{
queue_empty_flag
.
stamp_
++
,
EMPTY_QUEUE_STATE
::
QUEUE_NON_EMPTY
};
queue_non_empty_flag
{
queue_empty_flag
.
stamp_
++
,
EMPTY_QUEUE_STATE
::
QUEUE_NON_EMPTY
};
spawning_state
.
get_queue_empty_flag
().
store
(
queue_non_empty_flag
);
spawning_state
.
get_queue_empty_flag
().
store
(
queue_non_empty_flag
,
std
::
memory_order_release
);
spawning_state
.
get_scheduler
().
empty_queue_decrease_counter_and_wake
();
spawning_state
.
get_scheduler
().
empty_queue_decrease_counter_and_wake
();
break
;
break
;
}
}
...
...
lib/pls/src/internal/scheduling/lock_free/external_trading_deque.cpp
View file @
82ccdc91
...
@@ -114,8 +114,16 @@ task *external_trading_deque::pop_top(task *offered_task, peek_result peek_resul
...
@@ -114,8 +114,16 @@ task *external_trading_deque::pop_top(task *offered_task, peek_result peek_resul
if
(
forwarding_stamp
!=
expected_top
.
stamp_
)
{
if
(
forwarding_stamp
!=
expected_top
.
stamp_
)
{
// ...we failed because the top tag lags behind...try to fix it.
// ...we failed because the top tag lags behind...try to fix it.
// This means only updating the tag, as this location can still hold data we need.
// This means only updating the tag, as this location can still hold data we need.
top_
.
compare_exchange_strong
(
expected_top
,
{
forwarding_stamp
,
expected_top
.
value_
},
std
::
memory_order_relaxed
);
data_structures
::
stamped_integer
forwarded_top
{
forwarding_stamp
,
expected_top
.
value_
};
return
nullptr
;
if
(
top_
.
compare_exchange_strong
(
expected_top
,
forwarded_top
,
std
::
memory_order_relaxed
))
{
// We could update the top as needed, continue the pop request
expected_top
=
forwarded_top
;
}
else
{
// We did not get to update the top tag, back off
return
nullptr
;
}
}
}
// Try to get it by CAS with the expected field entry, giving up our offered_task for it
// Try to get it by CAS with the expected field entry, giving up our offered_task for it
...
...
lib/pls/src/internal/scheduling/scheduler.cpp
View file @
82ccdc91
...
@@ -68,8 +68,8 @@ void scheduler::work_thread_work_section() {
...
@@ -68,8 +68,8 @@ void scheduler::work_thread_work_section() {
thread_state
&
target_state
=
my_state
.
get_scheduler
().
thread_state_for
(
target
);
thread_state
&
target_state
=
my_state
.
get_scheduler
().
thread_state_for
(
target
);
#if PLS_SLEEP_WORKERS_ON_EMPTY
#if PLS_SLEEP_WORKERS_ON_EMPTY
queue_empty_flag_retry_steal
:
queue_empty_flag_retry_steal
:
// TODO: relax atomics for empty flag
data_structures
::
stamped_integer
data_structures
::
stamped_integer
target_queue_empty_flag
=
target_state
.
get_queue_empty_flag
().
load
(
);
target_queue_empty_flag
=
target_state
.
get_queue_empty_flag
().
load
(
std
::
memory_order_relaxed
);
#endif
#endif
base_task
*
stolen_task
;
base_task
*
stolen_task
;
...
@@ -93,7 +93,7 @@ void scheduler::work_thread_work_section() {
...
@@ -93,7 +93,7 @@ void scheduler::work_thread_work_section() {
strain_local_resource
::
acquire_locally
(
stolen_resources
,
my_state
.
get_thread_id
());
strain_local_resource
::
acquire_locally
(
stolen_resources
,
my_state
.
get_thread_id
());
PLS_ASSERT_EXPENSIVE
(
check_task_chain_forward
(
*
my_state
.
get_active_task
()),
PLS_ASSERT_EXPENSIVE
(
check_task_chain_forward
(
*
my_state
.
get_active_task
()),
"We are sole owner of this chain, it has to be valid!"
);
"We are sole owner of this chain, it has to be valid!"
);
// Execute the stolen task by jumping to it's continuation.
// Execute the stolen task by jumping to it's continuation.
PLS_ASSERT
(
stolen_task
->
continuation_
.
valid
(),
PLS_ASSERT
(
stolen_task
->
continuation_
.
valid
(),
...
@@ -125,7 +125,8 @@ void scheduler::work_thread_work_section() {
...
@@ -125,7 +125,8 @@ void scheduler::work_thread_work_section() {
data_structures
::
stamped_integer
data_structures
::
stamped_integer
maybe_empty_flag
{
target_queue_empty_flag
.
stamp_
+
1
,
EMPTY_QUEUE_STATE
::
QUEUE_MAYBE_EMPTY
};
maybe_empty_flag
{
target_queue_empty_flag
.
stamp_
+
1
,
EMPTY_QUEUE_STATE
::
QUEUE_MAYBE_EMPTY
};
if
(
target_state
.
get_queue_empty_flag
().
compare_exchange_strong
(
target_queue_empty_flag
,
if
(
target_state
.
get_queue_empty_flag
().
compare_exchange_strong
(
target_queue_empty_flag
,
maybe_empty_flag
))
{
maybe_empty_flag
,
std
::
memory_order_acq_rel
))
{
goto
queue_empty_flag_retry_steal
;
goto
queue_empty_flag_retry_steal
;
}
}
break
;
break
;
...
@@ -135,7 +136,9 @@ void scheduler::work_thread_work_section() {
...
@@ -135,7 +136,9 @@ void scheduler::work_thread_work_section() {
// We can safely mark it empty and increment the central counter.
// We can safely mark it empty and increment the central counter.
data_structures
::
stamped_integer
data_structures
::
stamped_integer
empty_flag
{
target_queue_empty_flag
.
stamp_
+
1
,
EMPTY_QUEUE_STATE
::
QUEUE_EMPTY
};
empty_flag
{
target_queue_empty_flag
.
stamp_
+
1
,
EMPTY_QUEUE_STATE
::
QUEUE_EMPTY
};
if
(
target_state
.
get_queue_empty_flag
().
compare_exchange_strong
(
target_queue_empty_flag
,
empty_flag
))
{
if
(
target_state
.
get_queue_empty_flag
().
compare_exchange_strong
(
target_queue_empty_flag
,
empty_flag
,
std
::
memory_order_acq_rel
))
{
// We marked it empty, now its our duty to modify the central counter
// We marked it empty, now its our duty to modify the central counter
my_state
.
get_scheduler
().
empty_queue_increase_counter
();
my_state
.
get_scheduler
().
empty_queue_increase_counter
();
}
}
...
...
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