-
Notifications
You must be signed in to change notification settings - Fork 29
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
High-performance hub component for dealing with many sockets and high throughput #760
Changes from 89 commits
a1e7416
fff2ff4
8ece440
80a5588
4ef9caa
0ae6bf1
0178288
8a7d3c8
d8a5615
e659189
22e2579
9c68404
4f8e8db
78691b9
dd1ed87
0fc10f0
6de3725
7132261
a98007f
b2d2f49
d6fce5e
b1a3162
6697d6e
83314f8
4003263
75cce4c
be7ffd5
3caaf9e
b057848
0b178cb
412eb86
bda595b
d384fcd
51fe936
9e622c2
c4c9bff
803f5b7
6696891
f0ee164
024f96d
c666165
f568068
42c370e
70ecb96
9e03b5b
e996774
13ed147
f9fe772
f56ac28
bad32e7
c96e108
e3aba68
0465ed1
addec73
b155643
0ce5214
1a9f939
710a9bb
ff1f1c3
ebef72e
0e5f960
0d1ea13
f40c92c
4422475
49bc1be
04c9aaf
c86c375
19ceb97
dac5d9a
0475a1f
d0890cb
28968ce
ad6c8da
b84727e
26ccb99
e68dbad
aa60f18
7bf8b3b
5ff2f5d
60779aa
c2d2ac1
e97d1b1
9864e0b
cff3c6e
0f7960a
2edb40e
67b73a1
ed2c799
2e58e61
d869a7b
3b883c7
39d50d2
4820101
523412d
3b9647e
6b80335
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** \copyright | ||
* Copyright (c) 2013, Balazs Racz | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* - Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* - Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* \file AsyncNotifiableBlock.cxx | ||
* | ||
* An advanced notifiable construct that acts as a fixed pool of | ||
* BarrierNotifiables. A stateflow can pend on acquiring one of them, use that | ||
* barrier, with it automatically returning to the next caller when the Barrier | ||
* goes out of counts. | ||
* | ||
* @author Balazs Racz | ||
* @date 18 Feb 2020 | ||
*/ | ||
|
||
#ifndef _DEFAULT_SOURCE | ||
#define _DEFAULT_SOURCE | ||
#endif | ||
|
||
#include "AsyncNotifiableBlock.hxx" | ||
|
||
#include <unistd.h> | ||
|
||
AsyncNotifiableBlock::~AsyncNotifiableBlock() | ||
{ | ||
unsigned max = 10; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be good to rename this from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is this constant 10 chosen? Should it somehow be related to count_? Some commentary would help. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the constant is removed. |
||
// Recollects all notifiable instances, including waiting a bit if | ||
// there are some that have not finished yet. Limits the total amount | ||
// of wait. | ||
for (unsigned i = 0; i < count_; ++i) | ||
{ | ||
while (true) | ||
{ | ||
QMember *m = next().item; | ||
if (!m) | ||
{ | ||
LOG(VERBOSE, | ||
"shutdown async notifiable block: waiting for returns"); | ||
usleep(100); | ||
HASSERT(--max); | ||
} | ||
else | ||
{ | ||
HASSERT(initialize(m)->abort_if_almost_done()); | ||
break; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#include "executor/AsyncNotifiableBlock.hxx" | ||
|
||
#include "utils/test_main.hxx" | ||
|
||
class AsyncNotifiableBlockTest : public ::testing::Test | ||
{ | ||
protected: | ||
AsyncNotifiableBlock b_ {2}; | ||
}; | ||
|
||
TEST_F(AsyncNotifiableBlockTest, create) | ||
{ | ||
} | ||
|
||
TEST_F(AsyncNotifiableBlockTest, count_request_release) | ||
{ | ||
EXPECT_EQ(2u, b_.pending()); | ||
QMember *e = b_.next(0); | ||
EXPECT_NE(nullptr, e); | ||
EXPECT_EQ(1u, b_.pending()); | ||
|
||
QMember *f = b_.next(0); | ||
EXPECT_NE(nullptr, f); | ||
EXPECT_EQ(0u, b_.pending()); | ||
|
||
QMember *g = b_.next(0); | ||
EXPECT_EQ(nullptr, g); | ||
EXPECT_EQ(0u, b_.pending()); | ||
|
||
b_.initialize(e)->notify(); | ||
EXPECT_EQ(1u, b_.pending()); | ||
|
||
QMember *h = b_.next(0); | ||
EXPECT_EQ(e, h); | ||
|
||
EXPECT_EQ(0u, b_.pending()); | ||
|
||
b_.initialize(f)->notify(); | ||
b_.initialize(h)->notify(); | ||
} | ||
|
||
TEST_F(AsyncNotifiableBlockTest, barrier_semantics) | ||
{ | ||
EXPECT_EQ(2u, b_.pending()); | ||
QMember *e = b_.next(0); | ||
BarrierNotifiable *bn = b_.initialize(e); | ||
EXPECT_EQ(1u, b_.pending()); | ||
|
||
bn->new_child(); | ||
bn->notify(); | ||
EXPECT_EQ(1u, b_.pending()); | ||
bn->notify(); | ||
EXPECT_EQ(2u, b_.pending()); | ||
} | ||
|
||
class FakeExecutable : public Executable | ||
{ | ||
public: | ||
void run() override | ||
{ | ||
DIE("unexpected."); | ||
} | ||
|
||
void alloc_result(QMember *m) override | ||
{ | ||
ASSERT_TRUE(m); | ||
m_ = m; | ||
} | ||
|
||
QMember *m_ {nullptr}; | ||
}; | ||
|
||
TEST_F(AsyncNotifiableBlockTest, async_allocation) | ||
{ | ||
EXPECT_EQ(2u, b_.pending()); | ||
QMember *e = b_.next(0); | ||
EXPECT_NE(nullptr, e); | ||
EXPECT_EQ(1u, b_.pending()); | ||
|
||
FakeExecutable cli1, cli2, cli3; | ||
EXPECT_EQ(nullptr, cli1.m_); | ||
EXPECT_EQ(nullptr, cli2.m_); | ||
EXPECT_EQ(nullptr, cli3.m_); | ||
|
||
b_.next_async(&cli1); | ||
EXPECT_EQ(0u, b_.pending()); | ||
EXPECT_NE(nullptr, cli1.m_); | ||
EXPECT_NE(e, cli1.m_); | ||
|
||
b_.next_async(&cli2); | ||
b_.next_async(&cli3); | ||
EXPECT_EQ(nullptr, cli2.m_); | ||
EXPECT_EQ(nullptr, cli3.m_); | ||
EXPECT_EQ(0u, b_.pending()); | ||
|
||
b_.initialize(e)->notify(); // will be handed out to cli2 | ||
|
||
EXPECT_EQ(0u, b_.pending()); | ||
EXPECT_EQ(e, cli2.m_); | ||
|
||
b_.initialize(cli1.m_)->notify(); // will be handed out to cli3 | ||
EXPECT_EQ(cli1.m_, cli3.m_); | ||
EXPECT_EQ(0u, b_.pending()); | ||
|
||
b_.initialize(cli3.m_)->notify(); // will be handed back | ||
EXPECT_EQ(1u, b_.pending()); | ||
|
||
b_.initialize(cli2.m_)->notify(); // will be handed back | ||
EXPECT_EQ(2u, b_.pending()); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/** \copyright | ||
* Copyright (c) 2013, Balazs Racz | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* - Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* - Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* \file AsyncNotifiableBlock.hxx | ||
* | ||
* An advanced notifiable construct that acts as a fixed pool of | ||
* BarrierNotifiables. A stateflow can pend on acquiring one of them, use that | ||
* barrier, with it automatically returning to the next caller when the Barrier | ||
* goes out of counts. | ||
* | ||
* @author Balazs Racz | ||
* @date 18 Feb 2020 | ||
*/ | ||
|
||
#ifndef _EXECUTOR_ASYNCNOTIFIABLEBLOCK_HXX_ | ||
#define _EXECUTOR_ASYNCNOTIFIABLEBLOCK_HXX_ | ||
|
||
#include <memory> | ||
|
||
#include "executor/Notifiable.hxx" | ||
#include "utils/Queue.hxx" | ||
#include "utils/logging.h" | ||
|
||
#include "utils/Buffer.hxx" | ||
|
||
/// A block of BarrierNotifiable objects, with an asynchronous allocation | ||
/// call. Caller StateFlows can block on allocating a new entry, and then get | ||
/// back a fresh BarrierNotifiable, which, upon being released will | ||
/// automatically be reallocated to a waiting flow, if any. | ||
class AsyncNotifiableBlock : private Notifiable, public QAsync | ||
{ | ||
private: | ||
/// Notifiable class that can act as a BarrierNotifiable but also be | ||
/// enlisted in a queue. | ||
class QueuedBarrier : public BarrierNotifiable, public QMember | ||
{ | ||
public: | ||
/// Notification implementation. | ||
/// | ||
/// Theory of operation: If this was the last notification (count goes | ||
/// from 1 to 0), we take the done_ pointer, cast it to the owning | ||
/// AsyncNotifiableBlock, and release outselves into the queue | ||
/// there. We keep the count at 1 at all times, which ensures that the | ||
/// done_ pointer remains pointing to the owner AsyncNotifiableBlock. | ||
void notify() override | ||
{ | ||
AtomicHolder h(this); | ||
if (count_ == 1) | ||
{ | ||
LOG(VERBOSE, "block notifiable %p returned pool size %u", | ||
(BarrierNotifiable *)this, | ||
(unsigned)mainBufferPool->total_size()); | ||
auto *tgt = static_cast<AsyncNotifiableBlock *>(done_); | ||
tgt->insert(this); | ||
} | ||
else | ||
{ | ||
--count_; | ||
} | ||
} | ||
|
||
/// Checks that there is exactly one count in here. | ||
void check_one_count() | ||
{ | ||
HASSERT(count_ == 1); | ||
} | ||
}; | ||
|
||
public: | ||
/// Constructor. @param num_parallelism tells how many BarrierNotifiables | ||
/// we should have and hand out to callers requesting them. | ||
AsyncNotifiableBlock(unsigned num_parallelism) | ||
: count_(num_parallelism) | ||
, barriers_(new QueuedBarrier[num_parallelism]) | ||
{ | ||
for (unsigned i = 0; i < num_parallelism; ++i) | ||
{ | ||
barriers_[i].reset(this); | ||
this->insert(&barriers_[i]); | ||
} | ||
} | ||
|
||
/// Destructor. | ||
~AsyncNotifiableBlock(); | ||
|
||
/// Turns an allocated entry from the QAsync into a usable | ||
/// BarrierNotifiable. | ||
/// @param entry a QMember that was allocated from *this. | ||
/// @return an initialized BarrierNotifiable with exactly one count, and | ||
/// done_ set up to be returned for further use. | ||
BarrierNotifiable *initialize(QMember *entry) | ||
{ | ||
QueuedBarrier *b = static_cast<QueuedBarrier *>(entry); | ||
// We must be owning this entry. | ||
HASSERT(barriers_.get() <= b); | ||
HASSERT(b <= (barriers_.get() + count_)); | ||
b->check_one_count(); | ||
return b; | ||
} | ||
|
||
/// Notification implementation -- should never be called. | ||
void notify() override | ||
{ | ||
DIE("Should not receive this notification"); | ||
} | ||
|
||
private: | ||
/// How many barriers do we have. | ||
unsigned count_; | ||
/// The pointer to the block of barriernotifiables. | ||
std::unique_ptr<QueuedBarrier[]> barriers_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(AsyncNotifiableBlock); | ||
}; | ||
|
||
#endif // _EXECUTOR_ASYNCNOTIFIABLEBLOCK_HXX_ |
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.
check date
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.
fixed