mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
fix some bugs; add performance data to README.md
This commit is contained in:
parent
12efd8c973
commit
4253c1341c
69
README.md
69
README.md
@ -2,4 +2,71 @@
|
||||
|
||||
[](https://github.com/mutouyun/cpp-ipc/blob/master/LICENSE) [](https://travis-ci.org/mutouyun/cpp-ipc)
|
||||
|
||||
C++ IPC Library: A high-performance inter-process communication using shared memory on Linux/Windows.
|
||||
C++ IPC Library:
|
||||
A high-performance inter-process communication using shared memory on Linux/Windows.
|
||||
使用共享内存的跨平台(Linux/Windows,x86/x64/ARM)高性能IPC通讯库。
|
||||
|
||||
* 需要支持C++17的编译器(msvc-2017/gcc-7/clang-4)
|
||||
* 除STL外,无其他依赖
|
||||
* 无锁(lock-free)或轻量级shared-spin-lock(`ipc::channel::connect`/`disconnect`)
|
||||
* 底层数据结构为循环数组(circular array),无动态内存分配
|
||||
* `ipc::route`支持单生产者多消费者(1vN),`ipc::channel`支持多生产者多消费者
|
||||
|
||||
## Performance
|
||||
|
||||
| Environment ||
|
||||
| ------ | ------ |
|
||||
| Device | Lenovo ThinkPad T450 |
|
||||
| CPU | Intel(R) Core(TM) i5-4300U @ 2.5 GHz |
|
||||
| RAM | 16 GB |
|
||||
| OS | Windows 7 Ultimate x64 |
|
||||
| Compiler | MSVC 2017 15.9.3 |
|
||||
|
||||
UT & benchmark test function, see: [test](test)
|
||||
|
||||
### ipc::circ::queue
|
||||
|
||||
| PROD-CONS: 1-N | DATAS: 12bits * 1000000 |
|
||||
| ------ | ------ |
|
||||
| `1-1` | `072.150 ms, 0.072150 us/d` |
|
||||
| `1-2` | `114.889 ms, 0.114889 us/d` |
|
||||
| `1-4` | `155.712 ms, 0.155712 us/d` |
|
||||
| `1-8` | `234.662 ms, 0.234662 us/d` |
|
||||
|
||||
### ipc::route
|
||||
|
||||
| PROD-CONS: 1-N | DATAS: Random 2-256bits * 100000 |
|
||||
| ------ | ------ |
|
||||
| `RTT` | `185.862 ms, 1.85862 us/d` |
|
||||
| `1-1` | `117.126 ms, 1.17126 us/d` |
|
||||
| `1-2` | `174.284 ms, 1.74284 us/d` |
|
||||
| `1-4` | `329.550 ms, 3.29550 us/d` |
|
||||
| `1-8` | `494.970 ms, 4.94970 us/d` |
|
||||
|
||||
### ipc::channel
|
||||
|
||||
| PROD-CONS: 1-N | DATAS: Random 2-256bits * 100000 |
|
||||
| ------ | ------ |
|
||||
| `RTT` | `221.500 ms, 2.21500 us/d` |
|
||||
| `1-1` | `141.013 ms, 1.41013 us/d` |
|
||||
| `1-2` | `270.092 ms, 2.70092 us/d` |
|
||||
| `1-4` | `609.792 ms, 6.09792 us/d` |
|
||||
| `1-8` | `968.309 ms, 9.68309 us/d` |
|
||||
|
||||
| PROD-CONS: N-1 | DATAS: Random 2-256bits * 100000 |
|
||||
| ------ | ------ |
|
||||
| `2-1` | `313.916 ms, 1.56958 us/d` |
|
||||
| `4-1` | `804.254 ms, 2.01064 us/d` |
|
||||
| `8-1` | `1800.42 ms, 2.25053 us/d` |
|
||||
|
||||
| PROD-CONS: N-N | DATAS: Random 2-256bits * 100000 |
|
||||
| ------ | ------ |
|
||||
| `2-2` | `550.972 ms, 2.75486 us/d` |
|
||||
| `4-4` | `1942.46 ms, 4.85616 us/d` |
|
||||
| `8-8` | `7684.91 ms, 9.60614 us/d` |
|
||||
|
||||
## Reference
|
||||
|
||||
* [http://www.drdobbs.com/lock-free-data-structures/184401865](http://www.drdobbs.com/lock-free-data-structures/184401865)
|
||||
* [https://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular](https://www.codeproject.com/Articles/153898/Yet-another-implementation-of-a-lock-free-circular)
|
||||
* [http://www.cnblogs.com/gaochundong/p/lock_free_programming.html](http://www.cnblogs.com/gaochundong/p/lock_free_programming.html)
|
||||
@ -5,12 +5,14 @@ QT -= gui
|
||||
CONFIG += console c++1z
|
||||
CONFIG -= app_bundle
|
||||
|
||||
DESTDIR = ../output
|
||||
|
||||
msvc:QMAKE_CXXFLAGS += /std:c++17
|
||||
else:QMAKE_CXXFLAGS += -std=gnu++1z
|
||||
|
||||
DESTDIR = ../output
|
||||
|
||||
INCLUDEPATH += \
|
||||
../test \
|
||||
../test/capo \
|
||||
../include \
|
||||
../src \
|
||||
../src/platform
|
||||
@ -24,4 +26,5 @@ SOURCES += \
|
||||
../test/test_circ.cpp \
|
||||
../test/test_ipc.cpp
|
||||
|
||||
LIBS += -L$${DESTDIR} -lipc
|
||||
LIBS += \
|
||||
-L$${DESTDIR} -lipc
|
||||
|
||||
19
src/ipc.cpp
19
src/ipc.cpp
@ -9,6 +9,7 @@
|
||||
|
||||
#include "def.h"
|
||||
#include "circ_queue.h"
|
||||
#include "shm.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -27,16 +28,20 @@ using queue_t = circ::queue<msg_t>;
|
||||
using msg_id_t = decltype(msg_t::id_);
|
||||
|
||||
struct shm_info_t {
|
||||
std::atomic<msg_id_t> id_acc_; // message id accumulator
|
||||
queue_t::array_t elems_; // the circ_elem_array in shm
|
||||
};
|
||||
|
||||
constexpr queue_t* queue_of(handle_t h) {
|
||||
return static_cast<queue_t*>(h);
|
||||
inline auto acc_of(queue_t*) {
|
||||
static shm::handle g_shm { "GLOBAL_ACC_STORAGE__", sizeof(std::atomic<msg_id_t>) };
|
||||
return static_cast<std::atomic<msg_id_t>*>(g_shm.get());
|
||||
}
|
||||
|
||||
inline std::atomic<msg_id_t>* acc_of(queue_t* que) {
|
||||
return reinterpret_cast<std::atomic<msg_id_t>*>(que->elems()) - 1;
|
||||
constexpr void* head_of(queue_t* que) {
|
||||
return static_cast<void*>(que->elems());
|
||||
}
|
||||
|
||||
constexpr queue_t* queue_of(handle_t h) {
|
||||
return static_cast<queue_t*>(h);
|
||||
}
|
||||
|
||||
inline auto& recv_cache() {
|
||||
@ -73,7 +78,7 @@ void disconnect(handle_t h) {
|
||||
return;
|
||||
}
|
||||
que->disconnect(); // needn't to detach, cause it will be deleted soon.
|
||||
shm::release(acc_of(que), sizeof(shm_info_t));
|
||||
shm::release(head_of(que), sizeof(shm_info_t));
|
||||
delete que;
|
||||
}
|
||||
|
||||
@ -86,7 +91,7 @@ std::size_t recv_count(handle_t h) {
|
||||
}
|
||||
|
||||
void clear_recv(handle_t h) {
|
||||
auto* head = acc_of(queue_of(h));
|
||||
auto* head = head_of(queue_of(h));
|
||||
if (head == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
18
test/test.h
18
test/test.h
@ -40,7 +40,7 @@ struct test_stopwatch {
|
||||
|
||||
void print_elapsed(int N, int M, int Loops) {
|
||||
auto ts = sw_.elapsed<std::chrono::microseconds>();
|
||||
std::cout << "[" << N << ":" << M << ", " << Loops << "]" << std::endl
|
||||
std::cout << "[" << N << ":" << M << ", " << Loops << "] "
|
||||
<< "performance: " << (ts / 1000.0) << " ms, "
|
||||
<< (double(ts) / double(Loops * N)) << " us/d" << std::endl;
|
||||
}
|
||||
@ -94,16 +94,16 @@ void benchmark_prod_cons(T* cq) {
|
||||
auto cn = tcq.connect();
|
||||
int i = 0;
|
||||
tcq.recv(cn, [&](auto&& msg) {
|
||||
if (i % ((Loops * N) / 10) == 0) {
|
||||
std::printf("%d-recving: %d%%\n", cid, (i * 100) / (Loops * N));
|
||||
}
|
||||
// if (i % ((Loops * N) / 10) == 0) {
|
||||
// std::printf("%d-recving: %d%%\n", cid, (i * 100) / (Loops * N));
|
||||
// }
|
||||
vf.push_data(cid, msg);
|
||||
++i;
|
||||
});
|
||||
std::printf("%d-consumer-disconnect\n", cid);
|
||||
// std::printf("%d-consumer-disconnect\n", cid);
|
||||
tcq.disconnect(cn);
|
||||
if (++fini_c != std::extent<decltype(consumers)>::value) {
|
||||
std::printf("%d-consumer-end\n", cid);
|
||||
// std::printf("%d-consumer-end\n", cid);
|
||||
return;
|
||||
}
|
||||
sw.print_elapsed(N, M, Loops);
|
||||
@ -122,9 +122,9 @@ void benchmark_prod_cons(T* cq) {
|
||||
sw.start();
|
||||
for (int i = 0; i < Loops; ++i) {
|
||||
tcq.send(cn, { pid, i });
|
||||
if (i % (Loops / 10) == 0) {
|
||||
std::printf("%d-sending: %d%%\n", pid, i * 100 / Loops);
|
||||
}
|
||||
// if (i % (Loops / 10) == 0) {
|
||||
// std::printf("%d-sending: %d%%\n", pid, i * 100 / Loops);
|
||||
// }
|
||||
}
|
||||
if (++fini_p != std::extent<decltype(producers)>::value) return;
|
||||
// quit
|
||||
|
||||
@ -159,7 +159,7 @@ struct test_cq<ipc::channel> {
|
||||
thread_local struct s_dummy {
|
||||
s_dummy(cn_t* cn, int m) {
|
||||
cn->wait_for_recv(m);
|
||||
std::printf("start to send: %d.\n", m);
|
||||
// std::printf("start to send: %d.\n", m);
|
||||
}
|
||||
} _(cn, m_);
|
||||
int n = info[1];
|
||||
@ -190,9 +190,7 @@ private slots:
|
||||
void test_route_performance();
|
||||
void test_channel();
|
||||
void test_channel_rtt();
|
||||
void test_channel_performance_1vN();
|
||||
void test_channel_performance_Nv1();
|
||||
void test_channel_performance_NvN();
|
||||
void test_channel_performance();
|
||||
} unit__;
|
||||
|
||||
#include "test_ipc.moc"
|
||||
@ -450,7 +448,7 @@ struct test_performance<1, 1, V> {
|
||||
};
|
||||
|
||||
void Unit::test_route_performance() {
|
||||
test_performance<1, 10>::start();
|
||||
test_performance<1, 10, true>::start();
|
||||
}
|
||||
|
||||
void Unit::test_channel() {
|
||||
@ -512,20 +510,9 @@ void Unit::test_channel_rtt() {
|
||||
t2.join();
|
||||
}
|
||||
|
||||
void Unit::test_channel_performance_1vN() {
|
||||
test_performance<1, 10, true>::start<ipc::channel>();
|
||||
// test_prod_cons<ipc::channel, 1, 2, false>();
|
||||
}
|
||||
|
||||
void Unit::test_channel_performance_Nv1() {
|
||||
test_performance<10, 1>::start<ipc::channel>();
|
||||
// test_prod_cons<ipc::channel, 1, 1, false>();
|
||||
// test_prod_cons<ipc::channel, 2, 1, false>();
|
||||
// test_prod_cons<ipc::channel, 3, 1, false>();
|
||||
// test_prod_cons<ipc::channel, 4, 1, false>();
|
||||
}
|
||||
|
||||
void Unit::test_channel_performance_NvN() {
|
||||
void Unit::test_channel_performance() {
|
||||
test_performance<1 , 10, true>::start<ipc::channel>();
|
||||
test_performance<10, 1 >::start<ipc::channel>();
|
||||
test_performance<10, 10>::start<ipc::channel>();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user