diff options
author | David S. Miller <davem@davemloft.net> | 2016-03-08 15:28:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-08 15:28:33 -0500 |
commit | f14b488d50b7dc234ddaed53ce4293c9eac47457 (patch) | |
tree | ff802293cd7a0020211818c8039cd9f117f30a35 /samples | |
parent | 8aba8b83128a04197991518e241aafd3323b705d (diff) | |
parent | c3f85cffc50d2f259903555979581a632b945ec2 (diff) | |
download | op-kernel-dev-f14b488d50b7dc234ddaed53ce4293c9eac47457.zip op-kernel-dev-f14b488d50b7dc234ddaed53ce4293c9eac47457.tar.gz |
Merge branch 'bpf-map-prealloc'
Alexei Starovoitov says:
====================
bpf: map pre-alloc
v1->v2:
. fix few issues spotted by Daniel
. converted stackmap into pre-allocation as well
. added a workaround for lockdep false positive
. added pcpu_freelist_populate to be used by hashmap and stackmap
this path set switches bpf hash map to use pre-allocation by default
and introduces BPF_F_NO_PREALLOC flag to keep old behavior for cases
where full map pre-allocation is too memory expensive.
Some time back Daniel Wagner reported crashes when bpf hash map is
used to compute time intervals between preempt_disable->preempt_enable
and recently Tom Zanussi reported a dead lock in iovisor/bcc/funccount
tool if it's used to count the number of invocations of kernel
'*spin*' functions. Both problems are due to the recursive use of
slub and can only be solved by pre-allocating all map elements.
A lot of different solutions were considered. Many implemented,
but at the end pre-allocation seems to be the only feasible answer.
As far as pre-allocation goes it also was implemented 4 different ways:
- simple free-list with single lock
- percpu_ida with optimizations
- blk-mq-tag variant customized for bpf use case
- percpu_freelist
For bpf style of alloc/free patterns percpu_freelist is the best
and implemented in this patch set.
Detailed performance numbers in patch 3.
Patch 2 introduces percpu_freelist
Patch 1 fixes simple deadlocks due to missing recursion checks
Patch 5: converts stackmap to pre-allocation
Patches 6-9: prepare test infra
Patch 10: stress test for hash map infra. It attaches to spin_lock
functions and bpf_map_update/delete are called from different contexts
Patch 11: stress for bpf_get_stackid
Patch 12: map performance test
Reported-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Reported-by: Tom Zanussi <tom.zanussi@linux.intel.com>
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples')
-rw-r--r-- | samples/bpf/bpf_helpers.h | 1 | ||||
-rw-r--r-- | samples/bpf/bpf_load.c | 70 | ||||
-rw-r--r-- | samples/bpf/bpf_load.h | 6 | ||||
-rw-r--r-- | samples/bpf/fds_example.c | 2 | ||||
-rw-r--r-- | samples/bpf/libbpf.c | 5 | ||||
-rw-r--r-- | samples/bpf/libbpf.h | 2 | ||||
-rw-r--r-- | samples/bpf/offwaketime_user.c | 67 | ||||
-rw-r--r-- | samples/bpf/sock_example.c | 2 | ||||
-rw-r--r-- | samples/bpf/test_maps.c | 29 | ||||
-rw-r--r-- | samples/bpf/test_verifier.c | 4 |
10 files changed, 105 insertions, 83 deletions
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index 811bcca..9363500 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -61,6 +61,7 @@ struct bpf_map_def { unsigned int key_size; unsigned int value_size; unsigned int max_entries; + unsigned int map_flags; }; static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index da86a8e..58f86bd 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -157,9 +157,13 @@ static int load_maps(struct bpf_map_def *maps, int len) map_fd[i] = bpf_create_map(maps[i].type, maps[i].key_size, maps[i].value_size, - maps[i].max_entries); - if (map_fd[i] < 0) + maps[i].max_entries, + maps[i].map_flags); + if (map_fd[i] < 0) { + printf("failed to create a map: %d %s\n", + errno, strerror(errno)); return 1; + } if (maps[i].type == BPF_MAP_TYPE_PROG_ARRAY) prog_array_fd = map_fd[i]; @@ -343,3 +347,65 @@ void read_trace_pipe(void) } } } + +#define MAX_SYMS 300000 +static struct ksym syms[MAX_SYMS]; +static int sym_cnt; + +static int ksym_cmp(const void *p1, const void *p2) +{ + return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr; +} + +int load_kallsyms(void) +{ + FILE *f = fopen("/proc/kallsyms", "r"); + char func[256], buf[256]; + char symbol; + void *addr; + int i = 0; + + if (!f) + return -ENOENT; + + while (!feof(f)) { + if (!fgets(buf, sizeof(buf), f)) + break; + if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3) + break; + if (!addr) + continue; + syms[i].addr = (long) addr; + syms[i].name = strdup(func); + i++; + } + sym_cnt = i; + qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); + return 0; +} + +struct ksym *ksym_search(long key) +{ + int start = 0, end = sym_cnt; + int result; + + while (start < end) { + size_t mid = start + (end - start) / 2; + + result = key - syms[mid].addr; + if (result < 0) + end = mid; + else if (result > 0) + start = mid + 1; + else + return &syms[mid]; + } + + if (start >= 1 && syms[start - 1].addr < key && + key < syms[start].addr) + /* valid ksym */ + return &syms[start - 1]; + + /* out of range. return _stext */ + return &syms[0]; +} diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h index cbd7c2b..dfa57fe 100644 --- a/samples/bpf/bpf_load.h +++ b/samples/bpf/bpf_load.h @@ -23,5 +23,11 @@ extern int event_fd[MAX_PROGS]; int load_bpf_file(char *path); void read_trace_pipe(void); +struct ksym { + long addr; + char *name; +}; +int load_kallsyms(void); +struct ksym *ksym_search(long key); #endif diff --git a/samples/bpf/fds_example.c b/samples/bpf/fds_example.c index e2fd16c..625e797 100644 --- a/samples/bpf/fds_example.c +++ b/samples/bpf/fds_example.c @@ -44,7 +44,7 @@ static void usage(void) static int bpf_map_create(void) { return bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t), - sizeof(uint32_t), 1024); + sizeof(uint32_t), 1024, 0); } static int bpf_prog_create(const char *object) diff --git a/samples/bpf/libbpf.c b/samples/bpf/libbpf.c index 65a8d48..9969e35 100644 --- a/samples/bpf/libbpf.c +++ b/samples/bpf/libbpf.c @@ -19,13 +19,14 @@ static __u64 ptr_to_u64(void *ptr) } int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, - int max_entries) + int max_entries, int map_flags) { union bpf_attr attr = { .map_type = map_type, .key_size = key_size, .value_size = value_size, - .max_entries = max_entries + .max_entries = max_entries, + .map_flags = map_flags, }; return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h index 014aacf..364582b 100644 --- a/samples/bpf/libbpf.h +++ b/samples/bpf/libbpf.h @@ -5,7 +5,7 @@ struct bpf_insn; int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, - int max_entries); + int max_entries, int map_flags); int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags); int bpf_lookup_elem(int fd, void *key, void *value); int bpf_delete_elem(int fd, void *key); diff --git a/samples/bpf/offwaketime_user.c b/samples/bpf/offwaketime_user.c index 17cf302..6f002a9 100644 --- a/samples/bpf/offwaketime_user.c +++ b/samples/bpf/offwaketime_user.c @@ -18,80 +18,15 @@ #include "libbpf.h" #include "bpf_load.h" -#define MAX_SYMS 300000 #define PRINT_RAW_ADDR 0 -static struct ksym { - long addr; - char *name; -} syms[MAX_SYMS]; -static int sym_cnt; - -static int ksym_cmp(const void *p1, const void *p2) -{ - return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr; -} - -static int load_kallsyms(void) -{ - FILE *f = fopen("/proc/kallsyms", "r"); - char func[256], buf[256]; - char symbol; - void *addr; - int i = 0; - - if (!f) - return -ENOENT; - - while (!feof(f)) { - if (!fgets(buf, sizeof(buf), f)) - break; - if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3) - break; - if (!addr) - continue; - syms[i].addr = (long) addr; - syms[i].name = strdup(func); - i++; - } - sym_cnt = i; - qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); - return 0; -} - -static void *search(long key) -{ - int start = 0, end = sym_cnt; - int result; - - while (start < end) { - size_t mid = start + (end - start) / 2; - - result = key - syms[mid].addr; - if (result < 0) - end = mid; - else if (result > 0) - start = mid + 1; - else - return &syms[mid]; - } - - if (start >= 1 && syms[start - 1].addr < key && - key < syms[start].addr) - /* valid ksym */ - return &syms[start - 1]; - - /* out of range. return _stext */ - return &syms[0]; -} - static void print_ksym(__u64 addr) { struct ksym *sym; if (!addr) return; - sym = search(addr); + sym = ksym_search(addr); if (PRINT_RAW_ADDR) printf("%s/%llx;", sym->name, addr); else diff --git a/samples/bpf/sock_example.c b/samples/bpf/sock_example.c index a0ce251..28b60ba 100644 --- a/samples/bpf/sock_example.c +++ b/samples/bpf/sock_example.c @@ -34,7 +34,7 @@ static int test_sock(void) long long value = 0, tcp_cnt, udp_cnt, icmp_cnt; map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), - 256); + 256, 0); if (map_fd < 0) { printf("failed to create map '%s'\n", strerror(errno)); goto cleanup; diff --git a/samples/bpf/test_maps.c b/samples/bpf/test_maps.c index ad466ed..47bf085 100644 --- a/samples/bpf/test_maps.c +++ b/samples/bpf/test_maps.c @@ -2,6 +2,7 @@ * Testsuite for eBPF maps * * Copyright (c) 2014 PLUMgrid, http://plumgrid.com + * Copyright (c) 2016 Facebook * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -17,13 +18,16 @@ #include <stdlib.h> #include "libbpf.h" +static int map_flags; + /* sanity tests for map API */ static void test_hashmap_sanity(int i, void *data) { long long key, next_key, value; int map_fd; - map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 2); + map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), + 2, map_flags); if (map_fd < 0) { printf("failed to create hashmap '%s'\n", strerror(errno)); exit(1); @@ -99,7 +103,7 @@ static void test_percpu_hashmap_sanity(int task, void *data) int map_fd, i; map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key), - sizeof(value[0]), 2); + sizeof(value[0]), 2, map_flags); if (map_fd < 0) { printf("failed to create hashmap '%s'\n", strerror(errno)); exit(1); @@ -188,7 +192,8 @@ static void test_arraymap_sanity(int i, void *data) int key, next_key, map_fd; long long value; - map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2); + map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), + 2, 0); if (map_fd < 0) { printf("failed to create arraymap '%s'\n", strerror(errno)); exit(1); @@ -244,7 +249,7 @@ static void test_percpu_arraymap_many_keys(void) int key, map_fd, i; map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), - sizeof(values[0]), nr_keys); + sizeof(values[0]), nr_keys, 0); if (map_fd < 0) { printf("failed to create per-cpu arraymap '%s'\n", strerror(errno)); @@ -275,7 +280,7 @@ static void test_percpu_arraymap_sanity(int i, void *data) int key, next_key, map_fd; map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), - sizeof(values[0]), 2); + sizeof(values[0]), 2, 0); if (map_fd < 0) { printf("failed to create arraymap '%s'\n", strerror(errno)); exit(1); @@ -336,7 +341,7 @@ static void test_map_large(void) /* allocate 4Mbyte of memory */ map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), - MAP_SIZE); + MAP_SIZE, map_flags); if (map_fd < 0) { printf("failed to create large map '%s'\n", strerror(errno)); exit(1); @@ -421,7 +426,7 @@ static void test_map_parallel(void) int data[2]; map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), - MAP_SIZE); + MAP_SIZE, map_flags); if (map_fd < 0) { printf("failed to create map for parallel test '%s'\n", strerror(errno)); @@ -463,7 +468,7 @@ static void test_map_parallel(void) assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT); } -int main(void) +static void run_all_tests(void) { test_hashmap_sanity(0, NULL); test_percpu_hashmap_sanity(0, NULL); @@ -474,6 +479,14 @@ int main(void) test_map_large(); test_map_parallel(); test_map_stress(); +} + +int main(void) +{ + map_flags = 0; + run_all_tests(); + map_flags = BPF_F_NO_PREALLOC; + run_all_tests(); printf("test_maps: OK\n"); return 0; } diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 563c507..4b51a90 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -1198,7 +1198,7 @@ static int create_map(void) int map_fd; map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, - sizeof(long long), sizeof(long long), 1024); + sizeof(long long), sizeof(long long), 1024, 0); if (map_fd < 0) printf("failed to create map '%s'\n", strerror(errno)); @@ -1210,7 +1210,7 @@ static int create_prog_array(void) int map_fd; map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, - sizeof(int), sizeof(int), 4); + sizeof(int), sizeof(int), 4, 0); if (map_fd < 0) printf("failed to create prog_array '%s'\n", strerror(errno)); |