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
9cf034e4
authored
Jun 12, 2019
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Unify interface from different deques
parent
daee4696
Pipeline
#1264
failed with stages
in 50 seconds
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
264 additions
and
204 deletions
+264
-204
lib/pls/CMakeLists.txt
+1
-0
lib/pls/include/pls/internal/data_structures/locking_deque.h
+12
-64
lib/pls/include/pls/internal/data_structures/locking_deque_impl.h
+89
-0
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
+0
-5
test/data_structures_test.cpp
+162
-135
No files found.
lib/pls/CMakeLists.txt
View file @
9cf034e4
...
...
@@ -23,6 +23,7 @@ add_library(pls STATIC
include/pls/internal/data_structures/aligned_stack.h src/internal/data_structures/aligned_stack.cpp
include/pls/internal/data_structures/aligned_stack_impl.h
include/pls/internal/data_structures/locking_deque.h
include/pls/internal/data_structures/locking_deque_impl.h
include/pls/internal/data_structures/work_stealing_deque.h include/pls/internal/data_structures/work_stealing_deque_impl.h
include/pls/internal/data_structures/stamped_integer.h
...
...
lib/pls/include/pls/internal/data_structures/locking_deque.h
View file @
9cf034e4
...
...
@@ -28,7 +28,8 @@ struct locking_deque_container : public locking_deque_item<Item> {
Content
content_
;
public
:
explicit
locking_deque_container
(
const
Content
&
content_
)
:
content_
{
content_
}
{}
template
<
typename
...
ARGS
>
explicit
locking_deque_container
(
ARGS
&&
...
args
)
:
content_
{
std
::
forward
<
ARGS
>
(
args
)...}
{}
};
/**
...
...
@@ -52,73 +53,20 @@ class locking_deque {
explicit
locking_deque
(
aligned_stack
*
stack
)
:
stack_
{
stack
},
head_
{
nullptr
},
tail_
{
nullptr
},
lock_
{}
{}
template
<
typename
T
>
T
*
push_tail
(
const
T
&
new_item
)
{
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>"
);
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
auto
deque_item
=
stack_
->
push
<
locking_deque_container
<
Item
,
T
>>
(
new_item
);
deque_item
->
item_
=
&
deque_item
->
content_
;
if
(
tail_
!=
nullptr
)
{
tail_
->
next_
=
deque_item
;
}
else
{
head_
=
deque_item
;
}
deque_item
->
prev_
=
tail_
;
deque_item
->
next_
=
nullptr
;
tail_
=
deque_item
;
return
&
deque_item
->
content_
;
}
Item
*
pop_tail
()
{
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
if
(
tail_
==
nullptr
)
{
return
nullptr
;
}
auto
result
=
tail_
;
tail_
=
tail_
->
prev_
;
if
(
tail_
==
nullptr
)
{
head_
=
nullptr
;
}
else
{
tail_
->
next_
=
nullptr
;
}
return
result
->
item_
;
}
Item
*
pop_head
()
{
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
if
(
head_
==
nullptr
)
{
return
nullptr
;
}
auto
result
=
head_
;
head_
=
head_
->
next_
;
if
(
head_
==
nullptr
)
{
tail_
=
nullptr
;
}
else
{
head_
->
prev_
=
nullptr
;
}
return
result
->
item_
;
}
void
release_memory_until
(
state
state
)
{
stack_
->
reset_state
(
state
);
}
state
save_state
()
{
return
stack_
->
save_state
();
}
template
<
typename
T
,
typename
...
ARGS
>
T
*
push_tail
(
ARGS
&&
...
args
);
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
T
*
push_tail_cb
(
const
Function
&
after_creation
,
ARGS
&&
...
args
);
Item
*
pop_tail
();
Item
*
pop_head
();
void
release_memory_until
(
state
state
);
state
save_state
();
};
}
}
}
#include "locking_deque_impl.h"
#endif //PLS_LOCKING_DEQUE_H
lib/pls/include/pls/internal/data_structures/locking_deque_impl.h
0 → 100644
View file @
9cf034e4
#ifndef PLS_LOCKING_DEQUE_IMPL_H_
#define PLS_LOCKING_DEQUE_IMPL_H_
namespace
pls
{
namespace
internal
{
namespace
data_structures
{
template
<
typename
Item
>
template
<
typename
T
,
typename
...
ARGS
>
T
*
locking_deque
<
Item
>::
push_tail
(
ARGS
&&
...
args
)
{
return
push_tail_cb
<
T
>
([](
T
*
)
{},
std
::
forward
<
ARGS
>
(
args
)...);
}
template
<
typename
Item
>
template
<
typename
T
,
typename
Function
,
typename
...
ARGS
>
T
*
locking_deque
<
Item
>::
push_tail_cb
(
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>"
);
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
auto
deque_item
=
stack_
->
push
<
locking_deque_container
<
Item
,
T
>>
(
std
::
forward
<
ARGS
>
(
args
)...);
deque_item
->
item_
=
&
deque_item
->
content_
;
after_creation
(
&
deque_item
->
content_
);
if
(
tail_
!=
nullptr
)
{
tail_
->
next_
=
deque_item
;
}
else
{
head_
=
deque_item
;
}
deque_item
->
prev_
=
tail_
;
deque_item
->
next_
=
nullptr
;
tail_
=
deque_item
;
return
&
deque_item
->
content_
;
}
template
<
typename
Item
>
Item
*
locking_deque
<
Item
>::
pop_tail
()
{
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
if
(
tail_
==
nullptr
)
{
return
nullptr
;
}
auto
result
=
tail_
;
tail_
=
tail_
->
prev_
;
if
(
tail_
==
nullptr
)
{
head_
=
nullptr
;
}
else
{
tail_
->
next_
=
nullptr
;
}
return
result
->
item_
;
}
template
<
typename
Item
>
Item
*
locking_deque
<
Item
>::
pop_head
()
{
std
::
lock_guard
<
base
::
spin_lock
>
lock
{
lock_
};
if
(
head_
==
nullptr
)
{
return
nullptr
;
}
auto
result
=
head_
;
head_
=
head_
->
next_
;
if
(
head_
==
nullptr
)
{
tail_
=
nullptr
;
}
else
{
head_
->
prev_
=
nullptr
;
}
return
result
->
item_
;
}
template
<
typename
Item
>
void
locking_deque
<
Item
>::
release_memory_until
(
state
state
)
{
stack_
->
reset_state
(
state
);
}
template
<
typename
Item
>
typename
locking_deque
<
Item
>::
state
locking_deque
<
Item
>::
save_state
()
{
return
stack_
->
save_state
();
}
}
}
}
#endif //PLS_LOCKING_DEQUE_IMPL_H_
lib/pls/include/pls/internal/data_structures/work_stealing_deque.h
View file @
9cf034e4
...
...
@@ -75,11 +75,6 @@ class work_stealing_deque {
previous_tail_
{
0
}
{
reset_base_pointer
();
}
work_stealing_deque
(
const
work_stealing_deque
&
other
)
:
stack_
{
other
.
stack_
},
base_pointer_
{
other
.
base_pointer_
},
head_
{
other
.
head_
.
load
()},
tail_
{
other
.
tail_
.
load
()},
previous_tail_
{
other
.
previous_tail_
}
{}
template
<
typename
T
,
typename
...
ARGS
>
T
*
push_tail
(
ARGS
&&
...
args
);
...
...
test/data_structures_test.cpp
View file @
9cf034e4
...
...
@@ -76,145 +76,172 @@ TEST_CASE("aligned stack stores objects correctly", "[internal/data_structures/a
}
}
TEST_CASE
(
"deque stores objects correctly"
,
"[internal/data_structures/deque.h]"
)
{
class
my_item
{
};
constexpr
long
data_size
=
2
<<
14
;
char
data
[
data_size
];
aligned_stack
stack
{
data
,
data_size
};
locking_deque
<
int
>
deque
{
&
stack
};
int
one
=
1
,
two
=
2
,
three
=
3
;
TEST_CASE
(
"work_stealing_deque functions correctly"
,
"[internal/data_structures/work_stealing_deque.h]"
)
{
SECTION
(
"add and remove items form the tail"
)
{
deque
.
push_tail
(
one
);
deque
.
push_tail
(
two
);
deque
.
push_tail
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
}
SECTION
(
"handles getting empty by popping the tail correctly"
)
{
deque
.
push_tail
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
}
SECTION
(
"remove items form the head"
)
{
deque
.
push_tail
(
one
);
deque
.
push_tail
(
two
);
deque
.
push_tail
(
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
}
SECTION
(
"handles getting empty by popping the head correctly"
)
{
deque
.
push_tail
(
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
deque
.
push_tail
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
}
SECTION
(
"handles getting empty by popping the head and tail correctly"
)
{
deque
.
push_tail
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
deque
.
push_tail
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
constexpr
long
data_size
=
2
<<
14
;
char
data
[
data_size
];
aligned_stack
stack
{
data
,
data_size
};
work_stealing_deque
<
int
>
deque
{
&
stack
};
int
one
=
1
,
two
=
2
,
three
=
3
,
four
=
4
;
SECTION
(
"add and remove items form the tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
}
SECTION
(
"handles getting empty by popping the tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
}
SECTION
(
"remove items form the head"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
}
SECTION
(
"handles getting empty by popping the head correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
}
SECTION
(
"handles getting empty by popping the head and tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
}
SECTION
(
"handles jumps bigger 1 correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
four
);
}
SECTION
(
"handles stack reset 1 correctly when emptied by tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
auto
state
=
deque
.
save_state
();
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
release_memory_until
(
state
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
four
);
}
}
}
TEST_CASE
(
"work stealing deque stores objects correctly"
,
"[internal/data_structures/aligned_stack.h]"
)
{
constexpr
long
data_size
=
2
<<
14
;
char
data
[
data_size
];
aligned_stack
stack
{
data
,
data_size
};
work_stealing_deque
<
int
>
deque
{
&
stack
};
int
one
=
1
,
two
=
2
,
three
=
3
,
four
=
4
;
TEST_CASE
(
"locking_deque functions correctly"
,
"[internal/data_structures/locking_deque.h]"
)
{
SECTION
(
"add and remove items form the tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
}
SECTION
(
"handles getting empty by popping the tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
}
SECTION
(
"remove items form the head"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
}
SECTION
(
"handles getting empty by popping the head correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
}
SECTION
(
"handles getting empty by popping the head and tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
}
SECTION
(
"handles jumps bigger 1 correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
four
);
}
SECTION
(
"handles stack reset 1 correctly when emptied by tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
auto
state
=
deque
.
save_state
();
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
release_memory_until
(
state
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
four
);
constexpr
long
data_size
=
2
<<
14
;
char
data
[
data_size
];
aligned_stack
stack
{
data
,
data_size
};
locking_deque
<
int
>
deque
{
&
stack
};
int
one
=
1
,
two
=
2
,
three
=
3
,
four
=
4
;
SECTION
(
"add and remove items form the tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
}
SECTION
(
"handles getting empty by popping the tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
}
SECTION
(
"remove items form the head"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
}
SECTION
(
"handles getting empty by popping the head correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
}
SECTION
(
"handles getting empty by popping the head and tail correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_head
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
three
);
}
SECTION
(
"handles jumps bigger 1 correctly"
)
{
deque
.
push_tail
<
int
>
(
one
);
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
one
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_head
()
==
four
);
}
SECTION
(
"handles stack reset 1 correctly when emptied by tail"
)
{
deque
.
push_tail
<
int
>
(
one
);
auto
state
=
deque
.
save_state
();
deque
.
push_tail
<
int
>
(
two
);
REQUIRE
(
*
deque
.
pop_tail
()
==
two
);
deque
.
release_memory_until
(
state
);
REQUIRE
(
*
deque
.
pop_tail
()
==
one
);
deque
.
push_tail
<
int
>
(
three
);
deque
.
push_tail
<
int
>
(
four
);
REQUIRE
(
*
deque
.
pop_head
()
==
three
);
REQUIRE
(
*
deque
.
pop_tail
()
==
four
);
}
}
}
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