ibireme / yyjson

The fastest JSON library in C
https://ibireme.github.io/yyjson/doc/doxygen/html/
MIT License
2.98k stars 262 forks source link

WASM performance vs native #127

Closed Kiddinglife closed 1 year ago

Kiddinglife commented 1 year ago

Does it still keep the super high performance considering that there are lots of tricks used in yyjson ? Thx.

ibireme commented 1 year ago

It's an interesting question. I wrote a simple test program to measure the throughput of JSON parsing, and compiled it to both wasm and native:

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef __EMSCRIPTEN__
#include "emscripten.h"
#endif
#include "yyjson.h"

double get_time(void) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec / 1000000.0;
}

#ifdef __EMSCRIPTEN__
EMSCRIPTEN_KEEPALIVE
#endif
int run() {
    const char *path = "twitter.json";
    const int iter = 30;
    const int repeat_per_iter = 100;

#define err(msg) { if (fd) fclose(fd); if (dat) free(dat); printf(msg); return 1; }
    char *dat = NULL;
    FILE *fd = fopen(path, "rb");
    if (!fd) err("failed to open file");
    fseek(fd, 0, SEEK_END);
    size_t len = ftell(fd);
    fseek(fd, 0, SEEK_SET);
    if (len == 0) err("empty file");
    dat = malloc(len);
    if (!dat) err("failed to alloc memory");
    if (fread(dat, 1, len, fd) != len) err("failed to read file");
    fclose(fd);
    fd = NULL;

    for(int i = 0; i < iter; i++) {
        double t1 = get_time();
        for(int j = 0; j < repeat_per_iter; j++) {
            yyjson_doc *doc = yyjson_read(dat, len, 0);
            if (!doc) err("failed to parse json");
            yyjson_doc_free(doc);
        }
        double t2 = get_time();
        double speed = len * repeat_per_iter / (t2 - t1) / 1024.0 / 1024 / 1024;
        printf("iter %d: %f ms (%.2fGB/s)\n", i, (t2 - t1) * 1000, speed);
    }

    free(dat);
    return 0;
}

#ifndef __EMSCRIPTEN__
int main() { return run(); }
#endif
emcc -O3 -s WASM=1 -s EXPORTED_RUNTIME_METHODS='["cwrap"]' yyjson.c test.c --embed-file twitter.json
clang -O3 yyjson.c test.c -o test

Chrome: 1.40 GB/s, Native: 3.53 GB/s (M1 Mac) Chrome: 0.62 GB/s, Native: 1.57 GB/s (Old Mac, 7th gen Intel Core)

I found a more extensive performance test report: https://00f.net/2023/01/04/webassembly-benchmark-2023/ which mentions that

When using the fastest runtime, WebAssembly was only about 2.32 times slower (median) than native code with architecture-specific optimizations

It seems that the performance of yyjson on wasm is not much different from other libraries.