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