blob: 1c07c496bc5824689d7cf711bc398d8174a93eea [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
Stephan Pleines682928d2024-05-31 20:43:48 -07004#include <stdint.h>
Austin Schuh20b2b082019-09-11 20:42:56 -07005
Stephan Pleines682928d2024-05-31 20:43:48 -07006#include <atomic>
7#include <chrono>
8#include <cstring>
9#include <functional>
10#include <vector>
11
12#include "aos/ipc_lib/index.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070013#include "aos/ipc_lib/lockless_queue.h"
Stephan Pleines682928d2024-05-31 20:43:48 -070014#include "aos/time/time.h"
15#include "aos/uuid.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070016
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080017namespace aos::ipc_lib {
Austin Schuh20b2b082019-09-11 20:42:56 -070018
19struct ThreadState;
20
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070021struct QueueRacerConfiguration {
22 // Number of threads that send messages
23 const int num_threads;
24 // Number of messages sent by each thread
25 const uint64_t num_messages;
26 // Allows QueueRacer to check for multiple returns from calling Send()
27 const std::vector<LocklessQueueSender::Result> expected_send_results = {
28 LocklessQueueSender::Result::GOOD};
29 // Channel Storage Duration for queue used by QueueRacer
30 const monotonic_clock::duration channel_storage_duration =
31 std::chrono::nanoseconds(1);
32 // Set to true if all writes and reads are expected to be successful
33 // This allows QueueRacer to be used for checking failure scenarios
34 const bool check_writes_and_reads;
35};
36
Austin Schuh20b2b082019-09-11 20:42:56 -070037// Class to test the queue by spinning up a bunch of writing threads and racing
38// them together to all write at once.
39class QueueRacer {
40 public:
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070041 QueueRacer(LocklessQueue queue, int num_threads, uint64_t num_messages);
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070042 QueueRacer(LocklessQueue queue, const QueueRacerConfiguration &config);
Austin Schuh20b2b082019-09-11 20:42:56 -070043
44 // Runs an iteration of the race.
45 //
46 // This spins up num_threads, each of which sends num_messages. These must
47 // both be able to fit in the queue without wrapping.
48 //
49 // Then, this reads back all the messages and confirms that all were received
50 // in order, and none were missed.
51 //
52 // If race_reads is set, start reading (and retry if data isn't ready yet)
53 // while writes are still happening.
54 //
55 // If wrap_writes is nonzero, write enough to overwrite old data. This
56 // necesitates a loser check at the end.
57 //
58 // If both are set, run an even looser test.
Austin Schuh82ea7382023-07-14 15:17:34 -070059 //
60 // set_should_read is used to determine if we should pass in a valid
61 // should_read function, and should_read_result is the return result of that
62 // function.
63 void RunIteration(bool race_reads, int write_wrap_count, bool set_should_read,
64 bool should_read_result);
Austin Schuh20b2b082019-09-11 20:42:56 -070065
66 size_t CurrentIndex() {
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070067 return LocklessQueueReader(queue_).LatestIndex().index();
Austin Schuh20b2b082019-09-11 20:42:56 -070068 }
69
70 private:
71 // Wipes the queue memory out so we get a clean start.
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070072 void Reset() {
Austin Schuhfaec51a2023-09-08 17:43:32 -070073 memset(reinterpret_cast<void *>(queue_.memory()), 0,
74 LocklessQueueMemorySize(queue_.config()));
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070075 }
Austin Schuh20b2b082019-09-11 20:42:56 -070076
77 // This is a separate method so that when all the ASSERT_* methods, we still
78 // clean up all the threads. Otherwise we get an assert on the way out of
79 // RunIteration instead of getting all the way back to gtest.
80 void CheckReads(bool race_reads, int write_wrap_count,
Austin Schuh82ea7382023-07-14 15:17:34 -070081 ::std::vector<ThreadState> *threads, bool set_should_read,
82 bool should_read_result);
Austin Schuh20b2b082019-09-11 20:42:56 -070083
Brian Silvermanfc0d2e82020-08-12 19:58:35 -070084 LocklessQueue queue_;
Austin Schuh20b2b082019-09-11 20:42:56 -070085 const uint64_t num_threads_;
86 const uint64_t num_messages_;
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -070087 const monotonic_clock::duration channel_storage_duration_;
88 // Allows QueueRacer to check for multiple returns from calling Send()
89 const std::vector<LocklessQueueSender::Result> expected_send_results_;
90 const bool check_writes_and_reads_;
Austin Schuh20b2b082019-09-11 20:42:56 -070091 // The overall number of writes executed will always be between the two of
92 // these. We can't atomically count writes, so we have to bound them.
93 //
94 // Number of writes about to be started.
95 ::std::atomic<uint64_t> started_writes_;
96 // Number of writes completed.
97 ::std::atomic<uint64_t> finished_writes_;
Austin Schuh82ea7382023-07-14 15:17:34 -070098
99 std::function<bool(uint32_t, monotonic_clock::time_point,
100 realtime_clock::time_point, monotonic_clock::time_point,
101 realtime_clock::time_point, uint32_t, UUID, size_t)>
102 should_read_ = [](uint32_t, monotonic_clock::time_point,
103 realtime_clock::time_point, monotonic_clock::time_point,
104 realtime_clock::time_point, uint32_t, UUID,
105 size_t) { return true; };
Austin Schuh20b2b082019-09-11 20:42:56 -0700106};
107
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800108} // namespace aos::ipc_lib
Austin Schuh20b2b082019-09-11 20:42:56 -0700109
110#endif // AOS_IPC_LIB_QUEUE_RACER_H_