#define _POSIX_C_SOURCE 200809L #include "runtime.h" #include #include #include #include #include extern long long dever_test_allocations(void); static void text_clone(const void *source, void *target) { *(void **)target = dever_rt_v1_text_retain(*(void *const *)source); } static void text_drop(void *value) { dever_rt_v1_text_release(*(void **)value); *(void **)value = NULL; } static uint8_t text_equal(const void *left, const void *right) { return dever_rt_v1_text_equal(*(void *const *)left, *(void *const *)right); } static const DeverRtType text_type = { sizeof(void *), _Alignof(void *), text_clone, text_drop, text_equal, NULL }; static uint32_t input_field(void *inputs, void *out, DeverRtBuffer *error) { const DeverRtWireName name = {(const uint8_t *)"source", 6}; uint8_t present = 0; return dever_rt_v1_cmd_input_field(inputs, &name, 1, out, &present, error); } static uint32_t decode(const void *reader, void *out, DeverRtBuffer *error) { return dever_rt_v1_wire_read_raw(reader, out, error); } static uint32_t encode(const void *value, void *encoder, DeverRtBuffer *error) { return dever_rt_v1_wire_encoder_json(encoder, *(void *const *)value, error); } static uint32_t operation(unsigned phase, void *body, void *source, void **out, DeverRtBuffer *error) { if (phase == 0) return dever_rt_v1_cmd_decode(body, &text_type, input_field, out, error); if (phase == 1) return dever_rt_v1_wire_decode(source, &text_type, decode, out, error); if (phase == 2) return dever_rt_v1_wire_encode(&source, &text_type, encode, out, error); return dever_rt_v1_json_from_text(source, out, error); } int dever_test_run(void) { const char *setting = getenv("DEVER_WIRE_BENCH_ROWS"); size_t rows = setting == NULL ? 128 : (size_t)strtoul(setting, NULL, 10); int wide = getenv("DEVER_WIRE_BENCH_WIDE") != NULL; if (rows != 1 && rows != 16 && rows != 128 && !(wide && rows == 1024)) return 1; const char *row = "{\"id\":9007199254740993,\"text\":\"雪😀\\n\\\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\",\"weight\":1.25,\"note\":null}"; const char *suffix = "],\"raw\":{\"large\":123456789012345678901234567890}}"; size_t capacity = rows * (strlen(row) + 1) + strlen(suffix) + 64; char *raw = malloc(capacity); if (raw == NULL) return 2; strcpy(raw, wide ? "{" : "{\"rows\":["); for (size_t index = 0; index < rows; ++index) { if (index != 0) strcat(raw, ","); if (wide) { char field[64]; snprintf(field, sizeof(field), "\"field_%zu\":%zu", index, index); strcat(raw, field); } else { strcat(raw, row); } } strcat(raw, wide ? "}" : suffix); size_t length = strlen(raw); DeverRtBuffer error = {0}; void *source = NULL, *body = NULL; if (dever_rt_v1_text_new((const uint8_t *)raw, length, &source, &error)) return 3; if (getenv("DEVER_WIRE_BENCH_VALIDATED") != NULL) { void *validated = NULL; if (dever_rt_v1_wire_decode(source, &text_type, decode, &validated, &error)) return 11; dever_rt_v1_text_release(source); source = validated; } char *request = malloc(length + 12); if (request == NULL) return 4; snprintf(request, length + 12, "{\"source\":%s}", raw); if (dever_rt_v1_text_new((const uint8_t *)request, strlen(request), &body, &error)) return 5; free(request); for (unsigned phase = 0; phase < 4; ++phase) { void *output = NULL; if (operation(phase, body, source, &output, &error)) return 6; DeverRtBuffer bytes = {0}; if (dever_rt_v1_text_export(output, &bytes) || bytes.len != length || memcmp(bytes.ptr, raw, length) != 0) return 7; dever_rt_v1_buffer_free(bytes.ptr, bytes.len); dever_rt_v1_text_release(output); struct timespec started, finished; if (clock_gettime(CLOCK_MONOTONIC, &started)) return 8; long long allocations = dever_test_allocations(); const size_t iterations = 500; for (size_t iteration = 0; iteration < iterations; ++iteration) { if (operation(phase, body, source, &output, &error)) return 9; dever_rt_v1_text_release(output); } allocations = dever_test_allocations() - allocations; if (clock_gettime(CLOCK_MONOTONIC, &finished)) return 10; int64_t elapsed = (int64_t)(finished.tv_sec - started.tv_sec) * INT64_C(1000000000) + finished.tv_nsec - started.tv_nsec; printf("{\"phase\":%u,\"rows\":%zu,\"iterations\":%zu,\"elapsed_ns\":%lld,\"allocations\":%lld}\n", phase, rows, iterations, (long long)elapsed, allocations); } dever_rt_v1_text_release(source); dever_rt_v1_text_release(body); free(raw); return 0; }