162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Facebook 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#define _GNU_SOURCE 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include <stdio.h> 862306a36Sopenharmony_ci#include <unistd.h> 962306a36Sopenharmony_ci#include <linux/bpf.h> 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <assert.h> 1362306a36Sopenharmony_ci#include <sched.h> 1462306a36Sopenharmony_ci#include <sys/wait.h> 1562306a36Sopenharmony_ci#include <sys/stat.h> 1662306a36Sopenharmony_ci#include <fcntl.h> 1762306a36Sopenharmony_ci#include <stdlib.h> 1862306a36Sopenharmony_ci#include <time.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <bpf/bpf.h> 2162306a36Sopenharmony_ci#include "bpf_util.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define min(a, b) ((a) < (b) ? (a) : (b)) 2462306a36Sopenharmony_ci#ifndef offsetof 2562306a36Sopenharmony_ci# define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci#define container_of(ptr, type, member) ({ \ 2862306a36Sopenharmony_ci const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 2962306a36Sopenharmony_ci (type *)( (char *)__mptr - offsetof(type,member) );}) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int nr_cpus; 3262306a36Sopenharmony_cistatic unsigned long long *dist_keys; 3362306a36Sopenharmony_cistatic unsigned int dist_key_counts; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct list_head { 3662306a36Sopenharmony_ci struct list_head *next, *prev; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline void INIT_LIST_HEAD(struct list_head *list) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci list->next = list; 4262306a36Sopenharmony_ci list->prev = list; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic inline void __list_add(struct list_head *new, 4662306a36Sopenharmony_ci struct list_head *prev, 4762306a36Sopenharmony_ci struct list_head *next) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci next->prev = new; 5062306a36Sopenharmony_ci new->next = next; 5162306a36Sopenharmony_ci new->prev = prev; 5262306a36Sopenharmony_ci prev->next = new; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline void list_add(struct list_head *new, struct list_head *head) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci __list_add(new, head, head->next); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline void __list_del(struct list_head *prev, struct list_head *next) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci next->prev = prev; 6362306a36Sopenharmony_ci prev->next = next; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline void __list_del_entry(struct list_head *entry) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci __list_del(entry->prev, entry->next); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic inline void list_move(struct list_head *list, struct list_head *head) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci __list_del_entry(list); 7462306a36Sopenharmony_ci list_add(list, head); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define list_entry(ptr, type, member) \ 7862306a36Sopenharmony_ci container_of(ptr, type, member) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define list_last_entry(ptr, type, member) \ 8162306a36Sopenharmony_ci list_entry((ptr)->prev, type, member) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct pfect_lru_node { 8462306a36Sopenharmony_ci struct list_head list; 8562306a36Sopenharmony_ci unsigned long long key; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct pfect_lru { 8962306a36Sopenharmony_ci struct list_head list; 9062306a36Sopenharmony_ci struct pfect_lru_node *free_nodes; 9162306a36Sopenharmony_ci unsigned int cur_size; 9262306a36Sopenharmony_ci unsigned int lru_size; 9362306a36Sopenharmony_ci unsigned int nr_unique; 9462306a36Sopenharmony_ci unsigned int nr_misses; 9562306a36Sopenharmony_ci unsigned int total; 9662306a36Sopenharmony_ci int map_fd; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void pfect_lru_init(struct pfect_lru *lru, unsigned int lru_size, 10062306a36Sopenharmony_ci unsigned int nr_possible_elems) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci lru->map_fd = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, 10362306a36Sopenharmony_ci sizeof(unsigned long long), 10462306a36Sopenharmony_ci sizeof(struct pfect_lru_node *), 10562306a36Sopenharmony_ci nr_possible_elems, NULL); 10662306a36Sopenharmony_ci assert(lru->map_fd != -1); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci lru->free_nodes = malloc(lru_size * sizeof(struct pfect_lru_node)); 10962306a36Sopenharmony_ci assert(lru->free_nodes); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci INIT_LIST_HEAD(&lru->list); 11262306a36Sopenharmony_ci lru->cur_size = 0; 11362306a36Sopenharmony_ci lru->lru_size = lru_size; 11462306a36Sopenharmony_ci lru->nr_unique = lru->nr_misses = lru->total = 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void pfect_lru_destroy(struct pfect_lru *lru) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci close(lru->map_fd); 12062306a36Sopenharmony_ci free(lru->free_nodes); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int pfect_lru_lookup_or_insert(struct pfect_lru *lru, 12462306a36Sopenharmony_ci unsigned long long key) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct pfect_lru_node *node = NULL; 12762306a36Sopenharmony_ci int seen = 0; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci lru->total++; 13062306a36Sopenharmony_ci if (!bpf_map_lookup_elem(lru->map_fd, &key, &node)) { 13162306a36Sopenharmony_ci if (node) { 13262306a36Sopenharmony_ci list_move(&node->list, &lru->list); 13362306a36Sopenharmony_ci return 1; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci seen = 1; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (lru->cur_size < lru->lru_size) { 13962306a36Sopenharmony_ci node = &lru->free_nodes[lru->cur_size++]; 14062306a36Sopenharmony_ci INIT_LIST_HEAD(&node->list); 14162306a36Sopenharmony_ci } else { 14262306a36Sopenharmony_ci struct pfect_lru_node *null_node = NULL; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci node = list_last_entry(&lru->list, 14562306a36Sopenharmony_ci struct pfect_lru_node, 14662306a36Sopenharmony_ci list); 14762306a36Sopenharmony_ci bpf_map_update_elem(lru->map_fd, &node->key, &null_node, BPF_EXIST); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci node->key = key; 15162306a36Sopenharmony_ci list_move(&node->list, &lru->list); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci lru->nr_misses++; 15462306a36Sopenharmony_ci if (seen) { 15562306a36Sopenharmony_ci assert(!bpf_map_update_elem(lru->map_fd, &key, &node, BPF_EXIST)); 15662306a36Sopenharmony_ci } else { 15762306a36Sopenharmony_ci lru->nr_unique++; 15862306a36Sopenharmony_ci assert(!bpf_map_update_elem(lru->map_fd, &key, &node, BPF_NOEXIST)); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return seen; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic unsigned int read_keys(const char *dist_file, 16562306a36Sopenharmony_ci unsigned long long **keys) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct stat fst; 16862306a36Sopenharmony_ci unsigned long long *retkeys; 16962306a36Sopenharmony_ci unsigned int counts = 0; 17062306a36Sopenharmony_ci int dist_fd; 17162306a36Sopenharmony_ci char *b, *l; 17262306a36Sopenharmony_ci int i; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dist_fd = open(dist_file, 0); 17562306a36Sopenharmony_ci assert(dist_fd != -1); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci assert(fstat(dist_fd, &fst) == 0); 17862306a36Sopenharmony_ci b = malloc(fst.st_size); 17962306a36Sopenharmony_ci assert(b); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci assert(read(dist_fd, b, fst.st_size) == fst.st_size); 18262306a36Sopenharmony_ci close(dist_fd); 18362306a36Sopenharmony_ci for (i = 0; i < fst.st_size; i++) { 18462306a36Sopenharmony_ci if (b[i] == '\n') 18562306a36Sopenharmony_ci counts++; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci counts++; /* in case the last line has no \n */ 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci retkeys = malloc(counts * sizeof(unsigned long long)); 19062306a36Sopenharmony_ci assert(retkeys); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci counts = 0; 19362306a36Sopenharmony_ci for (l = strtok(b, "\n"); l; l = strtok(NULL, "\n")) 19462306a36Sopenharmony_ci retkeys[counts++] = strtoull(l, NULL, 10); 19562306a36Sopenharmony_ci free(b); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci *keys = retkeys; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return counts; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int create_map(int map_type, int map_flags, unsigned int size) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci LIBBPF_OPTS(bpf_map_create_opts, opts, 20562306a36Sopenharmony_ci .map_flags = map_flags, 20662306a36Sopenharmony_ci ); 20762306a36Sopenharmony_ci int map_fd; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci map_fd = bpf_map_create(map_type, NULL, sizeof(unsigned long long), 21062306a36Sopenharmony_ci sizeof(unsigned long long), size, &opts); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (map_fd == -1) 21362306a36Sopenharmony_ci perror("bpf_create_map"); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return map_fd; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int sched_next_online(int pid, int next_to_try) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci cpu_set_t cpuset; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (next_to_try == nr_cpus) 22362306a36Sopenharmony_ci return -1; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci while (next_to_try < nr_cpus) { 22662306a36Sopenharmony_ci CPU_ZERO(&cpuset); 22762306a36Sopenharmony_ci CPU_SET(next_to_try++, &cpuset); 22862306a36Sopenharmony_ci if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return next_to_try; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void run_parallel(unsigned int tasks, void (*fn)(int i, void *data), 23662306a36Sopenharmony_ci void *data) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int next_sched_cpu = 0; 23962306a36Sopenharmony_ci pid_t pid[tasks]; 24062306a36Sopenharmony_ci int i; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 24362306a36Sopenharmony_ci pid[i] = fork(); 24462306a36Sopenharmony_ci if (pid[i] == 0) { 24562306a36Sopenharmony_ci next_sched_cpu = sched_next_online(0, next_sched_cpu); 24662306a36Sopenharmony_ci fn(i, data); 24762306a36Sopenharmony_ci exit(0); 24862306a36Sopenharmony_ci } else if (pid[i] == -1) { 24962306a36Sopenharmony_ci printf("couldn't spawn #%d process\n", i); 25062306a36Sopenharmony_ci exit(1); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci /* It is mostly redundant and just allow the parent 25362306a36Sopenharmony_ci * process to update next_shced_cpu for the next child 25462306a36Sopenharmony_ci * process 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci next_sched_cpu = sched_next_online(pid[i], next_sched_cpu); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci for (i = 0; i < tasks; i++) { 25962306a36Sopenharmony_ci int status; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci assert(waitpid(pid[i], &status, 0) == pid[i]); 26262306a36Sopenharmony_ci assert(status == 0); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void do_test_lru_dist(int task, void *data) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci unsigned int nr_misses = 0; 26962306a36Sopenharmony_ci struct pfect_lru pfect_lru; 27062306a36Sopenharmony_ci unsigned long long key, value = 1234; 27162306a36Sopenharmony_ci unsigned int i; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci unsigned int lru_map_fd = ((unsigned int *)data)[0]; 27462306a36Sopenharmony_ci unsigned int lru_size = ((unsigned int *)data)[1]; 27562306a36Sopenharmony_ci unsigned long long key_offset = task * dist_key_counts; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pfect_lru_init(&pfect_lru, lru_size, dist_key_counts); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci for (i = 0; i < dist_key_counts; i++) { 28062306a36Sopenharmony_ci key = dist_keys[i] + key_offset; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci pfect_lru_lookup_or_insert(&pfect_lru, key); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (!bpf_map_lookup_elem(lru_map_fd, &key, &value)) 28562306a36Sopenharmony_ci continue; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (bpf_map_update_elem(lru_map_fd, &key, &value, BPF_NOEXIST)) { 28862306a36Sopenharmony_ci printf("bpf_map_update_elem(lru_map_fd, %llu): errno:%d\n", 28962306a36Sopenharmony_ci key, errno); 29062306a36Sopenharmony_ci assert(0); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci nr_misses++; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci printf(" task:%d BPF LRU: nr_unique:%u(/%u) nr_misses:%u(/%u)\n", 29762306a36Sopenharmony_ci task, pfect_lru.nr_unique, dist_key_counts, nr_misses, 29862306a36Sopenharmony_ci dist_key_counts); 29962306a36Sopenharmony_ci printf(" task:%d Perfect LRU: nr_unique:%u(/%u) nr_misses:%u(/%u)\n", 30062306a36Sopenharmony_ci task, pfect_lru.nr_unique, pfect_lru.total, 30162306a36Sopenharmony_ci pfect_lru.nr_misses, pfect_lru.total); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci pfect_lru_destroy(&pfect_lru); 30462306a36Sopenharmony_ci close(lru_map_fd); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void test_parallel_lru_dist(int map_type, int map_flags, 30862306a36Sopenharmony_ci int nr_tasks, unsigned int lru_size) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int child_data[2]; 31162306a36Sopenharmony_ci int lru_map_fd; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X):\n", __func__, map_type, 31462306a36Sopenharmony_ci map_flags); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 31762306a36Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 31862306a36Sopenharmony_ci nr_cpus * lru_size); 31962306a36Sopenharmony_ci else 32062306a36Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 32162306a36Sopenharmony_ci nr_tasks * lru_size); 32262306a36Sopenharmony_ci assert(lru_map_fd != -1); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci child_data[0] = lru_map_fd; 32562306a36Sopenharmony_ci child_data[1] = lru_size; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci run_parallel(nr_tasks, do_test_lru_dist, child_data); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci close(lru_map_fd); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic void test_lru_loss0(int map_type, int map_flags) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci unsigned long long key, value[nr_cpus]; 33562306a36Sopenharmony_ci unsigned int old_unused_losses = 0; 33662306a36Sopenharmony_ci unsigned int new_unused_losses = 0; 33762306a36Sopenharmony_ci unsigned int used_losses = 0; 33862306a36Sopenharmony_ci int map_fd; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 34162306a36Sopenharmony_ci map_flags); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci assert(sched_next_online(0, 0) != -1); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 34662306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 900 * nr_cpus); 34762306a36Sopenharmony_ci else 34862306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 900); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci assert(map_fd != -1); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci value[0] = 1234; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci for (key = 1; key <= 1000; key++) { 35562306a36Sopenharmony_ci int start_key, end_key; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST) == 0); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci start_key = 101; 36062306a36Sopenharmony_ci end_key = min(key, 900); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci while (start_key <= end_key) { 36362306a36Sopenharmony_ci bpf_map_lookup_elem(map_fd, &start_key, value); 36462306a36Sopenharmony_ci start_key++; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci for (key = 1; key <= 1000; key++) { 36962306a36Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) { 37062306a36Sopenharmony_ci if (key <= 100) 37162306a36Sopenharmony_ci old_unused_losses++; 37262306a36Sopenharmony_ci else if (key <= 900) 37362306a36Sopenharmony_ci used_losses++; 37462306a36Sopenharmony_ci else 37562306a36Sopenharmony_ci new_unused_losses++; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci close(map_fd); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci printf("older-elem-losses:%d(/100) active-elem-losses:%d(/800) " 38262306a36Sopenharmony_ci "newer-elem-losses:%d(/100)\n", 38362306a36Sopenharmony_ci old_unused_losses, used_losses, new_unused_losses); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void test_lru_loss1(int map_type, int map_flags) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci unsigned long long key, value[nr_cpus]; 38962306a36Sopenharmony_ci int map_fd; 39062306a36Sopenharmony_ci unsigned int nr_losses = 0; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 39362306a36Sopenharmony_ci map_flags); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci assert(sched_next_online(0, 0) != -1); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 39862306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 1000 * nr_cpus); 39962306a36Sopenharmony_ci else 40062306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 1000); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci assert(map_fd != -1); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci value[0] = 1234; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci for (key = 1; key <= 1000; key++) 40762306a36Sopenharmony_ci assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST)); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (key = 1; key <= 1000; key++) { 41062306a36Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) 41162306a36Sopenharmony_ci nr_losses++; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci close(map_fd); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci printf("nr_losses:%d(/1000)\n", nr_losses); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void do_test_parallel_lru_loss(int task, void *data) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci const unsigned int nr_stable_elems = 1000; 42262306a36Sopenharmony_ci const unsigned int nr_repeats = 100000; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci int map_fd = *(int *)data; 42562306a36Sopenharmony_ci unsigned long long stable_base; 42662306a36Sopenharmony_ci unsigned long long key, value[nr_cpus]; 42762306a36Sopenharmony_ci unsigned long long next_ins_key; 42862306a36Sopenharmony_ci unsigned int nr_losses = 0; 42962306a36Sopenharmony_ci unsigned int i; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci stable_base = task * nr_repeats * 2 + 1; 43262306a36Sopenharmony_ci next_ins_key = stable_base; 43362306a36Sopenharmony_ci value[0] = 1234; 43462306a36Sopenharmony_ci for (i = 0; i < nr_stable_elems; i++) { 43562306a36Sopenharmony_ci assert(bpf_map_update_elem(map_fd, &next_ins_key, value, 43662306a36Sopenharmony_ci BPF_NOEXIST) == 0); 43762306a36Sopenharmony_ci next_ins_key++; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci for (i = 0; i < nr_repeats; i++) { 44162306a36Sopenharmony_ci int rn; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci rn = rand(); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (rn % 10) { 44662306a36Sopenharmony_ci key = rn % nr_stable_elems + stable_base; 44762306a36Sopenharmony_ci bpf_map_lookup_elem(map_fd, &key, value); 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci bpf_map_update_elem(map_fd, &next_ins_key, value, 45062306a36Sopenharmony_ci BPF_NOEXIST); 45162306a36Sopenharmony_ci next_ins_key++; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci key = stable_base; 45662306a36Sopenharmony_ci for (i = 0; i < nr_stable_elems; i++) { 45762306a36Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) 45862306a36Sopenharmony_ci nr_losses++; 45962306a36Sopenharmony_ci key++; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci printf(" task:%d nr_losses:%u\n", task, nr_losses); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void test_parallel_lru_loss(int map_type, int map_flags, int nr_tasks) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int map_fd; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X):\n", __func__, map_type, 47062306a36Sopenharmony_ci map_flags); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Give 20% more than the active working set */ 47362306a36Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 47462306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 47562306a36Sopenharmony_ci nr_cpus * (1000 + 200)); 47662306a36Sopenharmony_ci else 47762306a36Sopenharmony_ci map_fd = create_map(map_type, map_flags, 47862306a36Sopenharmony_ci nr_tasks * (1000 + 200)); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci assert(map_fd != -1); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci run_parallel(nr_tasks, do_test_parallel_lru_loss, &map_fd); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci close(map_fd); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ciint main(int argc, char **argv) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int map_flags[] = {0, BPF_F_NO_COMMON_LRU}; 49062306a36Sopenharmony_ci const char *dist_file; 49162306a36Sopenharmony_ci int nr_tasks = 1; 49262306a36Sopenharmony_ci int lru_size; 49362306a36Sopenharmony_ci int f; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (argc < 4) { 49662306a36Sopenharmony_ci printf("Usage: %s <dist-file> <lru-size> <nr-tasks>\n", 49762306a36Sopenharmony_ci argv[0]); 49862306a36Sopenharmony_ci return -1; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci dist_file = argv[1]; 50262306a36Sopenharmony_ci lru_size = atoi(argv[2]); 50362306a36Sopenharmony_ci nr_tasks = atoi(argv[3]); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci setbuf(stdout, NULL); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci srand(time(NULL)); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci nr_cpus = bpf_num_possible_cpus(); 51062306a36Sopenharmony_ci assert(nr_cpus != -1); 51162306a36Sopenharmony_ci printf("nr_cpus:%d\n\n", nr_cpus); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci nr_tasks = min(nr_tasks, nr_cpus); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci dist_key_counts = read_keys(dist_file, &dist_keys); 51662306a36Sopenharmony_ci if (!dist_key_counts) { 51762306a36Sopenharmony_ci printf("%s has no key\n", dist_file); 51862306a36Sopenharmony_ci return -1; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci for (f = 0; f < ARRAY_SIZE(map_flags); f++) { 52262306a36Sopenharmony_ci test_lru_loss0(BPF_MAP_TYPE_LRU_HASH, map_flags[f]); 52362306a36Sopenharmony_ci test_lru_loss1(BPF_MAP_TYPE_LRU_HASH, map_flags[f]); 52462306a36Sopenharmony_ci test_parallel_lru_loss(BPF_MAP_TYPE_LRU_HASH, map_flags[f], 52562306a36Sopenharmony_ci nr_tasks); 52662306a36Sopenharmony_ci test_parallel_lru_dist(BPF_MAP_TYPE_LRU_HASH, map_flags[f], 52762306a36Sopenharmony_ci nr_tasks, lru_size); 52862306a36Sopenharmony_ci printf("\n"); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci free(dist_keys); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 535