lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAP_z_Cg1Yvyq1qEkYXcyL-=zqTxqMxpV3Ap7ggzd4Q8f+=Zd9A@mail.gmail.com>
Date: Wed, 30 Jul 2025 14:05:18 -0700
From: Blake Jones <blakejones@...gle.com>
To: Ingo Molnar <mingo@...hat.com>, Peter Zijlstra <peterz@...radead.org>, 
	Juri Lelli <juri.lelli@...hat.com>, Vincent Guittot <vincent.guittot@...aro.org>
Cc: Madadi Vineeth Reddy <vineethr@...ux.ibm.com>, Josh Don <joshdon@...gle.com>, 
	Dietmar Eggemann <dietmar.eggemann@....com>, Steven Rostedt <rostedt@...dmis.org>, 
	Ben Segall <bsegall@...gle.com>, Mel Gorman <mgorman@...e.de>, 
	Valentin Schneider <vschneid@...hat.com>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2] Reorder some fields in struct rq.

Below is the source for the load test that I used. Although it
performs some timing calculations, the actual metric I used to
evaluate the change was "average amount of CPU time spent in
sched_balance_rq()", as described above.

------------------------------------------------------------------------

#include <poll.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

struct {
        /* "-m": Number of milliseconds to sleep for. */
        int sleep_ms;

        /* "-l": (base 2) Log of number of sleeps to do. */
        int log_loops;

        /* "-c": Number of children. */
        int children;
} params = {
        .sleep_ms = 1,
        .log_loops = 13,
        .children = 1000,
};

/* ------------------------------------------------------------------ */

typedef struct {
        pthread_mutex_t        mutex;
        pthread_cond_t        cv;
        pthread_cond_t        parent_cv;
        int                nthreads;
        int                nthreads_total;
        int                go;
        int                stop;
} thread_group_t;

void
thread_data_init(thread_group_t *tg)
{
        pthread_mutexattr_t mattr;
        pthread_mutexattr_init(&mattr);
        pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
        pthread_mutex_init(&tg->mutex, &mattr);
        pthread_mutexattr_destroy(&mattr);

        pthread_condattr_t cattr;
        pthread_condattr_init(&cattr);
        pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
        pthread_cond_init(&tg->cv, &cattr);
        pthread_cond_init(&tg->parent_cv, &cattr);
        pthread_condattr_destroy(&cattr);

        tg->nthreads = 0;
        tg->nthreads_total = params.children;
        tg->go = 0;
        tg->stop = 0;
}

void
parent_thread(thread_group_t *tg)
{
        pthread_mutex_lock(&tg->mutex);
        while (tg->nthreads != tg->nthreads_total) {
                pthread_cond_wait(&tg->parent_cv, &tg->mutex);
        }
        tg->go = 1;
        pthread_cond_broadcast(&tg->cv);
        pthread_mutex_unlock(&tg->mutex);

        pthread_mutex_lock(&tg->mutex);
        while (tg->nthreads != 0) {
                pthread_cond_wait(&tg->parent_cv, &tg->mutex);
        }
        tg->stop = 1;
        pthread_cond_broadcast(&tg->cv);
        pthread_mutex_unlock(&tg->mutex);
}

void
loop(unsigned long long loops)
{
        struct timespec ts;
        ts.tv_sec = 0;
        ts.tv_nsec = params.sleep_ms * 1000000;

        for (unsigned long long i = 0; i < loops; i++) {
                nanosleep(&ts, NULL);
        }
}

void *
child_thread(thread_group_t *tg)
{
        pthread_mutex_lock(&tg->mutex);
        ++tg->nthreads;
        if (tg->nthreads == tg->nthreads_total) {
                pthread_cond_signal(&tg->parent_cv);
        }
        while (!tg->go) {
                pthread_cond_wait(&tg->cv, &tg->mutex);
        }
        pthread_mutex_unlock(&tg->mutex);

        loop(1ULL << params.log_loops);

        pthread_mutex_lock(&tg->mutex);
        --tg->nthreads;
        if (tg->nthreads == 0) {
                pthread_cond_signal(&tg->parent_cv);
        }
        while (!tg->stop) {
                pthread_cond_wait(&tg->cv, &tg->mutex);
        }
        pthread_mutex_unlock(&tg->mutex);
        return NULL;
}

void
thread_data_fini(thread_group_t *tg)
{
        pthread_mutex_destroy(&tg->mutex);
        pthread_cond_destroy(&tg->cv);
        pthread_cond_destroy(&tg->parent_cv);
}

/* ------------------------------------------------------------------ */

void *
spawn_procs(thread_group_t *tg)
{
        pid_t *pids = malloc(params.children * sizeof (pid_t));
        for (int c = 0; c < params.children; c++) {
                pid_t pid;
                switch (pid = fork()) {
                case 0:
                        child_thread(tg);
                        _exit(0);
                        break;
                case -1:
                        perror("fork() failed");
                        return NULL;
                default:
                        pids[c] = pid;
                        break;
                }
        }
        return pids;
}

void
await_procs(void *data)
{
        pid_t *pids = (pid_t *)data;
        for (int c = 0; c < params.children; c++) {
                int rv = waitpid(pids[c], NULL, 0);
                if (rv != pids[c]) {
                        char msg[256];
                        snprintf(msg, sizeof(msg),
                            "waitpid(%d) = %d", pids[c], rv);
                        perror(msg);
                }
        }
        free(pids);
}

double
main_loop(void)
{
        void *mem = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                         MAP_ANONYMOUS | MAP_SHARED, -1, 0);
        if (mem == MAP_FAILED) {
                perror("mmap() failed");
                return 0;
        }
        thread_group_t *tg = mem;
        thread_data_init(tg);

        void *data = spawn_procs(tg);

        struct timespec ts1, ts2;
        if (clock_gettime(CLOCK_MONOTONIC, &ts1) == -1) {
                perror("clock_gettime(ts1)");
                return 1;
        }
        parent_thread(tg);
        if (clock_gettime(CLOCK_MONOTONIC, &ts2) == -1) {
                perror("clock_gettime(ts2)");
                return 1;
        }

        await_procs(data);
        thread_data_fini(tg);
        munmap(mem, 4096);

        double t1 = (double)ts1.tv_sec + (double)ts1.tv_nsec / 1e9;
        double t2 = (double)ts2.tv_sec + (double)ts2.tv_nsec / 1e9;
        return t2 - t1;
}

int
main(int argc, char **argv)
{
        int opt;
        while ((opt = getopt(argc, argv, "m:l:c:f")) != -1) {
                switch (opt) {
                case 'm':
                        params.sleep_ms = atoi(optarg);
                        break;
                case 'l':
                        params.log_loops = atoi(optarg);
                        break;
                case 'c':
                        params.children = atoi(optarg);
                        break;
                default:
                        fprintf(stderr, "Usage: "
                            "%s [-m <ms> -l <log> -c <children>]\n", argv[0]);
                        return 1;
                }
        }

        printf("Running: "
                "%5d children, 1<<%d loops, %d ms sleep/loop\n",
                params.children, params.log_loops, params.sleep_ms);

        printf("%.5lf\n", main_loop());

        return 0;
}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ