259 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */3 4#include <sys/types.h>5#include <sys/socket.h>6#include <pthread.h>7#include <argp.h>8 9#include "bench.h"10#include "bench_local_storage_create.skel.h"11 12struct thread {13 int *fds;14 pthread_t *pthds;15 int *pthd_results;16};17 18static struct bench_local_storage_create *skel;19static struct thread *threads;20static long create_owner_errs;21static int storage_type = BPF_MAP_TYPE_SK_STORAGE;22static int batch_sz = 32;23 24enum {25 ARG_BATCH_SZ = 9000,26 ARG_STORAGE_TYPE = 9001,27};28 29static const struct argp_option opts[] = {30 { "batch-size", ARG_BATCH_SZ, "BATCH_SIZE", 0,31 "The number of storage creations in each batch" },32 { "storage-type", ARG_STORAGE_TYPE, "STORAGE_TYPE", 0,33 "The type of local storage to test (socket or task)" },34 {},35};36 37static error_t parse_arg(int key, char *arg, struct argp_state *state)38{39 int ret;40 41 switch (key) {42 case ARG_BATCH_SZ:43 ret = atoi(arg);44 if (ret < 1) {45 fprintf(stderr, "invalid batch-size\n");46 argp_usage(state);47 }48 batch_sz = ret;49 break;50 case ARG_STORAGE_TYPE:51 if (!strcmp(arg, "task")) {52 storage_type = BPF_MAP_TYPE_TASK_STORAGE;53 } else if (!strcmp(arg, "socket")) {54 storage_type = BPF_MAP_TYPE_SK_STORAGE;55 } else {56 fprintf(stderr, "invalid storage-type (socket or task)\n");57 argp_usage(state);58 }59 break;60 default:61 return ARGP_ERR_UNKNOWN;62 }63 64 return 0;65}66 67const struct argp bench_local_storage_create_argp = {68 .options = opts,69 .parser = parse_arg,70};71 72static void validate(void)73{74 if (env.consumer_cnt != 0) {75 fprintf(stderr,76 "local-storage-create benchmark does not need consumer\n");77 exit(1);78 }79}80 81static void setup(void)82{83 int i;84 85 skel = bench_local_storage_create__open_and_load();86 if (!skel) {87 fprintf(stderr, "error loading skel\n");88 exit(1);89 }90 91 skel->bss->bench_pid = getpid();92 if (storage_type == BPF_MAP_TYPE_SK_STORAGE) {93 if (!bpf_program__attach(skel->progs.socket_post_create)) {94 fprintf(stderr, "Error attaching bpf program\n");95 exit(1);96 }97 } else {98 if (!bpf_program__attach(skel->progs.sched_process_fork)) {99 fprintf(stderr, "Error attaching bpf program\n");100 exit(1);101 }102 }103 104 if (!bpf_program__attach(skel->progs.kmalloc)) {105 fprintf(stderr, "Error attaching bpf program\n");106 exit(1);107 }108 109 threads = calloc(env.producer_cnt, sizeof(*threads));110 111 if (!threads) {112 fprintf(stderr, "cannot alloc thread_res\n");113 exit(1);114 }115 116 for (i = 0; i < env.producer_cnt; i++) {117 struct thread *t = &threads[i];118 119 if (storage_type == BPF_MAP_TYPE_SK_STORAGE) {120 t->fds = malloc(batch_sz * sizeof(*t->fds));121 if (!t->fds) {122 fprintf(stderr, "cannot alloc t->fds\n");123 exit(1);124 }125 } else {126 t->pthds = malloc(batch_sz * sizeof(*t->pthds));127 if (!t->pthds) {128 fprintf(stderr, "cannot alloc t->pthds\n");129 exit(1);130 }131 t->pthd_results = malloc(batch_sz * sizeof(*t->pthd_results));132 if (!t->pthd_results) {133 fprintf(stderr, "cannot alloc t->pthd_results\n");134 exit(1);135 }136 }137 }138}139 140static void measure(struct bench_res *res)141{142 res->hits = atomic_swap(&skel->bss->create_cnts, 0);143 res->drops = atomic_swap(&skel->bss->kmalloc_cnts, 0);144}145 146static void *sk_producer(void *input)147{148 struct thread *t = &threads[(long)(input)];149 int *fds = t->fds;150 int i;151 152 while (true) {153 for (i = 0; i < batch_sz; i++) {154 fds[i] = socket(AF_INET6, SOCK_DGRAM, 0);155 if (fds[i] == -1)156 atomic_inc(&create_owner_errs);157 }158 159 for (i = 0; i < batch_sz; i++) {160 if (fds[i] != -1)161 close(fds[i]);162 }163 }164 165 return NULL;166}167 168static void *thread_func(void *arg)169{170 return NULL;171}172 173static void *task_producer(void *input)174{175 struct thread *t = &threads[(long)(input)];176 pthread_t *pthds = t->pthds;177 int *pthd_results = t->pthd_results;178 int i;179 180 while (true) {181 for (i = 0; i < batch_sz; i++) {182 pthd_results[i] = pthread_create(&pthds[i], NULL, thread_func, NULL);183 if (pthd_results[i])184 atomic_inc(&create_owner_errs);185 }186 187 for (i = 0; i < batch_sz; i++) {188 if (!pthd_results[i])189 pthread_join(pthds[i], NULL);190 }191 }192 193 return NULL;194}195 196static void *producer(void *input)197{198 if (storage_type == BPF_MAP_TYPE_SK_STORAGE)199 return sk_producer(input);200 else201 return task_producer(input);202}203 204static void report_progress(int iter, struct bench_res *res, long delta_ns)205{206 double creates_per_sec, kmallocs_per_create;207 208 creates_per_sec = res->hits / 1000.0 / (delta_ns / 1000000000.0);209 kmallocs_per_create = (double)res->drops / res->hits;210 211 printf("Iter %3d (%7.3lfus): ",212 iter, (delta_ns - 1000000000) / 1000.0);213 printf("creates %8.3lfk/s (%7.3lfk/prod), ",214 creates_per_sec, creates_per_sec / env.producer_cnt);215 printf("%3.2lf kmallocs/create\n", kmallocs_per_create);216}217 218static void report_final(struct bench_res res[], int res_cnt)219{220 double creates_mean = 0.0, creates_stddev = 0.0;221 long total_creates = 0, total_kmallocs = 0;222 int i;223 224 for (i = 0; i < res_cnt; i++) {225 creates_mean += res[i].hits / 1000.0 / (0.0 + res_cnt);226 total_creates += res[i].hits;227 total_kmallocs += res[i].drops;228 }229 230 if (res_cnt > 1) {231 for (i = 0; i < res_cnt; i++)232 creates_stddev += (creates_mean - res[i].hits / 1000.0) *233 (creates_mean - res[i].hits / 1000.0) /234 (res_cnt - 1.0);235 creates_stddev = sqrt(creates_stddev);236 }237 printf("Summary: creates %8.3lf \u00B1 %5.3lfk/s (%7.3lfk/prod), ",238 creates_mean, creates_stddev, creates_mean / env.producer_cnt);239 printf("%4.2lf kmallocs/create\n", (double)total_kmallocs / total_creates);240 if (create_owner_errs || skel->bss->create_errs)241 printf("%s() errors %ld create_errs %ld\n",242 storage_type == BPF_MAP_TYPE_SK_STORAGE ?243 "socket" : "pthread_create",244 create_owner_errs,245 skel->bss->create_errs);246}247 248/* Benchmark performance of creating bpf local storage */249const struct bench bench_local_storage_create = {250 .name = "local-storage-create",251 .argp = &bench_local_storage_create_argp,252 .validate = validate,253 .setup = setup,254 .producer_thread = producer,255 .measure = measure,256 .report_progress = report_progress,257 .report_final = report_final,258};259