A C++ library for logging very fast and without allocating.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

274 lignes
6.5 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<OverflowWait>(nullptr, page_size), disruptor_exception);
  124. }
  125. TEST_CASE("Fails if buffer size is 0") {
  126. REQUIRE_THROWS_AS(disruptor<OverflowWait>(nullptr, 0), disruptor_exception);
  127. }
  128. TEST_CASE("Disruptor works on overflow mode if things are not too contentious", "[long][unstable]") {
  129. std::array<char, 8192> buffer{};
  130. disruptor<strategy_that_overflows> v{buffer.data(), buffer.size()};
  131. SECTION("117") {
  132. auto W = v.reserve_write(100);
  133. v[W.start] = 117;
  134. v.conclude_write(W);
  135. auto R = v.reserve_read();
  136. REQUIRE(v[R.start]== 117);
  137. v.conclude_read(R);
  138. }
  139. SECTION("12") {
  140. {
  141. auto W = v.reserve_write(6);
  142. v[W.start] = 12;
  143. v.conclude_write(W);
  144. auto R = v.reserve_read();
  145. REQUIRE(v[R.start]== 12);
  146. v.conclude_read(R);
  147. }
  148. {
  149. auto W = v.reserve_write(6);
  150. v[W.start] = 8;
  151. v.conclude_write(W);
  152. auto R = v.reserve_read();
  153. REQUIRE(v[R.start]== 8);
  154. v.conclude_read(R);
  155. }
  156. }
  157. SECTION("Disruptor loop around") {
  158. std::multiset<char> mset;
  159. for(int i = 0; i != 255; i++) {
  160. auto W = v.reserve_write(100);
  161. v[W.start] = (char)i;
  162. for(size_t idx = W.start; idx != W.end; idx = (idx+1)%v.size()) {
  163. v[idx] = (char)i;
  164. }
  165. v.conclude_write(W);
  166. auto R = v.reserve_read();
  167. for(size_t idx = R.start; idx != R.end; idx = (idx+1)%v.size()) {
  168. mset.insert(v[idx]);
  169. }
  170. v.conclude_read(R);
  171. }
  172. for(int i = 0; i != 255; i++) {
  173. REQUIRE(mset.count((char)i) == 100);
  174. }
  175. }
  176. SECTION("Disruptor concurrent odd vs even") {
  177. std::atomic<bool> trigger = false;
  178. std::multiset<char> mset;
  179. std::stringstream continuity;
  180. int acc = 0;
  181. for(int i = 0; i<= 255; i++) {
  182. acc+=i;
  183. }
  184. using namespace std::chrono_literals;
  185. std::thread reader([&](){
  186. int cnt = 0;
  187. auto start = std::chrono::high_resolution_clock::now();
  188. while (std::chrono::high_resolution_clock::now() - start < 150ms) {
  189. auto R = v.reserve_read();
  190. for (size_t idx = R.start; idx != R.end; idx = (idx + 1) % v.size()) {
  191. mset.insert(v[idx]);
  192. continuity << (char)v[idx];
  193. }
  194. v.conclude_read(R);
  195. cnt += (R.end > R.start) * (R.end - R.start)
  196. + (R.end < R.start) * (v.size() - R.start + R.end);
  197. }
  198. });
  199. std::thread even([&]() {
  200. while(!trigger.load());
  201. for (int i = 2; i <= 255; i += 2) {
  202. auto W = v.reserve_write(i);
  203. v[W.start] = (char) i;
  204. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  205. v[idx] = (char) i;
  206. }
  207. v.conclude_write(W);
  208. std::this_thread::sleep_for(50us);
  209. }
  210. });
  211. std::thread odd([&]() {
  212. while(!trigger.load());
  213. for (int i = 1; i <= 255; i += 2) {
  214. auto W = v.reserve_write(i);
  215. v[W.start] = (char) i;
  216. for (size_t idx = W.start; idx != W.end; idx = (idx + 1) % v.size()) {
  217. v[idx] = (char) i;
  218. }
  219. v.conclude_write(W);
  220. std::this_thread::sleep_for(50us);
  221. }
  222. });
  223. // byte received count test
  224. trigger.store(true);
  225. reader.join();
  226. even.join();
  227. odd.join();
  228. uint16_t cnt = 0;
  229. for(int i = 1; i <= 255; i++) {
  230. cnt += (mset.count((char)i) == i);
  231. }
  232. REQUIRE(cnt >= 100);
  233. // Continuity tests
  234. int changes = 0;
  235. auto str = continuity.str();
  236. char current = *str.begin();
  237. auto it = str.begin();
  238. for(;it != str.end();) {
  239. while(it != str.end() && *it == current) {++it;}
  240. changes += 1;
  241. current = *it;
  242. }
  243. REQUIRE(changes >= 100);
  244. }
  245. }