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
0dc56d42
authored
May 13, 2019
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rework cas_integer interface to be OO instead of functional.
parent
d553ed51
Pipeline
#1189
passed with stages
in 3 minutes 53 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
51 additions
and
75 deletions
+51
-75
lib/pls/CMakeLists.txt
+0
-1
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
+23
-22
lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h
+28
-28
lib/pls/include/pls/internal/helpers/split_integer.h
+0
-24
No files found.
lib/pls/CMakeLists.txt
View file @
0dc56d42
...
...
@@ -27,7 +27,6 @@ add_library(pls STATIC
include/pls/internal/helpers/profiler.h
include/pls/internal/helpers/mini_benchmark.h
include/pls/internal/helpers/unique_id.h
include/pls/internal/helpers/split_integer.h
include/pls/internal/scheduling/root_task.h src/internal/scheduling/root_task.cpp
include/pls/internal/scheduling/thread_state.h src/internal/scheduling/thread_state.cpp
...
...
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
View file @
0dc56d42
...
...
@@ -7,7 +7,6 @@
#include "pls/internal/scheduling/thread_state.h"
#include "pls/internal/base/system_details.h"
#include "pls/internal/base/error_handling.h"
#include "pls/internal/helpers/split_integer.h"
#include "aligned_stack.h"
...
...
@@ -19,21 +18,23 @@ using base::system_details::pointer_t;
// Integer split into two halfs, can be used in CAS operations
constexpr
unsigned
long
HALF_CACHE_LINE
=
base
::
system_details
::
CACHE_LINE_SIZE
/
2
;
using
cas_integer
=
helpers
::
split_integer
<
HALF_CACHE_LINE
,
HALF_CACHE_LINE
>
;
static
unsigned
long
get_stamp
(
cas_integer
n
)
{
return
n
.
left
;
}
static
unsigned
long
get_offset
(
cas_integer
n
)
{
return
n
.
right
;
}
static
cas_integer
set_stamp
(
cas_integer
n
,
unsigned
long
new_value
)
{
n
.
left
=
new_value
;
return
n
;
}
using
offset_t
=
base
::
system_details
::
cas_integer
;
struct
stamped_integer
{
offset_t
stamp
:
HALF_CACHE_LINE
;
offset_t
offset
:
HALF_CACHE_LINE
;
stamped_integer
()
:
stamp
{
0
},
offset
{
0
}
{};
stamped_integer
(
offset_t
new_offset
)
:
stamp
{
0
},
offset
{
new_offset
}
{};
stamped_integer
(
offset_t
new_stamp
,
offset_t
new_offset
)
:
stamp
{
new_stamp
},
offset
{
new_offset
}
{};
};
// Single Item in the deque
class
work_stealing_deque_item
{
// Pointer to the actual data
pointer_t
data_
;
// Index (relative to stack base) to the next and previous element
unsigned
long
next_item_
;
unsigned
long
previous_item_
;
offset_t
next_item_
;
offset_t
previous_item_
;
public
:
work_stealing_deque_item
()
:
data_
{
0
},
next_item_
{},
previous_item_
{}
{}
...
...
@@ -48,11 +49,11 @@ class work_stealing_deque_item {
data_
=
reinterpret_cast
<
pointer_t
>
(
data
);
}
unsigned
long
next_item
()
const
{
return
next_item_
;
}
void
set_next_item
(
unsigned
long
next_item
)
{
next_item_
=
next_item
;
}
offset_t
next_item
()
const
{
return
next_item_
;
}
void
set_next_item
(
offset_t
next_item
)
{
next_item_
=
next_item
;
}
unsigned
long
previous_item
()
const
{
return
previous_item_
;
}
void
set_previous_item
(
unsigned
long
previous_item
)
{
previous_item_
=
previous_item
;
}
offset_t
previous_item
()
const
{
return
previous_item_
;
}
void
set_previous_item
(
offset_t
previous_item
)
{
previous_item_
=
previous_item
;
}
};
static_assert
(
sizeof
(
work_stealing_deque_item
)
<
base
::
system_details
::
CACHE_LINE_SIZE
,
"Work stealing deque relies on memory layout and requires cache lines to be longer than one 'work_stealing_deque_item' instance!"
);
...
...
@@ -64,18 +65,18 @@ class work_stealing_deque {
aligned_stack
*
stack_
;
pointer_t
base_pointer_
;
std
::
atomic
<
cas
_integer
>
head_
;
std
::
atomic
<
cas_integer
>
tail_
;
cas_integer
previous_tail_
;
std
::
atomic
<
stamped
_integer
>
head_
;
std
::
atomic
<
offset_t
>
tail_
;
offset_t
previous_tail_
;
public
:
using
state
=
aligned_stack
::
state
;
explicit
work_stealing_deque
(
aligned_stack
*
stack
)
:
stack_
{
stack
},
base_pointer_
{
0
},
head_
{
cas_integer
{
}},
tail_
{
cas_integer
{}
},
previous_tail_
{
cas_integer
{}
}
{
head_
{
stamped_integer
{
0
,
0
}},
tail_
{
0
},
previous_tail_
{
0
}
{
reset_base_pointer
();
}
work_stealing_deque
(
const
work_stealing_deque
&
other
)
:
stack_
{
other
.
stack_
},
...
...
@@ -85,8 +86,8 @@ class work_stealing_deque {
previous_tail_
{
other
.
previous_tail_
}
{}
void
reset_base_pointer
();
work_stealing_deque_item
*
item_at
(
unsigned
long
offset
);
unsigned
long
current_stack_offset
();
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
);
...
...
lib/pls/include/pls/internal/data_structures/work_stealing_deque_impl.h
View file @
0dc56d42
...
...
@@ -12,13 +12,13 @@ void work_stealing_deque<Item>::reset_base_pointer() {
}
template
<
typename
Item
>
work_stealing_deque_item
*
work_stealing_deque
<
Item
>::
item_at
(
unsigned
long
offset
)
{
work_stealing_deque_item
*
work_stealing_deque
<
Item
>::
item_at
(
offset_t
offset
)
{
return
reinterpret_cast
<
work_stealing_deque_item
*>
(
base_pointer_
+
(
base
::
system_details
::
CACHE_LINE_SIZE
*
offset
));
}
template
<
typename
Item
>
unsigned
long
work_stealing_deque
<
Item
>::
current_stack_offset
()
{
offset_t
work_stealing_deque
<
Item
>::
current_stack_offset
()
{
return
(
stack_
->
save_state
()
-
base_pointer_
)
/
base
::
system_details
::
CACHE_LINE_SIZE
;
}
...
...
@@ -39,18 +39,18 @@ std::pair<work_stealing_deque_item, T> *work_stealing_deque<Item>::allocate_item
template
<
typename
Item
>
template
<
typename
T
>
Item
*
work_stealing_deque
<
Item
>::
push_tail
(
const
T
&
new_item
)
{
cas_integer
local_tail
=
tail_
;
offset_t
local_tail
=
tail_
;
auto
new_pair
=
allocate_item
(
new_item
);
// Prepare current tail to point to correct next items
auto
tail_deque_item
=
item_at
(
get_offset
(
local_tail
)
);
auto
tail_deque_item
=
item_at
(
local_tail
);
tail_deque_item
->
set_data
(
&
(
new_pair
->
second
));
tail_deque_item
->
set_next_item
(
current_stack_offset
());
tail_deque_item
->
set_previous_item
(
get_offset
(
previous_tail_
)
);
tail_deque_item
->
set_previous_item
(
previous_tail_
);
previous_tail_
=
local_tail
;
// Linearization point, item appears after this write
cas_integer
new_tail
=
cas_integer
{
0
,
current_stack_offset
()}
;
offset_t
new_tail
=
current_stack_offset
()
;
tail_
=
new_tail
;
return
&
(
new_pair
->
second
);
...
...
@@ -58,28 +58,28 @@ Item *work_stealing_deque<Item>::push_tail(const T &new_item) {
template
<
typename
Item
>
Item
*
work_stealing_deque
<
Item
>::
pop_tail
()
{
cas_integer
local_tail
=
tail_
;
cas
_integer
local_head
=
head_
;
offset_t
local_tail
=
tail_
;
stamped
_integer
local_head
=
head_
;
if
(
get_offset
(
local_tail
)
<=
get_offset
(
local_head
)
)
{
if
(
local_tail
<=
local_head
.
offset
)
{
return
nullptr
;
// EMPTY
}
work_stealing_deque_item
*
previous_tail_item
=
item_at
(
get_offset
(
previous_tail_
)
);
cas_integer
new_tail
=
previous_tail_
;
previous_tail_
=
cas_integer
{
0
,
previous_tail_item
->
previous_item
()}
;
work_stealing_deque_item
*
previous_tail_item
=
item_at
(
previous_tail_
);
offset_t
new_tail
=
previous_tail_
;
previous_tail_
=
previous_tail_item
->
previous_item
()
;
// Publish our wish to set the tail back
tail_
=
new_tail
;
// Get the state of local head AFTER we published our wish
local_head
=
head_
;
// Linearization point, outside knows list is empty
if
(
get_offset
(
local_head
)
<
get_offset
(
new_tail
)
)
{
if
(
local_head
.
offset
<
new_tail
)
{
return
previous_tail_item
->
data
<
Item
>
();
// Success, enough distance to other threads
}
if
(
get_offset
(
local_head
)
==
get_offset
(
new_tail
)
)
{
cas_integer
new_head
=
set_stamp
(
new_tail
,
get_stamp
(
local_head
)
+
1
)
;
if
(
local_head
.
offset
==
new_tail
)
{
stamped_integer
new_head
=
stamped_integer
{
local_head
.
stamp
+
1
,
new_tail
}
;
// Try competing with consumers by updating the head's stamp value
if
(
head_
.
compare_exchange_strong
(
local_head
,
new_head
))
{
return
previous_tail_item
->
data
<
Item
>
();
// SUCCESS, we won the competition with other threads
...
...
@@ -89,25 +89,25 @@ Item *work_stealing_deque<Item>::pop_tail() {
// Some other thread either won the competition or it already set the head further than we are
// before we even tried to compete with it.
// Reset the queue into an empty state => head_ = tail_
tail_
=
cas_integer
{
0
,
get_offset
(
local_head
)}
;
// ...we give up to the other winning thread
tail_
=
local_head
.
offset
;
// ...we give up to the other winning thread
return
nullptr
;
// EMPTY, we lost the competition with other threads
}
template
<
typename
Item
>
Item
*
work_stealing_deque
<
Item
>::
pop_head
()
{
cas
_integer
local_head
=
head_
;
cas_integer
local_tail
=
tail_
;
stamped
_integer
local_head
=
head_
;
offset_t
local_tail
=
tail_
;
if
(
get_offset
(
local_tail
)
<=
get_offset
(
local_head
)
)
{
if
(
local_tail
<=
local_head
.
offset
)
{
return
nullptr
;
// EMPTY
}
// Load info on current deque item.
// In case we have a race with a new (aba) overwritten item at this position,
// there has to be a competition over the tail -> the stamp increased and our next
// operation will fail anyways!
work_stealing_deque_item
*
head_deque_item
=
item_at
(
get_offset
(
local_head
)
);
unsigned
long
next_item_offset
=
head_deque_item
->
next_item
();
work_stealing_deque_item
*
head_deque_item
=
item_at
(
local_head
.
offset
);
offset_t
next_item_offset
=
head_deque_item
->
next_item
();
Item
*
head_data_item
=
head_deque_item
->
data
<
Item
>
();
// We try to set the head to this new position.
...
...
@@ -115,7 +115,7 @@ Item *work_stealing_deque<Item>::pop_head() {
// 1) no one interrupted us, we win this competition
// 2) other thread took the head, we lose to this
// 3) owning thread removed tail, we lose to this
cas_integer
new_head
=
cas_integer
{
get_stamp
(
local_head
)
+
1
,
next_item_offset
};
stamped_integer
new_head
=
stamped_integer
{
local_head
.
stamp
+
1
,
next_item_offset
};
if
(
head_
.
compare_exchange_strong
(
local_head
,
new_head
))
{
return
head_data_item
;
// SUCCESS, we won the competition
}
...
...
@@ -127,15 +127,15 @@ template<typename Item>
void
work_stealing_deque
<
Item
>::
release_memory_until
(
state
state
)
{
unsigned
long
item_offset
=
(
state
-
base_pointer_
)
/
base
::
system_details
::
CACHE_LINE_SIZE
;
cas
_integer
local_head
=
head_
;
cas_integer
local_tail
=
tail_
;
stamped
_integer
local_head
=
head_
;
offset_t
local_tail
=
tail_
;
stack_
->
reset_state
(
state
);
if
(
item_offset
<
get_offset
(
local_tail
)
)
{
tail_
=
cas_integer
{
0
,
item_offset
}
;
if
(
get_offset
(
local_head
)
>=
get_offset
(
local_tail
)
)
{
head_
=
cas_integer
{
get_stamp
(
local_head
)
+
1
,
item_offset
};
if
(
item_offset
<
local_tail
)
{
tail_
=
item_offset
;
if
(
local_head
.
offset
>=
local_tail
)
{
head_
=
stamped_integer
{
local_head
.
stamp
+
1
,
item_offset
};
}
}
}
...
...
lib/pls/include/pls/internal/helpers/split_integer.h
deleted
100644 → 0
View file @
d553ed51
#ifndef PLS_SPLIT_INTEGER_H_
#define PLS_SPLIT_INTEGER_H_
#include "pls/internal/base/system_details.h"
namespace
pls
{
namespace
internal
{
namespace
helpers
{
template
<
int
L
,
int
R
>
struct
split_integer
{
unsigned
long
left
:
L
;
unsigned
long
right
:
R
;
split_integer
()
:
left
{
0
},
right
{
0
}
{};
split_integer
(
unsigned
long
new_left
,
unsigned
long
new_right
)
:
left
{
new_left
},
right
{
new_right
}
{};
};
}
}
}
#endif //PLS_SPLIT_CAS_INTEGER_H_
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