diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 14:42:21 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 14:42:21 +0300 |
| commit | 93ea4e79528ba9f42d57f9004260dcba309492ba (patch) | |
| tree | 9db04347f5e85195e27550e2ec6a803884112d28 /tests/benchmark.c | |
| parent | dfebac1019560e278c605247de3b98cff1d73226 (diff) | |
benchmarks: add yasl-benchmark meson target and document in README
Diffstat (limited to 'tests/benchmark.c')
| -rw-r--r-- | tests/benchmark.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/tests/benchmark.c b/tests/benchmark.c new file mode 100644 index 0000000..a685e8b --- /dev/null +++ b/tests/benchmark.c @@ -0,0 +1,165 @@ +#define _POSIX_C_SOURCE 200809L +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <time.h> +#include <limits.h> + +#include "yasl/yasl.h" +#include "yasl/loop.h" +#include "common/loop.h" +#include "common/input.h" +#if YASL_HAS_WAYLAND +#include "wayland/internal.h" +#endif + +static inline uint64_t get_time_ns(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec; +} + +#if YASL_HAS_WAYLAND +/* Benchmark 1: Surface Lookup in conn_surface_for */ +static void bench_surface_lookup(void) { + const int num_surfaces = 16; + const int lookups = 10000000; + struct wayland_display c = {0}; + struct wayland_surface surfaces[num_surfaces]; + void *dummy_proxies[num_surfaces][16]; + + for (int i = 0; i < num_surfaces; i++) { + memset(&surfaces[i], 0, sizeof(surfaces[i])); + memset(dummy_proxies[i], 0, sizeof(dummy_proxies[i])); + surfaces[i].conn = &c; + surfaces[i].surface = (struct wl_surface *)dummy_proxies[i]; + wl_proxy_set_user_data((struct wl_proxy *)dummy_proxies[i], &surfaces[i]); + surfaces[i].conn_next = c.surfaces; + c.surfaces = &surfaces[i]; + } + + struct wl_surface *target = (struct wl_surface *)dummy_proxies[0]; + + uint64_t t0 = get_time_ns(); + uintptr_t sum = 0; + for (int i = 0; i < lookups; i++) { + struct wayland_surface *found = conn_surface_for(&c, target); + sum += (uintptr_t)found; + } + uint64_t t1 = get_time_ns(); + printf("[1] conn_surface_for : %7.2f ms (%d lookups over %d surfaces, checksum=%lx)\n", + (double)(t1 - t0) / 1e6, lookups, num_surfaces, (unsigned long)sum); +} + +/* Benchmark 2: Wayland Output & Refresh Tracking */ +static void bench_output_follow(void) { + const int iters = 10000000; + struct wayland_display c = {0}; + struct wl_conn_output outs[4]; + for (int i = 0; i < 4; i++) { + memset(&outs[i], 0, sizeof(outs[i])); + outs[i].mask = 1ull << i; + outs[i].scale = i + 1; + outs[i].refresh_ns = 16666666 / (i + 1); + outs[i].next = (i < 3) ? &outs[i + 1] : NULL; + } + c.outputs = &outs[0]; + struct wayland_surface w = {0}; + w.conn = &c; + w.outputs = 0x3; + w.pending_scale_120 = 2 * YASL_SCALE_UNIT; + w.frac_scale = (struct wp_fractional_scale_v1 *)1; + + uint64_t t0 = get_time_ns(); + for (int i = 0; i < iters; i++) { + surface_follow_outputs(&w); + } + uint64_t t1 = get_time_ns(); + printf("[2] surface_follow_outputs : %7.2f ms (%d iterations over outputs list)\n", + (double)(t1 - t0) / 1e6, iters); +} +#endif + +/* Benchmark 3: Input Queue Resizing Throughput */ +static void bench_input_queue_resize(void) { + const int batches = 50000; + const int size = 2048; + + uint64_t t0 = get_time_ns(); + for (int b = 0; b < batches; b++) { + struct input_queue q = {0}; + for (int i = 0; i < size; i++) { + struct yasl_input_event ev = { + .kind = YASL_INPUT_MOUSE, + .mouse = { .pos = { .x = i, .y = b } }, + }; + input_queue_push(&q, &ev); + } + input_queue_clear(&q); + } + uint64_t t1 = get_time_ns(); + printf("[3] input_queue_resize : %7.2f ms (%d batches x %d events = 102.4M events)\n", + (double)(t1 - t0) / 1e6, batches, size); +} + +/* Benchmark 4: Input Queue Push & Pop Throughput */ +static void bench_input_queue_push_pop(void) { + const int rounds = 20000; + const int events_per_round = 500; + struct input_queue q = {0}; + + uint64_t t0 = get_time_ns(); + for (int r = 0; r < rounds; r++) { + for (int i = 0; i < events_per_round; i++) { + struct yasl_input_event ev = { + .kind = YASL_INPUT_MOUSE, + .mouse = { .pos = { .x = i, .y = r }, .button = 1 }, + }; + input_queue_push(&q, &ev); + } + struct yasl_input_event out; + while (input_queue_pop(&q, &out)) { + /* consume */ + } + } + uint64_t t1 = get_time_ns(); + input_queue_clear(&q); + printf("[4] input_queue_push_pop : %7.2f ms (%d batches x %d events = 10M events)\n", + (double)(t1 - t0) / 1e6, rounds, events_per_round); +} + +/* Benchmark 5: Event Loop Timers Add & Delete */ +static uint64_t timer_dummy_cb(void *ud, yasl_timer_id id, uint64_t interval_ns) { + (void)ud; (void)id; (void)interval_ns; + return 0; +} + +static void bench_timers(void) { + const int iters = 2000000; + struct yasl_loop *loop = yasl_loop_create(); + + uint64_t t0 = get_time_ns(); + for (int i = 0; i < iters; i++) { + yasl_timer_id id = yasl_loop_add_timer(loop, 1000000, timer_dummy_cb, NULL); + yasl_loop_del_timer(loop, id); + } + uint64_t t1 = get_time_ns(); + yasl_loop_destroy(loop); + printf("[5] timers_add_del : %7.2f ms (%d arm/disarm cycles)\n", + (double)(t1 - t0) / 1e6, iters); +} + +int main(void) { + printf("==================== YASL Performance Benchmark ====================\n"); +#if YASL_HAS_WAYLAND + bench_surface_lookup(); + bench_output_follow(); +#endif + bench_input_queue_resize(); + bench_input_queue_push_pop(); + bench_timers(); + printf("====================================================================\n"); + return 0; +} |
