blob: 2cbe3ed22a8791ebf56802061512fe641f056043 [file] [log] [blame]
Austin Schuh20b2b082019-09-11 20:42:56 -07001#ifndef AOS_IPC_LIB_QUEUE_RACER_H_
2#define AOS_IPC_LIB_QUEUE_RACER_H_
3
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cstring>
Austin Schuh20b2b082019-09-11 20:42:56 -07005
6#include "aos/ipc_lib/lockless_queue.h"
7
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -08008namespace aos::ipc_lib {
Austin Schuh20b2b082019-09-11 20:42:56 -07009
10struct ThreadState;
11
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070012struct QueueRacerConfiguration {
13 // Number of threads that send messages
14 const int num_threads;
15 // Number of messages sent by each thread
16 const uint64_t num_messages;
17 // Allows QueueRacer to check for multiple returns from calling Send()
18 const std::vector<LocklessQueueSender::Result> expected_send_results = {
19 LocklessQueueSender::Result::GOOD};
20 // Channel Storage Duration for queue used by QueueRacer
21 const monotonic_clock::duration channel_storage_duration =
22 std::chrono::nanoseconds(1);
23 // Set to true if all writes and reads are expected to be successful
24 // This allows QueueRacer to be used for checking failure scenarios
25 const bool check_writes_and_reads;
26};
27
Austin Schuh20b2b082019-09-11 20:42:56 -070028// Class to test the queue by spinning up a bunch of writing threads and racing
29// them together to all write at once.
30class QueueRacer {
31 public:
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070032 QueueRacer(LocklessQueue queue, int num_threads, uint64_t num_messages);
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070033 QueueRacer(LocklessQueue queue, const QueueRacerConfiguration &config);
Austin Schuh20b2b082019-09-11 20:42:56 -070034
35 // Runs an iteration of the race.
36 //
37 // This spins up num_threads, each of which sends num_messages. These must
38 // both be able to fit in the queue without wrapping.
39 //
40 // Then, this reads back all the messages and confirms that all were received
41 // in order, and none were missed.
42 //
43 // If race_reads is set, start reading (and retry if data isn't ready yet)
44 // while writes are still happening.
45 //
46 // If wrap_writes is nonzero, write enough to overwrite old data. This
47 // necesitates a loser check at the end.
48 //
49 // If both are set, run an even looser test.
Austin Schuh82ea7382023-07-14 15:17:34 -070050 //
51 // set_should_read is used to determine if we should pass in a valid
52 // should_read function, and should_read_result is the return result of that
53 // function.
54 void RunIteration(bool race_reads, int write_wrap_count, bool set_should_read,
55 bool should_read_result);
Austin Schuh20b2b082019-09-11 20:42:56 -070056
57 size_t CurrentIndex() {
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070058 return LocklessQueueReader(queue_).LatestIndex().index();
Austin Schuh20b2b082019-09-11 20:42:56 -070059 }
60
61 private:
62 // Wipes the queue memory out so we get a clean start.
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070063 void Reset() {
Austin Schuhfaec51a2023-09-08 17:43:32 -070064 memset(reinterpret_cast<void *>(queue_.memory()), 0,
65 LocklessQueueMemorySize(queue_.config()));
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070066 }
Austin Schuh20b2b082019-09-11 20:42:56 -070067
68 // This is a separate method so that when all the ASSERT_* methods, we still
69 // clean up all the threads. Otherwise we get an assert on the way out of
70 // RunIteration instead of getting all the way back to gtest.
71 void CheckReads(bool race_reads, int write_wrap_count,
Austin Schuh82ea7382023-07-14 15:17:34 -070072 ::std::vector<ThreadState> *threads, bool set_should_read,
73 bool should_read_result);
Austin Schuh20b2b082019-09-11 20:42:56 -070074
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070075 LocklessQueue queue_;
Austin Schuh20b2b082019-09-11 20:42:56 -070076 const uint64_t num_threads_;
77 const uint64_t num_messages_;
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070078 const monotonic_clock::duration channel_storage_duration_;
79 // Allows QueueRacer to check for multiple returns from calling Send()
80 const std::vector<LocklessQueueSender::Result> expected_send_results_;
81 const bool check_writes_and_reads_;
Austin Schuh20b2b082019-09-11 20:42:56 -070082 // The overall number of writes executed will always be between the two of
83 // these. We can't atomically count writes, so we have to bound them.
84 //
85 // Number of writes about to be started.
86 ::std::atomic<uint64_t> started_writes_;
87 // Number of writes completed.
88 ::std::atomic<uint64_t> finished_writes_;
Austin Schuh82ea7382023-07-14 15:17:34 -070089
90 std::function<bool(uint32_t, monotonic_clock::time_point,
91 realtime_clock::time_point, monotonic_clock::time_point,
92 realtime_clock::time_point, uint32_t, UUID, size_t)>
93 should_read_ = [](uint32_t, monotonic_clock::time_point,
94 realtime_clock::time_point, monotonic_clock::time_point,
95 realtime_clock::time_point, uint32_t, UUID,
96 size_t) { return true; };
Austin Schuh20b2b082019-09-11 20:42:56 -070097};
98
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080099} // namespace aos::ipc_lib
Austin Schuh20b2b082019-09-11 20:42:56 -0700100
101#endif // AOS_IPC_LIB_QUEUE_RACER_H_