tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_ring_buffer.cpp (6010B)


      1 /*
      2 * Copyright © 2016 Mozilla Foundation
      3 *
      4 * This program is made available under an ISC-style license.  See the
      5 * accompanying file LICENSE for details.
      6 */
      7 
      8 #ifndef NOMINMAX
      9 #define NOMINMAX
     10 #endif
     11 
     12 #include "cubeb_ringbuffer.h"
     13 #include "gtest/gtest.h"
     14 #include <chrono>
     15 #include <iostream>
     16 #include <thread>
     17 
     18 /* Generate a monotonically increasing sequence of numbers. */
     19 template <typename T> class sequence_generator {
     20 public:
     21  sequence_generator(size_t channels) : channels(channels) {}
     22  void get(T * elements, size_t frames)
     23  {
     24    for (size_t i = 0; i < frames; i++) {
     25      for (size_t c = 0; c < channels; c++) {
     26        elements[i * channels + c] = static_cast<T>(index_);
     27      }
     28      index_++;
     29    }
     30  }
     31  void rewind(size_t frames) { index_ -= frames; }
     32 
     33 private:
     34  size_t index_ = 0;
     35  size_t channels = 0;
     36 };
     37 
     38 /* Checks that a sequence is monotonically increasing. */
     39 template <typename T> class sequence_verifier {
     40 public:
     41  sequence_verifier(size_t channels) : channels(channels) {}
     42  void check(T * elements, size_t frames)
     43  {
     44    for (size_t i = 0; i < frames; i++) {
     45      for (size_t c = 0; c < channels; c++) {
     46        if (elements[i * channels + c] != static_cast<T>(index_)) {
     47          std::cerr << "Element " << i << " is different. Expected "
     48                    << static_cast<T>(index_) << ", got " << elements[i]
     49                    << ". (channel count: " << channels << ")." << std::endl;
     50          ASSERT_TRUE(false);
     51        }
     52      }
     53      index_++;
     54    }
     55  }
     56 
     57 private:
     58  size_t index_ = 0;
     59  size_t channels = 0;
     60 };
     61 
     62 template <typename T>
     63 void
     64 test_ring(lock_free_audio_ring_buffer<T> & buf, int channels,
     65          int capacity_frames)
     66 {
     67  std::unique_ptr<T[]> seq(new T[capacity_frames * channels]);
     68  sequence_generator<T> gen(channels);
     69  sequence_verifier<T> checker(channels);
     70 
     71  int iterations = 1002;
     72 
     73  const int block_size = 128;
     74 
     75  while (iterations--) {
     76    gen.get(seq.get(), block_size);
     77    int rv = buf.enqueue(seq.get(), block_size);
     78    ASSERT_EQ(rv, block_size);
     79    PodZero(seq.get(), block_size);
     80    rv = buf.dequeue(seq.get(), block_size);
     81    ASSERT_EQ(rv, block_size);
     82    checker.check(seq.get(), block_size);
     83  }
     84 }
     85 
     86 template <typename T>
     87 void
     88 test_ring_multi(lock_free_audio_ring_buffer<T> & buf, int channels,
     89                int capacity_frames)
     90 {
     91  sequence_verifier<T> checker(channels);
     92  std::unique_ptr<T[]> out_buffer(new T[capacity_frames * channels]);
     93 
     94  const int block_size = 128;
     95 
     96  std::thread t([=, &buf] {
     97    int iterations = 1002;
     98    std::unique_ptr<T[]> in_buffer(new T[capacity_frames * channels]);
     99    sequence_generator<T> gen(channels);
    100 
    101    while (iterations--) {
    102      std::this_thread::yield();
    103      gen.get(in_buffer.get(), block_size);
    104      int rv = buf.enqueue(in_buffer.get(), block_size);
    105      ASSERT_TRUE(rv <= block_size);
    106      if (rv != block_size) {
    107        gen.rewind(block_size - rv);
    108      }
    109    }
    110  });
    111 
    112  int remaining = 1002;
    113 
    114  while (remaining--) {
    115    std::this_thread::yield();
    116    int rv = buf.dequeue(out_buffer.get(), block_size);
    117    ASSERT_TRUE(rv <= block_size);
    118    checker.check(out_buffer.get(), rv);
    119  }
    120 
    121  t.join();
    122 }
    123 
    124 template <typename T>
    125 void
    126 basic_api_test(T & ring)
    127 {
    128  ASSERT_EQ(ring.capacity(), 128);
    129 
    130  ASSERT_EQ(ring.available_read(), 0);
    131  ASSERT_EQ(ring.available_write(), 128);
    132 
    133  int rv = ring.enqueue_default(63);
    134 
    135  ASSERT_TRUE(rv == 63);
    136  ASSERT_EQ(ring.available_read(), 63);
    137  ASSERT_EQ(ring.available_write(), 65);
    138 
    139  rv = ring.enqueue_default(65);
    140 
    141  ASSERT_EQ(rv, 65);
    142  ASSERT_EQ(ring.available_read(), 128);
    143  ASSERT_EQ(ring.available_write(), 0);
    144 
    145  rv = ring.dequeue(nullptr, 63);
    146 
    147  ASSERT_EQ(ring.available_read(), 65);
    148  ASSERT_EQ(ring.available_write(), 63);
    149 
    150  rv = ring.dequeue(nullptr, 65);
    151 
    152  ASSERT_EQ(ring.available_read(), 0);
    153  ASSERT_EQ(ring.available_write(), 128);
    154 }
    155 
    156 void
    157 test_reset_api()
    158 {
    159  const size_t ring_buffer_size = 128;
    160  const size_t enqueue_size = ring_buffer_size / 2;
    161 
    162  lock_free_queue<float> ring(ring_buffer_size);
    163  std::thread t([=, &ring] {
    164    std::unique_ptr<float[]> in_buffer(new float[enqueue_size]);
    165    ring.enqueue(in_buffer.get(), enqueue_size);
    166  });
    167 
    168  t.join();
    169 
    170  ring.reset_thread_ids();
    171 
    172  // Enqueue with a different thread. We have reset the thread ID
    173  // in the ring buffer, this should work.
    174  std::thread t2([=, &ring] {
    175    std::unique_ptr<float[]> in_buffer(new float[enqueue_size]);
    176    ring.enqueue(in_buffer.get(), enqueue_size);
    177  });
    178 
    179  t2.join();
    180 
    181  ASSERT_TRUE(true);
    182 }
    183 
    184 TEST(cubeb, ring_buffer)
    185 {
    186  /* Basic API test. */
    187  const int min_channels = 1;
    188  const int max_channels = 10;
    189  const int min_capacity = 199;
    190  const int max_capacity = 1277;
    191  const int capacity_increment = 27;
    192 
    193  lock_free_queue<float> q1(128);
    194  basic_api_test(q1);
    195  lock_free_queue<short> q2(128);
    196  basic_api_test(q2);
    197 
    198  for (size_t channels = min_channels; channels < max_channels; channels++) {
    199    lock_free_audio_ring_buffer<float> q3(channels, 128);
    200    basic_api_test(q3);
    201    lock_free_audio_ring_buffer<short> q4(channels, 128);
    202    basic_api_test(q4);
    203  }
    204 
    205  /* Single thread testing. */
    206  /* Test mono to 9.1 */
    207  for (size_t channels = min_channels; channels < max_channels; channels++) {
    208    /* Use non power-of-two numbers to catch edge-cases. */
    209    for (size_t capacity_frames = min_capacity; capacity_frames < max_capacity;
    210         capacity_frames += capacity_increment) {
    211      lock_free_audio_ring_buffer<float> ring(channels, capacity_frames);
    212      test_ring(ring, channels, capacity_frames);
    213    }
    214  }
    215 
    216  /* Multi thread testing */
    217  for (size_t channels = min_channels; channels < max_channels; channels++) {
    218    /* Use non power-of-two numbers to catch edge-cases. */
    219    for (size_t capacity_frames = min_capacity; capacity_frames < max_capacity;
    220         capacity_frames += capacity_increment) {
    221      lock_free_audio_ring_buffer<short> ring(channels, capacity_frames);
    222      test_ring_multi(ring, channels, capacity_frames);
    223    }
    224  }
    225 
    226  test_reset_api();
    227 }
    228 
    229 #undef NOMINMAX