blob: e5905aca71dc91e2259ae6cdb259b838dc6c1845 [file] [log] [blame]
Stephan Pleines682928d2024-05-31 20:43:48 -07001#include <arpa/inet.h>
2#include <errno.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08003#include <fcntl.h>
Stephan Pleines682928d2024-05-31 20:43:48 -07004#include <inttypes.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08005#include <mqueue.h>
Brian Silvermane4d8b282015-12-24 13:44:48 -08006#include <netinet/in.h>
Brian Silvermanfd788882016-09-10 16:56:20 -04007#include <netinet/tcp.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08008#include <pthread.h>
9#include <semaphore.h>
Stephan Pleines682928d2024-05-31 20:43:48 -070010#include <stdio.h>
11#include <string.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -080012#include <sys/eventfd.h>
Stephan Pleines682928d2024-05-31 20:43:48 -070013#include <sys/ipc.h>
Brian Silvermane4d8b282015-12-24 13:44:48 -080014#include <sys/msg.h>
15#include <sys/sem.h>
Austin Schuhf2a50ba2016-12-24 16:16:26 -080016#include <sys/socket.h>
17#include <sys/stat.h>
Stephan Pleines682928d2024-05-31 20:43:48 -070018#include <unistd.h>
Brian Silvermane4d8b282015-12-24 13:44:48 -080019
Austin Schuhf2a50ba2016-12-24 16:16:26 -080020#include <atomic>
21#include <chrono>
Stephan Pleines682928d2024-05-31 20:43:48 -070022#include <compare>
Tyler Chatowbf0609c2021-07-31 16:13:27 -070023#include <cstdint>
Brian Silvermane4d8b282015-12-24 13:44:48 -080024#include <memory>
25#include <string>
Austin Schuhf2a50ba2016-12-24 16:16:26 -080026#include <thread>
Stephan Pleines682928d2024-05-31 20:43:48 -070027#include <utility>
Brian Silvermane4d8b282015-12-24 13:44:48 -080028
Austin Schuh99f7c6a2024-06-25 22:07:44 -070029#include "absl/flags/flag.h"
30#include "absl/flags/usage.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070031
John Park33858a32018-09-28 23:05:48 -070032#include "aos/condition.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -070033#include "aos/init.h"
Brian Silverman7b266d92021-02-17 21:24:02 -080034#include "aos/ipc_lib/event.h"
John Park33858a32018-09-28 23:05:48 -070035#include "aos/logging/implementations.h"
John Park33858a32018-09-28 23:05:48 -070036#include "aos/mutex/mutex.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070037#include "aos/realtime.h"
John Park33858a32018-09-28 23:05:48 -070038#include "aos/time/time.h"
Brian Silvermane4d8b282015-12-24 13:44:48 -080039
Austin Schuh99f7c6a2024-06-25 22:07:44 -070040ABSL_FLAG(std::string, method, "", "Which IPC method to use");
41ABSL_FLAG(int32_t, messages, 1000000,
42 "How many messages to send back and forth");
43ABSL_FLAG(int32_t, client_cpu, 0, "CPU to pin client to");
44ABSL_FLAG(int32_t, server_cpu, 0, "CPU to pin server to");
45ABSL_FLAG(int32_t, client_priority, 1,
46 "Realtime priority for client. Negative for don't change");
47ABSL_FLAG(int32_t, server_priority, 1,
48 "Realtime priority for server. Negative for don't change");
Brian Silvermane4d8b282015-12-24 13:44:48 -080049
50namespace aos {
51
Austin Schuhf2a50ba2016-12-24 16:16:26 -080052namespace chrono = ::std::chrono;
53
Brian Silvermane4d8b282015-12-24 13:44:48 -080054// A generic interface for an object which can send some data to another thread
55// and back.
56//
57// One side is called the "server". It should constantly Wait, do something with
58// the result, and then call Pong.
59// The other side is called the "client". It should repeatedly call Ping.
60class PingPongerInterface {
61 public:
62 // A chunk of memory definitely on its own cache line anywhere sane.
63 typedef uint8_t Data[1024] __attribute__((aligned(128)));
64
65 virtual ~PingPongerInterface() {}
66
67 // Returns where the "client" side should write data in preparation to send to
68 // the server.
69 // The result is valid until the next Ping call.
70 virtual Data *PingData() = 0;
71
72 // Sends the data returned from the most recent PingData call to the "server"
73 // side and returns its response.
74 // PingData must be called exactly once before each call of this method.
75 // The result is valid until the next PingData call.
76 virtual const Data *Ping() = 0;
77
78 // Waits for a Ping call and then returns the associated data.
79 // The result is valid until the beginning of the next Pong call.
80 virtual const Data *Wait() = 0;
81
82 // Returns where the "server" side should write data in preparation to send
83 // back to the "client".
84 // The result is valid until the next Pong call.
85 virtual Data *PongData() = 0;
86
87 // Sends data back to an in-progress Ping.
88 // Sends the data returned from the most recent PongData call back to an
89 // in-progress Ping.
90 // PongData must be called exactly once before each call of this method.
91 virtual void Pong() = 0;
92};
93
94// Base class for implementations which simple use a pair of Data objects for
95// all Pings and Pongs.
96class StaticPingPonger : public PingPongerInterface {
97 public:
98 Data *PingData() override { return &ping_data_; }
99 Data *PongData() override { return &pong_data_; }
100
101 private:
102 Data ping_data_, pong_data_;
103};
104
105// Implements ping-pong by sending the data over file descriptors.
106class FDPingPonger : public StaticPingPonger {
107 protected:
108 // Subclasses must override and call Init.
109 FDPingPonger() {}
110
111 // Subclasses must call this in their constructor.
112 // Does not take ownership of any of the file descriptors, any/all of which
113 // may be the same.
114 // {server,client}_read must be open for reading and {server,client}_write
115 // must be open for writing.
116 void Init(int server_read, int server_write, int client_read,
117 int client_write) {
118 server_read_ = server_read;
119 server_write_ = server_write;
120 client_read_ = client_read;
121 client_write_ = client_write;
122 }
123
124 private:
125 const Data *Ping() override {
126 WriteFully(client_write_, *PingData());
127 ReadFully(client_read_, &read_by_client_);
128 return &read_by_client_;
129 }
130
131 const Data *Wait() override {
132 ReadFully(server_read_, &read_by_server_);
133 return &read_by_server_;
134 }
135
136 void Pong() override { WriteFully(server_write_, *PongData()); }
137
138 void ReadFully(int fd, Data *data) {
139 size_t remaining = sizeof(*data);
140 uint8_t *current = &(*data)[0];
141 while (remaining > 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700142 const ssize_t result = AOS_PCHECK(read(fd, current, remaining));
143 AOS_CHECK_LE(static_cast<size_t>(result), remaining);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800144 remaining -= result;
145 current += result;
146 }
147 }
148
149 void WriteFully(int fd, const Data &data) {
150 size_t remaining = sizeof(data);
151 const uint8_t *current = &data[0];
152 while (remaining > 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700153 const ssize_t result = AOS_PCHECK(write(fd, current, remaining));
154 AOS_CHECK_LE(static_cast<size_t>(result), remaining);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800155 remaining -= result;
156 current += result;
157 }
158 }
159
160 Data read_by_client_, read_by_server_;
161 int server_read_ = -1, server_write_ = -1, client_read_ = -1,
162 client_write_ = -1;
163};
164
165class PipePingPonger : public FDPingPonger {
166 public:
167 PipePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700168 AOS_PCHECK(pipe(to_server));
169 AOS_PCHECK(pipe(from_server));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800170 Init(to_server[0], from_server[1], from_server[0], to_server[1]);
171 }
172 ~PipePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700173 AOS_PCHECK(close(to_server[0]));
174 AOS_PCHECK(close(to_server[1]));
175 AOS_PCHECK(close(from_server[0]));
176 AOS_PCHECK(close(from_server[1]));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800177 }
178
179 private:
180 int to_server[2], from_server[2];
181};
182
183class NamedPipePingPonger : public FDPingPonger {
184 public:
185 NamedPipePingPonger() {
186 OpenFifo("/tmp/to_server", &client_write_, &server_read_);
187 OpenFifo("/tmp/from_server", &server_write_, &client_read_);
188
189 Init(server_read_, server_write_, client_read_, client_write_);
190 }
191 ~NamedPipePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700192 AOS_PCHECK(close(server_read_));
193 AOS_PCHECK(close(client_write_));
194 AOS_PCHECK(close(client_read_));
195 AOS_PCHECK(close(server_write_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800196 }
197
198 private:
199 void OpenFifo(const char *name, int *write, int *read) {
200 {
201 const int ret = unlink(name);
202 if (ret == -1 && errno != ENOENT) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700203 AOS_PLOG(FATAL, "unlink(%s)", name);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800204 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700205 AOS_PCHECK(mkfifo(name, S_IWUSR | S_IRUSR));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800206 // Have to open it nonblocking because the other end isn't open yet...
Austin Schuhf257f3c2019-10-27 21:00:43 -0700207 *read = AOS_PCHECK(open(name, O_RDONLY | O_NONBLOCK));
208 *write = AOS_PCHECK(open(name, O_WRONLY));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800209 {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700210 const int flags = AOS_PCHECK(fcntl(*read, F_GETFL));
211 AOS_PCHECK(fcntl(*read, F_SETFL, flags & ~O_NONBLOCK));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800212 }
213 }
214 }
215
216 int server_read_, server_write_, client_read_, client_write_;
217};
218
219class UnixPingPonger : public FDPingPonger {
220 public:
221 UnixPingPonger(int type) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700222 AOS_PCHECK(socketpair(AF_UNIX, type, 0, to_server));
223 AOS_PCHECK(socketpair(AF_UNIX, type, 0, from_server));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800224 Init(to_server[0], from_server[1], from_server[0], to_server[1]);
225 }
226 ~UnixPingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700227 AOS_PCHECK(close(to_server[0]));
228 AOS_PCHECK(close(to_server[1]));
229 AOS_PCHECK(close(from_server[0]));
230 AOS_PCHECK(close(from_server[1]));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800231 }
232
233 private:
234 int to_server[2], from_server[2];
235};
236
237class TCPPingPonger : public FDPingPonger {
238 public:
Brian Silvermanfd788882016-09-10 16:56:20 -0400239 TCPPingPonger(bool nodelay) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700240 server_ = AOS_PCHECK(socket(AF_INET, SOCK_STREAM, 0));
Brian Silvermanfd788882016-09-10 16:56:20 -0400241 if (nodelay) {
242 const int yes = 1;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700243 AOS_PCHECK(
244 setsockopt(server_, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)));
Brian Silvermanfd788882016-09-10 16:56:20 -0400245 }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800246 {
247 sockaddr_in server_address;
248 memset(&server_address, 0, sizeof(server_address));
249 server_address.sin_family = AF_INET;
250 server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700251 AOS_PCHECK(bind(server_, reinterpret_cast<sockaddr *>(&server_address),
252 sizeof(server_address)));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800253 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700254 AOS_PCHECK(listen(server_, 1));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800255
Austin Schuhf257f3c2019-10-27 21:00:43 -0700256 client_ = AOS_PCHECK(socket(AF_INET, SOCK_STREAM, 0));
Brian Silvermanfd788882016-09-10 16:56:20 -0400257 if (nodelay) {
258 const int yes = 1;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700259 AOS_PCHECK(
260 setsockopt(client_, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)));
Brian Silvermanfd788882016-09-10 16:56:20 -0400261 }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800262 {
263 sockaddr_in client_address;
264 unsigned int length = sizeof(client_address);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700265 AOS_PCHECK(getsockname(
266 server_, reinterpret_cast<sockaddr *>(&client_address), &length));
267 AOS_PCHECK(connect(client_, reinterpret_cast<sockaddr *>(&client_address),
268 length));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800269 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700270 server_connection_ = AOS_PCHECK(accept(server_, nullptr, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800271
272 Init(server_connection_, server_connection_, client_, client_);
273 }
274 ~TCPPingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700275 AOS_PCHECK(close(client_));
276 AOS_PCHECK(close(server_connection_));
277 AOS_PCHECK(close(server_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800278 }
279
280 private:
281 int server_, client_, server_connection_;
282};
283
284class UDPPingPonger : public FDPingPonger {
285 public:
286 UDPPingPonger() {
287 CreatePair(&server_read_, &client_write_);
288 CreatePair(&client_read_, &server_write_);
289
290 Init(server_read_, server_write_, client_read_, client_write_);
291 }
292 ~UDPPingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700293 AOS_PCHECK(close(server_read_));
294 AOS_PCHECK(close(client_write_));
295 AOS_PCHECK(close(client_read_));
296 AOS_PCHECK(close(server_write_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800297 }
298
299 private:
300 void CreatePair(int *server, int *client) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700301 *server = AOS_PCHECK(socket(AF_INET, SOCK_DGRAM, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800302 {
303 sockaddr_in server_address;
304 memset(&server_address, 0, sizeof(server_address));
305 server_address.sin_family = AF_INET;
306 server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
307 // server_address.sin_port = htons(server_ + 3000);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700308 AOS_PCHECK(bind(*server, reinterpret_cast<sockaddr *>(&server_address),
309 sizeof(server_address)));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800310 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700311 *client = AOS_PCHECK(socket(AF_INET, SOCK_DGRAM, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800312 {
313 sockaddr_in client_address;
314 unsigned int length = sizeof(client_address);
Austin Schuhf257f3c2019-10-27 21:00:43 -0700315 AOS_PCHECK(getsockname(
316 *server, reinterpret_cast<sockaddr *>(&client_address), &length));
317 AOS_PCHECK(connect(*client, reinterpret_cast<sockaddr *>(&client_address),
318 length));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800319 }
320 }
321
322 int server_read_, server_write_, client_read_, client_write_;
323};
324
325// Implements ping-pong without copying the data using a condition variable-like
326// interface.
327class ConditionVariablePingPonger : public StaticPingPonger {
328 protected:
329 // Represents a condition variable bundled with a mutex.
330 //
331 // Wait may return spuriously.
332 class ConditionVariableInterface {
333 public:
334 virtual ~ConditionVariableInterface() {}
335
336 // Locks the mutex.
337 virtual void Lock() = 0;
338
339 // Unlocks the mutex.
340 virtual void Unlock() = 0;
341
342 // Waits on the condition variable.
343 //
344 // The mutex must be locked when this is called.
345 virtual void Wait() = 0;
346
347 // Signals the condition variable.
348 //
349 // The mutex does not have to be locked during this.
350 virtual void Signal() = 0;
351 };
352
353 ConditionVariablePingPonger(
354 ::std::unique_ptr<ConditionVariableInterface> ping,
355 ::std::unique_ptr<ConditionVariableInterface> pong)
356 : ping_(::std::move(ping)), pong_(::std::move(pong)) {}
357
358 private:
359 const Data *Ping() override {
360 ping_->Lock();
361 to_server_ = PingData();
362 ping_->Unlock();
363 ping_->Signal();
364 pong_->Lock();
365 while (from_server_ == nullptr) {
366 pong_->Wait();
367 }
368 const Data *r = from_server_;
369 from_server_ = nullptr;
370 pong_->Unlock();
371 return r;
372 }
373
374 const Data *Wait() override {
375 ping_->Lock();
376 while (to_server_ == nullptr) {
377 ping_->Wait();
378 }
379 const Data *r = to_server_;
380 to_server_ = nullptr;
381 ping_->Unlock();
382 return r;
383 }
384
385 void Pong() override {
386 pong_->Lock();
387 from_server_ = PongData();
388 pong_->Unlock();
389 pong_->Signal();
390 }
391
392 const Data *to_server_ = nullptr, *from_server_ = nullptr;
393 const ::std::unique_ptr<ConditionVariableInterface> ping_, pong_;
394};
395
396// Implements ping-pong without copying the data using a semaphore-like
397// interface.
398class SemaphorePingPonger : public StaticPingPonger {
399 protected:
400 // Represents a semaphore, which need only count to 1.
401 //
402 // The behavior when calling Get/Put in anything other than alternating order
403 // is undefined.
404 //
405 // Wait may NOT return spuriously.
406 class SemaphoreInterface {
407 public:
408 virtual ~SemaphoreInterface() {}
409
410 virtual void Get() = 0;
411 virtual void Put() = 0;
412 };
413
414 SemaphorePingPonger(::std::unique_ptr<SemaphoreInterface> ping,
415 ::std::unique_ptr<SemaphoreInterface> pong)
416 : ping_(::std::move(ping)), pong_(::std::move(pong)) {}
417
418 private:
419 const Data *Ping() override {
420 to_server_ = PingData();
421 ping_->Put();
422 pong_->Get();
423 return from_server_;
424 }
425
426 const Data *Wait() override {
427 ping_->Get();
428 return to_server_;
429 }
430
431 void Pong() override {
432 from_server_ = PongData();
433 pong_->Put();
434 }
435
436 const Data *to_server_ = nullptr, *from_server_ = nullptr;
437 const ::std::unique_ptr<SemaphoreInterface> ping_, pong_;
438};
439
Brian Silvermane4d8b282015-12-24 13:44:48 -0800440class AOSMutexPingPonger : public ConditionVariablePingPonger {
441 public:
442 AOSMutexPingPonger()
443 : ConditionVariablePingPonger(
444 ::std::unique_ptr<ConditionVariableInterface>(
445 new AOSConditionVariable()),
446 ::std::unique_ptr<ConditionVariableInterface>(
447 new AOSConditionVariable())) {}
448
449 private:
450 class AOSConditionVariable : public ConditionVariableInterface {
451 public:
452 AOSConditionVariable() : condition_(&mutex_) {}
453
454 private:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700455 void Lock() override { AOS_CHECK(!mutex_.Lock()); }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800456 void Unlock() override { mutex_.Unlock(); }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700457 void Wait() override { AOS_CHECK(!condition_.Wait()); }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800458 void Signal() override { condition_.Broadcast(); }
459
460 Mutex mutex_;
461 Condition condition_;
462 };
463};
464
465class AOSEventPingPonger : public SemaphorePingPonger {
466 public:
467 AOSEventPingPonger()
468 : SemaphorePingPonger(
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700469 ::std::unique_ptr<SemaphoreInterface>(new AOSEventSemaphore()),
470 ::std::unique_ptr<SemaphoreInterface>(new AOSEventSemaphore())) {}
Brian Silvermane4d8b282015-12-24 13:44:48 -0800471
472 private:
473 class AOSEventSemaphore : public SemaphoreInterface {
474 private:
475 void Get() override {
476 event_.Wait();
477 event_.Clear();
478 }
479 void Put() override { event_.Set(); }
480
481 Event event_;
482 };
483};
484
485class PthreadMutexPingPonger : public ConditionVariablePingPonger {
486 public:
Brian Silvermanfd788882016-09-10 16:56:20 -0400487 PthreadMutexPingPonger(int pshared, bool pi)
Brian Silvermane4d8b282015-12-24 13:44:48 -0800488 : ConditionVariablePingPonger(
489 ::std::unique_ptr<ConditionVariableInterface>(
Brian Silvermanfd788882016-09-10 16:56:20 -0400490 new PthreadConditionVariable(pshared, pi)),
Brian Silvermane4d8b282015-12-24 13:44:48 -0800491 ::std::unique_ptr<ConditionVariableInterface>(
Brian Silvermanfd788882016-09-10 16:56:20 -0400492 new PthreadConditionVariable(pshared, pi))) {}
Brian Silvermane4d8b282015-12-24 13:44:48 -0800493
494 private:
495 class PthreadConditionVariable : public ConditionVariableInterface {
496 public:
Brian Silvermanfd788882016-09-10 16:56:20 -0400497 PthreadConditionVariable(bool pshared, bool pi) {
498 {
499 pthread_condattr_t cond_attr;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700500 AOS_PRCHECK(pthread_condattr_init(&cond_attr));
Brian Silvermanfd788882016-09-10 16:56:20 -0400501 if (pshared) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700502 AOS_PRCHECK(
Brian Silvermanfd788882016-09-10 16:56:20 -0400503 pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED));
504 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700505 AOS_PRCHECK(pthread_cond_init(&condition_, &cond_attr));
506 AOS_PRCHECK(pthread_condattr_destroy(&cond_attr));
Brian Silvermanfd788882016-09-10 16:56:20 -0400507 }
508
509 {
510 pthread_mutexattr_t mutex_attr;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700511 AOS_PRCHECK(pthread_mutexattr_init(&mutex_attr));
Brian Silvermanfd788882016-09-10 16:56:20 -0400512 if (pshared) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700513 AOS_PRCHECK(pthread_mutexattr_setpshared(&mutex_attr,
514 PTHREAD_PROCESS_SHARED));
Brian Silvermanfd788882016-09-10 16:56:20 -0400515 }
516 if (pi) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700517 AOS_PRCHECK(
Brian Silvermanfd788882016-09-10 16:56:20 -0400518 pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT));
519 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700520 AOS_PRCHECK(pthread_mutex_init(&mutex_, nullptr));
521 AOS_PRCHECK(pthread_mutexattr_destroy(&mutex_attr));
Brian Silvermanfd788882016-09-10 16:56:20 -0400522 }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800523 }
524 ~PthreadConditionVariable() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700525 AOS_PRCHECK(pthread_mutex_destroy(&mutex_));
526 AOS_PRCHECK(pthread_cond_destroy(&condition_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800527 }
528
529 private:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700530 void Lock() override { AOS_PRCHECK(pthread_mutex_lock(&mutex_)); }
531 void Unlock() override { AOS_PRCHECK(pthread_mutex_unlock(&mutex_)); }
532 void Wait() override {
533 AOS_PRCHECK(pthread_cond_wait(&condition_, &mutex_));
534 }
535 void Signal() override { AOS_PRCHECK(pthread_cond_broadcast(&condition_)); }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800536
537 pthread_cond_t condition_;
538 pthread_mutex_t mutex_;
539 };
540};
541
542class EventFDPingPonger : public SemaphorePingPonger {
543 public:
544 EventFDPingPonger()
545 : SemaphorePingPonger(
546 ::std::unique_ptr<SemaphoreInterface>(new EventFDSemaphore()),
547 ::std::unique_ptr<SemaphoreInterface>(new EventFDSemaphore())) {}
548
549 private:
550 class EventFDSemaphore : public SemaphoreInterface {
551 public:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700552 EventFDSemaphore() : fd_(AOS_PCHECK(eventfd(0, 0))) {}
553 ~EventFDSemaphore() { AOS_PCHECK(close(fd_)); }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800554
555 private:
556 void Get() override {
557 uint64_t value;
558 if (read(fd_, &value, sizeof(value)) != sizeof(value)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700559 AOS_PLOG(FATAL, "reading from eventfd %d failed\n", fd_);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800560 }
Austin Schuhf257f3c2019-10-27 21:00:43 -0700561 AOS_CHECK_EQ(1u, value);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800562 }
563 void Put() override {
564 uint64_t value = 1;
565 if (write(fd_, &value, sizeof(value)) != sizeof(value)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700566 AOS_PLOG(FATAL, "writing to eventfd %d failed\n", fd_);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800567 }
568 }
569
570 const int fd_;
571 };
572};
573
574class SysvSemaphorePingPonger : public SemaphorePingPonger {
575 public:
576 SysvSemaphorePingPonger()
577 : SemaphorePingPonger(
578 ::std::unique_ptr<SemaphoreInterface>(new SysvSemaphore()),
579 ::std::unique_ptr<SemaphoreInterface>(new SysvSemaphore())) {}
580
581 private:
582 class SysvSemaphore : public SemaphoreInterface {
583 public:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700584 SysvSemaphore() : sem_id_(AOS_PCHECK(semget(IPC_PRIVATE, 1, 0600))) {}
Brian Silvermane4d8b282015-12-24 13:44:48 -0800585
586 private:
587 void Get() override {
588 struct sembuf op;
589 op.sem_num = 0;
590 op.sem_op = -1;
591 op.sem_flg = 0;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700592 AOS_PCHECK(semop(sem_id_, &op, 1));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800593 }
594 void Put() override {
595 struct sembuf op;
596 op.sem_num = 0;
597 op.sem_op = 1;
598 op.sem_flg = 0;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700599 AOS_PCHECK(semop(sem_id_, &op, 1));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800600 }
601
602 const int sem_id_;
603 };
604};
605
606class PosixSemaphorePingPonger : public SemaphorePingPonger {
607 protected:
608 PosixSemaphorePingPonger(sem_t *ping_sem, sem_t *pong_sem)
609 : SemaphorePingPonger(
610 ::std::unique_ptr<SemaphoreInterface>(new PosixSemaphore(ping_sem)),
611 ::std::unique_ptr<SemaphoreInterface>(
612 new PosixSemaphore(pong_sem))) {}
613
614 private:
615 class PosixSemaphore : public SemaphoreInterface {
616 public:
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700617 PosixSemaphore(sem_t *sem) : sem_(sem) {}
Brian Silvermane4d8b282015-12-24 13:44:48 -0800618
619 private:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700620 void Get() override { AOS_PCHECK(sem_wait(sem_)); }
621 void Put() override { AOS_PCHECK(sem_post(sem_)); }
Brian Silvermane4d8b282015-12-24 13:44:48 -0800622
623 sem_t *const sem_;
624 };
625};
626
627class SysvQueuePingPonger : public StaticPingPonger {
628 public:
629 SysvQueuePingPonger()
Austin Schuhf257f3c2019-10-27 21:00:43 -0700630 : ping_(AOS_PCHECK(msgget(IPC_PRIVATE, 0600))),
631 pong_(AOS_PCHECK(msgget(IPC_PRIVATE, 0600))) {}
Brian Silvermane4d8b282015-12-24 13:44:48 -0800632
633 const Data *Ping() override {
634 {
635 Message to_send;
636 memcpy(&to_send.data, PingData(), sizeof(Data));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700637 AOS_PCHECK(msgsnd(ping_, &to_send, sizeof(Data), 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800638 }
639 {
640 Message received;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700641 AOS_PCHECK(msgrcv(pong_, &received, sizeof(Data), 1, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800642 memcpy(&pong_received_, &received.data, sizeof(Data));
643 }
644 return &pong_received_;
645 }
646
647 const Data *Wait() override {
648 {
649 Message received;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700650 AOS_PCHECK(msgrcv(ping_, &received, sizeof(Data), 1, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800651 memcpy(&ping_received_, &received.data, sizeof(Data));
652 }
653 return &ping_received_;
654 }
655
656 virtual void Pong() override {
657 Message to_send;
658 memcpy(&to_send.data, PongData(), sizeof(Data));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700659 AOS_PCHECK(msgsnd(pong_, &to_send, sizeof(Data), 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800660 }
661
662 private:
663 struct Message {
664 long mtype = 1;
665 char data[sizeof(Data)];
666 };
667
668 Data ping_received_, pong_received_;
669
670 const int ping_, pong_;
671};
672
673class PosixQueuePingPonger : public StaticPingPonger {
674 public:
675 PosixQueuePingPonger() : ping_(Open("/ping")), pong_(Open("/pong")) {}
676 ~PosixQueuePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700677 AOS_PCHECK(mq_close(ping_));
678 AOS_PCHECK(mq_close(pong_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800679 }
680
681 const Data *Ping() override {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700682 AOS_PCHECK(mq_send(ping_,
683 static_cast<char *>(static_cast<void *>(PingData())),
684 sizeof(Data), 1));
685 AOS_PCHECK(mq_receive(
686 pong_, static_cast<char *>(static_cast<void *>(&pong_received_)),
687 sizeof(Data), nullptr));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800688 return &pong_received_;
689 }
690
691 const Data *Wait() override {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700692 AOS_PCHECK(mq_receive(
693 ping_, static_cast<char *>(static_cast<void *>(&ping_received_)),
694 sizeof(Data), nullptr));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800695 return &ping_received_;
696 }
697
698 virtual void Pong() override {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700699 AOS_PCHECK(mq_send(pong_,
700 static_cast<char *>(static_cast<void *>(PongData())),
701 sizeof(Data), 1));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800702 }
703
704 private:
705 mqd_t Open(const char *name) {
706 if (mq_unlink(name) == -1 && errno != ENOENT) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700707 AOS_PLOG(FATAL, "mq_unlink(%s) failed", name);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800708 }
709 struct mq_attr attr;
710 attr.mq_flags = 0;
711 attr.mq_maxmsg = 1;
712 attr.mq_msgsize = sizeof(Data);
713 attr.mq_curmsgs = 0;
714 const mqd_t r = mq_open(name, O_CREAT | O_RDWR | O_EXCL, 0600, &attr);
715 if (r == reinterpret_cast<mqd_t>(-1)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700716 AOS_PLOG(FATAL, "mq_open(%s, O_CREAT | O_RDWR | O_EXCL) failed", name);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800717 }
718 return r;
719 }
720
721 const mqd_t ping_, pong_;
722 Data ping_received_, pong_received_;
723};
724
725class PosixUnnamedSemaphorePingPonger : public PosixSemaphorePingPonger {
726 public:
727 PosixUnnamedSemaphorePingPonger(int pshared)
728 : PosixSemaphorePingPonger(&ping_sem_, &pong_sem_) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700729 AOS_PCHECK(sem_init(&ping_sem_, pshared, 0));
730 AOS_PCHECK(sem_init(&pong_sem_, pshared, 0));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800731 }
732 ~PosixUnnamedSemaphorePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700733 AOS_PCHECK(sem_destroy(&ping_sem_));
734 AOS_PCHECK(sem_destroy(&pong_sem_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800735 }
736
737 private:
738 sem_t ping_sem_, pong_sem_;
739};
740
741class PosixNamedSemaphorePingPonger : public PosixSemaphorePingPonger {
742 public:
743 PosixNamedSemaphorePingPonger()
744 : PosixSemaphorePingPonger(ping_sem_ = Open("/ping"),
745 pong_sem_ = Open("/pong")) {}
746 ~PosixNamedSemaphorePingPonger() {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700747 AOS_PCHECK(sem_close(ping_sem_));
748 AOS_PCHECK(sem_close(pong_sem_));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800749 }
750
751 private:
752 sem_t *Open(const char *name) {
753 if (sem_unlink(name) == -1 && errno != ENOENT) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700754 AOS_PLOG(FATAL, "shm_unlink(%s) failed", name);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800755 }
756 sem_t *const r = sem_open(name, O_CREAT | O_RDWR | O_EXCL, 0600, 0);
757 if (r == SEM_FAILED) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700758 AOS_PLOG(FATAL, "sem_open(%s, O_CREAT | O_RDWR | O_EXCL) failed", name);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800759 }
760 return r;
761 }
762
763 sem_t *ping_sem_, *pong_sem_;
764};
765
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700766int Main() {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800767 ::std::unique_ptr<PingPongerInterface> ping_ponger;
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700768 if (absl::GetFlag(FLAGS_method) == "pipe") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800769 ping_ponger.reset(new PipePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700770 } else if (absl::GetFlag(FLAGS_method) == "named_pipe") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800771 ping_ponger.reset(new NamedPipePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700772 } else if (absl::GetFlag(FLAGS_method) == "aos_mutex") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800773 ping_ponger.reset(new AOSMutexPingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700774 } else if (absl::GetFlag(FLAGS_method) == "aos_event") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800775 ping_ponger.reset(new AOSEventPingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700776 } else if (absl::GetFlag(FLAGS_method) == "pthread_mutex") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400777 ping_ponger.reset(new PthreadMutexPingPonger(false, false));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700778 } else if (absl::GetFlag(FLAGS_method) == "pthread_mutex_pshared") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400779 ping_ponger.reset(new PthreadMutexPingPonger(true, false));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700780 } else if (absl::GetFlag(FLAGS_method) == "pthread_mutex_pshared_pi") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400781 ping_ponger.reset(new PthreadMutexPingPonger(true, true));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700782 } else if (absl::GetFlag(FLAGS_method) == "pthread_mutex_pi") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400783 ping_ponger.reset(new PthreadMutexPingPonger(false, true));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700784 } else if (absl::GetFlag(FLAGS_method) == "eventfd") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800785 ping_ponger.reset(new EventFDPingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700786 } else if (absl::GetFlag(FLAGS_method) == "sysv_semaphore") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800787 ping_ponger.reset(new SysvSemaphorePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700788 } else if (absl::GetFlag(FLAGS_method) == "sysv_queue") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800789 ping_ponger.reset(new SysvQueuePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700790 } else if (absl::GetFlag(FLAGS_method) == "posix_semaphore_unnamed_shared") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800791 ping_ponger.reset(new PosixUnnamedSemaphorePingPonger(1));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700792 } else if (absl::GetFlag(FLAGS_method) ==
793 "posix_semaphore_unnamed_unshared") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800794 ping_ponger.reset(new PosixUnnamedSemaphorePingPonger(0));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700795 } else if (absl::GetFlag(FLAGS_method) == "posix_semaphore_named") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800796 ping_ponger.reset(new PosixNamedSemaphorePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700797 } else if (absl::GetFlag(FLAGS_method) == "posix_queue") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800798 ping_ponger.reset(new PosixQueuePingPonger());
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700799 } else if (absl::GetFlag(FLAGS_method) == "unix_stream") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800800 ping_ponger.reset(new UnixPingPonger(SOCK_STREAM));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700801 } else if (absl::GetFlag(FLAGS_method) == "unix_datagram") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800802 ping_ponger.reset(new UnixPingPonger(SOCK_DGRAM));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700803 } else if (absl::GetFlag(FLAGS_method) == "unix_seqpacket") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800804 ping_ponger.reset(new UnixPingPonger(SOCK_SEQPACKET));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700805 } else if (absl::GetFlag(FLAGS_method) == "tcp") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400806 ping_ponger.reset(new TCPPingPonger(false));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700807 } else if (absl::GetFlag(FLAGS_method) == "tcp_nodelay") {
Brian Silvermanfd788882016-09-10 16:56:20 -0400808 ping_ponger.reset(new TCPPingPonger(true));
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700809 } else if (absl::GetFlag(FLAGS_method) == "udp") {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800810 ping_ponger.reset(new UDPPingPonger());
811 } else {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700812 fprintf(stderr, "Unknown IPC method to test '%s'\n",
813 absl::GetFlag(FLAGS_method).c_str());
Brian Silvermane4d8b282015-12-24 13:44:48 -0800814 return 1;
815 }
816
Brian Silverman1d42ce22016-09-10 16:55:40 -0400817 ::std::atomic<bool> done{false};
Brian Silvermane4d8b282015-12-24 13:44:48 -0800818
819 ::std::thread server([&ping_ponger, &done]() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700820 if (absl::GetFlag(FLAGS_server_priority) > 0) {
821 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_server_priority));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800822 }
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700823 SetCurrentThreadAffinity(
824 MakeCpusetFromCpus({absl::GetFlag(FLAGS_server_cpu)}));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800825
826 while (!done) {
827 const PingPongerInterface::Data *data = ping_ponger->Wait();
828 PingPongerInterface::Data *response = ping_ponger->PongData();
829 for (size_t i = 0; i < sizeof(*data); ++i) {
830 (*response)[i] = (*data)[i] + 1;
831 }
832 ping_ponger->Pong();
833 }
834 });
835
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700836 if (absl::GetFlag(FLAGS_client_priority) > 0) {
837 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_client_priority));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800838 }
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700839 SetCurrentThreadAffinity(
840 MakeCpusetFromCpus({absl::GetFlag(FLAGS_client_cpu)}));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800841
842 // Warm everything up.
843 for (int i = 0; i < 1000; ++i) {
844 PingPongerInterface::Data *warmup_data = ping_ponger->PingData();
845 memset(*warmup_data, i % 255, sizeof(*warmup_data));
846 ping_ponger->Ping();
847 }
848
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800849 const monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermane4d8b282015-12-24 13:44:48 -0800850
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700851 for (int32_t i = 0; i < absl::GetFlag(FLAGS_messages); ++i) {
Brian Silvermane4d8b282015-12-24 13:44:48 -0800852 PingPongerInterface::Data *to_send = ping_ponger->PingData();
853 memset(*to_send, i % 123, sizeof(*to_send));
854 const PingPongerInterface::Data *received = ping_ponger->Ping();
855 for (size_t ii = 0; ii < sizeof(*received); ++ii) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700856 AOS_CHECK_EQ(((i % 123) + 1) % 255, (*received)[ii]);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800857 }
858 }
859
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800860 const monotonic_clock::time_point end = monotonic_clock::now();
Brian Silvermane4d8b282015-12-24 13:44:48 -0800861
Brian Silverman1d42ce22016-09-10 16:55:40 -0400862 // Try to make sure the server thread gets past its check of done so our
863 // Ping() down below doesn't hang. Kind of lame, but doing better would
864 // require complicating the interface to each implementation which isn't worth
865 // it here.
866 ::std::this_thread::sleep_for(::std::chrono::milliseconds(200));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800867 done = true;
868 ping_ponger->PingData();
869 ping_ponger->Ping();
870 server.join();
871
Austin Schuhf257f3c2019-10-27 21:00:43 -0700872 AOS_LOG(INFO, "Took %f seconds to send %" PRId32 " messages\n",
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700873 ::aos::time::DurationInSeconds(end - start),
874 absl::GetFlag(FLAGS_messages));
875 const chrono::nanoseconds per_message =
876 (end - start) / absl::GetFlag(FLAGS_messages);
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800877 if (per_message >= chrono::seconds(1)) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700878 AOS_LOG(INFO, "More than 1 second per message ?!?\n");
Brian Silvermane4d8b282015-12-24 13:44:48 -0800879 } else {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700880 AOS_LOG(INFO, "That is %" PRId32 " nanoseconds per message\n",
881 static_cast<int>(per_message.count()));
Brian Silvermane4d8b282015-12-24 13:44:48 -0800882 }
883
884 return 0;
885}
886
887} // namespace aos
888
889int main(int argc, char **argv) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700890 absl::SetProgramUsageMessage(
Brian Silvermane4d8b282015-12-24 13:44:48 -0800891 ::std::string("Compares various forms of IPC. Usage:\n") + argv[0] +
892 " --method=METHOD\n"
893 "METHOD can be one of the following:\n"
894 "\tpipe\n"
895 "\tnamed_pipe\n"
896 "\taos_mutex\n"
897 "\taos_event\n"
898 "\tpthread_mutex\n"
Brian Silvermanfd788882016-09-10 16:56:20 -0400899 "\tpthread_mutex_pshared\n"
900 "\tpthread_mutex_pshared_pi\n"
901 "\tpthread_mutex_pi\n"
Brian Silvermane4d8b282015-12-24 13:44:48 -0800902 "\teventfd\n"
903 "\tsysv_semaphore\n"
904 "\tsysv_queue\n"
905 "\tposix_semaphore_unnamed_shared\n"
906 "\tposix_semaphore_unnamed_unshared\n"
907 "\tposix_semaphore_named\n"
908 "\tposix_queue\n"
909 "\tunix_stream\n"
910 "\tunix_datagram\n"
911 "\tunix_seqpacket\n"
912 "\ttcp\n"
Brian Silvermanfd788882016-09-10 16:56:20 -0400913 "\ttcp_nodelay\n"
Brian Silvermane4d8b282015-12-24 13:44:48 -0800914 "\tudp\n");
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700915 aos::InitGoogle(&argc, &argv);
Brian Silvermane4d8b282015-12-24 13:44:48 -0800916
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700917 return ::aos::Main();
Brian Silvermane4d8b282015-12-24 13:44:48 -0800918}