A C++ library for logging very fast and without allocating.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

282 řádky
6.7 KiB

  1. #include <thread>
  2. #include "catch2/catch_all.hpp"
  3. #include "../LibSnugLog/include/disruptor.h"
  4. struct strategy {
  5. static constexpr overflow_response_t on_overflow = overflow_response_t::must_wait;
  6. void wait() {}
  7. };
  8. struct strategy_that_overflows {
  9. static constexpr overflow_response_t on_overflow = overflow_response_t::must_overflow;
  10. void wait() {}
  11. };
  12. TEST_CASE("Disruptor works sequentially") {
  13. std::array<char, 8192> buffer{};
  14. disruptor<strategy> v{buffer.data(), buffer.size()};
  15. SECTION("117") {
  16. auto W = v.reserve_write(100);
  17. v[W.start] = 117;
  18. v.conclude_write(W);
  19. auto R = v.reserve_read();
  20. REQUIRE(v[R.start]== 117);
  21. v.conclude_read(R);
  22. }
  23. SECTION("12") {
  24. {
  25. auto W = v.reserve_write(6);
  26. v[W.start] = 12;
  27. v.conclude_write(W);
  28. auto R = v.reserve_read();
  29. REQUIRE(v[R.start]== 12);
  30. v.conclude_read(R);
  31. }
  32. {
  33. auto W = v.reserve_write(6);
  34. v[W.start] = 8;
  35. v.conclude_write(W);
  36. auto R = v.reserve_read();
  37. REQUIRE(v[R.start]== 8);
  38. v.conclude_read(R);
  39. }
  40. }
  41. SECTION("Disruptor loop around") {
  42. std::multiset<char> mset;
  43. for(int i = 0; i != 255; i++) {
  44. auto W = v.reserve_write(100);
  45. v[W.start] = (char)i;
  46. for(size_t idx = W.start; idx != W.end; idx = (idx+1)%v.size()) {
  47. v[idx] = (char)i;
  48. }
  49. v.conclude_write(W);
  50. auto R = v.reserve_read();
  51. for(size_t idx = R.start; idx != R.end; idx = (idx+1)%v.size()) {
  52. mset.insert(v[idx]);
  53. }
  54. v.conclude_read(R);
  55. }
  56. for(int i = 0; i != 255; i++) {
  57. REQUIRE(mset.count((char)i) == 100);
  58. }
  59. }
  60. SECTION("Disruptor concurrent odd vs even") {
  61. std::atomic<bool> trigger = false;
  62. std::multiset<char> mset;
  63. std::stringstream continuity;
  64. int acc = 0;
  65. for(int i = 0; i<= 255; i++) {
  66. acc+=i;
  67. }
  68. std::thread reader([&](){
  69. int cnt = 0;
  70. while (cnt != acc) {
  71. auto R = v.reserve_read();
  72. for (size_t idx = R.start; idx != R.end; idx = (idx + 1) % v.size()) {
  73. mset.insert(v[idx]);
  74. continuity << (char)v[idx];
  75. }
  76. v.conclude_read(R);
  77. cnt += (R.end > R.start) * (R.end - R.start)
  78. + (R.end < R.start) * (v.size() - R.start + R.end);
  79. }
  80. });
  81. std::thread even([&]() {
  82. while(!trigger.load());
  83. for (int i = 2; i <= 255; i += 2) {
  84. auto W = v.reserve_write(i);
  85. v[W.start] = (char) i;
  86. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  87. v[idx] = (char) i;
  88. }
  89. v.conclude_write(W);
  90. }
  91. });
  92. std::thread odd([&]() {
  93. while(!trigger.load());
  94. for (int i = 1; i <= 255; i += 2) {
  95. auto W = v.reserve_write(i);
  96. v[W.start] = (char) i;
  97. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  98. v[idx] = (char) i;
  99. }
  100. v.conclude_write(W);
  101. }
  102. });
  103. // byte received count test
  104. trigger.store(true);
  105. reader.join(); even.join(); odd.join();
  106. for(int i = 1; i <= 255; i++) {
  107. REQUIRE(mset.count((char)i) == i);
  108. }
  109. // Continuity tests
  110. int changes = 0;
  111. auto str = continuity.str();
  112. char current = *str.begin();
  113. auto it = str.begin();
  114. for(;it != str.end();) {
  115. while(it != str.end() && *it == current) {++it;}
  116. changes += 1;
  117. current = *it;
  118. }
  119. REQUIRE(changes == 255);
  120. }
  121. }
  122. TEST_CASE("Fails if buffer too small") {
  123. REQUIRE_THROWS_AS(disruptor<strategy>(nullptr, page_size), disruptor_exception);
  124. }
  125. TEST_CASE("Fails if buffer size is 0") {
  126. REQUIRE_THROWS_AS(disruptor<strategy>(nullptr, 0), disruptor_exception);
  127. }
  128. TEST_CASE("Fails if buffer too small") {
  129. REQUIRE_THROWS_AS(disruptor<strategy_that_overflows>(nullptr, page_size), disruptor_exception);
  130. }
  131. TEST_CASE("Fails if buffer size is 0") {
  132. REQUIRE_THROWS_AS(disruptor<strategy_that_overflows>(nullptr, 0), disruptor_exception);
  133. }
  134. TEST_CASE("Disruptor works on overflow mode if things are not too contentious", "[long][unstable]") {
  135. std::array<char, 8192> buffer{};
  136. disruptor<strategy_that_overflows> v{buffer.data(), buffer.size()};
  137. SECTION("117") {
  138. auto W = v.reserve_write(100);
  139. v[W.start] = 117;
  140. v.conclude_write(W);
  141. auto R = v.reserve_read();
  142. REQUIRE(v[R.start]== 117);
  143. v.conclude_read(R);
  144. }
  145. SECTION("12") {
  146. {
  147. auto W = v.reserve_write(6);
  148. v[W.start] = 12;
  149. v.conclude_write(W);
  150. auto R = v.reserve_read();
  151. REQUIRE(v[R.start]== 12);
  152. v.conclude_read(R);
  153. }
  154. {
  155. auto W = v.reserve_write(6);
  156. v[W.start] = 8;
  157. v.conclude_write(W);
  158. auto R = v.reserve_read();
  159. REQUIRE(v[R.start]== 8);
  160. v.conclude_read(R);
  161. }
  162. }
  163. SECTION("Disruptor loop around") {
  164. std::multiset<char> mset;
  165. for(int i = 0; i != 255; i++) {
  166. auto W = v.reserve_write(100);
  167. v[W.start] = (char)i;
  168. for(size_t idx = W.start; idx != W.end; idx = (idx+1)%v.size()) {
  169. v[idx] = (char)i;
  170. }
  171. v.conclude_write(W);
  172. auto R = v.reserve_read();
  173. for(size_t idx = R.start; idx != R.end; idx = (idx+1)%v.size()) {
  174. mset.insert(v[idx]);
  175. }
  176. v.conclude_read(R);
  177. }
  178. for(int i = 0; i != 255; i++) {
  179. REQUIRE(mset.count((char)i) == 100);
  180. }
  181. }
  182. SECTION("Disruptor concurrent odd vs even") {
  183. std::atomic<bool> trigger = false;
  184. std::multiset<char> mset;
  185. std::stringstream continuity;
  186. int acc = 0;
  187. for(int i = 0; i<= 255; i++) {
  188. acc+=i;
  189. }
  190. using namespace std::chrono_literals;
  191. std::thread reader([&](){
  192. int cnt = 0;
  193. auto start = std::chrono::high_resolution_clock::now();
  194. while (std::chrono::high_resolution_clock::now() - start < 150ms) {
  195. auto R = v.reserve_read();
  196. for (size_t idx = R.start; idx != R.end; idx = (idx + 1) % v.size()) {
  197. mset.insert(v[idx]);
  198. continuity << (char)v[idx];
  199. }
  200. v.conclude_read(R);
  201. cnt += (R.end > R.start) * (R.end - R.start)
  202. + (R.end < R.start) * (v.size() - R.start + R.end);
  203. }
  204. });
  205. std::thread even([&]() {
  206. while(!trigger.load());
  207. for (int i = 2; i <= 255; i += 2) {
  208. auto W = v.reserve_write(i);
  209. v[W.start] = (char) i;
  210. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  211. v[idx] = (char) i;
  212. }
  213. v.conclude_write(W);
  214. std::this_thread::sleep_for(50us);
  215. }
  216. });
  217. std::thread odd([&]() {
  218. while(!trigger.load());
  219. for (int i = 1; i <= 255; i += 2) {
  220. auto W = v.reserve_write(i);
  221. v[W.start] = (char) i;
  222. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  223. v[idx] = (char) i;
  224. }
  225. v.conclude_write(W);
  226. std::this_thread::sleep_for(50us);
  227. }
  228. });
  229. // byte received count test
  230. trigger.store(true);
  231. reader.join();
  232. even.join();
  233. odd.join();
  234. uint16_t cnt = 0;
  235. for(int i = 1; i <= 255; i++) {
  236. cnt += (mset.count((char)i) == i);
  237. }
  238. REQUIRE(cnt >= 100);
  239. // Continuity tests
  240. int changes = 0;
  241. auto str = continuity.str();
  242. char current = *str.begin();
  243. auto it = str.begin();
  244. for(;it != str.end();) {
  245. while(it != str.end() && *it == current) {++it;}
  246. changes += 1;
  247. current = *it;
  248. }
  249. REQUIRE(changes >= 100);
  250. }
  251. }