Skip to content

Instantly share code, notes, and snippets.

@mathis-m
Created January 20, 2022 08:40
Show Gist options
  • Save mathis-m/fa7cb0e6e22191e23c11902a19f6db1c to your computer and use it in GitHub Desktop.
Save mathis-m/fa7cb0e6e22191e23c11902a19f6db1c to your computer and use it in GitHub Desktop.
#define _CRT_SECURE_NO_WARNINGS
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdbool.h>
#include <fcntl.h>
#include <time.h>
//https://linux.die.net/man/7/pipe#:~:text=Since%20Linux%202.6.11%2C%20the%20pipe%20capacity%20is%2065536%20bytes
double getDifferenceTimeOfDay(struct timeval *begin, struct timeval *end) {
return ((end->tv_sec - begin->tv_sec) + ((end->tv_usec - begin->tv_usec) / (1000.0 * 1000.0)));
}
int main(int argc, char *argv[]) {
// get arguments passed
bool logToConsole = atoi(argv[1]);
int count = atoi(argv[2]);
bool aufgabe2 = atoi(argv[3]);
FILE *fWrite = NULL;
FILE *fRead = NULL;
FILE *fTotalTime = NULL;
if (logToConsole == false) {
// setup file headers (mode w => file wird überschrieben)
fWrite = fopen("write.csv", "w");
if (fWrite == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fWrite, "Size,Throughput,Precise Throughput\n");
fclose(fWrite);
fRead = fopen("read.csv", "w");
if (fRead == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fRead, "Size,Throughput,Precise Throughput\n");
fclose(fRead);
fTotalTime = fopen("total-time.csv", "w");
if (fTotalTime == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fTotalTime, "Size,Total Time, Precise Total Time\n");
fclose(fTotalTime);
}
// for 16, 64, 256, ... 16MiB
for (int size = 16; size <= 16 * 1024 * 1024; size *= 4) {
printf("\n\n=== Buffer Size %d ===\n", size);
int pipefd[2] = {0};
int pipefdBack[2] = {0};
char *buf;
char *buf2;
buf = malloc(size);
buf2 = malloc(size);
double mbPerS, totalTimeTaken, preciseThroughput, preciseTotalTimeTaken;
if (buf == NULL) {
perror("malloc");
return 1;
}
// Create Parent2Child Pipe
if (pipe(pipefd) == -1) {
perror("pipe");
return 1;
}
fcntl(pipefd[1], F_SETPIPE_SZ, size);
// printf("Pipe Size is %d\n", pipeSize);
// Create Child2Parent Pipe
if (pipe(pipefdBack) == -1) {
perror("pipe");
return 1;
}
fcntl(pipefdBack[1], F_SETPIPE_SZ, size);
// printf("Pipe Size is %d\n", pipeSize);
// Split process to Parent and Child Process
if (fork() == 0) {
struct timeval readStart, readEnd;
struct timespec readStartPrecise, readEndPrecise;
bool started = false;
// child Process
for (int i = 0; i < count; i++) {
int totalCount = 0;
while (totalCount < size) {
int readByteCount = read(pipefd[0], buf + totalCount, size - totalCount);
totalCount += readByteCount;
if (readByteCount == -1) {
perror("read");
return 1;
}
}
if (aufgabe2 == true) {
size_t bytesWritten = write(pipefdBack[1], buf2, size);
if (bytesWritten != size) {
fprintf(stderr, "write2 size did not match: %zu bytes were written.\n", bytesWritten);
return 1;
}
}
if (started == false) {
gettimeofday(&readStart, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &readStartPrecise);
started = true;
}
if (totalCount != size) {
printf("[%d] size error, expected: %d bytes but got %d\n", i, size, totalCount);
return 1;
}
}
gettimeofday(&readEnd, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &readEndPrecise);
long diffInNanos = (readEndPrecise.tv_sec - readStartPrecise.tv_sec) * (long) 1e9 +
(readEndPrecise.tv_nsec - readStartPrecise.tv_nsec);
double diffInS = (diffInNanos / 1e9);
double measuredBytes = (count - 1) * (double) size;
double preciseThroughput = measuredBytes / ((double) diffInS * 1024 * 1024);
// check how long it has taken to send data to child process
double timeTaken = getDifferenceTimeOfDay(&readStart, &readEnd);
// calc total bytes send per time in MiB/s
double readThroughtput = ((double) (count - 1) * size) / ((double) timeTaken * 1024 * 1024);
sleep(1);
printf("\tRead:\n\t\tThroughput: %f MiB/s\n\t\tPrecise Throughput: %f MiB/s\n",
readThroughtput, preciseThroughput);
if (logToConsole == false) {
fRead = fopen("read.csv", "a");
if (fRead == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fRead, "%d,%f,%f\n", size, readThroughtput, preciseThroughput);
fclose(fRead);
}
return 0;
} else {
// parent process
struct timeval begin, end, totalBegin, endTotal;
struct timespec beginPrecise, endPrecise, beginTotalPrecise, endTotalPrecise;
// check how long it has taken to send data to child process
double timeTaken = 0;
double timeTakenPrecise = 0;
// set begin times
gettimeofday(&totalBegin, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &beginTotalPrecise);
// send data to child process
for (int i = 0; i < count; i++) {
gettimeofday(&begin, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &beginPrecise);
// actual call to send data via pipe
size_t bytesWritten = write(pipefd[1], buf, size);
gettimeofday(&end, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endPrecise);
timeTaken += getDifferenceTimeOfDay(&begin, &end);
long diffInNanos = (endPrecise.tv_sec - beginPrecise.tv_sec) * (long) 1e9 +
(endPrecise.tv_nsec - beginPrecise.tv_nsec);
timeTakenPrecise += diffInNanos / 1e9;
// for benchmark it makes sense to check if the size of bytes written to the pipe is the expected size
if (bytesWritten != size) {
fprintf(stderr, "write size did not match: %zu bytes were written.\n", bytesWritten);
return 1;
}
if (aufgabe2 == true) {
// read from pipe 2
int totalCount = 0;
while (totalCount < size) {
int readByteCount = read(pipefdBack[0], buf2 + totalCount, size - totalCount);
totalCount += readByteCount;
if (readByteCount == -1) {
perror("read");
return 1;
}
}
if (totalCount != size) {
printf("[%d] size error, expected: %d bytes but got %d\n", i, size, totalCount);
return 1;
}
}
}
gettimeofday(&endTotal, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endTotalPrecise);
// get total avg time it has taken: parent -> child -> parent
totalTimeTaken = getDifferenceTimeOfDay(&totalBegin, &endTotal) / count;
long diffInNanos = (endTotalPrecise.tv_sec - beginTotalPrecise.tv_sec) * (long) 1e9 +
(endTotalPrecise.tv_nsec - beginTotalPrecise.tv_nsec);
preciseTotalTimeTaken = ((double)diffInNanos / 1e9) / count;
// calc total bytes send per time in MiB/s
double measuredBytes = count * (double) size;
mbPerS = measuredBytes / ((double) timeTaken * 1024 * 1024);
preciseThroughput = measuredBytes / ((double) timeTakenPrecise * 1024 * 1024);
}
// log for current size, durchsatz und total time taken
if (aufgabe2 == true) {
printf("\tRound Trip:\n\t\tTime: %fs\n\t\tPrecise Time: %fs\n",
totalTimeTaken, preciseTotalTimeTaken);
}
printf("\tWrite:\n\t\tThroughput: %f MiB/s\n\t\tPrecise Throughput: %f MiB/s\n",
mbPerS, preciseThroughput);
if (logToConsole == false) {
// open file in append mode
fWrite = fopen("write.csv", "a");
if (fWrite == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fWrite, "%d,%f,%f\n", size, mbPerS, preciseThroughput);
fclose(fWrite);
fTotalTime = fopen("total-time.csv", "a");
if (fTotalTime == NULL) {
printf("Error opening file!\n");
exit(1);
}
fprintf(fTotalTime, "%d,%f,%f\n", size, totalTimeTaken, preciseTotalTimeTaken);
fclose(fTotalTime);
}
sleep(2);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment