ring_buffer.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cstddef>
  7. #include <numeric>
  8. #include <thread>
  9. #include <vector>
  10. #include <catch2/catch.hpp>
  11. #include "common/ring_buffer.h"
  12. namespace Common {
  13. TEST_CASE("RingBuffer: Basic Tests", "[common]") {
  14. RingBuffer<char, 4, 1> buf;
  15. // Pushing values into a ring buffer with space should succeed.
  16. for (std::size_t i = 0; i < 4; i++) {
  17. const char elem = static_cast<char>(i);
  18. const std::size_t count = buf.Push(&elem, 1);
  19. REQUIRE(count == 1);
  20. }
  21. REQUIRE(buf.Size() == 4);
  22. // Pushing values into a full ring buffer should fail.
  23. {
  24. const char elem = static_cast<char>(42);
  25. const std::size_t count = buf.Push(&elem, 1);
  26. REQUIRE(count == 0);
  27. }
  28. REQUIRE(buf.Size() == 4);
  29. // Popping multiple values from a ring buffer with values should succeed.
  30. {
  31. const std::vector<char> popped = buf.Pop(2);
  32. REQUIRE(popped.size() == 2);
  33. REQUIRE(popped[0] == 0);
  34. REQUIRE(popped[1] == 1);
  35. }
  36. REQUIRE(buf.Size() == 2);
  37. // Popping a single value from a ring buffer with values should succeed.
  38. {
  39. const std::vector<char> popped = buf.Pop(1);
  40. REQUIRE(popped.size() == 1);
  41. REQUIRE(popped[0] == 2);
  42. }
  43. REQUIRE(buf.Size() == 1);
  44. // Pushing more values than space available should partially suceed.
  45. {
  46. std::vector<char> to_push(6);
  47. std::iota(to_push.begin(), to_push.end(), 88);
  48. const std::size_t count = buf.Push(to_push);
  49. REQUIRE(count == 3);
  50. }
  51. REQUIRE(buf.Size() == 4);
  52. // Doing an unlimited pop should pop all values.
  53. {
  54. const std::vector<char> popped = buf.Pop();
  55. REQUIRE(popped.size() == 4);
  56. REQUIRE(popped[0] == 3);
  57. REQUIRE(popped[1] == 88);
  58. REQUIRE(popped[2] == 89);
  59. REQUIRE(popped[3] == 90);
  60. }
  61. REQUIRE(buf.Size() == 0);
  62. }
  63. TEST_CASE("RingBuffer: Threaded Test", "[common]") {
  64. RingBuffer<char, 4, 2> buf;
  65. const char seed = 42;
  66. const std::size_t count = 1000000;
  67. std::size_t full = 0;
  68. std::size_t empty = 0;
  69. const auto next_value = [](std::array<char, 2>& value) {
  70. value[0] += 1;
  71. value[1] += 2;
  72. };
  73. std::thread producer{[&] {
  74. std::array<char, 2> value = {seed, seed};
  75. std::size_t i = 0;
  76. while (i < count) {
  77. if (const std::size_t c = buf.Push(&value[0], 1); c > 0) {
  78. REQUIRE(c == 1);
  79. i++;
  80. next_value(value);
  81. } else {
  82. full++;
  83. std::this_thread::yield();
  84. }
  85. }
  86. }};
  87. std::thread consumer{[&] {
  88. std::array<char, 2> value = {seed, seed};
  89. std::size_t i = 0;
  90. while (i < count) {
  91. if (const std::vector<char> v = buf.Pop(1); v.size() > 0) {
  92. REQUIRE(v.size() == 2);
  93. REQUIRE(v[0] == value[0]);
  94. REQUIRE(v[1] == value[1]);
  95. i++;
  96. next_value(value);
  97. } else {
  98. empty++;
  99. std::this_thread::yield();
  100. }
  101. }
  102. }};
  103. producer.join();
  104. consumer.join();
  105. REQUIRE(buf.Size() == 0);
  106. printf("RingBuffer: Threaded Test: full: %zu, empty: %zu\n", full, empty);
  107. }
  108. } // namespace Common