From 4253c1341cbfd634f1528acb5e627fbcae22f2d1 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Thu, 27 Dec 2018 20:06:36 +0800 Subject: [PATCH] fix some bugs; add performance data to README.md --- README.md | 69 ++++++++++++++++++++++++++++++++++- build/test.pro | 9 +++-- src/ipc.cpp | 21 +++++++---- test/{ => capo}/random.hpp | 0 test/{ => capo}/spin_lock.hpp | 0 test/{ => capo}/stopwatch.hpp | 0 test/test.h | 18 ++++----- test/test_ipc.cpp | 25 +++---------- 8 files changed, 102 insertions(+), 40 deletions(-) rename test/{ => capo}/random.hpp (100%) rename test/{ => capo}/spin_lock.hpp (100%) rename test/{ => capo}/stopwatch.hpp (100%) diff --git a/README.md b/README.md index 4536d94..78c36f1 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,71 @@ [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/mutouyun/cpp-ipc/blob/master/LICENSE) [![Build Status](https://travis-ci.org/mutouyun/cpp-ipc.svg?branch=master)](https://travis-ci.org/mutouyun/cpp-ipc) -C++ IPC Library: A high-performance inter-process communication using shared memory on Linux/Windows. \ No newline at end of file +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) \ No newline at end of file diff --git a/build/test.pro b/build/test.pro index 0c3c572..0923953 100644 --- a/build/test.pro +++ b/build/test.pro @@ -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 diff --git a/src/ipc.cpp b/src/ipc.cpp index 45f0a03..abb762a 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -9,6 +9,7 @@ #include "def.h" #include "circ_queue.h" +#include "shm.h" namespace { @@ -27,18 +28,22 @@ using queue_t = circ::queue; using msg_id_t = decltype(msg_t::id_); struct shm_info_t { - std::atomic id_acc_; // message id accumulator - queue_t::array_t elems_; // the circ_elem_array in shm + queue_t::array_t elems_; // the circ_elem_array in shm }; +inline auto acc_of(queue_t*) { + static shm::handle g_shm { "GLOBAL_ACC_STORAGE__", sizeof(std::atomic) }; + return static_cast*>(g_shm.get()); +} + +constexpr void* head_of(queue_t* que) { + return static_cast(que->elems()); +} + constexpr queue_t* queue_of(handle_t h) { return static_cast(h); } -inline std::atomic* acc_of(queue_t* que) { - return reinterpret_cast*>(que->elems()) - 1; -} - inline auto& recv_cache() { /* * the performance of tls::pointer is not good enough @@ -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; } diff --git a/test/random.hpp b/test/capo/random.hpp similarity index 100% rename from test/random.hpp rename to test/capo/random.hpp diff --git a/test/spin_lock.hpp b/test/capo/spin_lock.hpp similarity index 100% rename from test/spin_lock.hpp rename to test/capo/spin_lock.hpp diff --git a/test/stopwatch.hpp b/test/capo/stopwatch.hpp similarity index 100% rename from test/stopwatch.hpp rename to test/capo/stopwatch.hpp diff --git a/test/test.h b/test/test.h index 25e5186..270190a 100644 --- a/test/test.h +++ b/test/test.h @@ -40,7 +40,7 @@ struct test_stopwatch { void print_elapsed(int N, int M, int Loops) { auto ts = sw_.elapsed(); - 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::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::value) return; // quit diff --git a/test/test_ipc.cpp b/test/test_ipc.cpp index 838354e..50b48f0 100644 --- a/test/test_ipc.cpp +++ b/test/test_ipc.cpp @@ -159,7 +159,7 @@ struct test_cq { 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(); -// test_prod_cons(); -} - -void Unit::test_channel_performance_Nv1() { - test_performance<10, 1>::start(); -// test_prod_cons(); -// test_prod_cons(); -// test_prod_cons(); -// test_prod_cons(); -} - -void Unit::test_channel_performance_NvN() { +void Unit::test_channel_performance() { + test_performance<1 , 10, true>::start(); + test_performance<10, 1 >::start(); test_performance<10, 10>::start(); }