31#include <sys/socket.h>
38#include <linux/memfd.h>
41#include <fairmq/Channel.h>
42#include <fairmq/Message.h>
43#include <fairmq/Parts.h>
44#include <fairmq/ProgOptions.h>
45#include <fairmq/TransportFactory.h>
50static constexpr int MAX_MESSAGES = 256;
51static constexpr int N_ITERATIONS = 1000;
52static constexpr size_t ALIGNMENT = 64;
60static Scenario makeManySmallScenario()
62 std::vector<size_t>
sizes;
63 for (
int i = 0;
i < 50; ++
i) {
64 sizes.push_back(4 * 1024);
66 for (
int i = 0;
i < 30; ++
i) {
67 sizes.push_back(64 * 1024);
69 for (
int i = 0;
i < 15; ++
i) {
70 sizes.push_back(256 * 1024);
72 for (
int i = 0;
i < 5; ++
i) {
73 sizes.push_back(1024 * 1024);
75 return {
"100 messages (50x4KB + 30x64KB + 15x256KB + 5x1MB)", std::move(
sizes)};
79static Scenario makeFewLargeScenario()
81 std::vector<size_t>
sizes;
82 for (
int i = 0;
i < 5; ++
i) {
83 sizes.push_back(16 * 1024 * 1024);
85 return {
"5 messages (5x16MB)", std::move(
sizes)};
88static size_t totalPayloadSize(
const std::vector<size_t>&
sizes)
90 return std::accumulate(
sizes.begin(),
sizes.end(),
size_t{0});
93static size_t alignUp(
size_t v,
size_t align)
95 return (
v + align - 1) & ~(
align - 1);
100static void fillPattern(
void*
buf,
size_t size, uint8_t iterSeed,
int msgIndex)
104 for (
size_t i = 0;
i <
size; ++
i) {
105 p[
i] =
static_cast<uint8_t>(base + (
i & 0xFF));
109static bool verifyPattern(
const void*
buf,
size_t size, uint8_t iterSeed,
int msgIndex)
113 for (
size_t i = 0;
i <
size; ++
i) {
114 if (p[
i] !=
static_cast<uint8_t>(base + (
i & 0xFF))) {
135using Clock = std::chrono::high_resolution_clock;
137static double msElapsed(Clock::time_point
start, Clock::time_point
end)
139 return std::chrono::duration<double, std::milli>(
end -
start).count();
146static int createAnonymousShmFd(
size_t size)
149 int fd = memfd_create(
"benchmark_region", MFD_CLOEXEC);
151 perror(
"memfd_create");
157 static int shmCounter = 0;
159 snprintf(
name,
sizeof(
name),
"/bm_%d_%d", getpid(), shmCounter++);
160 int fd = shm_open(
name, O_RDWR | O_CREAT | O_EXCL, 0600);
167 if (ftruncate(fd,
static_cast<off_t
>(
size)) != 0) {
187 std::string ipcPath =
"ipc:///tmp/benchmark_fairmq_" +
std::to_string(getpid());
191 if (pipe(timePipe) != 0) {
198 if (pipe(syncPipe) != 0) {
205 if (pipe(ackPipe) != 0) {
224 if (
read(syncPipe[0], &syncByte, 1) != 1) {
229 size_t session =
static_cast<size_t>(getppid()) * 1000 + 1;
230 fair::mq::ProgOptions config;
231 config.SetProperty<std::string>(
"session",
std::to_string(session));
232 config.SetProperty<
size_t>(
"shm-segment-size",
size_t{2} << 30);
234 auto factory = fair::mq::TransportFactory::CreateTransportFactory(
"shmem",
"bench_recv", &config);
235 fair::mq::Channel channel(
"benchmark",
"pull", factory);
236 channel.Connect(ipcPath);
239 double totalReceiveMs = 0.0;
241 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
242 fair::mq::Parts parts;
243 auto t0 = Clock::now();
244 auto rc = channel.Receive(parts, 30000);
245 auto t1 = Clock::now();
248 fprintf(stderr,
"FairMQ Receive failed: %ld\n", (
long)rc);
253 for (
int i = 0; i < static_cast<int>(parts.Size()); ++
i) {
254 if (!verifyPattern(parts[
i].GetData(), parts[
i].GetSize(),
255 static_cast<uint8_t>(iter & 0xFF),
i)) {
256 fprintf(stderr,
"FairMQ: data verification failed at iter=%d msg=%d\n", iter,
i);
260 totalReceiveMs += msElapsed(
t0,
t1);
264 if (write(ackPipe[1], &ack, 1) != 1) {
273 perror(
"write timing");
284 size_t session =
static_cast<size_t>(getpid()) * 1000 + 1;
285 size_t shmSegSize =
size_t{2} << 30;
286 fair::mq::ProgOptions config;
287 config.SetProperty<std::string>(
"session",
std::to_string(session));
288 config.SetProperty<
size_t>(
"shm-segment-size", shmSegSize);
290 auto factory = fair::mq::TransportFactory::CreateTransportFactory(
"shmem",
"bench_send", &config);
291 fair::mq::Channel channel(
"benchmark",
"push", factory);
292 channel.Bind(ipcPath);
297 if (write(syncPipe[1], &syncByte, 1) != 1) {
298 perror(
"write sync");
305 double totalAllocFillMs = 0.0;
306 double totalSendMs = 0.0;
308 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
309 fair::mq::Parts parts;
311 auto t0 = Clock::now();
312 for (
int m = 0; m < static_cast<int>(
sizes.size()); ++
m) {
313 auto msg = factory->CreateMessage(
sizes[
m]);
315 parts.AddPart(std::move(
msg));
317 auto t1 = Clock::now();
319 auto rc = channel.Send(parts, 30000);
320 auto t2 = Clock::now();
323 fprintf(stderr,
"FairMQ Send failed: %ld\n", (
long)rc);
327 totalAllocFillMs += msElapsed(
t0,
t1);
328 totalSendMs += msElapsed(
t1, t2);
332 if (
read(ackPipe[0], &ack, 1) != 1) {
333 fprintf(stderr,
"FairMQ: failed to read ack at iter=%d\n", iter);
342 if (
read(timePipe[0], &childResult,
sizeof(childResult)) !=
sizeof(childResult)) {
343 perror(
"read timing");
348 waitpid(
pid, &status, 0);
349 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
350 fprintf(stderr,
"FairMQ child exited abnormally\n");
354 std::string ipcFile =
"/tmp/benchmark_fairmq_" +
std::to_string(getpid());
355 unlink(ipcFile.c_str());
358 totalAllocFillMs / N_ITERATIONS,
359 totalSendMs / N_ITERATIONS,
360 childResult.totalMs / N_ITERATIONS};
380static bool sendFdAndManifest(
int sockFd,
int shmFd,
const Manifest& manifest)
382 struct msghdr
msg = {};
383 struct iovec iov = {};
384 iov.iov_base =
const_cast<Manifest*
>(&manifest);
385 iov.iov_len =
sizeof(manifest);
391 char buf[CMSG_SPACE(
sizeof(
int))];
392 struct cmsghdr
align;
395 msg.msg_control = cmsgBuf.buf;
396 msg.msg_controllen =
sizeof(cmsgBuf.buf);
398 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&
msg);
399 cmsg->cmsg_level = SOL_SOCKET;
400 cmsg->cmsg_type = SCM_RIGHTS;
401 cmsg->cmsg_len = CMSG_LEN(
sizeof(
int));
402 memcpy(CMSG_DATA(cmsg), &shmFd,
sizeof(
int));
404 ssize_t sent = sendmsg(sockFd, &
msg, 0);
409static bool recvFdAndManifest(
int sockFd,
int& shmFd,
Manifest& manifest)
411 struct msghdr
msg = {};
412 struct iovec iov = {};
413 iov.iov_base = &manifest;
414 iov.iov_len =
sizeof(manifest);
419 char buf[CMSG_SPACE(
sizeof(
int))];
420 struct cmsghdr
align;
423 msg.msg_control = cmsgBuf.buf;
424 msg.msg_controllen =
sizeof(cmsgBuf.buf);
426 ssize_t received = recvmsg(sockFd, &
msg, 0);
427 if (received <
static_cast<ssize_t
>(
sizeof(manifest))) {
431 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&
msg);
432 if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
433 memcpy(&shmFd, CMSG_DATA(cmsg),
sizeof(
int));
453 std::string sockPath =
"/tmp/benchmark_memfd_" +
std::to_string(getpid()) +
".sock";
454 unlink(sockPath.c_str());
458 if (pipe(timePipe) != 0) {
465 if (pipe(syncPipe) != 0) {
471 size_t regionSize = 0;
472 for (
int m = 0; m < static_cast<int>(
sizes.size()); ++
m) {
473 regionSize += alignUp(
sizes[
m], ALIGNMENT);
489 if (
read(syncPipe[0], &syncByte, 1) != 1) {
494 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
500 struct sockaddr_un addr = {};
501 addr.sun_family = AF_UNIX;
502 strncpy(addr.sun_path, sockPath.c_str(),
sizeof(addr.sun_path) - 1);
504 if (connect(sock,
reinterpret_cast<struct sockaddr*
>(&addr),
sizeof(addr)) != 0) {
511 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
515 auto t0 = Clock::now();
516 if (!recvFdAndManifest(sock, shmFd, manifest)) {
517 fprintf(stderr,
"memfd: recvFdAndManifest failed at iter=%d\n", iter);
520 auto t1 = Clock::now();
522 int mmapFlags = MAP_SHARED;
524 mmapFlags |= MAP_POPULATE;
526 void* region = mmap(
nullptr, manifest.
totalSize, PROT_READ, mmapFlags, shmFd, 0);
527 if (region == MAP_FAILED) {
528 perror(
"mmap receiver");
531 auto t2 = Clock::now();
534 for (uint32_t
m = 0;
m < manifest.
count; ++
m) {
536 if (!verifyPattern(
static_cast<const uint8_t*
>(region) +
entry.offset,
537 entry.size,
static_cast<uint8_t>(iter & 0xFF),
static_cast<int>(
m))) {
538 fprintf(stderr,
"memfd: data verification failed at iter=%d msg=%u\n", iter,
m);
542 auto t3 = Clock::now();
546 auto t4 = Clock::now();
548 timing.recvMs += msElapsed(
t0,
t1);
549 timing.mmapMs += msElapsed(
t1, t2);
550 timing.verifyMs += msElapsed(t2, t3);
551 timing.unmapMs += msElapsed(t3, t4);
556 if (write(timePipe[1], &timing,
sizeof(timing)) !=
sizeof(timing)) {
557 perror(
"write timing");
567 int listenSock = socket(AF_UNIX, SOCK_STREAM, 0);
568 if (listenSock < 0) {
573 struct sockaddr_un addr = {};
574 addr.sun_family = AF_UNIX;
575 strncpy(addr.sun_path, sockPath.c_str(),
sizeof(addr.sun_path) - 1);
577 if (bind(listenSock,
reinterpret_cast<struct sockaddr*
>(&addr),
sizeof(addr)) != 0) {
581 if (listen(listenSock, 1) != 0) {
588 if (write(syncPipe[1], &syncByte, 1) != 1) {
589 perror(
"write sync");
593 int connSock = accept(listenSock,
nullptr,
nullptr);
599 double totalMemfdCreateMs = 0.0;
600 double totalSenderMmapMs = 0.0;
601 double totalFillMs = 0.0;
602 double totalSendMs = 0.0;
603 double totalSenderUnmapMs = 0.0;
605 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
606 auto t0 = Clock::now();
609 int shmFd = createAnonymousShmFd(regionSize);
613 auto t1 = Clock::now();
615 int senderMmapFlags = MAP_SHARED;
617 senderMmapFlags |= MAP_POPULATE;
619 void* region = mmap(
nullptr, regionSize, PROT_READ | PROT_WRITE, senderMmapFlags, shmFd, 0);
620 if (region == MAP_FAILED) {
621 perror(
"mmap sender");
624 auto t2 = Clock::now();
628 manifest.
count =
static_cast<uint32_t
>(
sizes.size());
629 manifest.
totalSize =
static_cast<uint32_t
>(regionSize);
631 for (
int m = 0; m < static_cast<int>(
sizes.size()); ++
m) {
635 static_cast<uint8_t>(iter & 0xFF),
m);
638 auto t3 = Clock::now();
641 munmap(region, regionSize);
642 auto t4 = Clock::now();
645 if (!sendFdAndManifest(connSock, shmFd, manifest)) {
646 fprintf(stderr,
"memfd: sendFdAndManifest failed at iter=%d\n", iter);
649 auto t5 = Clock::now();
652 auto t6 = Clock::now();
654 totalMemfdCreateMs += msElapsed(
t0,
t1);
655 totalSenderMmapMs += msElapsed(
t1, t2);
656 totalFillMs += msElapsed(t2, t3);
657 totalSenderUnmapMs += msElapsed(t3, t4) + msElapsed(t5, t6);
658 totalSendMs += msElapsed(t4, t5);
663 unlink(sockPath.c_str());
667 if (
read(timePipe[0], &childTiming,
sizeof(childTiming)) !=
sizeof(childTiming)) {
668 perror(
"read timing");
673 waitpid(
pid, &status, 0);
674 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
675 fprintf(stderr,
"memfd child exited abnormally\n");
679 totalMemfdCreateMs / N_ITERATIONS,
680 totalSenderMmapMs / N_ITERATIONS,
681 totalFillMs / N_ITERATIONS,
682 totalSendMs / N_ITERATIONS,
683 totalSenderUnmapMs / N_ITERATIONS,
684 childTiming.recvMs / N_ITERATIONS,
685 childTiming.mmapMs / N_ITERATIONS,
686 childTiming.verifyMs / N_ITERATIONS,
687 childTiming.unmapMs / N_ITERATIONS};
698static constexpr int N_SLABS = 4;
699static constexpr size_t SLAB_SIZE = 128 * 1024 * 1024;
700static constexpr size_t PAGE_SIZE = 4096;
713static bool sendSlabManifest(
int sockFd,
const SlabManifest& manifest)
715 ssize_t sent = send(sockFd, &manifest,
sizeof(manifest), 0);
716 return sent ==
sizeof(manifest);
719static bool recvSlabManifest(
int sockFd,
SlabManifest& manifest)
721 size_t remaining =
sizeof(manifest);
722 char*
buf =
reinterpret_cast<char*
>(&manifest);
723 while (remaining > 0) {
724 ssize_t
n = recv(sockFd,
buf, remaining, 0);
741 return send(sockFd, &update,
sizeof(update), 0) ==
sizeof(update);
746 return recv(sockFd, &update,
sizeof(update), MSG_WAITALL) ==
sizeof(update);
770 std::string sockPath =
"/tmp/benchmark_slab_" +
std::to_string(getpid()) +
".sock";
771 unlink(sockPath.c_str());
775 for (
size_t s :
sizes) {
776 tfSize += alignUp(s, ALIGNMENT);
780 if (pipe(timePipe) != 0) {
786 if (pipe(syncPipe) != 0) {
792 int slabFds[N_SLABS];
793 for (
int i = 0;
i < N_SLABS; ++
i) {
794 slabFds[
i] = createAnonymousShmFd(SLAB_SIZE);
795 if (slabFds[
i] < 0) {
796 fprintf(stderr,
"Failed to create slab %d\n",
i);
813 if (
read(syncPipe[0], &syncByte, 1) != 1) {
818 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
824 struct sockaddr_un addr = {};
825 addr.sun_family = AF_UNIX;
826 strncpy(addr.sun_path, sockPath.c_str(),
sizeof(addr.sun_path) - 1);
828 if (connect(sock,
reinterpret_cast<struct sockaddr*
>(&addr),
sizeof(addr)) != 0) {
834 void* slabMaps[N_SLABS];
835 for (
int i = 0;
i < N_SLABS; ++
i) {
836 slabMaps[
i] = mmap(
nullptr, SLAB_SIZE, PROT_READ, MAP_SHARED, slabFds[
i], 0);
837 if (slabMaps[
i] == MAP_FAILED) {
838 perror(
"mmap slab receiver");
846 size_t slabAdvisedUpTo[N_SLABS] = {};
848 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
851 auto t0 = Clock::now();
852 if (!recvSlabManifest(sock, manifest)) {
853 fprintf(stderr,
"slab: recvSlabManifest failed at iter=%d\n", iter);
856 auto t1 = Clock::now();
860 for (uint32_t
m = 0;
m < manifest.
count; ++
m) {
864 static_cast<int>(
m))) {
865 fprintf(stderr,
"slab: data verification failed at iter=%d msg=%u slab=%d\n",
870 auto t2 = Clock::now();
875 auto tm0 = Clock::now();
882 if (manifest.
baseOffset < slabAdvisedUpTo[si]) {
883 slabAdvisedUpTo[si] = 0;
887 size_t pageAlignedStart = (slabAdvisedUpTo[si] + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
888 size_t pageAlignedEnd = tfEnd & ~(PAGE_SIZE - 1);
889 if (pageAlignedEnd > pageAlignedStart) {
891 madvise(
static_cast<uint8_t*
>(slabMaps[si]) + pageAlignedStart,
892 pageAlignedEnd - pageAlignedStart, MADV_DONTNEED);
895 slabAdvisedUpTo[si] = tfEnd;
897 auto tm1 = Clock::now();
898 madvMs = msElapsed(tm0, tm1);
902 if (!sendOldestTF(sock, update)) {
903 perror(
"sendOldestTF");
907 timing.recvManifestMs += msElapsed(
t0,
t1);
908 timing.verifyMs += msElapsed(
t1, t2);
909 timing.madviseMs += madvMs;
913 for (
int i = 0;
i < N_SLABS; ++
i) {
914 munmap(slabMaps[
i], SLAB_SIZE);
919 if (write(timePipe[1], &timing,
sizeof(timing)) !=
sizeof(timing)) {
920 perror(
"write timing");
930 int listenSock = socket(AF_UNIX, SOCK_STREAM, 0);
931 if (listenSock < 0) {
936 struct sockaddr_un addr = {};
937 addr.sun_family = AF_UNIX;
938 strncpy(addr.sun_path, sockPath.c_str(),
sizeof(addr.sun_path) - 1);
940 if (bind(listenSock,
reinterpret_cast<struct sockaddr*
>(&addr),
sizeof(addr)) != 0) {
944 if (listen(listenSock, 1) != 0) {
950 if (write(syncPipe[1], &syncByte, 1) != 1) {
951 perror(
"write sync");
955 int connSock = accept(listenSock,
nullptr,
nullptr);
962 void* slabMaps[N_SLABS];
963 for (
int i = 0;
i < N_SLABS; ++
i) {
964 int flags = MAP_SHARED;
966 flags |= MAP_POPULATE;
968 slabMaps[
i] = mmap(
nullptr, SLAB_SIZE, PROT_READ | PROT_WRITE,
flags, slabFds[
i], 0);
969 if (slabMaps[
i] == MAP_FAILED) {
970 perror(
"mmap slab sender");
977 int32_t knownOldestTF = 0;
979 double totalFillMs = 0.0;
980 double totalSendManifestMs = 0.0;
983 size_t slabOffset = 0;
985 for (
int iter = 0; iter < N_ITERATIONS; ++iter) {
987 if (slabOffset + tfSize > SLAB_SIZE) {
989 int nextSlab = (currentSlab + 1) % N_SLABS;
993 while (senderSlabs[nextSlab].lastTFIndex >= 0 &&
994 knownOldestTF <= senderSlabs[nextSlab].lastTFIndex) {
996 if (!recvOldestTF(connSock, update)) {
997 fprintf(stderr,
"slab: recvOldestTF failed waiting for slab %d\n", nextSlab);
1003 currentSlab = nextSlab;
1007 auto t0 = Clock::now();
1010 auto* base =
static_cast<uint8_t*
>(slabMaps[currentSlab]);
1014 manifest.
count =
static_cast<uint32_t
>(
sizes.size());
1015 manifest.
baseOffset =
static_cast<uint32_t
>(slabOffset);
1016 manifest.
totalSize =
static_cast<uint32_t
>(tfSize);
1018 size_t localOffset = 0;
1019 for (
int m = 0; m < static_cast<int>(
sizes.size()); ++
m) {
1022 fillPattern(base + slabOffset + localOffset,
sizes[
m],
1023 static_cast<uint8_t>(iter & 0xFF),
m);
1024 localOffset += alignUp(
sizes[
m], ALIGNMENT);
1026 auto t1 = Clock::now();
1028 if (!sendSlabManifest(connSock, manifest)) {
1029 fprintf(stderr,
"slab: sendSlabManifest failed at iter=%d\n", iter);
1032 auto t2 = Clock::now();
1035 slabOffset += tfSize;
1037 totalFillMs += msElapsed(
t0,
t1);
1038 totalSendManifestMs += msElapsed(
t1, t2);
1042 if (!recvOldestTF(connSock, update)) {
1043 fprintf(stderr,
"slab: recvOldestTF failed at iter=%d\n", iter);
1050 for (
int i = 0;
i < N_SLABS; ++
i) {
1051 munmap(slabMaps[
i], SLAB_SIZE);
1056 unlink(sockPath.c_str());
1060 if (
read(timePipe[0], &childTiming,
sizeof(childTiming)) !=
sizeof(childTiming)) {
1061 perror(
"read timing");
1066 waitpid(
pid, &status, 0);
1067 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
1068 fprintf(stderr,
"slab child exited abnormally\n");
1072 totalFillMs / N_ITERATIONS,
1073 totalSendManifestMs / N_ITERATIONS,
1074 childTiming.recvManifestMs / N_ITERATIONS,
1075 childTiming.verifyMs / N_ITERATIONS,
1076 childTiming.madviseMs / N_ITERATIONS};
1082static void runScenario(
const Scenario& scenario)
1085 int nMessages =
static_cast<int>(
sizes.size());
1086 size_t totalBytes = totalPayloadSize(
sizes);
1087 double totalMB =
static_cast<double>(totalBytes) / (1024.0 * 1024.0);
1089 printf(
"--------------------------------------------------------------\n");
1090 printf(
"Scenario: %s\n", scenario.
name);
1091 printf(
" Total payload: %.2f MB per TF\n", totalMB);
1092 printf(
" Iterations: %d\n\n", N_ITERATIONS);
1094 printf(
"Running FairMQ shmem benchmark...\n");
1095 auto resultA = benchmarkFairMQShmem(
sizes);
1097 printf(
"Running memfd+UDS benchmark...\n");
1098 auto resultB = benchmarkMemfdUDS(
sizes);
1100 printf(
"Running slab memfd benchmark...\n");
1101 auto resultC = benchmarkSlabMemfd(
sizes);
1103 double totalA = resultA.allocFillMs + resultA.sendMs + resultA.receiveMs;
1104 double throughputA = totalMB / (totalA / 1000.0);
1106 double senderB = resultB.memfdCreateMs + resultB.senderMmapMs + resultB.fillMs + resultB.sendMs + resultB.senderUnmapMs;
1107 double receiverB = resultB.recvMs + resultB.receiverMmapMs + resultB.verifyMs + resultB.receiverUnmapMs;
1108 double totalB = senderB + receiverB;
1109 double throughputB = totalMB / (totalB / 1000.0);
1111 printf(
"\n=== FairMQ shmem (%d iterations, %d messages/TF) ===\n",
1112 N_ITERATIONS, nMessages);
1113 printf(
" Alloc+Fill: %.2f ms/TF\n", resultA.allocFillMs);
1114 printf(
" Send: %.2f ms/TF\n", resultA.sendMs);
1115 printf(
" Receive: %.2f ms/TF\n", resultA.receiveMs);
1116 printf(
" Total: %.2f ms/TF\n", totalA);
1117 printf(
" Throughput: %.2f GB/s\n", throughputA / 1024.0);
1119 printf(
"\n=== memfd + bump + UDS (%d iterations, %d messages/TF) ===\n",
1120 N_ITERATIONS, nMessages);
1121 printf(
" Sender breakdown:\n");
1122 printf(
" memfd_create: %.2f ms/TF\n", resultB.memfdCreateMs);
1123 printf(
" mmap: %.2f ms/TF\n", resultB.senderMmapMs);
1124 printf(
" fill: %.2f ms/TF\n", resultB.fillMs);
1125 printf(
" sendmsg: %.2f ms/TF\n", resultB.sendMs);
1126 printf(
" munmap+close: %.2f ms/TF\n", resultB.senderUnmapMs);
1127 printf(
" subtotal: %.2f ms/TF\n", senderB);
1128 printf(
" Receiver breakdown:\n");
1129 printf(
" recvmsg: %.2f ms/TF\n", resultB.recvMs);
1130 printf(
" mmap: %.2f ms/TF\n", resultB.receiverMmapMs);
1131 printf(
" verify: %.2f ms/TF\n", resultB.verifyMs);
1132 printf(
" munmap+close: %.2f ms/TF\n", resultB.receiverUnmapMs);
1133 printf(
" subtotal: %.2f ms/TF\n", receiverB);
1134 printf(
" Total: %.2f ms/TF\n", totalB);
1135 printf(
" Throughput: %.2f GB/s\n", throughputB / 1024.0);
1137 printf(
"\nSpeedup (memfd vs FairMQ): %.1fx\n", totalA / totalB);
1139 double senderC = resultC.fillMs + resultC.sendManifestMs;
1140 double receiverC = resultC.recvManifestMs + resultC.verifyMs + resultC.madviseMs;
1141 double totalC = senderC + receiverC;
1142 double throughputC = totalMB / (totalC / 1000.0);
1144 printf(
"\n=== slab memfd + oldest-TF madvise (%d iterations, %d messages/TF, %d slabs x %zuMB) ===\n",
1145 N_ITERATIONS, nMessages, N_SLABS, SLAB_SIZE / (1024 * 1024));
1146 printf(
" Sender breakdown:\n");
1147 printf(
" fill: %.2f ms/TF\n", resultC.fillMs);
1148 printf(
" send manifest:%.2f ms/TF\n", resultC.sendManifestMs);
1149 printf(
" subtotal: %.2f ms/TF\n", senderC);
1150 printf(
" Receiver breakdown:\n");
1151 printf(
" recv manifest:%.2f ms/TF\n", resultC.recvManifestMs);
1152 printf(
" verify: %.2f ms/TF\n", resultC.verifyMs);
1153 printf(
" madvise: %.2f ms/TF\n", resultC.madviseMs);
1154 printf(
" subtotal: %.2f ms/TF\n", receiverC);
1155 printf(
" Total: %.2f ms/TF\n", totalC);
1156 printf(
" Throughput: %.2f GB/s\n", throughputC / 1024.0);
1158 printf(
"\nSpeedup (slab vs FairMQ): %.1fx\n\n", totalA / totalC);
1166 printf(
"Benchmark: FairMQ shmem vs memfd+UDS\n\n");
1168 auto scenario1 = makeManySmallScenario();
1169 auto scenario2 = makeFewLargeScenario();
1171 runScenario(scenario1);
1172 runScenario(scenario2);
std::chrono::high_resolution_clock Clock
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
GLuint const GLchar * name
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
GLenum GLuint GLenum GLsizei const GLchar * buf
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
uint8_t itsSharedClusterMap uint8_t
DeliveryType read(const std::string &str)
Polygon< T > close(Polygon< T > polygon)
void align(gsl::span< ElinkEncoder< BareFormat, CHARGESUM > > elinks)
std::string to_string(gsl::span< T, Size > span)
ManifestEntry entries[MAX_MESSAGES]
std::vector< size_t > sizes
ManifestEntry entries[MAX_MESSAGES]
uint64_t const void const *restrict const msg