18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Facebook 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#define _GNU_SOURCE 68c2ecf20Sopenharmony_ci#include <linux/types.h> 78c2ecf20Sopenharmony_ci#include <stdio.h> 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include <linux/bpf.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#include <assert.h> 138c2ecf20Sopenharmony_ci#include <sched.h> 148c2ecf20Sopenharmony_ci#include <sys/wait.h> 158c2ecf20Sopenharmony_ci#include <sys/stat.h> 168c2ecf20Sopenharmony_ci#include <sys/resource.h> 178c2ecf20Sopenharmony_ci#include <fcntl.h> 188c2ecf20Sopenharmony_ci#include <stdlib.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <bpf/bpf.h> 228c2ecf20Sopenharmony_ci#include "bpf_util.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define min(a, b) ((a) < (b) ? (a) : (b)) 258c2ecf20Sopenharmony_ci#ifndef offsetof 268c2ecf20Sopenharmony_ci# define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) 278c2ecf20Sopenharmony_ci#endif 288c2ecf20Sopenharmony_ci#define container_of(ptr, type, member) ({ \ 298c2ecf20Sopenharmony_ci const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 308c2ecf20Sopenharmony_ci (type *)( (char *)__mptr - offsetof(type,member) );}) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int nr_cpus; 338c2ecf20Sopenharmony_cistatic unsigned long long *dist_keys; 348c2ecf20Sopenharmony_cistatic unsigned int dist_key_counts; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct list_head { 378c2ecf20Sopenharmony_ci struct list_head *next, *prev; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline void INIT_LIST_HEAD(struct list_head *list) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci list->next = list; 438c2ecf20Sopenharmony_ci list->prev = list; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline int list_empty(const struct list_head *head) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci return head->next == head; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic inline void __list_add(struct list_head *new, 528c2ecf20Sopenharmony_ci struct list_head *prev, 538c2ecf20Sopenharmony_ci struct list_head *next) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci next->prev = new; 568c2ecf20Sopenharmony_ci new->next = next; 578c2ecf20Sopenharmony_ci new->prev = prev; 588c2ecf20Sopenharmony_ci prev->next = new; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline void list_add(struct list_head *new, struct list_head *head) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci __list_add(new, head, head->next); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline void __list_del(struct list_head *prev, struct list_head *next) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci next->prev = prev; 698c2ecf20Sopenharmony_ci prev->next = next; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline void __list_del_entry(struct list_head *entry) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci __list_del(entry->prev, entry->next); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline void list_move(struct list_head *list, struct list_head *head) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci __list_del_entry(list); 808c2ecf20Sopenharmony_ci list_add(list, head); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define list_entry(ptr, type, member) \ 848c2ecf20Sopenharmony_ci container_of(ptr, type, member) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define list_last_entry(ptr, type, member) \ 878c2ecf20Sopenharmony_ci list_entry((ptr)->prev, type, member) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct pfect_lru_node { 908c2ecf20Sopenharmony_ci struct list_head list; 918c2ecf20Sopenharmony_ci unsigned long long key; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct pfect_lru { 958c2ecf20Sopenharmony_ci struct list_head list; 968c2ecf20Sopenharmony_ci struct pfect_lru_node *free_nodes; 978c2ecf20Sopenharmony_ci unsigned int cur_size; 988c2ecf20Sopenharmony_ci unsigned int lru_size; 998c2ecf20Sopenharmony_ci unsigned int nr_unique; 1008c2ecf20Sopenharmony_ci unsigned int nr_misses; 1018c2ecf20Sopenharmony_ci unsigned int total; 1028c2ecf20Sopenharmony_ci int map_fd; 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void pfect_lru_init(struct pfect_lru *lru, unsigned int lru_size, 1068c2ecf20Sopenharmony_ci unsigned int nr_possible_elems) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci lru->map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, 1098c2ecf20Sopenharmony_ci sizeof(unsigned long long), 1108c2ecf20Sopenharmony_ci sizeof(struct pfect_lru_node *), 1118c2ecf20Sopenharmony_ci nr_possible_elems, 0); 1128c2ecf20Sopenharmony_ci assert(lru->map_fd != -1); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci lru->free_nodes = malloc(lru_size * sizeof(struct pfect_lru_node)); 1158c2ecf20Sopenharmony_ci assert(lru->free_nodes); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&lru->list); 1188c2ecf20Sopenharmony_ci lru->cur_size = 0; 1198c2ecf20Sopenharmony_ci lru->lru_size = lru_size; 1208c2ecf20Sopenharmony_ci lru->nr_unique = lru->nr_misses = lru->total = 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void pfect_lru_destroy(struct pfect_lru *lru) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci close(lru->map_fd); 1268c2ecf20Sopenharmony_ci free(lru->free_nodes); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int pfect_lru_lookup_or_insert(struct pfect_lru *lru, 1308c2ecf20Sopenharmony_ci unsigned long long key) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct pfect_lru_node *node = NULL; 1338c2ecf20Sopenharmony_ci int seen = 0; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci lru->total++; 1368c2ecf20Sopenharmony_ci if (!bpf_map_lookup_elem(lru->map_fd, &key, &node)) { 1378c2ecf20Sopenharmony_ci if (node) { 1388c2ecf20Sopenharmony_ci list_move(&node->list, &lru->list); 1398c2ecf20Sopenharmony_ci return 1; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci seen = 1; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (lru->cur_size < lru->lru_size) { 1458c2ecf20Sopenharmony_ci node = &lru->free_nodes[lru->cur_size++]; 1468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&node->list); 1478c2ecf20Sopenharmony_ci } else { 1488c2ecf20Sopenharmony_ci struct pfect_lru_node *null_node = NULL; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci node = list_last_entry(&lru->list, 1518c2ecf20Sopenharmony_ci struct pfect_lru_node, 1528c2ecf20Sopenharmony_ci list); 1538c2ecf20Sopenharmony_ci bpf_map_update_elem(lru->map_fd, &node->key, &null_node, BPF_EXIST); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci node->key = key; 1578c2ecf20Sopenharmony_ci list_move(&node->list, &lru->list); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci lru->nr_misses++; 1608c2ecf20Sopenharmony_ci if (seen) { 1618c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru->map_fd, &key, &node, BPF_EXIST)); 1628c2ecf20Sopenharmony_ci } else { 1638c2ecf20Sopenharmony_ci lru->nr_unique++; 1648c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(lru->map_fd, &key, &node, BPF_NOEXIST)); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return seen; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic unsigned int read_keys(const char *dist_file, 1718c2ecf20Sopenharmony_ci unsigned long long **keys) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct stat fst; 1748c2ecf20Sopenharmony_ci unsigned long long *retkeys; 1758c2ecf20Sopenharmony_ci unsigned int counts = 0; 1768c2ecf20Sopenharmony_ci int dist_fd; 1778c2ecf20Sopenharmony_ci char *b, *l; 1788c2ecf20Sopenharmony_ci int i; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci dist_fd = open(dist_file, 0); 1818c2ecf20Sopenharmony_ci assert(dist_fd != -1); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci assert(fstat(dist_fd, &fst) == 0); 1848c2ecf20Sopenharmony_ci b = malloc(fst.st_size); 1858c2ecf20Sopenharmony_ci assert(b); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci assert(read(dist_fd, b, fst.st_size) == fst.st_size); 1888c2ecf20Sopenharmony_ci close(dist_fd); 1898c2ecf20Sopenharmony_ci for (i = 0; i < fst.st_size; i++) { 1908c2ecf20Sopenharmony_ci if (b[i] == '\n') 1918c2ecf20Sopenharmony_ci counts++; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci counts++; /* in case the last line has no \n */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci retkeys = malloc(counts * sizeof(unsigned long long)); 1968c2ecf20Sopenharmony_ci assert(retkeys); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci counts = 0; 1998c2ecf20Sopenharmony_ci for (l = strtok(b, "\n"); l; l = strtok(NULL, "\n")) 2008c2ecf20Sopenharmony_ci retkeys[counts++] = strtoull(l, NULL, 10); 2018c2ecf20Sopenharmony_ci free(b); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci *keys = retkeys; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return counts; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int create_map(int map_type, int map_flags, unsigned int size) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci int map_fd; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci map_fd = bpf_create_map(map_type, sizeof(unsigned long long), 2138c2ecf20Sopenharmony_ci sizeof(unsigned long long), size, map_flags); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (map_fd == -1) 2168c2ecf20Sopenharmony_ci perror("bpf_create_map"); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return map_fd; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int sched_next_online(int pid, int next_to_try) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci cpu_set_t cpuset; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (next_to_try == nr_cpus) 2268c2ecf20Sopenharmony_ci return -1; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci while (next_to_try < nr_cpus) { 2298c2ecf20Sopenharmony_ci CPU_ZERO(&cpuset); 2308c2ecf20Sopenharmony_ci CPU_SET(next_to_try++, &cpuset); 2318c2ecf20Sopenharmony_ci if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) 2328c2ecf20Sopenharmony_ci break; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return next_to_try; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void run_parallel(unsigned int tasks, void (*fn)(int i, void *data), 2398c2ecf20Sopenharmony_ci void *data) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int next_sched_cpu = 0; 2428c2ecf20Sopenharmony_ci pid_t pid[tasks]; 2438c2ecf20Sopenharmony_ci int i; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci for (i = 0; i < tasks; i++) { 2468c2ecf20Sopenharmony_ci pid[i] = fork(); 2478c2ecf20Sopenharmony_ci if (pid[i] == 0) { 2488c2ecf20Sopenharmony_ci next_sched_cpu = sched_next_online(0, next_sched_cpu); 2498c2ecf20Sopenharmony_ci fn(i, data); 2508c2ecf20Sopenharmony_ci exit(0); 2518c2ecf20Sopenharmony_ci } else if (pid[i] == -1) { 2528c2ecf20Sopenharmony_ci printf("couldn't spawn #%d process\n", i); 2538c2ecf20Sopenharmony_ci exit(1); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci /* It is mostly redundant and just allow the parent 2568c2ecf20Sopenharmony_ci * process to update next_shced_cpu for the next child 2578c2ecf20Sopenharmony_ci * process 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci next_sched_cpu = sched_next_online(pid[i], next_sched_cpu); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci for (i = 0; i < tasks; i++) { 2628c2ecf20Sopenharmony_ci int status; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci assert(waitpid(pid[i], &status, 0) == pid[i]); 2658c2ecf20Sopenharmony_ci assert(status == 0); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void do_test_lru_dist(int task, void *data) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci unsigned int nr_misses = 0; 2728c2ecf20Sopenharmony_ci struct pfect_lru pfect_lru; 2738c2ecf20Sopenharmony_ci unsigned long long key, value = 1234; 2748c2ecf20Sopenharmony_ci unsigned int i; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci unsigned int lru_map_fd = ((unsigned int *)data)[0]; 2778c2ecf20Sopenharmony_ci unsigned int lru_size = ((unsigned int *)data)[1]; 2788c2ecf20Sopenharmony_ci unsigned long long key_offset = task * dist_key_counts; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci pfect_lru_init(&pfect_lru, lru_size, dist_key_counts); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < dist_key_counts; i++) { 2838c2ecf20Sopenharmony_ci key = dist_keys[i] + key_offset; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci pfect_lru_lookup_or_insert(&pfect_lru, key); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!bpf_map_lookup_elem(lru_map_fd, &key, &value)) 2888c2ecf20Sopenharmony_ci continue; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (bpf_map_update_elem(lru_map_fd, &key, &value, BPF_NOEXIST)) { 2918c2ecf20Sopenharmony_ci printf("bpf_map_update_elem(lru_map_fd, %llu): errno:%d\n", 2928c2ecf20Sopenharmony_ci key, errno); 2938c2ecf20Sopenharmony_ci assert(0); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci nr_misses++; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci printf(" task:%d BPF LRU: nr_unique:%u(/%u) nr_misses:%u(/%u)\n", 3008c2ecf20Sopenharmony_ci task, pfect_lru.nr_unique, dist_key_counts, nr_misses, 3018c2ecf20Sopenharmony_ci dist_key_counts); 3028c2ecf20Sopenharmony_ci printf(" task:%d Perfect LRU: nr_unique:%u(/%u) nr_misses:%u(/%u)\n", 3038c2ecf20Sopenharmony_ci task, pfect_lru.nr_unique, pfect_lru.total, 3048c2ecf20Sopenharmony_ci pfect_lru.nr_misses, pfect_lru.total); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci pfect_lru_destroy(&pfect_lru); 3078c2ecf20Sopenharmony_ci close(lru_map_fd); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void test_parallel_lru_dist(int map_type, int map_flags, 3118c2ecf20Sopenharmony_ci int nr_tasks, unsigned int lru_size) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int child_data[2]; 3148c2ecf20Sopenharmony_ci int lru_map_fd; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X):\n", __func__, map_type, 3178c2ecf20Sopenharmony_ci map_flags); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 3208c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 3218c2ecf20Sopenharmony_ci nr_cpus * lru_size); 3228c2ecf20Sopenharmony_ci else 3238c2ecf20Sopenharmony_ci lru_map_fd = create_map(map_type, map_flags, 3248c2ecf20Sopenharmony_ci nr_tasks * lru_size); 3258c2ecf20Sopenharmony_ci assert(lru_map_fd != -1); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci child_data[0] = lru_map_fd; 3288c2ecf20Sopenharmony_ci child_data[1] = lru_size; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci run_parallel(nr_tasks, do_test_lru_dist, child_data); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci close(lru_map_fd); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void test_lru_loss0(int map_type, int map_flags) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 3388c2ecf20Sopenharmony_ci unsigned int old_unused_losses = 0; 3398c2ecf20Sopenharmony_ci unsigned int new_unused_losses = 0; 3408c2ecf20Sopenharmony_ci unsigned int used_losses = 0; 3418c2ecf20Sopenharmony_ci int map_fd; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 3448c2ecf20Sopenharmony_ci map_flags); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci assert(sched_next_online(0, 0) != -1); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 3498c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 900 * nr_cpus); 3508c2ecf20Sopenharmony_ci else 3518c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 900); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci assert(map_fd != -1); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci value[0] = 1234; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (key = 1; key <= 1000; key++) { 3588c2ecf20Sopenharmony_ci int start_key, end_key; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST) == 0); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci start_key = 101; 3638c2ecf20Sopenharmony_ci end_key = min(key, 900); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci while (start_key <= end_key) { 3668c2ecf20Sopenharmony_ci bpf_map_lookup_elem(map_fd, &start_key, value); 3678c2ecf20Sopenharmony_ci start_key++; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci for (key = 1; key <= 1000; key++) { 3728c2ecf20Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) { 3738c2ecf20Sopenharmony_ci if (key <= 100) 3748c2ecf20Sopenharmony_ci old_unused_losses++; 3758c2ecf20Sopenharmony_ci else if (key <= 900) 3768c2ecf20Sopenharmony_ci used_losses++; 3778c2ecf20Sopenharmony_ci else 3788c2ecf20Sopenharmony_ci new_unused_losses++; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci close(map_fd); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci printf("older-elem-losses:%d(/100) active-elem-losses:%d(/800) " 3858c2ecf20Sopenharmony_ci "newer-elem-losses:%d(/100)\n", 3868c2ecf20Sopenharmony_ci old_unused_losses, used_losses, new_unused_losses); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic void test_lru_loss1(int map_type, int map_flags) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 3928c2ecf20Sopenharmony_ci int map_fd; 3938c2ecf20Sopenharmony_ci unsigned int nr_losses = 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type, 3968c2ecf20Sopenharmony_ci map_flags); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci assert(sched_next_online(0, 0) != -1); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 4018c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 1000 * nr_cpus); 4028c2ecf20Sopenharmony_ci else 4038c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 1000); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci assert(map_fd != -1); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci value[0] = 1234; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci for (key = 1; key <= 1000; key++) 4108c2ecf20Sopenharmony_ci assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST)); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci for (key = 1; key <= 1000; key++) { 4138c2ecf20Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) 4148c2ecf20Sopenharmony_ci nr_losses++; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci close(map_fd); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci printf("nr_losses:%d(/1000)\n", nr_losses); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void do_test_parallel_lru_loss(int task, void *data) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci const unsigned int nr_stable_elems = 1000; 4258c2ecf20Sopenharmony_ci const unsigned int nr_repeats = 100000; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci int map_fd = *(int *)data; 4288c2ecf20Sopenharmony_ci unsigned long long stable_base; 4298c2ecf20Sopenharmony_ci unsigned long long key, value[nr_cpus]; 4308c2ecf20Sopenharmony_ci unsigned long long next_ins_key; 4318c2ecf20Sopenharmony_ci unsigned int nr_losses = 0; 4328c2ecf20Sopenharmony_ci unsigned int i; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci stable_base = task * nr_repeats * 2 + 1; 4358c2ecf20Sopenharmony_ci next_ins_key = stable_base; 4368c2ecf20Sopenharmony_ci value[0] = 1234; 4378c2ecf20Sopenharmony_ci for (i = 0; i < nr_stable_elems; i++) { 4388c2ecf20Sopenharmony_ci assert(bpf_map_update_elem(map_fd, &next_ins_key, value, 4398c2ecf20Sopenharmony_ci BPF_NOEXIST) == 0); 4408c2ecf20Sopenharmony_ci next_ins_key++; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci for (i = 0; i < nr_repeats; i++) { 4448c2ecf20Sopenharmony_ci int rn; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci rn = rand(); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (rn % 10) { 4498c2ecf20Sopenharmony_ci key = rn % nr_stable_elems + stable_base; 4508c2ecf20Sopenharmony_ci bpf_map_lookup_elem(map_fd, &key, value); 4518c2ecf20Sopenharmony_ci } else { 4528c2ecf20Sopenharmony_ci bpf_map_update_elem(map_fd, &next_ins_key, value, 4538c2ecf20Sopenharmony_ci BPF_NOEXIST); 4548c2ecf20Sopenharmony_ci next_ins_key++; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci key = stable_base; 4598c2ecf20Sopenharmony_ci for (i = 0; i < nr_stable_elems; i++) { 4608c2ecf20Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) 4618c2ecf20Sopenharmony_ci nr_losses++; 4628c2ecf20Sopenharmony_ci key++; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci printf(" task:%d nr_losses:%u\n", task, nr_losses); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic void test_parallel_lru_loss(int map_type, int map_flags, int nr_tasks) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int map_fd; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci printf("%s (map_type:%d map_flags:0x%X):\n", __func__, map_type, 4738c2ecf20Sopenharmony_ci map_flags); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Give 20% more than the active working set */ 4768c2ecf20Sopenharmony_ci if (map_flags & BPF_F_NO_COMMON_LRU) 4778c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 4788c2ecf20Sopenharmony_ci nr_cpus * (1000 + 200)); 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci map_fd = create_map(map_type, map_flags, 4818c2ecf20Sopenharmony_ci nr_tasks * (1000 + 200)); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci assert(map_fd != -1); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci run_parallel(nr_tasks, do_test_parallel_lru_loss, &map_fd); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci close(map_fd); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciint main(int argc, char **argv) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 4938c2ecf20Sopenharmony_ci int map_flags[] = {0, BPF_F_NO_COMMON_LRU}; 4948c2ecf20Sopenharmony_ci const char *dist_file; 4958c2ecf20Sopenharmony_ci int nr_tasks = 1; 4968c2ecf20Sopenharmony_ci int lru_size; 4978c2ecf20Sopenharmony_ci int f; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (argc < 4) { 5008c2ecf20Sopenharmony_ci printf("Usage: %s <dist-file> <lru-size> <nr-tasks>\n", 5018c2ecf20Sopenharmony_ci argv[0]); 5028c2ecf20Sopenharmony_ci return -1; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci dist_file = argv[1]; 5068c2ecf20Sopenharmony_ci lru_size = atoi(argv[2]); 5078c2ecf20Sopenharmony_ci nr_tasks = atoi(argv[3]); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci setbuf(stdout, NULL); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci assert(!setrlimit(RLIMIT_MEMLOCK, &r)); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci srand(time(NULL)); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci nr_cpus = bpf_num_possible_cpus(); 5168c2ecf20Sopenharmony_ci assert(nr_cpus != -1); 5178c2ecf20Sopenharmony_ci printf("nr_cpus:%d\n\n", nr_cpus); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci nr_tasks = min(nr_tasks, nr_cpus); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci dist_key_counts = read_keys(dist_file, &dist_keys); 5228c2ecf20Sopenharmony_ci if (!dist_key_counts) { 5238c2ecf20Sopenharmony_ci printf("%s has no key\n", dist_file); 5248c2ecf20Sopenharmony_ci return -1; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci for (f = 0; f < sizeof(map_flags) / sizeof(*map_flags); f++) { 5288c2ecf20Sopenharmony_ci test_lru_loss0(BPF_MAP_TYPE_LRU_HASH, map_flags[f]); 5298c2ecf20Sopenharmony_ci test_lru_loss1(BPF_MAP_TYPE_LRU_HASH, map_flags[f]); 5308c2ecf20Sopenharmony_ci test_parallel_lru_loss(BPF_MAP_TYPE_LRU_HASH, map_flags[f], 5318c2ecf20Sopenharmony_ci nr_tasks); 5328c2ecf20Sopenharmony_ci test_parallel_lru_dist(BPF_MAP_TYPE_LRU_HASH, map_flags[f], 5338c2ecf20Sopenharmony_ci nr_tasks, lru_size); 5348c2ecf20Sopenharmony_ci printf("\n"); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci free(dist_keys); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 541