Repository: valkey-io/valkey
File: src/valkey-benchmark.c (C)

Code before:
    while (config.liveclients < config.numclients) {
        int thread_id = -1;
        if (config.num_threads) thread_id = config.liveclients % config.num_threads;
        createClient(NULL, 0, 0, c, thread_id);

        /* Listen backlog is quite limited on most systems */
        if (++n > 64) {
            usleep(50000);
            n = 0;
        }
    }
}

static void showRPSReport(void) {
    if (config.rps_histogram && config.rps_histogram->total_count > 0) {
        float avg_rps = (float)config.requests_finished / ((float)config.totlatency / 1000.0f);

        float p50 = (float)hdr_value_at_percentile(config.rps_histogram, 50.0);
        float p95 = (float)hdr_value_at_percentile(config.rps_histogram, 95.0);
        float p99 = (float)hdr_value_at_percentile(config.rps_histogram, 99.0);

        // Bottleneck detection using target RPS
        float target_rps = (float)config.rps;
        const char *rps_status = NULL;

        if (p99 < 0.9 * target_rps) {
            rps_status = "SEVERE BOTTLENECK DETECTED";
        } else if (p99 < target_rps) {
            rps_status = "BOTTLENECK DETECTED";
        }

        if (rps_status) {
            printf("\nRPS Percentiles:\n");
            printf("  P50: %.0f\n", p50);
            printf("  P95: %.0f\n", p95);
            printf("  P99: %.0f\n", p99);
            printf("  Average: %.0f\n", avg_rps);
            printf("Status: %s\n", rps_status);
        }
    }
}

static void showLatencyReport(void) {
    const float reqpersec = (float)config.requests_finished / ((float)config.totlatency / 1000.0f);
    const float p0 = ((float)hdr_min(config.latency_histogram)) / 1000.0f;
    const float p50 = hdr_value_at_percentile(config.latency_histogram, 50.0) / 1000.0f;
    const float p95 = hdr_value_at_percentile(config.latency_histogram, 95.0) / 1000.0f;
    const float p99 = hdr_value_at_percentile(config.latency_histogram, 99.0) / 1000.0f;
    const float p100 = ((float)hdr_max(config.latency_histogram)) / 1000.0f;
    const float avg = hdr_mean(config.latency_histogram) / 1000.0f;


Review comment (performance):
This logic is a little confusing one, but I think it means that if 99% of the requests are less than 90% of the throughput, then we are severely bottlenecked. If 99% of the requests are less than RPS, then it is just bottlenecked.

I would suggest to make it P90 instead of P99 for both cases (as it is too lenient). If 90% of the requests are not able to reach 90% of the set RPS, it is a bottleneck. I also feel these thresholds 90% of the throughput, and 100% of the throughput, to detect bottleneck, could be a configuration that a user can set. Not everyone may agree with our thresholds.

@zuiderkwast what do you think?

Code after:
    while (config.liveclients < config.numclients) {
        int thread_id = -1;
        if (config.num_threads) thread_id = config.liveclients % config.num_threads;
        createClient(NULL, 0, 0, c, thread_id);

        /* Listen backlog is quite limited on most systems */
        if (++n > 64) {
            usleep(50000);
            n = 0;
        }
    }
}

static void showRPSReport(void) {
    if (config.rps_histogram && config.rps_histogram->total_count > 0) {
        const float target_rps = (float)config.rps;

        const float avg_rps = hdr_mean(config.rps_histogram);
        const float p0 = (float)hdr_min(config.rps_histogram);
        const float p50 = (float)hdr_value_at_percentile(config.rps_histogram, 50.0);
        const float p95 = (float)hdr_value_at_percentile(config.rps_histogram, 95.0);
        const float p99 = (float)hdr_value_at_percentile(config.rps_histogram, 99.0);
        const float p100 = (float)hdr_max(config.rps_histogram);

        printf("\n");
        printf("RPS Summary:\n");
        printf("  target RPS: %.2f\n", target_rps);
        printf("  RPS distribution (reqs/sec):\n");
        printf("    %9s %9s %9s %9s %9s %9s\n", "avg", "min", "p50", "p95", "p99", "max");
        printf("    %9.3f %9.3f %9.3f %9.3f %9.3f %9.3f\n", avg_rps, p0, p50, p95, p99, p100);
    }
}

static void showReport(void) {
    const float reqpersec = (float)config.requests_finished / ((float)config.totlatency / 1000.0f);
    const float p0 = ((float)hdr_min(config.latency_histogram)) / 1000.0f;
    const float p50 = hdr_value_at_percentile(config.latency_histogram, 50.0) / 1000.0f;
    const float p95 = hdr_value_at_percentile(config.latency_histogram, 95.0) / 1000.0f;
    const float p99 = hdr_value_at_percentile(config.latency_histogram, 99.0) / 1000.0f;
    const float p100 = ((float)hdr_max(config.latency_histogram)) / 1000.0f;
    const float avg = hdr_mean(config.latency_histogram) / 1000.0f;

    if (!config.quiet && !config.csv) {
        printf("%*s\r", config.last_printed_bytes, " "); // ensure there is a clean line
        printf("====== %s ======\n", config.title);
        printf("  %d requests completed in %.2f seconds\n", config.requests_finished, (float)config.totlatency / 1000);
        printf("  %d parallel clients\n", config.numclients);
        printf("  %d bytes payload\n", config.datasize);
        printf("  keep alive: %d\n", config.keepalive);
        if (config.cluster_mode) {
            const char *node_roles = NULL;