Path: blob/master/tools/testing/selftests/bpf/benchs/bench_htab_mem.c
29270 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (C) 2023. Huawei Technologies Co., Ltd */2#include <argp.h>3#include <stdbool.h>4#include <pthread.h>5#include <sys/types.h>6#include <sys/stat.h>7#include <sys/param.h>8#include <fcntl.h>910#include "bench.h"11#include "bpf_util.h"12#include "cgroup_helpers.h"13#include "htab_mem_bench.skel.h"1415struct htab_mem_use_case {16const char *name;17const char **progs;18/* Do synchronization between addition thread and deletion thread */19bool need_sync;20};2122static struct htab_mem_ctx {23const struct htab_mem_use_case *uc;24struct htab_mem_bench *skel;25pthread_barrier_t *notify;26int fd;27} ctx;2829const char *ow_progs[] = {"overwrite", NULL};30const char *batch_progs[] = {"batch_add_batch_del", NULL};31const char *add_del_progs[] = {"add_only", "del_only", NULL};32const static struct htab_mem_use_case use_cases[] = {33{ .name = "overwrite", .progs = ow_progs },34{ .name = "batch_add_batch_del", .progs = batch_progs },35{ .name = "add_del_on_diff_cpu", .progs = add_del_progs, .need_sync = true },36};3738static struct htab_mem_args {39u32 value_size;40const char *use_case;41bool preallocated;42} args = {43.value_size = 8,44.use_case = "overwrite",45.preallocated = false,46};4748enum {49ARG_VALUE_SIZE = 10000,50ARG_USE_CASE = 10001,51ARG_PREALLOCATED = 10002,52};5354static const struct argp_option opts[] = {55{ "value-size", ARG_VALUE_SIZE, "VALUE_SIZE", 0,56"Set the value size of hash map (default 8)" },57{ "use-case", ARG_USE_CASE, "USE_CASE", 0,58"Set the use case of hash map: overwrite|batch_add_batch_del|add_del_on_diff_cpu" },59{ "preallocated", ARG_PREALLOCATED, NULL, 0, "use preallocated hash map" },60{},61};6263static error_t htab_mem_parse_arg(int key, char *arg, struct argp_state *state)64{65switch (key) {66case ARG_VALUE_SIZE:67args.value_size = strtoul(arg, NULL, 10);68if (args.value_size > 4096) {69fprintf(stderr, "too big value size %u\n", args.value_size);70argp_usage(state);71}72break;73case ARG_USE_CASE:74args.use_case = strdup(arg);75if (!args.use_case) {76fprintf(stderr, "no mem for use-case\n");77argp_usage(state);78}79break;80case ARG_PREALLOCATED:81args.preallocated = true;82break;83default:84return ARGP_ERR_UNKNOWN;85}8687return 0;88}8990const struct argp bench_htab_mem_argp = {91.options = opts,92.parser = htab_mem_parse_arg,93};9495static void htab_mem_validate(void)96{97if (!strcmp(use_cases[2].name, args.use_case) && env.producer_cnt % 2) {98fprintf(stderr, "%s needs an even number of producers\n", args.use_case);99exit(1);100}101}102103static int htab_mem_bench_init_barriers(void)104{105pthread_barrier_t *barriers;106unsigned int i, nr;107108if (!ctx.uc->need_sync)109return 0;110111nr = (env.producer_cnt + 1) / 2;112barriers = calloc(nr, sizeof(*barriers));113if (!barriers)114return -1;115116/* Used for synchronization between two threads */117for (i = 0; i < nr; i++)118pthread_barrier_init(&barriers[i], NULL, 2);119120ctx.notify = barriers;121return 0;122}123124static void htab_mem_bench_exit_barriers(void)125{126unsigned int i, nr;127128if (!ctx.notify)129return;130131nr = (env.producer_cnt + 1) / 2;132for (i = 0; i < nr; i++)133pthread_barrier_destroy(&ctx.notify[i]);134free(ctx.notify);135}136137static const struct htab_mem_use_case *htab_mem_find_use_case_or_exit(const char *name)138{139unsigned int i;140141for (i = 0; i < ARRAY_SIZE(use_cases); i++) {142if (!strcmp(name, use_cases[i].name))143return &use_cases[i];144}145146fprintf(stderr, "no such use-case: %s\n", name);147fprintf(stderr, "available use case:");148for (i = 0; i < ARRAY_SIZE(use_cases); i++)149fprintf(stderr, " %s", use_cases[i].name);150fprintf(stderr, "\n");151exit(1);152}153154static void htab_mem_setup(void)155{156struct bpf_map *map;157const char **names;158int err;159160setup_libbpf();161162ctx.uc = htab_mem_find_use_case_or_exit(args.use_case);163err = htab_mem_bench_init_barriers();164if (err) {165fprintf(stderr, "failed to init barrier\n");166exit(1);167}168169ctx.fd = cgroup_setup_and_join("/htab_mem");170if (ctx.fd < 0)171goto cleanup;172173ctx.skel = htab_mem_bench__open();174if (!ctx.skel) {175fprintf(stderr, "failed to open skeleton\n");176goto cleanup;177}178179map = ctx.skel->maps.htab;180bpf_map__set_value_size(map, args.value_size);181/* Ensure that different CPUs can operate on different subset */182bpf_map__set_max_entries(map, MAX(8192, 64 * env.nr_cpus));183if (args.preallocated)184bpf_map__set_map_flags(map, bpf_map__map_flags(map) & ~BPF_F_NO_PREALLOC);185186names = ctx.uc->progs;187while (*names) {188struct bpf_program *prog;189190prog = bpf_object__find_program_by_name(ctx.skel->obj, *names);191if (!prog) {192fprintf(stderr, "no such program %s\n", *names);193goto cleanup;194}195bpf_program__set_autoload(prog, true);196names++;197}198ctx.skel->bss->nr_thread = env.producer_cnt;199200err = htab_mem_bench__load(ctx.skel);201if (err) {202fprintf(stderr, "failed to load skeleton\n");203goto cleanup;204}205err = htab_mem_bench__attach(ctx.skel);206if (err) {207fprintf(stderr, "failed to attach skeleton\n");208goto cleanup;209}210return;211212cleanup:213htab_mem_bench__destroy(ctx.skel);214htab_mem_bench_exit_barriers();215if (ctx.fd >= 0) {216close(ctx.fd);217cleanup_cgroup_environment();218}219exit(1);220}221222static void htab_mem_add_fn(pthread_barrier_t *notify)223{224while (true) {225/* Do addition */226(void)syscall(__NR_getpgid, 0);227/* Notify deletion thread to do deletion */228pthread_barrier_wait(notify);229/* Wait for deletion to complete */230pthread_barrier_wait(notify);231}232}233234static void htab_mem_delete_fn(pthread_barrier_t *notify)235{236while (true) {237/* Wait for addition to complete */238pthread_barrier_wait(notify);239/* Do deletion */240(void)syscall(__NR_getppid);241/* Notify addition thread to do addition */242pthread_barrier_wait(notify);243}244}245246static void *htab_mem_producer(void *arg)247{248pthread_barrier_t *notify;249int seq;250251if (!ctx.uc->need_sync) {252while (true)253(void)syscall(__NR_getpgid, 0);254return NULL;255}256257seq = (long)arg;258notify = &ctx.notify[seq / 2];259if (seq & 1)260htab_mem_delete_fn(notify);261else262htab_mem_add_fn(notify);263return NULL;264}265266static void htab_mem_read_mem_cgrp_file(const char *name, unsigned long *value)267{268char buf[32];269ssize_t got;270int fd;271272fd = openat(ctx.fd, name, O_RDONLY);273if (fd < 0) {274/* cgroup v1 ? */275fprintf(stderr, "no %s\n", name);276*value = 0;277return;278}279280got = read(fd, buf, sizeof(buf) - 1);281close(fd);282if (got <= 0) {283*value = 0;284return;285}286buf[got] = 0;287288*value = strtoull(buf, NULL, 0);289}290291static void htab_mem_measure(struct bench_res *res)292{293res->hits = atomic_swap(&ctx.skel->bss->op_cnt, 0) / env.producer_cnt;294htab_mem_read_mem_cgrp_file("memory.current", &res->gp_ct);295}296297static void htab_mem_report_progress(int iter, struct bench_res *res, long delta_ns)298{299double loop, mem;300301loop = res->hits / 1000.0 / (delta_ns / 1000000000.0);302mem = res->gp_ct / 1048576.0;303printf("Iter %3d (%7.3lfus): ", iter, (delta_ns - 1000000000) / 1000.0);304printf("per-prod-op %7.2lfk/s, memory usage %7.2lfMiB\n", loop, mem);305}306307static void htab_mem_report_final(struct bench_res res[], int res_cnt)308{309double mem_mean = 0.0, mem_stddev = 0.0;310double loop_mean = 0.0, loop_stddev = 0.0;311unsigned long peak_mem;312int i;313314for (i = 0; i < res_cnt; i++) {315loop_mean += res[i].hits / 1000.0 / (0.0 + res_cnt);316mem_mean += res[i].gp_ct / 1048576.0 / (0.0 + res_cnt);317}318if (res_cnt > 1) {319for (i = 0; i < res_cnt; i++) {320loop_stddev += (loop_mean - res[i].hits / 1000.0) *321(loop_mean - res[i].hits / 1000.0) /322(res_cnt - 1.0);323mem_stddev += (mem_mean - res[i].gp_ct / 1048576.0) *324(mem_mean - res[i].gp_ct / 1048576.0) /325(res_cnt - 1.0);326}327loop_stddev = sqrt(loop_stddev);328mem_stddev = sqrt(mem_stddev);329}330331htab_mem_read_mem_cgrp_file("memory.peak", &peak_mem);332printf("Summary: per-prod-op %7.2lf \u00B1 %7.2lfk/s, memory usage %7.2lf \u00B1 %7.2lfMiB,"333" peak memory usage %7.2lfMiB\n",334loop_mean, loop_stddev, mem_mean, mem_stddev, peak_mem / 1048576.0);335336close(ctx.fd);337cleanup_cgroup_environment();338}339340const struct bench bench_htab_mem = {341.name = "htab-mem",342.argp = &bench_htab_mem_argp,343.validate = htab_mem_validate,344.setup = htab_mem_setup,345.producer_thread = htab_mem_producer,346.measure = htab_mem_measure,347.report_progress = htab_mem_report_progress,348.report_final = htab_mem_report_final,349};350351352