Skip to content

Commit

Permalink
bpf/benchs: Add benchmarks for comparing hashmap lookups w/ vs. w/out…
Browse files Browse the repository at this point in the history
… bloom filter

This patch adds benchmark tests for comparing the performance of hashmap
lookups without the bloom filter vs. hashmap lookups with the bloom filter.

Checking the bloom filter first for whether the element exists should
overall enable a higher throughput for hashmap lookups, since if the
element does not exist in the bloom filter, we can avoid a costly lookup in
the hashmap.

On average, using 5 hash functions in the bloom filter tended to perform
the best across the widest range of different entry sizes. The benchmark
results using 5 hash functions (running on 8 threads on a machine with one
numa node, and taking the average of 3 runs) were roughly as follows:

value_size = 4 bytes -
	10k entries: 30% faster
	50k entries: 40% faster
	100k entries: 40% faster
	500k entres: 70% faster
	1 million entries: 90% faster
	5 million entries: 140% faster

value_size = 8 bytes -
	10k entries: 30% faster
	50k entries: 40% faster
	100k entries: 50% faster
	500k entres: 80% faster
	1 million entries: 100% faster
	5 million entries: 150% faster

value_size = 16 bytes -
	10k entries: 20% faster
	50k entries: 30% faster
	100k entries: 35% faster
	500k entres: 65% faster
	1 million entries: 85% faster
	5 million entries: 110% faster

value_size = 40 bytes -
	10k entries: 5% faster
	50k entries: 15% faster
	100k entries: 20% faster
	500k entres: 65% faster
	1 million entries: 75% faster
	5 million entries: 120% faster

Signed-off-by: Joanne Koong <joannekoong@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20211027234504.30744-6-joannekoong@fb.com
  • Loading branch information
jkoong-fb authored and Alexei Starovoitov committed Oct 28, 2021
1 parent 57fd1c6 commit f44bc54
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 5 deletions.
23 changes: 18 additions & 5 deletions tools/testing/selftests/bpf/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,22 @@ void hits_drops_report_progress(int iter, struct bench_res *res, long delta_ns)
printf("Iter %3d (%7.3lfus): ",
iter, (delta_ns - 1000000000) / 1000.0);

printf("hits %8.3lfM/s (%7.3lfM/prod), drops %8.3lfM/s\n",
hits_per_sec, hits_per_prod, drops_per_sec);
printf("hits %8.3lfM/s (%7.3lfM/prod), drops %8.3lfM/s, total operations %8.3lfM/s\n",
hits_per_sec, hits_per_prod, drops_per_sec, hits_per_sec + drops_per_sec);
}

void hits_drops_report_final(struct bench_res res[], int res_cnt)
{
int i;
double hits_mean = 0.0, drops_mean = 0.0;
double hits_stddev = 0.0, drops_stddev = 0.0;
double hits_mean = 0.0, drops_mean = 0.0, total_ops_mean = 0.0;
double hits_stddev = 0.0, drops_stddev = 0.0, total_ops_stddev = 0.0;
double total_ops;

for (i = 0; i < res_cnt; i++) {
hits_mean += res[i].hits / 1000000.0 / (0.0 + res_cnt);
drops_mean += res[i].drops / 1000000.0 / (0.0 + res_cnt);
}
total_ops_mean = hits_mean + drops_mean;

if (res_cnt > 1) {
for (i = 0; i < res_cnt; i++) {
Expand All @@ -115,14 +117,21 @@ void hits_drops_report_final(struct bench_res res[], int res_cnt)
drops_stddev += (drops_mean - res[i].drops / 1000000.0) *
(drops_mean - res[i].drops / 1000000.0) /
(res_cnt - 1.0);
total_ops = res[i].hits + res[i].drops;
total_ops_stddev += (total_ops_mean - total_ops / 1000000.0) *
(total_ops_mean - total_ops / 1000000.0) /
(res_cnt - 1.0);
}
hits_stddev = sqrt(hits_stddev);
drops_stddev = sqrt(drops_stddev);
total_ops_stddev = sqrt(total_ops_stddev);
}
printf("Summary: hits %8.3lf \u00B1 %5.3lfM/s (%7.3lfM/prod), ",
hits_mean, hits_stddev, hits_mean / env.producer_cnt);
printf("drops %8.3lf \u00B1 %5.3lfM/s\n",
printf("drops %8.3lf \u00B1 %5.3lfM/s, ",
drops_mean, drops_stddev);
printf("total operations %8.3lf \u00B1 %5.3lfM/s\n",
total_ops_mean, total_ops_stddev);
}

const char *argp_program_version = "benchmark";
Expand Down Expand Up @@ -357,6 +366,8 @@ extern const struct bench bench_pb_custom;
extern const struct bench bench_bloom_lookup;
extern const struct bench bench_bloom_update;
extern const struct bench bench_bloom_false_positive;
extern const struct bench bench_hashmap_without_bloom;
extern const struct bench bench_hashmap_with_bloom;

static const struct bench *benchs[] = {
&bench_count_global,
Expand All @@ -381,6 +392,8 @@ static const struct bench *benchs[] = {
&bench_bloom_lookup,
&bench_bloom_update,
&bench_bloom_false_positive,
&bench_hashmap_without_bloom,
&bench_hashmap_with_bloom,
};

static void setup_benchmark()
Expand Down
57 changes: 57 additions & 0 deletions tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,41 @@ static void false_positive_setup(void)
}
}

static void hashmap_with_bloom_setup(void)
{
struct bpf_link *link;

ctx.use_hashmap = true;
ctx.hashmap_use_bloom = true;

ctx.skel = setup_skeleton();

populate_maps();

link = bpf_program__attach(ctx.skel->progs.bloom_hashmap_lookup);
if (!link) {
fprintf(stderr, "failed to attach program!\n");
exit(1);
}
}

static void hashmap_no_bloom_setup(void)
{
struct bpf_link *link;

ctx.use_hashmap = true;

ctx.skel = setup_skeleton();

populate_maps();

link = bpf_program__attach(ctx.skel->progs.bloom_hashmap_lookup);
if (!link) {
fprintf(stderr, "failed to attach program!\n");
exit(1);
}
}

static void measure(struct bench_res *res)
{
unsigned long total_hits = 0, total_drops = 0, total_false_hits = 0;
Expand Down Expand Up @@ -418,3 +453,25 @@ const struct bench bench_bloom_false_positive = {
.report_progress = false_hits_report_progress,
.report_final = false_hits_report_final,
};

const struct bench bench_hashmap_without_bloom = {
.name = "hashmap-without-bloom",
.validate = validate,
.setup = hashmap_no_bloom_setup,
.producer_thread = producer,
.consumer_thread = consumer,
.measure = measure,
.report_progress = hits_drops_report_progress,
.report_final = hits_drops_report_final,
};

const struct bench bench_hashmap_with_bloom = {
.name = "hashmap-with-bloom",
.validate = validate,
.setup = hashmap_with_bloom_setup,
.producer_thread = producer,
.consumer_thread = consumer,
.measure = measure,
.report_progress = hits_drops_report_progress,
.report_final = hits_drops_report_final,
};
17 changes: 17 additions & 0 deletions tools/testing/selftests/bpf/benchs/run_bench_bloom_filter_map.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,20 @@ subtitle "value_size: $v bytes, # threads: $t, # hashes: $h"
done
done
done

header "Hashmap without bloom filter vs. hashmap with bloom filter (throughput, 8 threads)"
for v in 2 4 8 16 40; do
for h in {1..10}; do
subtitle "value_size: $v, # hashes: $h"
for e in 10000 50000 75000 100000 250000 500000 750000 1000000 2500000 5000000; do
printf "%'d entries -\n" $e
printf "\t"
summarize_total "Hashmap without bloom filter: " \
"$($RUN_BENCH --nr_hash_funcs $h --nr_entries $e --value_size $v -p 8 hashmap-without-bloom)"
printf "\t"
summarize_total "Hashmap with bloom filter: " \
"$($RUN_BENCH --nr_hash_funcs $h --nr_entries $e --value_size $v -p 8 hashmap-with-bloom)"
done
printf "\n"
done
done
12 changes: 12 additions & 0 deletions tools/testing/selftests/bpf/benchs/run_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ function percentage()
echo "$*" | sed -E "s/.*Percentage\s=\s+([0-9]+\.[0-9]+).*/\1/"
}

function total()
{
echo "$*" | sed -E "s/.*total operations\s+([0-9]+\.[0-9]+ ± [0-9]+\.[0-9]+M\/s).*/\1/"
}

function summarize()
{
bench="$1"
Expand All @@ -46,3 +51,10 @@ function summarize_percentage()
summary=$(echo $2 | tail -n1)
printf "%-20s %s%%\n" "$bench" "$(percentage $summary)"
}

function summarize_total()
{
bench="$1"
summary=$(echo $2 | tail -n1)
printf "%-20s %s\n" "$bench" "$(total $summary)"
}

0 comments on commit f44bc54

Please sign in to comment.