Skip to content

Instantly share code, notes, and snippets.

@MichaelSnowden
Created July 29, 2020 04:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MichaelSnowden/1a6d3e79feb6a0e8901ff04cb617bf92 to your computer and use it in GitHub Desktop.
Save MichaelSnowden/1a6d3e79feb6a0e8901ff04cb617bf92 to your computer and use it in GitHub Desktop.
Comparison of jsonArray printing methods. I have no idea why, but for some reason the generic approach is virtually the same speed as the specific approach. Almost as if the function call overhead is negligible.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int Foo;
// repetitive approach
int foosToJsonArray(FILE *file, Foo *foos, int n) {
if (fputc('[', file) == EOF) {
return -1;
}
for (int i = 0; i < n; ++i) {
if (i > 0) {
if (fputs(", ", file) == EOF) {
return -1;
}
}
if (fprintf(file, "foo: %d", foos[i]) < 0) {
return -1;
}
}
if (fputc(']', file) == EOF) {
return -1;
}
return 0;
}
// generic approach
int jsonArray(FILE *file, void *context, int(*hasNext)(void *context), int(*next)(FILE *file, void *context)) {
if (fputc('[', file) == EOF) {
return -1;
}
int first = 1;
while (hasNext(context)) {
if (first) {
first = 0;
} else {
if (fputs(", ", file) == EOF) {
return -1;
}
}
if (next(file, context)) {
return -1;
}
}
if (fputc(']', file) == EOF) {
return -1;
}
return 0;
}
typedef struct {
int i;
int n;
Foo *foos;
} FooPrinter;
int FooPrinter_hasNext(void *context) {
FooPrinter *printer = context;
return printer->i < printer->n;
}
int FooPrinter_next(FILE *file, void *context) {
FooPrinter *printer = context;
if (printer->i >= printer->n) {
fprintf(stderr, "index out of bounds: %d/%d\n", printer->i, printer->n);
exit(EXIT_FAILURE);
}
if (fprintf(file, "foo: %d", printer->foos[printer->i]) < 0) {
return -1;
}
++printer->i;
return 0;
}
void startProfile(struct timespec *start) {
clock_gettime(CLOCK_MONOTONIC, start);
}
void endProfile(struct timespec *start, double *timeMs) {
struct timespec end;
clock_gettime(CLOCK_MONOTONIC, &end);
*timeMs += (double) (end.tv_sec - start->tv_sec) * 1e3 + (double) (end.tv_nsec - start->tv_nsec) * 1e-6;
}
void printResults(const char *name, double totalTime, int numTrials) {
printf("\033[1;32m%10s\033[0m strategy took \033[1;30m%6.2fms\033[0m on average\n", name, totalTime / (double) numTrials);
}
int main(int argc, char **argv) {
int n = 1024 * 1024;
Foo *foos = malloc(sizeof(Foo) * n);
FooPrinter context = {0, n, foos};
FILE *file = fopen("/dev/null", "w");
struct timespec start;
double totalTimeSpecific = 0.0;
double totalTimeGeneric = 0.0;
int numTrials = 10;
for (int i = 0; i < numTrials; ++i) {
startProfile(&start);
foosToJsonArray(file, foos, n);
endProfile(&start, &totalTimeSpecific);
context = (FooPrinter) {0, n, foos};
startProfile(&start);
jsonArray(file, &context, FooPrinter_hasNext, FooPrinter_next);
endProfile(&start, &totalTimeGeneric);
}
printResults("specific", totalTimeSpecific, numTrials);
printResults("generic", totalTimeGeneric, numTrials);
}
gcc -Ofast json.c && cmod +x a.out && ./a.out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment