-
Notifications
You must be signed in to change notification settings - Fork 359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Ready] Fast Concurrent Deque Through Explicit Timestamping #127
Open
EduardBlees
wants to merge
30
commits into
khizmax:integration
Choose a base branch
from
EduardBlees:develop
base: integration
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
9d2f2af
Init ts_deque
pr3sto 4e31819
init deque_buffer
EduardBlees fff2b21
Merge branch 'develop' of github.com:EduardBlees/libcds into develop
EduardBlees c20d3c3
init timestamp
vikkiorrikki 86ff17d
add Item and initialize method
pr3sto c7c96bf
try remove left impl
EduardBlees 9f6d53e
threadcontext
EduardBlees 92efc84
implement insert_right
pr3sto a136c71
timestamp hardware
vikkiorrikki 0dcef53
insert_left implementation
pr3sto 7fdf05c
try remove right impl
EduardBlees ab723b5
timestamp hardware interval
vikkiorrikki b2a8b91
implement ts_deque
pr3sto 0178ecb
methods for fixing aba problem added
pr3sto 2bb8dce
try remove fixes, use ABA functions
EduardBlees 06542ae
fixes insert methods
pr3sto 09052d7
timestamp atomic counter
vikkiorrikki 546b8b3
assign threadcontext to each thread
pr3sto 0e4fd30
code format
EduardBlees 0181934
add clear, size and empty methods
pr3sto c4ecac4
prepare to pull request
pr3sto eb5e9f6
add unit tests
pr3sto a5ecc16
move asm code to compiler folder
pr3sto 72f5ef0
fix
pr3sto ac02558
add copyright note
pr3sto 430297f
fix emptyness check, thread_id
pr3sto ff40ba7
stress tests added
pr3sto 5ee65b5
fix tests for different architectures
pr3sto d5ece4c
fix rdtsc and rdtscp for i386 arch
pr3sto 2410e88
add rdtscp check
pr3sto File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef CDSLIB_COMPILER_GCC_AMD64_TS_HARDWARETIMESTAMP_H | ||
#define CDSLIB_COMPILER_GCC_AMD64_TS_HARDWARETIMESTAMP_H | ||
|
||
#include <cstdint> | ||
#include <cpuid.h> | ||
|
||
namespace cds { namespace tshardwaretimestamp { | ||
namespace gcc { namespace amd64 { | ||
|
||
# define CDS_ts_hardwaretimestamp_hwptime_defined | ||
static inline uint64_t get_hwptime() | ||
{ | ||
uint64_t aux; | ||
uint64_t rax, rdx; | ||
__asm__ volatile ("rdtscp\n" : "=a" (rax), "=d" (rdx), "=c" (aux) : : ); | ||
return (rdx << 32) + rax; | ||
} | ||
|
||
# define CDS_ts_hardwaretimestamp_hwtime_defined | ||
static inline uint64_t get_hwtime() | ||
{ | ||
uint64_t high, low; | ||
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); | ||
return ((uint64_t)low) | (((uint64_t)high) << 32); | ||
} | ||
|
||
static inline int has_rdtscp() | ||
{ | ||
unsigned int eax, ebx, ecx, edx; | ||
if (__get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx)) | ||
return (edx >> 27) & 0x1; | ||
else | ||
return 0; | ||
} | ||
|
||
}} // namespace gcc::amd64 | ||
|
||
namespace platform { | ||
using namespace gcc::amd64; | ||
} | ||
}} // namespace cds::tshardwaretimestamp | ||
|
||
#endif // #ifndef CDSLIB_COMPILER_GCC_AMD64_TS_HARDWARETIMESTAMP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#ifndef CDSLIB_COMPILER_GCC_X86_TS_HARDWARETIMESTAMP_H | ||
#define CDSLIB_COMPILER_GCC_X86_TS_HARDWARETIMESTAMP_H | ||
|
||
#include <cstdint> | ||
#include <cpuid.h> | ||
|
||
namespace cds { namespace tshardwaretimestamp { | ||
namespace gcc { namespace x86 { | ||
|
||
# define CDS_ts_hardwaretimestamp_hwptime_defined | ||
static inline uint64_t get_hwptime() | ||
{ | ||
uint64_t ret; | ||
__asm__ volatile ("rdtscp\n" : "=A" (ret) : : "ecx"); | ||
return ret; | ||
} | ||
|
||
# define CDS_ts_hardwaretimestamp_hwtime_defined | ||
static inline uint64_t get_hwtime() | ||
{ | ||
uint64_t ret; | ||
__asm__ volatile("rdtsc" : "=A"(ret)); | ||
return ret; | ||
} | ||
|
||
static inline int has_rdtscp() | ||
{ | ||
unsigned int eax, ebx, ecx, edx; | ||
if (__get_cpuid(0x80000001, &eax, &ebx, &ecx, &edx)) | ||
return (edx >> 27) & 0x1; | ||
else | ||
return 0; | ||
} | ||
|
||
}} // namespace gcc::x86 | ||
|
||
namespace platform { | ||
using namespace gcc::x86; | ||
} | ||
}} // namespace cds::tshardwaretimestamp | ||
|
||
#endif // #ifndef CDSLIB_COMPILER_GCC_X86_TS_HARDWARETIMESTAMP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#ifndef CDSLIB_COMPILER_TS_HARDWARETIMESTAMP_H | ||
#define CDSLIB_COMPILER_TS_HARDWARETIMESTAMP_H | ||
|
||
// Choose appropriate header for current architecture and compiler | ||
|
||
#if CDS_COMPILER == CDS_COMPILER_GCC || CDS_COMPILER == CDS_COMPILER_CLANG || CDS_COMPILER == CDS_COMPILER_INTEL | ||
# if CDS_PROCESSOR_ARCH == CDS_PROCESSOR_X86 | ||
# include <cds/compiler/gcc/x86/ts_hardwaretimestamp.h> | ||
# elif CDS_PROCESSOR_ARCH == CDS_PROCESSOR_AMD64 | ||
# include <cds/compiler/gcc/amd64/ts_hardwaretimestamp.h> | ||
# endif | ||
#else | ||
# error "Undefined compiler" | ||
#endif | ||
|
||
#endif // #ifndef CDSLIB_COMPILER_TS_HARDWARETIMESTAMP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
#ifndef CDSLIB_CONTAINER_TS_DEQUE_H | ||
#define CDSLIB_CONTAINER_TS_DEQUE_H | ||
|
||
#include <atomic> | ||
#include <cds/opt/options.h> | ||
#include <cds/container/ts_deque_buffer.h> | ||
|
||
namespace cds { namespace container { | ||
|
||
/// TSDeque related definitions | ||
/** @ingroup cds_nonintrusive_helper | ||
*/ | ||
namespace tsdeque { | ||
/// TSDeque default type traits | ||
struct traits | ||
{ | ||
/// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting | ||
typedef cds::atomicity::empty_item_counter item_counter; | ||
|
||
/// Random engine to generate a random position in array of thread-local buffers | ||
typedef opt::v::c_rand random_engine; | ||
}; | ||
|
||
/// Metafunction converting option list to \p tsdeque::traits | ||
/** | ||
Supported \p Options are: | ||
- opt::item_counter - the type of item counting feature. | ||
Default is \p cds::atomicity::empty_item_counter (item counting disabled). | ||
- opt::random_engine - a random engine to generate a random position in array of thread-local buffers. | ||
Default is \p opt::v::c_rand. | ||
|
||
Example: declare \p %TSDeque with item counting | ||
\code | ||
typedef cds::container::TSDeque< Foo, | ||
typename cds::container::tsdeque::make_traits< | ||
cds::opt::item_counter< cds::atomicity::item_counter > | ||
>::type | ||
> myDeque; | ||
\endcode | ||
*/ | ||
template <typename... Options> | ||
struct make_traits { | ||
# ifdef CDS_DOXYGEN_INVOKED | ||
typedef implementation_defined type; ///< Metafunction result | ||
# else | ||
typedef typename cds::opt::make_options< | ||
typename cds::opt::find_type_traits< traits, Options... >::type | ||
, Options... | ||
>::type type; | ||
# endif | ||
}; | ||
|
||
} // namespace tsdeque | ||
|
||
/// Fast Concurrent Deque Through Explicit Timestamping | ||
/** @ingroup cds_nonintrusive_deque | ||
|
||
<b>Source</b> | ||
- [2014] Mike Dodds, Andreas Haas, Christoph M. Kirsch | ||
"Fast Concurrent Data-Structures Through Explicit Timestamping" | ||
|
||
<b>Template arguments</b> | ||
- \p T - value type to be stored in the deque | ||
- \p Timestamp - the way to acquire timestamps | ||
- \p Traits - deque traits, default is \p tsdeque::traits. You can use \p tsdeque::make_traits | ||
metafunction to make your traits or just derive your traits from \p %tsdeque::traits: | ||
\code | ||
struct myTraits: public cds::container::tsdeque::traits { | ||
typedef cds::atomicity::item_counter item_counter; | ||
}; | ||
typedef cds::container::TSDeque< Foo, Timestamp, myTraits > myDeque; | ||
|
||
// Equivalent make_traits example: | ||
typedef cds::container::TSDeque< Foo, Timestamp | ||
typename cds::container::tsdeque::make_traits< | ||
cds::opt::item_counter< cds::atomicity::item_counter > | ||
>::type | ||
> myDeque; | ||
\endcode | ||
*/ | ||
template <typename T, typename Timestamp, typename Traits = tsdeque::traits> | ||
class TSDeque | ||
{ | ||
public: | ||
typedef T value_type; ///< Type of value to be stored in the deque | ||
typedef Timestamp timestamp; ///< Algorithm of acquiring timestamps | ||
typedef Traits traits; ///< Deque traits | ||
|
||
typedef typename traits::item_counter item_counter; ///< Item counting policy used | ||
typedef typename traits::random_engine random_engine; ///< Random engine used | ||
|
||
private: | ||
TSDequeBuffer<value_type, timestamp, random_engine> *buffer_; | ||
timestamp *timestamping_; | ||
item_counter item_counter_; | ||
|
||
public: | ||
TSDeque(uint64_t num_threads, uint64_t delay) | ||
{ | ||
timestamping_ = new timestamp(); | ||
timestamping_->initialize(delay, num_threads); | ||
|
||
buffer_ = new TSDequeBuffer<value_type, timestamp, random_engine>(num_threads, timestamping_); | ||
} | ||
|
||
~TSDeque() | ||
{ | ||
clear(); | ||
|
||
delete timestamping_; | ||
delete buffer_; | ||
} | ||
|
||
/// Inserts a new element at the left end of the deque container | ||
/** | ||
The function always returns \p true | ||
*/ | ||
bool insert_left(value_type element) | ||
{ | ||
std::atomic<uint64_t> *item = buffer_->insert_left(element); | ||
timestamping_->set_timestamp(item); | ||
++item_counter_; | ||
return true; | ||
} | ||
|
||
/// Inserts a new element at the right end of the deque container | ||
/** | ||
The function always returns \p true | ||
*/ | ||
bool insert_right(value_type element) | ||
{ | ||
std::atomic<uint64_t> *item = buffer_->insert_right(element); | ||
timestamping_->set_timestamp(item); | ||
++item_counter_; | ||
return true; | ||
} | ||
|
||
/// Removes the element from the left end of the deque container | ||
/** | ||
The function returns \p false if the deque is empty, \p true otherwise. | ||
*/ | ||
bool remove_left(value_type *element) | ||
{ | ||
uint64_t invocation_time[2]; | ||
timestamping_->read_time(invocation_time); | ||
bool empty; | ||
while (buffer_->try_remove_left(element, invocation_time, &empty)) | ||
{ | ||
if (!empty) | ||
{ | ||
--item_counter_; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/// Removes the element from the right end of the deque container | ||
/** | ||
The function returns \p false if the deque is empty, \p true otherwise. | ||
*/ | ||
bool remove_right(value_type *element) | ||
{ | ||
uint64_t invocation_time[2]; | ||
timestamping_->read_time(invocation_time); | ||
bool empty; | ||
while (buffer_->try_remove_right(element, invocation_time, &empty)) | ||
{ | ||
if (!empty) | ||
{ | ||
--item_counter_; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/// Clears the deque (non-atomic) | ||
/** | ||
The function erases all items from the deque. | ||
|
||
The function is not atomic. It cleans up the deque and then resets the item counter to zero. | ||
If there are a thread that performs insertion while \p clear is working the result is undefined in general case: | ||
<tt> empty() </tt> may return \p true but the deque may contain item(s). | ||
Therefore, \p clear may be used only for debugging purposes. | ||
*/ | ||
void clear() | ||
{ | ||
value_type item; | ||
while (remove_right(&item)) {} | ||
item_counter_.reset(); | ||
} | ||
|
||
/// Checks if the deque is empty | ||
/** | ||
@warning If you use \p atomicity::empty_item_counter in \p traits::item_counter, | ||
the function always returns \p true. | ||
*/ | ||
bool empty() const | ||
{ | ||
return size() == 0; | ||
} | ||
|
||
/// Returns item count in the deque | ||
/** | ||
@warning If you use \p atomicity::empty_item_counter in \p traits::item_counter, | ||
the function always returns 0. | ||
*/ | ||
size_t size() const | ||
{ | ||
return item_counter_; | ||
} | ||
|
||
//@cond | ||
/// The class has no internal statistics. For test consistency only | ||
std::nullptr_t statistics() const | ||
{ | ||
return nullptr; | ||
} | ||
//@endcond | ||
}; | ||
|
||
}} // namespace cds::container | ||
|
||
#endif // #ifndef CDSLIB_CONTAINER_TS_DEQUE_H |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's quit strange to have "has_..." function returning logically boolean value with int signature