Skip to content

Commit

Permalink
Merge pull request #900 from Monkey857/develop
Browse files Browse the repository at this point in the history
eBPF_Performance_Analysis:添加测试代码
  • Loading branch information
chenamy2017 authored Sep 20, 2024
2 parents fd4679d + c6d30b3 commit 54a710b
Show file tree
Hide file tree
Showing 10 changed files with 946 additions and 10 deletions.
62 changes: 62 additions & 0 deletions eBPF_Supermarket/eBPF_Performance_Analysis/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \
| sed 's/arm.*/arm/' \
| sed 's/aarch64/arm64/' \
| sed 's/ppc64le/powerpc/' \
| sed 's/mips.*/mips/' \
| sed 's/riscv64/riscv/' \
| sed 's/loongarch64/loongarch/')
APP = src/ebpf_performance

# 编译器标志
CFLAGS=-g -O2 -Wall
BPF_CFLAGS=-g -O2 -target bpf

# 要链接的库
LIBS=-lbpf -lelf -lz -lzstd

# 默认目标
.PHONY: default
default: bpf

# 安装必要的依赖
.PHONY: deps
deps:
sudo apt-get update && \
sudo apt-get install -y clang libelf1 libelf-dev zlib1g-dev libbpf-dev \
linux-tools-$$(uname -r) linux-cloud-tools-$$(uname -r) \
libpcap-dev gcc-multilib build-essential lolcat

# 头文件目录
INCLUDE_DIRS=-I/usr/include/x86_64-linux-gnu -I. -I./include -I./include/bpf -I./include/helpers
# 生成 vmlinux.h
.PHONY: vmlinux
vmlinux:
bpftool btf dump file /sys/kernel/btf/kvm format c > ./include/vmlinux.h

# 编译BPF程序
$(APP).bpf.o: $(APP).bpf.c vmlinux
clang $(BPF_CFLAGS) -D__TARGET_ARCH_$(ARCH) $(INCLUDE_DIRS) -c $< -o $@

# 生成BPF骨架文件
$(APP).skel.h: $(APP).bpf.o
bpftool gen skeleton $< > $@

# 编译用户空间应用程序
${APP}.o: ${APP}.c
clang $(CFLAGS) $(INCLUDE_DIRS) -c $< -o $@

# 链接用户空间应用程序与库
$(notdir $(APP)): ${APP}.o $(HELPERS_OBJ_FILES)
clang -Wall $(CFLAGS) ${APP}.o $(HELPERS_OBJ_FILES) $(LIBS) -o $@
@echo "BPF program compiled successfully."

# bpf 目标
.PHONY: bpf
bpf: $(APP).skel.h $(APP).bpf.o ${APP}.o $(HELPERS_OBJ_FILES) $(notdir $(APP))


clean:
rm -f src/*.o src/*.skel.h src/helpers/*.o
sudo rm -rf $(notdir $(APP)) include/vmlinux.h temp


Original file line number Diff line number Diff line change
Expand Up @@ -421,19 +421,65 @@ GRUB_CMDLINE_LINUX="resume=/dev/mapper/ao_anolis-swap rd.lvm.lv=ao_anolis/root r

测试用例设计:

用例1:

| 事项 | 内容 |
| ---------------- | ------------------------------------------------------------ |
| 场景 | 在同一系统环境下,针对不同类型的eBPF Map(如HashMap、ArrayMap、LRUHashMap等)进行性能测试。测试内容包括增删改查(CRUD)操作的耗时情况。 |
| 测试目的 | 评估不同类型的eBPF Map在高频率的CRUD操作下的性能表现,特别是针对相同操作次数所需的时间差异。 |
| 负载压力产生方法 | 在ebpf程序中对不同类型的Map设置一个固定的操作次数并记录每次操作的开始和结束时间。确保每个Map类型在相同的条件下测试。 |
| 执行脚本 | map_difference.py |
| 执行方法 | 部署并加载eBPF程序;执行./run_ebpf_and_process.sh脚本;查看分析结果 |
| 与生产环境差异 | 测试环境为隔离的虚拟机,Map的操作次数可能高于生产环境的实际负载,以便突显性能差异。 |
| 指标要求 | 每种Map类型的CRUD操作次数必须相同;相同操作次数下,不同Map类型的耗时差异不应超过预期范围; |
| 测试结果 | 记录每种Map类型的总操作时间,并汇总到报告中,生成柱状图或折线图展示不同Map类型的性能差异。 |
| 测试结果分析 | 分析不同Map类型在CRUD操作下的性能差异,确定性能瓶颈。评估哪种Map类型在高并发场景下表现最优。 |
| 后续Action | 如果某种Map类型在测试中表现出显著劣势,建议在生产环境中慎用或优化其使用场景。 |
| 场景 | 在系统CPU高负载情况下(CPU使用率约为80%)并且CPU频率固定,针对不同类型的eBPF Map进行相同次数的增删改查操作,这里会多次变化操作次数来说明实验结果的正确性。查看每种类型的Map在CPU高负载的情况下对于不同操作次数的耗时情况。 |
| 测试目的 | 评估不同类型的eBPF Map在CPU高负载的情况下,进行相同次数的CRUD操作时的性能表现,特别是记录每种类型的Map在处理时间上的差异。 |
| 负载压力产生方法 | 使用stress-ng来对CPU进行加压,并且每次测试时,通过设置不同的操作次数来对ebpf程序进行CRUD的压力控制。 |
| 执行脚本 | map_difference_01.py |
| 执行方法 | 执行./run_ebpf_and_process.sh脚本;查看分析结果 |
| 与生产环境差异 | 测试环境为隔离的虚拟机,实际的CPU核心数要比生产环境少,并且在负载压力产生方面,也和生产环境有差异。 |
| 指标要求 | 每次测试之前,要控制好每种Map类型的CRUD操作次数必须相同;相同操作次数下,不同Map类型的耗时差异不应超过理论分析的预期范围; |
| 测试结果 | 记录每种Map类型的CRUD操作时间,并汇总到报告中,生成柱状图或折线图展示不同Map类型的性能差异。 |
| 测试结果分析 | 通过测试结果的内容,并结合python的数据分析能力,来分析出在高CPU负载的情况下,哪种Map类型更适合使用,并且验证理论分析的结果是否正确。 |
| 后续Action | 将详细的测试分析结果编写到文档中,并且给出一个不同Map类型的适用场景的有力指导。 |

用例2:

| 事项 | 内容 |
| ---------------- | ------------------------------------------------------------ |
| 场景 | 在系统内存高负载情况下(内存使用率约为75%)并且CPU频率固定,针对不同类型的eBPF Map进行相同次数的增删改查操作,这里会多次变化操作次数来说明实验结果的正确性。查看每种类型的Map在内存高负载的情况下对于不同操作次数的耗时情况。 |
| 测试目的 | 评估不同类型的eBPF Map在内存高负载的情况下,进行相同次数的CRUD操作时的性能表现,特别是记录每种类型的Map在处理时间上的差异。 |
| 负载压力产生方法 | 使用stress-ng来对内存进行加压,并且每次测试时,通过设置不同的操作次数来对ebpf程序进行CRUD的压力控制。 |
| 执行脚本 | map_difference_02.py |
| 执行方法 | 执行./run_ebpf_and_process.sh脚本;查看分析结果 |
| 与生产环境差异 | 测试环境为隔离的虚拟机,实际的内存总大小要比生产环境小,并且在负载压力产生方面,也和生产环境有差异。 |
| 指标要求 | 每次测试之前,要控制好每种Map类型的CRUD操作次数必须相同;相同操作次数下,不同Map类型的耗时差异不应超过理论分析的预期范围; |
| 测试结果 | 记录每种Map类型的CRUD操作时间,并汇总到报告中,生成柱状图或折线图展示不同Map类型的性能差异。 |
| 测试结果分析 | 通过测试结果的内容,并结合python的数据分析能力,来分析出在内存高负载的情况下,哪种Map类型更适合使用,并且验证理论分析的结果是否正确。 |
| 后续Action | 将详细的测试分析结果编写到文档中,并且给出一个不同Map类型的适用场景的有力指导。 |

用例3:

| 事项 | 内容 |
| ---------------- | ------------------------------------------------------------ |
| 场景 | 在系统开启CPU的P-states和C-states时,针对不同类型的eBPF Map进行相同次数的增删改查操作,这里会多次变化操作次数来说明实验结果的正确性。查看每种类型的Map在系统开启CPU的P-states和C-states的情况下对于不同操作次数的耗时情况。 |
| 测试目的 | 评估不同类型的eBPF Map在内存高负载的情况下,进行相同次数的CRUD操作时的性能表现,特别是记录每种类型的Map在处理时间上的差异。 |
| 负载压力产生方法 | 使用stress-ng来对系统进行加压,并且每次测试时,通过设置不同的操作次数来对ebpf程序进行CRUD的压力控制。 |
| 执行脚本 | map_difference_03.py |
| 执行方法 | 执行./run_ebpf_and_process.sh脚本;查看分析结果 |
| 与生产环境差异 | 测试环境为隔离的虚拟机,实际的CPU频率变化与生产环境有一定的差异,并且在负载压力产生方面,也和生产环境有差异。 |
| 指标要求 | 每次测试之前,要控制好每种Map类型的CRUD操作次数必须相同;相同操作次数下,不同Map类型的耗时差异不应超过理论分析的预期范围; |
| 测试结果 | 记录每种Map类型的CRUD操作时间,并汇总到报告中,生成柱状图或折线图展示不同Map类型的性能差异。 |
| 测试结果分析 | 通过测试结果的内容,并结合python的数据分析能力,来分析出在内存高负载的情况下,哪种Map类型更适合使用,并且验证理论分析的结果是否正确。 |
| 后续Action | 将详细的测试分析结果编写到文档中,并且给出一个不同Map类型的适用场景的有力指导。 |

用例4:

| 事项 | 内容 |
| ---------------- | ------------------------------------------------------------ |
| 场景 | 在系统关闭CPU的P-states和C-states时,针对不同类型的eBPF Map进行相同次数的增删改查操作,这里会多次变化操作次数来说明实验结果的正确性。查看每种类型的Map在系统关闭CPU的P-states和C-states的情况下对于不同操作次数的耗时情况。 |
| 测试目的 | 评估不同类型的eBPF Map在内存高负载的情况下,进行相同次数的CRUD操作时的性能表现,特别是记录每种类型的Map在处理时间上的差异。 |
| 负载压力产生方法 | 使用stress-ng来对系统进行加压,并且每次测试时,通过设置不同的操作次数来对ebpf程序进行CRUD的压力控制。 |
| 执行脚本 | map_difference_04.py |
| 执行方法 | 执行./run_ebpf_and_process.sh脚本,查看分析结果。 |
| 与生产环境差异 | 测试环境为隔离的虚拟机,实际的CPU频率变化与生产环境有一定的差异,并且在负载压力产生方面,也和生产环境有差异。 |
| 指标要求 | 每次测试之前,要控制好每种Map类型的CRUD操作次数必须相同;相同操作次数下,不同Map类型的耗时差异不应超过理论分析的预期范围; |
| 测试结果 | 记录每种Map类型的CRUD操作时间,并汇总到报告中,生成柱状图或折线图展示不同Map类型的性能差异。 |
| 测试结果分析 | 通过测试结果的内容,并结合python的数据分析能力,来分析出在关闭CPU的P-states和C-states的情况下,哪种Map类型更适合使用,并且验证理论分析的结果是否正确。 |
| 后续Action | 将详细的测试分析结果编写到文档中,并且给出一个不同Map类型的适用场景的有力指导。 |

#### 4.2对挂载点类型的测试方案:

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2024 The EBPF performance testing Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: [email protected]
//
// Kernel space BPF program used for eBPF performance testing.
#ifndef __ANALYZE_MAP_H
#define __ANALYZE_MAP_H

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include "common.h"

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);//12KB
__type(key, u32);
__type(value,u64);
} hash_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1024);
__type(key, u32);
__type(value,u64);
} array_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 1024);
__type(key, u32);
__type(value,u64);
} percpu_array_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
__uint(max_entries, 1024);
__type(key, u32);
__type(value,u64);
} percpu_hash_map SEC(".maps");
//在内核态中将数据信息存入到相应的map中
volatile __u64 k = 0;
#define MAX_ENTRIES 1024
static int analyze_maps(struct trace_event_raw_sys_enter *args,void *rb,
struct common_event *e){
u32 idx,counts;
u64 syscall_id = (u64)args->id;
// 使用原子操作递增k,并获取递增前的值
idx = __sync_fetch_and_add(&k, 1);
// 确保k在0到MAX_ENTRIES之间循环(避免同步问题)
if (idx >= MAX_ENTRIES) {
__sync_bool_compare_and_swap(&k, idx + 1, 0);
idx = 0;
}
// 向hash、array类型的map中存入数据
bpf_map_update_elem(&hash_map, &idx, &syscall_id, BPF_ANY);
bpf_map_update_elem(&array_map, &idx, &syscall_id, BPF_ANY);
bpf_map_update_elem(&percpu_array_map,&idx,&syscall_id,BPF_ANY);
bpf_map_update_elem(&percpu_hash_map,&idx,&syscall_id,BPF_ANY);
bpf_map_update_elem(&percpu_hash_map,&idx,&syscall_id,BPF_ANY);
RESERVE_RINGBUF_ENTRY(rb, e);
e->test_ringbuff.key = idx;
e->test_ringbuff.value = syscall_id;
bpf_ringbuf_submit(e, 0);
bpf_printk("syscall_id = %llu\n", syscall_id);
return 0;
}
#endif /* __ANALYZE_MAP_H */
60 changes: 60 additions & 0 deletions eBPF_Supermarket/eBPF_Performance_Analysis/include/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024 The EBPF performance testing Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: [email protected]
//
// Kernel space BPF program used for eBPF performance testing.
#ifndef __EBPF_PERFORMANCE_H
#define __EBPF_PERFORMANCE_H

typedef unsigned int __u32;
typedef long long unsigned int __u64;

#define OPTIONS_LIST "-a"
#define RING_BUFFER_TIMEOUT_MS 100
#define OUTPUT_INTERVAL(SECONDS) sleep(SECONDS)

#define PRINT_USAGE_ERR() \
do { \
fprintf(stderr, "Please specify exactly one option from %s.\n", \
OPTIONS_LIST); \
argp_state_help(state, stdout, ARGP_HELP_STD_HELP); \
} while (0)

#define SET_OPTION_AND_CHECK_USAGE(option, value) \
do { \
if (option == 0) { \
value = true; \
option = 1; \
} else { \
PRINT_USAGE_ERR(); \
} \
} while (0)
#define RESERVE_RINGBUF_ENTRY(rb, e) \
do { \
typeof(e) _tmp = bpf_ringbuf_reserve(rb, sizeof(*e), 0); \
if (!_tmp) \
return 0; \
e = _tmp; \
} while (0)
enum EventType {
NONE_TYPE,
EXECUTE_TEST_MAPS,
} event_type;

struct common_event{
union {
struct {
__u32 key;
__u64 value;
} test_ringbuff;
};
};
#endif
67 changes: 67 additions & 0 deletions eBPF_Supermarket/eBPF_Performance_Analysis/py/analy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pandas as pd
import matplotlib.pyplot as plt

# 步骤 1: 将 .txt 文件转换为 .csv 文件
input_txt_file = './output.txt' # 你的 .txt 文件路径
output_csv_file = './data.csv' # 输出 .csv 文件路径

# 读取 .txt 文件内容并写入 .csv 文件
with open(input_txt_file, 'r') as txt_file:
lines = txt_file.readlines()

# 写入 .csv 文件
with open(output_csv_file, 'w') as csv_file:
for line in lines:
# 替换多余空格为逗号,准备写入到 .csv 文件
formatted_line = ','.join(line.split())
csv_file.write(formatted_line + '\n')

# 步骤 2: 读取 .csv 文件并进行数据分析
data = pd.read_csv(output_csv_file, header=None)

# 给列命名,每三个数据为一组,分别对应 lookup、insert、delete 操作
data.columns = ['hash_lookup', 'hash_insert', 'hash_delete',
'array_lookup', 'array_insert', 'array_delete',
'percpu_array_lookup', 'percpu_array_insert', 'percpu_array_delete',
'percpu_hash_lookup', 'percpu_hash_insert', 'percpu_hash_delete']

# 计算每种 map 类型的平均操作时间
avg_hash = data[['hash_lookup', 'hash_insert', 'hash_delete']].mean()
avg_array = data[['array_lookup', 'array_insert', 'array_delete']].mean()
avg_percpu_array = data[['percpu_array_lookup', 'percpu_array_insert', 'percpu_array_delete']].mean()
avg_percpu_hash = data[['percpu_hash_lookup', 'percpu_hash_insert', 'percpu_hash_delete']].mean()

# 创建一个 DataFrame 来存储平均值
avg_table = pd.DataFrame({
'Operation': ['lookup', 'insert', 'delete'],
'Hash Map': avg_hash.values,
'Array Map': avg_array.values,
'Per-CPU Array': avg_percpu_array.values,
'Per-CPU Hash': avg_percpu_hash.values
})

# 打印平均值表格到控制台
print("Average Execution Time of eBPF Map Operations (in seconds):\n")
print(avg_table.to_string(index=False))

# 绘制平均操作时间的图表
plt.figure(figsize=(10, 6))

# 绘制四种 map 类型的平均时间曲线
operations = ['lookup', 'insert', 'delete']

plt.plot(operations, avg_hash, marker='o', linestyle='-', color='b', label='Hash')
plt.plot(operations, avg_array, marker='s', linestyle='-', color='r', label='Array')
plt.plot(operations, avg_percpu_array, marker='^', linestyle='-', color='g', label='Per-CPU Array')
plt.plot(operations, avg_percpu_hash, marker='d', linestyle='-', color='purple', label='Per-CPU Hash')

# 图表设置
plt.title('Average Execution Time of eBPF Map Operations')
plt.xlabel('Operation Type')
plt.ylabel('Time (seconds)')
plt.legend(loc='upper left')
plt.grid(True)

# 显示图表
plt.savefig('ebpf_map_operation_times.png') # 保存图表为文件
plt.show()
Loading

0 comments on commit 54a710b

Please sign in to comment.