135 lines
5.2 KiB
C++
135 lines
5.2 KiB
C++
#include <atomic>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#include <weaver.h>
|
|
|
|
constexpr std::size_t kConsumers = 2;
|
|
constexpr std::size_t kBufferSize = 256;
|
|
|
|
using std::chrono::nanoseconds;
|
|
using std::chrono::steady_clock;
|
|
|
|
int main() {
|
|
int n = 0;
|
|
if (!(std::cin >> n) || n <= 0) {
|
|
std::cerr << "n must be positive\n";
|
|
return 1;
|
|
}
|
|
|
|
using Fabric =
|
|
THWeaver::FanOutFabric<uint64_t, 8, kBufferSize, 8, kConsumers>;
|
|
Fabric fabric;
|
|
fabric.init();
|
|
|
|
std::atomic<bool> failed(false);
|
|
std::atomic<int> consumed0(0);
|
|
std::atomic<int> consumed1(0);
|
|
std::vector<int64_t> send_time(n, -1);
|
|
std::vector<int64_t> recv_time0(n, -1);
|
|
std::vector<int64_t> recv_time1(n, -1);
|
|
|
|
std::thread consumer0([&]() {
|
|
auto token = fabric.get_empty_borrowed_ref<0>();
|
|
int expected = 1;
|
|
while (expected <= n && !failed.load()) {
|
|
if (fabric.recv<0>(token) !=
|
|
THWeaver::FanOutFabricRecvResult::Ok) {
|
|
continue;
|
|
}
|
|
if (token.get() != static_cast<uint64_t>(expected)) {
|
|
std::cerr << "fan-out mismatch on consumer 0: "
|
|
<< "expected " << expected << " got "
|
|
<< token.get() << "\n";
|
|
failed.store(true);
|
|
break;
|
|
}
|
|
auto recv_time = steady_clock::now().time_since_epoch();
|
|
auto recv_ns =
|
|
std::chrono::duration_cast<nanoseconds>(
|
|
recv_time)
|
|
.count();
|
|
recv_time0[expected - 1] = recv_ns;
|
|
token.release();
|
|
consumed0.store(expected);
|
|
++expected;
|
|
}
|
|
});
|
|
|
|
std::thread consumer1([&]() {
|
|
auto token = fabric.get_empty_borrowed_ref<1>();
|
|
int expected = 1;
|
|
while (expected <= n && !failed.load()) {
|
|
if (fabric.recv<1>(token) !=
|
|
THWeaver::FanOutFabricRecvResult::Ok) {
|
|
continue;
|
|
}
|
|
if (token.get() != static_cast<uint64_t>(expected)) {
|
|
std::cerr << "fan-out mismatch on consumer 1: "
|
|
<< "expected " << expected << " got "
|
|
<< token.get() << "\n";
|
|
failed.store(true);
|
|
break;
|
|
}
|
|
auto recv_time = steady_clock::now().time_since_epoch();
|
|
auto recv_ns =
|
|
std::chrono::duration_cast<nanoseconds>(
|
|
recv_time)
|
|
.count();
|
|
recv_time1[expected - 1] = recv_ns;
|
|
token.release();
|
|
consumed1.store(expected);
|
|
++expected;
|
|
}
|
|
});
|
|
|
|
constexpr uint64_t policy = (1ULL << 0) | (1ULL << 1);
|
|
|
|
for (int i = 1; i <= n && !failed.load(); ++i) {
|
|
while (!failed.load()) {
|
|
auto now = steady_clock::now().time_since_epoch();
|
|
auto ns = std::chrono::duration_cast<nanoseconds>(now)
|
|
.count();
|
|
auto res = fabric.send(static_cast<uint64_t>(i), policy,
|
|
kBufferSize);
|
|
if (res.result ==
|
|
THWeaver::FanOutFabricSendResult<uint64_t>::Ok) {
|
|
send_time[i - 1] = ns;
|
|
break;
|
|
}
|
|
if (res.result ==
|
|
THWeaver::FanOutFabricSendResult<
|
|
uint64_t>::ErrPartialSuccess) {
|
|
std::cerr << "fan-out partial success for "
|
|
<< "message " << i << "\n";
|
|
failed.store(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (!failed.load() &&
|
|
(consumed0.load() < i || consumed1.load() < i)) {
|
|
}
|
|
}
|
|
|
|
consumer0.join();
|
|
consumer1.join();
|
|
|
|
if (failed.load()) {
|
|
return 1;
|
|
}
|
|
|
|
for (int i = 1; i <= n; ++i) {
|
|
int64_t send_ns = send_time[i - 1];
|
|
int64_t recv_ns0 = recv_time0[i - 1];
|
|
int64_t recv_ns1 = recv_time1[i - 1];
|
|
|
|
std::cout << i << "," << (recv_ns0 - send_ns) << "\n";
|
|
std::cout << i << "," << (recv_ns1 - send_ns) << "\n";
|
|
}
|
|
return 0;
|
|
}
|