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
b7f42e2b
authored
Apr 12, 2019
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add proper unique_ids for tasks.
parent
48804e8f
Pipeline
#1149
passed with stages
in 3 minutes 35 seconds
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
89 additions
and
32 deletions
+89
-32
NOTES.md
+25
-0
app/playground/CMakeLists.txt
+1
-2
app/playground/main.cpp
+6
-8
lib/pls/CMakeLists.txt
+1
-1
lib/pls/include/pls/algorithms/invoke_parallel_impl.h
+5
-2
lib/pls/include/pls/internal/helpers/unique_id.h
+31
-0
lib/pls/include/pls/internal/scheduling/abstract_task.h
+2
-12
lib/pls/include/pls/internal/scheduling/root_task.h
+7
-3
lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h
+6
-2
lib/pls/include/pls/pls.h
+3
-0
test/scheduling_tests.cpp
+2
-2
No files found.
NOTES.md
View file @
b7f42e2b
...
...
@@ -4,6 +4,31 @@ A collection of stuff that we noticed during development.
Useful later on two write a project report and to go back
in time to find out why certain decisions where made.
## 12.04.2019 - Unique IDs
Assigning unique IDs to logical different tasks is key to the
current model of separating timing/memory guarantees for certain
parallel patterns.
We do want to assign these IDs automatic in most cases (a call to
some parallel API should not require the end user to specific a
unique ID for each different call, as this would be error prone).
Instead we want to make sure that each DIFFERENT API call is separated
automatic, while leaving the option for manual ID assignment for later
implementations of GPU offloading (tasks need to have identifiers for
this to work properly).
Our first approach was using the
`__COUNTER__`
macro,
but this only works in ONE COMPLIATION UNIT and is not
portable to all compilers.
As all our unique instances are copled to a class/type
we decided to implement the unique IDs using
typeid(tuple
<T
..
>
) in automatic cases (bound to a specific type)
and fully manual IDs in other types. All this is wrapped in a
helper::unique_id class.
## 11.04.2019 - Lambda Pointer Abstraction
The question is if we could use a pointer to a lambda without
...
...
app/playground/CMakeLists.txt
View file @
b7f42e2b
add_executable
(
playground main.cpp
)
# Example for adding the library to your app (as a cmake project dependency)
target_link_libraries
(
playground pls
)
\ No newline at end of file
target_link_libraries
(
playground pls
)
app/playground/main.cpp
View file @
b7f42e2b
...
...
@@ -4,16 +4,14 @@
#include <array>
#include <atomic>
#include <memory>
#include <typeindex>
#include <tuple>
#include <pls/pls.h>
#include <pls/internal/helpers/prohibit_new.h>
#include <pls/internal/scheduling/thread_state.h>
#include <pls/internal/scheduling/root_task.h>
#include <pls/internal/helpers/unique_id.h>
using
namespace
pls
;
int
main
()
{
malloc_scheduler_memory
sched_memory
{
8
};
std
::
cout
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_for
(
0
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_for
(
1
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_for
(
2
)
%
64
<<
", "
<<
std
::
endl
;
std
::
cout
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_state_for
(
0
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_state_for
(
1
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
thread_state_for
(
2
)
%
64
<<
", "
<<
std
::
endl
;
std
::
cout
<<
(
std
::
uintptr_t
)
sched_memory
.
task_stack_for
(
0
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
task_stack_for
(
1
)
%
64
<<
", "
<<
(
std
::
uintptr_t
)
sched_memory
.
task_stack_for
(
2
)
%
64
<<
", "
<<
std
::
endl
;
std
::
cout
<<
pls
::
internal
::
scheduling
::
root_task
<
void
(
*
)
>::
create_id
().
type_
.
hash_code
()
<<
std
::
endl
;
std
::
cout
<<
pls
::
internal
::
helpers
::
unique_id
::
create
<
pls
::
internal
::
scheduling
::
root_task
<
void
(
*
)
>>
().
type_
.
hash_code
()
<<
std
::
endl
;
}
lib/pls/CMakeLists.txt
View file @
b7f42e2b
...
...
@@ -29,7 +29,7 @@ add_library(pls STATIC
include/pls/internal/scheduling/run_on_n_threads_task.h src/internal/scheduling/run_on_n_threads_task.cpp
include/pls/internal/scheduling/fork_join_task.h src/internal/scheduling/fork_join_task.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
)
include/pls/internal/helpers/unique_id.h
)
# Add everything in `./include` to be in the include path of this project
target_include_directories
(
pls
...
...
lib/pls/include/pls/algorithms/invoke_parallel_impl.h
View file @
b7f42e2b
...
...
@@ -4,6 +4,7 @@
#include "pls/internal/scheduling/fork_join_task.h"
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/helpers/unique_id.h"
namespace
pls
{
namespace
algorithm
{
...
...
@@ -29,7 +30,8 @@ namespace pls {
template
<
typename
Function1
,
typename
Function2
>
void
invoke_parallel
(
const
Function1
&
function1
,
const
Function2
&
function2
)
{
using
namespace
::
pls
::
internal
::
scheduling
;
static
abstract_task
::
id
id
{
PLS_UNIQUE_ID
,
true
};
using
namespace
::
pls
::
internal
::
helpers
;
static
abstract_task
::
id
id
=
unique_id
::
create
<
Function1
,
Function2
>
();
auto
internal_body
=
[
&
]
(
fork_join_sub_task
*
this_task
){
auto
sub_task_body_1
=
[
&
]
(
fork_join_sub_task
*
){
function1
();
};
...
...
@@ -46,7 +48,8 @@ namespace pls {
template
<
typename
Function1
,
typename
Function2
,
typename
Function3
>
void
invoke_parallel
(
const
Function1
&
function1
,
const
Function2
&
function2
,
const
Function3
&
function3
)
{
using
namespace
::
pls
::
internal
::
scheduling
;
static
abstract_task
::
id
id
{
PLS_UNIQUE_ID
,
true
};
using
namespace
::
pls
::
internal
::
helpers
;
static
abstract_task
::
id
id
=
unique_id
::
create
<
Function1
,
Function2
,
Function3
>
();
auto
internal_body
=
[
&
]
(
fork_join_sub_task
*
this_task
){
auto
sub_task_body_1
=
[
&
]
(
fork_join_sub_task
*
){
function1
();
};
...
...
lib/pls/include/pls/internal/helpers/unique_id.h
0 → 100644
View file @
b7f42e2b
#ifndef PLS_UNIQUE_ID_H
#define PLS_UNIQUE_ID_H
#include <typeindex>
#include <tuple>
#include <stdint.h>
namespace
pls
{
namespace
internal
{
namespace
helpers
{
struct
unique_id
{
const
uint32_t
id_
;
const
std
::
type_info
&
type_
;
bool
operator
==
(
const
unique_id
&
other
)
const
{
return
id_
==
other
.
id_
&&
type_
==
other
.
type_
;
}
static
constexpr
unique_id
create
(
const
uint32_t
id
)
{
return
unique_id
(
id
,
typeid
(
void
));
}
template
<
typename
...
T
>
static
constexpr
unique_id
create
()
{
return
unique_id
(
UINT32_MAX
,
typeid
(
std
::
tuple
<
T
...
>
));
}
private
:
explicit
constexpr
unique_id
(
const
uint32_t
id
,
const
std
::
type_info
&
type
)
:
id_
{
id
},
type_
{
type
}
{};
};
}
}
}
#endif //PLS_UNIQUE_ID_H
lib/pls/include/pls/internal/scheduling/abstract_task.h
View file @
b7f42e2b
...
...
@@ -2,25 +2,15 @@
#ifndef PLS_ABSTRACT_TASK_H
#define PLS_ABSTRACT_TASK_H
#define PLS_UNIQUE_ID __COUNTER__
#include "pls/internal/base/spin_lock.h"
#include "pls/internal/helpers/unique_id.h"
namespace
pls
{
namespace
internal
{
namespace
scheduling
{
class
abstract_task
{
public
:
struct
id
{
uint32_t
id_
;
bool
auto_generated_
;
explicit
id
(
uint32_t
id
,
bool
auto_generated
=
false
)
:
id_
{
id
},
auto_generated_
{
auto_generated
}
{};
bool
operator
==
(
const
abstract_task
::
id
&
other
)
const
{
return
id_
==
other
.
id_
&&
auto_generated_
==
other
.
auto_generated_
;
}
};
using
id
=
helpers
::
unique_id
;
private
:
int
depth_
;
...
...
lib/pls/include/pls/internal/scheduling/root_task.h
View file @
b7f42e2b
...
...
@@ -17,12 +17,14 @@ namespace pls {
Function
function_
;
std
::
atomic_uint8_t
finished_
;
public
:
static
constexpr
auto
create_id
=
helpers
::
unique_id
::
create
<
root_task
<
Function
>>
;
explicit
root_task
(
Function
function
)
:
abstract_task
{
0
,
id
{
0
}
},
abstract_task
{
0
,
create_id
()
},
function_
{
function
},
finished_
{
0
}
{}
root_task
(
const
root_task
&
other
)
:
abstract_task
{
0
,
id
{
0
}
},
abstract_task
{
0
,
create_id
()
},
function_
{
other
.
function_
},
finished_
{
0
}
{}
...
...
@@ -50,8 +52,10 @@ namespace pls {
root_task
<
Function
>*
master_task_
;
public
:
static
constexpr
auto
create_id
=
root_task
<
Function
>::
create_id
;
explicit
root_worker_task
(
root_task
<
Function
>*
master_task
)
:
abstract_task
{
0
,
id
{
0
}
},
abstract_task
{
0
,
create_id
()
},
master_task_
{
master_task
}
{}
void
execute
()
override
{
...
...
lib/pls/include/pls/internal/scheduling/run_on_n_threads_task.h
View file @
b7f42e2b
...
...
@@ -36,8 +36,10 @@ namespace pls {
return
counter
;
}
public
:
static
constexpr
auto
create_id
=
helpers
::
unique_id
::
create
<
run_on_n_threads_task
<
Function
>>
;
run_on_n_threads_task
(
Function
function
,
int
num_threads
)
:
abstract_task
{
0
,
id
{
PLS_UNIQUE_ID
,
true
}
},
abstract_task
{
0
,
create_id
()
},
function_
{
function
},
counter
{
num_threads
-
1
}
{}
...
...
@@ -65,8 +67,10 @@ namespace pls {
Function
function_
;
run_on_n_threads_task
<
Function
>*
root_
;
public
:
static
constexpr
auto
create_id
=
helpers
::
unique_id
::
create
<
run_on_n_threads_task_worker
<
Function
>>
;
run_on_n_threads_task_worker
(
Function
function
,
run_on_n_threads_task
<
Function
>*
root
)
:
abstract_task
{
0
,
id
{
PLS_UNIQUE_ID
,
true
}
},
abstract_task
{
0
,
create_id
()
},
function_
{
function
},
root_
{
root
}
{}
...
...
lib/pls/include/pls/pls.h
View file @
b7f42e2b
...
...
@@ -5,6 +5,7 @@
#include "pls/internal/scheduling/abstract_task.h"
#include "pls/internal/scheduling/fork_join_task.h"
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/helpers/unique_id.h"
namespace
pls
{
using
internal
::
scheduling
::
static_scheduler_memory
;
...
...
@@ -13,6 +14,8 @@ namespace pls {
using
internal
::
scheduling
::
scheduler
;
using
task_id
=
internal
::
scheduling
::
abstract_task
::
id
;
using
unique_id
=
internal
::
helpers
::
unique_id
;
using
internal
::
scheduling
::
fork_join_sub_task
;
using
internal
::
scheduling
::
fork_join_task
;
...
...
test/scheduling_tests.cpp
View file @
b7f42e2b
...
...
@@ -58,7 +58,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t
my_scheduler
.
perform_work
([
&
]
(){
once_sub_task
sub_task
{
&
counter
,
start_counter
};
fork_join_task
task
{
&
sub_task
,
task_id
{
42
}
};
fork_join_task
task
{
&
sub_task
,
unique_id
::
create
(
42
)
};
scheduler
::
execute_task
(
task
);
});
...
...
@@ -71,7 +71,7 @@ TEST_CASE( "tbb task are scheduled correctly", "[internal/scheduling/fork_join_t
my_scheduler
.
perform_work
([
&
]
(){
std
::
atomic
<
int
>
dummy_parent
{
1
},
overall_counter
{
8
};
force_steal_sub_task
sub_task
{
&
dummy_parent
,
&
overall_counter
};
fork_join_task
task
{
&
sub_task
,
task_id
{
42
}
};
fork_join_task
task
{
&
sub_task
,
unique_id
::
create
(
42
)
};
scheduler
::
execute_task
(
task
);
});
my_scheduler
.
terminate
(
true
);
...
...
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