Kernel
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- 43 participants
- 18659 discussions
Ian Rogers (1):
perf test bpf-counters: Add test for BPF event modifier
Tengda Wu (2):
perf stat: Support inherit events during fork() for bperf
perf test: Use sqrtloop workload to test bperf event
Veronika Molnarova (1):
perf test stat_bpf_counter.sh: Stabilize the test results
Xiaomeng Zhang (2):
perf stat: Increase perf_attr_map entries
perf stat: Fix incorrect display of bperf when event count is 0
tools/lib/perf/include/perf/bpf_perf.h | 1 +
tools/perf/builtin-stat.c | 1 +
tools/perf/tests/shell/stat_bpf_counters.sh | 79 ++++++++++-----
tools/perf/util/bpf_counter.c | 61 +++++++++---
tools/perf/util/bpf_skel/bperf_follower.bpf.c | 98 +++++++++++++++++--
tools/perf/util/bpf_skel/bperf_u.h | 5 +
tools/perf/util/target.h | 1 +
7 files changed, 198 insertions(+), 48 deletions(-)
--
2.34.1
2
7

[openeuler:OLK-5.10 2953/2953] kernel/locking/lockdep.o: warning: objtool: lockdep_unregister_key()+0x2ff: unreachable instruction
by kernel test robot 09 Jun '25
by kernel test robot 09 Jun '25
09 Jun '25
Hi Waiman,
First bad commit (maybe != root cause):
tree: https://gitee.com/openeuler/kernel.git OLK-5.10
head: dd32d51934d00fd319caec8710bd1a438bd69859
commit: b91170be2b1f1ef673f5e79c7a4beb5673a8f881 [2953/2953] locking/lockdep: Avoid potential access of invalid memory in lock_class
config: x86_64-randconfig-123-20250609 (https://download.01.org/0day-ci/archive/20250609/202506092002.S7MmpM4X-lkp@…)
compiler: clang version 20.1.2 (https://github.com/llvm/llvm-project 58df0ef89dd64126512e4ee27b4ac3fd8ddf6247)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250609/202506092002.S7MmpM4X-lkp@…)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp(a)intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202506092002.S7MmpM4X-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/locking/lockdep.o: warning: objtool: lockdep_unregister_key()+0x2ff: unreachable instruction
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
1
0
Support xcall prefetch.
Changes in v6:
- Only use one reserved kabi in task_struct for xcall.
- Free prefetch item after eventpoll_release_file() to avoid
possible competition between ep_prefetch_item_enqueue() and pfi free.
- Fix "echo > /proc/xcall/cpu_list" show problem.
Changes in v5:
- Fix dentry free before free_prefetch_item() and then UAF in
prefetch work by cancel_work_sync() before free pfi and move
free_prefetch_item() to the first of __fput().
- Fix __queue_work() oops bug.
- /proc/xcall/mask_list -> /proc/xcall/cpu_list
- Fix xcall_prefetch print data type.
- Update prefetch tracepoint, move xcall points definition
to separete header file.
- Make xcall_prefetch depends on EPOLL.
- Adjust xcall prefetch buf to 16KB by default.
- Add xcall_prefetch_init() function.
- Only use write lock in free_prefetch_item().
- Simplify xcall_read() and add some comment.
- Update commit message.
Changes in v4:
- Enable FAST_SYSCALL/IRQ and XCALL_PREFETCH by default.
- Fix xint sleeping function called from invalid context bug.
- free_prefetch_item() in file_free() instead of filp_close(), which
fix the alloc-queue and free competition.
- Fix kernel_read() warning for FMODE_READ not set.
- Add sock_from_file() limit for prefetch.
- Check NULL for rc_work.
- Simplfy the cpumask interface code, and rename
to "/proc/xcall/mask_list".
- Remove the xcall_cache_pages_order interface.
- tracepoint update: fd -> file.
- Simplify the xcall_read() function again.
- Handle copy_to_user() return value.
- Remove unused XCALL_CACHE_QUEUED.
- Update the commit message.
Changes in v3:
- Add XCALL_PREFETCH config to isolate feature code.
- Split the /proc/xxx interface code out to independent patches, which
will make it clear.
- Update the cpumask interface to "/proc/xcall/numa_mask", and it can
set the numa mask of all numas one time.
- Add xcall select count to make xcall_cache_pages_order adjust safe.
- Introduce xcall_read_start/end() to make it clear.
- Simplify the xcall_read() function.
- Use cpumask_next() instead of get_nth_cpu_in_cpumask() function.
- Use independent cpu select policy function.
- Remove some unnecessary pr_err().
- Update the commit message.
Changes in v2:
- Upadte the xcall prefetch state machine, remove the queued state and
add prefetch, cancel states.
- Remove the pfi lock and use atomic variables.
- Change the 'xcall select' semantics and simplify the code a lot.
- Remove keep_running, remove unrelated code.
- Remove the count in struct read_cache_entry, and use
percpu hit/miss count.
- Remove sync mode, so remove struct read_cache_entry
in struct task_struct.
- Use hash table to find prefetch item for a file, which will not
change the file struct KABI.
- Use rwlock instead of spinlock for hash table.
- Use alloc_page() instead kmalloc() to align 4KB.
- Update the commit message.
Jinjie Ruan (7):
arm64: Introduce Xint software solution
arm64: Add debugfs dir for xint
eventpoll: xcall: Support async prefetch data in epoll
xcall: Add /proc/xcall/prefetch dir for performance tuning
xcall: Add /proc/xcall/cpu_list for performance tuning
xcall: eventpoll: add tracepoint
config: Enable FAST_SYSCALL/IRQ and XCALL_PREFETCH by default
Liao Chen (1):
revert kpti bypass
Yipeng Zou (3):
arm64: Introduce xcall a faster svc exception handling
arm64: Faster SVC exception handler with xcall
xcall: Introduce xcall_select to mark special syscall
arch/Kconfig | 81 +++++
arch/arm64/Kconfig | 2 +
arch/arm64/configs/openeuler_defconfig | 7 +
arch/arm64/include/asm/cpucaps.h | 2 +
arch/arm64/include/asm/exception.h | 3 +
arch/arm64/kernel/asm-offsets.c | 3 +
arch/arm64/kernel/cpufeature.c | 56 ++++
arch/arm64/kernel/entry-common.c | 22 ++
arch/arm64/kernel/entry.S | 183 ++++++++++-
arch/arm64/kernel/syscall.c | 57 ++++
drivers/irqchip/irq-gic-v3.c | 130 ++++++++
fs/eventpoll.c | 409 +++++++++++++++++++++++++
fs/file_table.c | 1 +
fs/proc/base.c | 150 +++++++++
fs/read_write.c | 10 +-
include/linux/fs.h | 35 +++
include/linux/hardirq.h | 5 +
include/linux/irqchip/arm-gic-v3.h | 13 +
include/linux/sched.h | 4 +
include/linux/xcall.h | 19 ++
include/trace/events/xcall.h | 106 +++++++
kernel/fork.c | 25 ++
kernel/irq/debugfs.c | 33 ++
kernel/irq/internals.h | 18 ++
kernel/irq/irqdesc.c | 19 ++
kernel/irq/proc.c | 10 +
kernel/softirq.c | 73 +++++
27 files changed, 1473 insertions(+), 3 deletions(-)
create mode 100644 include/linux/xcall.h
create mode 100644 include/trace/events/xcall.h
--
2.34.1
2
12
Ian Rogers (1):
perf test bpf-counters: Add test for BPF event modifier
Tengda Wu (2):
perf stat: Support inherit events during fork() for bperf
perf test: Use sqrtloop workload to test bperf event
Veronika Molnarova (1):
perf test stat_bpf_counter.sh: Stabilize the test results
Xiaomeng Zhang (2):
perf stat: Increase perf_attr_map entries
perf stat: Fix incorrect display of bperf when event count is 0
tools/lib/perf/include/perf/bpf_perf.h | 1 +
tools/perf/builtin-stat.c | 1 +
tools/perf/tests/shell/stat_bpf_counters.sh | 79 ++++++++++-----
tools/perf/util/bpf_counter.c | 61 +++++++++---
tools/perf/util/bpf_skel/bperf_follower.bpf.c | 98 +++++++++++++++++--
tools/perf/util/bpf_skel/bperf_u.h | 5 +
tools/perf/util/target.h | 1 +
7 files changed, 198 insertions(+), 48 deletions(-)
--
2.34.1
2
7
hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/ICDKL2
--------------------------------
overlayfs has two types of inode, the overlayfs inode generated by
overlayfs and the real inode of the file. When IMA does the measurement,
process_measurement() will try to detect file content changes for files on
a overlayfs filesystem based on the i_version number of the real inode. But
now comparing with value of overlayfs inode, results in always
re-evaluating the file's integrity.
Therefore, ima_collect_measurement() should update iint->iversion with
real_inode iversion. Also, ima_check_last_writer() should compare i_version
base on real_inode.
This patch is based on the implementation of upstream patch (see below Link
tag). Due to merging the pre-patch to resolve conflicts introduces KABI
changes, we don't fix this with the mainline version.
Link: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/comm…
Fixes: b836c4d29f27 ("ima: detect changes to the backing overlay file")
Signed-off-by: Gu Bowen <gubowen5(a)huawei.com>
---
security/integrity/ima/ima_api.c | 2 +-
security/integrity/ima/ima_main.c | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index d88d7fb9f9a5..69bb71331e3f 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -278,7 +278,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
* which do not support i_version, support is limited to an initial
* measurement/appraisal/audit.
*/
- i_version = inode_query_iversion(inode);
+ i_version = inode_query_iversion(real_inode);
hash.hdr.algo = algo;
/* Initialize hash digest to 0's in case of failure */
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index c211a2c5f297..efa20bd18b97 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -222,16 +222,19 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
{
fmode_t mode = file->f_mode;
bool update;
+ struct inode *real_inode;
if (!(mode & FMODE_WRITE))
return;
mutex_lock(&iint->mutex);
if (atomic_read(&inode->i_writecount) == 1) {
+ real_inode = d_real_inode(file_dentry(file));
+
update = test_and_clear_bit(IMA_UPDATE_XATTR,
&iint->atomic_flags);
- if (!IS_I_VERSION(inode) ||
- !inode_eq_iversion(inode, iint->version) ||
+ if (!IS_I_VERSION(real_inode) ||
+ !inode_eq_iversion(real_inode, iint->version) ||
(iint->flags & IMA_NEW_FILE)) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
iint->measured_pcrs = 0;
--
2.25.1
2
1
hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IC88OM
--------------------------------
Add user manual for the MPAM features.
Signed-off-by: Zeng Heng <zengheng4(a)huawei.com>
---
Documentation/arch/arm64/mpam.md | 587 +++++++++++++++++++++++++++++++
1 file changed, 587 insertions(+)
create mode 100644 Documentation/arch/arm64/mpam.md
diff --git a/Documentation/arch/arm64/mpam.md b/Documentation/arch/arm64/mpam.md
new file mode 100644
index 000000000000..60f62cd7f781
--- /dev/null
+++ b/Documentation/arch/arm64/mpam.md
@@ -0,0 +1,587 @@
+MPAM 用户手册
+=========
+
+# 1 MPAM 简介
+
+MPAM(Memory system component Partioning and Monitoring)是Arm Architecture v8.4的拓展特性。用于解决服务器系统中,混合部署不同类型业务时,由于共享资源的竞争(L3/L2 Cache,MATA),而带来的关键应用性能下降或者系统整体性能下降问题。
+
+MPAM的应用可针对不同业务,将同时作用于硬件访存路径上产生的竞争和冲突进行隔离控制,从而帮助提升服务器利用率,降低服务部署成本。
+
+本手册只适用于OLK-6.6软件版本。
+
+# 2 内核编译选项
+
+配置 CONFIG_ARM64_MPAM=y 后,即使能MPAM完整功能。
+
+# 3 内核启动参数
+
+启动流程默认关闭MPAM,启动MPAM初始化需要**cmdline**添加**arm64.mpam**参数配置后重启机器。
+
+# 3 接口总览
+
+MPAM功能通过resctrl文件系统呈现,挂载点位于 */sys/fs/resctrl* 。系统启动后,需要手动挂载resctrl文件系统。
+
+## 3.1 系统挂载参数
+
+resctrl可以通过添加挂载参数支持多种挂载方式,具体指令如下:
+
+~~~
+# mount -t resctrl resctrl [-o cdp[,cdpl2][,debug][,l2]] /sys/fs/resctrl
+~~~
+
+挂载参数包括:
+
+* cdp: 针对L3缓存,根据访问指令和访问数据分别配置。
+* cdpl2: 针对L2缓存,根据访问指令和访问数据分别配置。
+* debug: 使能调试接口访问。
+* l2: 使能L2缓存配置和监控功能,默认关闭MPAM L2功能。
+
+## 3.2 resctrl 系统目录介绍
+
+### 3.2.1 Info 目录
+
+Info 目录包含有关已启用资源的信息,每个资源都有其自己的子目录,子目录的名称反映了资源的名称。
+
+每个子目录包含以下与分配相关的文件:
+
+缓存资源(L3/L2)子目录包含以下与分配相关的文件:
+
+**num_closids**: 适用于该资源的有效CLOSID(Class of Service ID)数量。内核会以所有已启用资源中最小的CLOSID数量作为限制。
+
+**cbm_mask**: 适用于该资源的有效位掩码(bitmask)。
+
+**min_cbm_bits**: 写入掩码时必须设置的连续位的最小数量。
+
+**shareable_bits**: 与其他执行实体共享资源的位掩码。用户在设置独占缓存分区时可以使用此字段。
+
+**bit_usage**: 标注了资源所有实例的使用情况的容量位掩码。说明如下:
+
+ * *0*: 对应区域未使用。当系统的资源已被分配,且在“bit_usage”中发现“0”时,这表明资源被浪费了。
+
+ * *H*: 对应区域仅由硬件使用,但可供软件使用。如果资源的“shareable_bits”中有位被设置,但这些位并未全部出现在资源组的分配方案中,则“shareable_bits”中出现但未分配给资源组的位将被标记为“H”。
+
+ * *X*: 对应区域可供共享,并被硬件和软件使用。这些位同时出现在“shareable_bits”和资源组的分配中。
+
+ * *S*: 对应区域由软件使用,并可供共享。
+
+ * *E*: 对应区域被一个资源组独占使用,不允许共享。
+
+**sparse_masks**: 指示是否支持CBM(Capacity Bit Mask)中的非连续1值。
+
+ * *0*: 仅支持CBM中的连续1值。
+
+ * *1*: 支持CBM中的非连续1值。
+
+MB(Memory bandwidth,内存带宽)子目录包含以下与分配相关的文件:
+
+**min_bandwidth**: 用户可以请求的最小内存带宽百分比。
+
+**bandwidth_gran**: 内存带宽百分比分配的粒度。分配的带宽百分比会四舍五入到硬件上可用的下一个控制步长。可用的带宽控制步长为:
+~~~
+min_bandwidth + N * bandwidth_gran
+~~~
+
+**delay_linear**: 指示延迟刻度是线性还是非线性的。该字段仅用于信息参考。
+
+如果支持监控功能,则会存在一个名为 L3_MON 和 MB_MON 的目录,其中包含以下文件:
+
+**num_rmids**: 可用的RMID(Resource Monitoring ID)数量。这是可以创建的“CTRL_MON”+“MON”组的最大数量。
+
+**mon_features**: 如果为该资源启用了监控功能,则列出监控事件。例如:
+~~~
+# grep . /sys/fs/resctrl/info/*_MON/mon_features
+/sys/fs/resctrl/info/L3_MON/mon_features:llc_occupancy
+/sys/fs/resctrl/info/MB_MON/mon_features:mbm_total_bytes
+~~~
+
+**max_threshold_occupancy**: 读/写文件,提供一个最大值(以字节为单位),低于此设定值下,之前使用过的LLC_occupancy计数器可以被考虑重新分配使用。
+
+> 请注意,一旦释放了RMID(资源监控ID),它可能不会立即可用,因为RMID仍然与之前使用该RMID的缓存行相关联。因此,这些RMID会被放入一个“待定”列表中,并在缓存占用量降低后再次检查。如果系统中存在大量处于“待定”状态的RMID,但它们尚未准备好被使用,用户在执行mkdir操作时可能会看到-EBUSY错误。
+
+> max_threshold_occupancy是一个用户可配置的值,用于确定在什么占用量下可以释放一个RMID。
+
+最后,在 Info 目录的顶层有一个名为 **last_cmd_status** 的文件。每次通过文件系统发出“命令”(例如创建新目录或写入任何控制文件)时,该文件都会被重置。如果命令成功,文件内容将显示为“ok”。如果命令失败,它将提供比文件操作错误返回更详细的信息。例如:
+~~~
+# echo "MB:1=110" > schemata
+-bash: echo: write error: Invalid argument
+# cat /sys/fs/resctrl/info/last_cmd_status
+MB value 110 out of range [0,100]
+~~~
+
+### 3.2.2 资源分配和监控
+
+资源组在resctrl文件系统中以目录的形式表示。默认组是根目录,刚挂载后,它拥有系统中的所有任务和CPU,并且可以充分利用所有资源。
+
+在支持RDT(资源分配技术)控制功能的系统中,可以在根目录下创建额外的目录,这些目录指定了每种资源的不同数量(参见下面的“schemata”)。根目录和这些额外的顶级目录在下文中被称为“CTRL_MON”组。
+
+在支持RDT监控的系统中,根目录和其他顶级目录中包含一个名为“mon_groups”的目录,在其中可以创建额外的目录来监控其父“CTRL_MON”组中任务的子集。这些在本文档的其余部分被称为“MON”组。
+
+删除一个目录会将其所代表的组拥有的所有任务和CPU移动到其父目录。删除一个创建的“CTRL_MON”组将自动删除其下所有的“MON”组。
+
+支持将“MON”组目录移动到一个新的父“CTRL_MON”组,以便在不影响其监控数据或分配的任务的情况下更改“MON”组的资源分配。此操作不适用于监控CPU的“MON”组。目前,除了简单地重命名“CTRL_MON”或“MON”组之外,不支持其他任何移动操作。
+
+所有组包含以下文件:
+
+**tasks**: 读取此文件将显示属于该组的所有任务列表。将任务ID写入该文件会将任务添加到该组中。可以通过用逗号分隔任务ID来添加多个任务。任务将按顺序分配。在尝试分配任务时遇到的任何单个失败都会导致操作中止,而在失败之前已添加到组中的任务将保留在组中。失败信息将记录到/sys/fs/resctrl/info/last_cmd_status。
+
+如果该组是一个“CTRL_MON”组,则任务将从之前拥有该任务的“CTRL_MON”组中移除,同时也会从任何拥有该任务的“MON”组中移除。如果该组是一个“MON”组,则任务必须已经属于该组的“CTRL_MON”父组。任务将从任何之前的“MON”组中移除。
+
+**cpus**: 读取此文件将显示该组拥有的逻辑CPU的位掩码。将掩码写入该文件将向该组添加或移除CPU。与“tasks”文件类似,维护了一个层级结构,其中“MON”组只能包含其父“CTRL_MON”组拥有的CPU。
+
+**cpus_list**: 与“cpus”类似,但使用CPU范围而不是位掩码。
+
+当启用控制功能时,所有“CTRL_MON”组还将包含以下文件:
+
+**schemata**: 列出该组可用的所有资源。每种资源都有自己的行和格式——详细信息请参见下文。
+
+**size**: 类似于“schemata”文件的显示,但显示的是每种资源分配的字节大小,而不是表示分配的位。
+
+**mode**: 资源组的“mode”决定了其分配的共享方式。“shareable”资源组允许共享其分配,而“exclusive”资源组则不允许。
+
+**ctrl_hw_id**: 仅在启用调试选项时可用。硬件用于控制组的标识符。在arm64架构上,即是 PARTID。
+
+当启用监控功能时,所有“MON”组还将包含以下文件:
+
+**mon_data**: 包含一组按L3域和MB域事件组织的文件。例如,在具有两个L3域的系统中,将存在子目录“mon_L3_00”和“mon_L3_01”。
+
+每个子目录中都有一个文件对应每个事件(例如“llc_occupancy”、“mbm_total_bytes”)。在“MON”组中,这些文件提供了组中所有任务的当前事件值。在“CTRL_MON”组中,这些文件提供了“CTRL_MON”组中所有任务以及所有“MON”组中任务的总和。有关使用方法的更多详细信息,请参见示例部分。
+
+**mon_hw_id**: 仅在启用调试选项时可用。硬件用于监控组的标识符。
+
+以下为resctrl文件系统目录树:
+
+~~~
+/sys/fs/resctrl(根分组)
+ ├── cpus # bitmask方式显示根分组关联的vcpu
+ ├── cpus_list # cpu list方式显示根分组关联的vcpu
+ ├── ctrl_hw_id # 硬件用于控制组的标识符
+ ├── info # 用于显示属性信息及错误提示信息
+ │ ├── L3
+ │ │ ├── bit_usage # 标注了资源所有实例的使用情况的容量位掩码
+ │ │ ├── cbm_mask # 系统所支持的最大cache way bitmask,一个bit代表一个cache way
+ │ │ ├── min_cbm_bits # 使用schemata所能配置的最小cache way bitmask
+ │ │ ├── num_closids # L3能够提供创建控制组的最大数量
+ │ │ ├── shareable_bits # 当前所有cbm_mask全部shareable,支持后续扩展
+ │ │ └── sparse_masks # 指示是否支持CBM(Capacity Bit Mask)中的非连续1值
+ │ ├── L3_MON
+ │ │ ├── max_threshold_occupancy # 低于此设定值下,之前使用过的LLC_occupancy计数器可以被考虑重新分配使用
+ │ │ ├── mon_features # 列出监控事件
+ │ │ └── num_rmids # 可创建控制组和监控组的总数
+ │ ├── last_cmd_status # 操作错误提示
+ │ ├── MB
+ │ │ ├── bandwidth_gran # 带宽百分比配置粒度
+ │ │ ├── delay_linear # 指示延迟刻度是线性还是非线性的
+ │ │ ├── min_bandwidth # 最小带宽配置百分比
+ │ │ └── num_closids # 同L3 num_closid
+ │ └── MB_MON
+ │ ├── mon_features # 同L3 mon_features
+ │ └── num_rmids # 同L3 num_rmids
+ ├── mode # 资源组的 mode 决定了其分配的共享方式
+ ├── mon_data
+ │ ├── mon_L3_01 # 标号代表L3 cache id
+ │ │ └── llc_occupancy # 表示当前分组所关联的pid/vcpu在该区域上实际占用L3 Cache大小,下同
+ │ ├── mon_L3_122
+ │ │ └── llc_occupancy
+ │ ├── mon_MB_00 # 标号代表numa id
+ │ │ └── mbm_total_bytes # 表示当前分组所关联的pid/vcpu在该区域上内存带宽流量大小,下同
+ │ └── mon_MB_01
+ │ └── mbm_total_bytes
+ ├── mon_groups # 创建监控组目录
+ ├── mon_hw_id # 硬件用于监控组的标识符
+ ├── schemata # 资源使用配置接口
+ ├── size # 显示的是每种资源分配的字节大小
+ └── tasks # 显示与根组关联的pid
+~~~
+
+### 3.2.3 控制组配置接口 Schemata 文件
+
+**schemata**文件中的每一行描述一种资源。每行以资源的名称开头,后面跟着该资源在系统中每个实例上要应用的具体值。
+
+#### Cache IDs
+
+在当前一代的系统中,每个插槽(socket)有一个L3缓存,而L2缓存通常仅由一个核心上的超线程共享,但这并不是架构上的强制要求。我们可能会在一个插槽上有多个独立的L3缓存,或者多个核心共享一个L2缓存。因此,我们不使用“插槽”或“核心”来定义共享资源的逻辑CPU集合,而是使用“Cache ID”(缓存ID)。
+
+在给定的缓存级别上,这将在整个系统中是一个唯一的数字(但不能保证是一个连续的序列,可能会有间隔)。要查找每个逻辑CPU的ID,请查看 /sys/devices/system/cpu/cpu*/cache/index*/id。
+
+#### Cache Bit Masks(CBM,缓存位掩码)
+
+对于缓存资源,我们使用位掩码来描述可用于分配的缓存部分。掩码的最大值由每种CPU型号定义(并且可能因不同的缓存级别而异)。该值在resctrl文件系统的“info”目录中提供,位于info/{resource}/cbm_mask。
+
+#### L3 缓存配置
+
+当未启用CDP(代码/数据缓存划分)时,L3 schemata的格式为:
+
+~~~
+L3:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+~~~
+
+当启用CDP时,L3控制被拆分为两个独立的资源,因此您可以分别为代码和数据指定独立的掩码,如下所示:
+
+~~~
+L3DATA:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+L3CODE:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+~~~
+
+读取schemata文件将显示所有域上所有资源的状态。在写入时,您只需要指定您希望更改的值。
+
+例如使用默认方式挂载,设置L3缓存位掩码只有4位:
+
+~~~
+# mount -t resctrl resctrl /sys/fs/resctrl/
+# cat /sys/fs/resctrl/schemata
+L3:1=fffffff;122=fffffff
+
+# echo "L3:122=3c0;" > /sys/fs/resctrl/schemata
+# cat /sys/fs/resctrl/schemata
+L3:1=fffffff;122=00003c0
+~~~
+
+使用开启CDP方式挂载,设置L3 data缓存位掩码只有4位:
+
+~~~
+# mount -t resctrl resctrl /sys/fs/resctrl/ -o cdp
+# cat /sys/fs/resctrl/schemata
+L3DATA:1=fffffff;122=fffffff
+L3CODE:1=fffffff;122=fffffff
+
+# echo "L3DATA:122=3c0;" > schemata
+# cat /sys/fs/resctrl/schemata
+L3DATA:1=fffffff;122=00003c0
+L3CODE:1=fffffff;122=fffffff
+~~~
+
+#### L2 缓存配置
+
+L2 缓存配置功能默认关闭,需要通过显式添加 l2 挂载参数,才会使能L2缓存配置功能。使能L2功能以后,系统关闭 cpuidle powerdown 功能和cpu下线功能。
+
+L2 schemata的格式是:
+
+~~~
+L2:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+~~~
+
+使用“cdpl2”挂载选项可以在L2上支持CDP:
+
+~~~
+L2DATA:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+L2CODE:<cache_id0>=<cbm>;<cache_id1>=<cbm>;...
+~~~
+
+L2 缓存配置示例,设置L2缓存位掩码只有4位:
+
+~~~
+# mount -t resctrl resctrl /sys/fs/resctrl/ -o l2
+# cat schemata
+L2:4=000ff;8=000ff
+
+# echo "L2:4=f;" > schemata
+# cat schemata
+L2:4=0000f;8=000ff
+~~~
+
+使用“cdpl2”挂载选项:
+
+~~~
+# mount -t resctrl resctrl /sys/fs/resctrl/ -o l2cdp,l2
+# cat schemata
+L2DATA:4=000ff;8=000ff
+L2CODE:4=000ff;8=000ff
+
+# echo "L2DATA:4=f;" > schemata
+# cat schemata
+L2DATA:4=0000f;8=000ff # 控制组 L2 DATA 只能使用L2 cache4的4个cache way
+L2CODE:4=000ff;8=000ff
+~~~
+
+#### MB 内存带宽分配
+
+对于内存带宽资源,默认情况下,用户通过指定总内存带宽的百分比来控制该资源。
+
+每种CPU型号的最小带宽百分比值是预定义的,可以通过info/MB/min_bandwidth查询。分配的带宽粒度也取决于CPU型号,可以在info/MB/bandwidth_gran中查询。可用的带宽控制步长为:min_bw + N * bw_gran。中间值会被四舍五入到硬件上可用的下一个控制步长。
+
+MB schemata的格式是:
+
+~~~
+MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;...
+~~~
+
+MB 带宽配置示例:
+
+~~~
+# cat /sys/fs/resctrl/schemata
+MB:0=0000100;1=0000100
+
+# echo "MB:0=50" > /sys/fs/resctrl/schemata
+# cat /sys/fs/resctrl/schemata
+MB:0=0000050;1=0000100 # 降低控制组 MB 内存带宽使用上限为50%
+~~~
+
+### 3.2.4 资源分配规则
+
+当一个任务正在运行时,以下规则定义了它可用的资源:
+1. 如果任务属于一个非默认组,则使用该组的分配方案(schemata)。
+2. 否则,如果任务属于默认组,但运行在一个被分配给某个特定组的CPU上,则使用该CPU所属组的分配方案。
+3. 否则,使用默认组的分配方案。
+
+### 3.2.5 监控组配置方法
+
+读取控制组和监控组的监控数据,可通过 mon_data 目录接口读取监控数据:
+
+~~~
+# grep . mon_data/*/*
+mon_data/mon_L3_01/llc_occupancy:73276416
+mon_data/mon_L3_122/llc_occupancy:11875328
+mon_data/mon_MB_00/mbm_total_bytes:32806
+mon_data/mon_MB_01/mbm_total_bytes:31700
+~~~
+
+其中,mon_data读取监控数据文件分别:
+ * llc_occupancy 代表 L3缓存当前占用量,单位 Byte
+ * mbm_total_bytes 代表内存带宽瞬时流量,单位 MB/s
+
+支持在控制组下创建子监控组,监控父控制组监控对象的子集:
+
+~~~
+# cd /sys/fs/resctrl/p1
+# cd mon_groups/ && mkdir m1 # 监控组只能监控,m1分组资源配置跟随p1分组
+# echo '0-1' > cpus_list
+# grep . mon_data/mon_*/*
+mon_data/mon_L3_01/llc_occupancy:18432
+mon_data/mon_L3_122/llc_occupancy:1024
+mon_data/mon_MB_00/mbm_total_bytes:0
+mon_data/mon_MB_01/mbm_total_bytes:0
+~~~
+
+控制组监控的是控制组本身及所有子监控组的监控值之和。
+
+## 3.3 QoS 增强特性
+
+### 3.3.1 PRI 优先级设置
+
+对共享资源优先级进行配置,包括 L3PRI 和 MBPRI:
+
+~~~
+# cat schemata
+ MBPRI:0=0000007;1=0000007
+ L3PRI:1=0000003;122=0000003
+
+# echo "MBPRI:0=0000003" > schemata
+# cat schemata
+ MBPRI:0=0000003;1=0000007 # 降低控制组 MB numa0的优先级
+ L3PRI:1=0000003;122=0000003
+
+# echo "MBPRI:0=0000003" > schemata
+
+~~~
+
+优先级设置数字越大,即优先级越高,反之,数字越小,优先级越低。
+
+> MBPRI 默认值为 3,MBPRI合法值范围 [0,7]。L3PRI 默认值为 0,L3PRI合法值范围 [0,3]。
+
+### 3.3.2 MIN 限低值设置
+
+共享资源实际使用占比低于设置值,会自动提高对该资源使用优先级,包括 L3MIN 和 MBMIN:
+
+~~~
+# cat schemata
+ MBMIN:0=00100
+ L3MIN:1=00100;5=00100
+
+# echo "MBMIN:0=00050" > schemata
+# cat schemata
+ MBMIN:0=00050
+ L3MIN:1=00100;5=00100
+
+# echo "L3MIN:1=00050" > schemata
+# cat schemata
+ MBMIN:0=00050
+ L3MIN:1=00050;5=00100
+~~~
+
+L3MIN 和 MBMIN 接口接受的输入参数为百分比,即设置值与总资源(内存带宽/缓存占用量)的占比。
+
+> MBMIN 和 L3MIN 默认值为 0,合法值范围都为 [0,100]。
+
+### 3.3.3 HDL 强制隔离设置
+
+当MBHDL=1,限制MB共享资源使用量不能超出MB设置值,若MBHDL=0,则允许空闲情况下,MB共享资源使用量超过MB设置值:
+
+~~~
+# cat schemata
+ MBHDL:0=0000001;1=0000001
+
+# echo "MBHDL:0=0000000" > schemata
+# cat schemata
+ MBHDL:0=0000000;1=0000001 # 关闭MB在numa0上的强制限制功能
+~~~
+
+> MBHDL 默认值为 1,合法值范围 [0,1]。
+
+### 3.3.4 MAX 资源上限设置
+
+设置允许分配的缓存容量的最大百分比,包括 L3MAX 接口:
+
+~~~
+# cat schemata
+ L3MAX:1=00100;5=00100
+
+# echo "L3MAX:1=00050" > schemata
+# cat schemata
+ L3MAX:1=00050;5=00100 # 降低L3分配的缓存最大容量百分比
+~~~
+
+> MB 和 L3MAX 默认值为 100,MB合法值范围 [1,100],L3MAX合法值范围 [0,100]。
+
+## 3.4 外设 IO 流量管控
+
+### 3.4.1 控制组绑定外设
+
+MPAM 提供通过绑定 iommu_group ID,对设备IO流量进行带宽限制和监控。
+
+譬如,控制网卡设备 eno2 ,首先查找该设备 PCI_SLOT 信息:
+
+~~~
+# cat /sys/class/net/eno2/device/uevent | grep PCI_SLOT
+PCI_SLOT_NAME=0000:35:00.1
+~~~
+
+或者通过 ethtool 工具查看 bus-info 信息:
+
+~~~
+# ethtool -i eno2 | grep bus-info
+bus-info: 0000:35:00.1
+~~~
+
+按照设备总线信息,查找到该设备所属的 iommu_group :
+
+~~~
+# find /sys/kernel/iommu_groups/ -name "0000:35:00.1"
+/sys/kernel/iommu_groups/17/devices/0000:35:00.1
+~~~
+
+或者通过 lspci 工具查看 iommu_group 信息:
+
+~~~
+# lspci -vvv -s 0000:35:00.1 | grep "IOMMU group"
+ IOMMU group: 17
+~~~
+
+将查询到的group id 17,通过 tasks 接口绑定到指定的控制组下:
+
+~~~
+# cd /sys/fs/resctrl/p1/
+# echo "iommu_group:17" > tasks
+# cat tasks
+iommu_group:17 # 此时iommu_group 17 已被绑定到控制组p1
+~~~
+
+### 3.4.2 查看外设带宽流量
+
+控制组绑定外设所属的iommu组后,可以查看设备流量带宽:
+
+~~~
+# grep . mon_data/mon_MB_0*/*
+mon_data/mon_MB_00/mbm_total_bytes:0
+mon_data/mon_MB_01/mbm_total_bytes:4230
+~~~
+
+### 3.4.3 配置外设带宽流量
+
+通过MB配置接口,可以实现限制设备的流量带宽:
+
+~~~
+# echo "MB:1=0000001" > schemata
+# cat schemata
+ MB:0=0000100;1=0000000
+
+# grep . mon_data/*/*
+mon_data/mon_MB_00/mbm_total_bytes:0
+mon_data/mon_MB_01/mbm_total_bytes:1208
+~~~
+
+# 4 控制组和监控组配置使用示例
+
+/sys/fs/resctrl 默认为根分组,根分组可以创建若干个控制组,一个控制组既可以关联一组pid/tid,也可以关联一组cpu集合。
+
+创建一个新的控制组,关联 pid/tid:
+
+~~~
+# cd /sys/fs/resctrl/ && mkdir p1
+# cd p1 && echo $$ > tasks # 关联当前shell进程pid到p1组
+# cat tasks # 可查看成功关联的pid
+29190
+29607
+~~~
+
+也可以选择关联 cpu:
+
+~~~
+# cd p1 && echo '0-1' > cpus_list
+# cat cpus_list # 可查看关联的cpu
+0-1
+~~~
+
+查看可创建的控制组和监控组数量:
+
+~~~
+# cat info/L3/num_closids # 可在info对应的资源的目录下查看closid数量,即可以创建控制组的数量
+32
+# cat info/MB/num_closids
+32
+# cat info/L3_MON/num_rmids # 可以创建控制组和监控组的总数量
+128
+# cat info/MB_MON/num_rmids
+128
+~~~
+
+通过配置控制组可达到隔离 L3 Cache/Memory Bandwidth 效果,通过读取对应分组mon_data接口可以获取该组资源占用情况,比如对一个控制组限制L3 Cache使用:
+
+~~~
+# cat info/L3/cbm_mask # 查看info目录下对应资源的属性
+fffffff
+# cat info/L3/min_cbm_bits
+1
+
+# cd /sys/fs/resctrl/p1
+# cat schemata
+ MB:0=0000100;1=0000100
+ L3:1=fffffff;122=fffffff
+
+# echo 'L3:0=1' > schemata # 配置1条cache way给p1分组
+# cat schemata
+ MB:0=0000100;1=0000100 # 若此时该组关联pid/cpu,那么该pid/cpu产生的访存请求只会分配到这条cache
+ L3:1=0000001;122=fffffff
+~~~
+
+对控制组限制MB使用:
+
+~~~
+# cat info/MB/min_bandwidth # 和配置L3类似,也可以查看MB的相关信息
+1
+# cat info/MB/bandwidth_gran
+1 # 可知,配置带宽最小百分比是1%,颗粒度是1%
+# cat schemata
+ MB:0=0000100;1=0000100
+ L3:1=0000001;122=fffffff
+# echo 'MB:0=1' > schemata
+# cat schemata
+ MB:0=0000001;1=0000100
+ L3:1=0000001;122=fffffff
+~~~
+
+支持在控制组下创建子监控组:
+
+~~~
+# cd /sys/fs/resctrl/p1
+# cd mon_groups/ && mkdir m1 # 监控组只能监控,m1分组资源配置跟随p1分组
+# ls m1/
+cpus cpus_list mon_data tasks
+# echo '0-1' > cpus_list
+# cat cpus_list
+0-1
+# grep . mon_data/mon_*/*
+mon_data/mon_L3_01/llc_occupancy:18432
+mon_data/mon_L3_122/llc_occupancy:1024
+mon_data/mon_MB_00/mbm_total_bytes:0
+mon_data/mon_MB_01/mbm_total_bytes:0
+~~~
--
2.25.1
2
1
Ian Rogers (1):
perf test bpf-counters: Add test for BPF event modifier
Tengda Wu (2):
perf stat: Support inherit events during fork() for bperf
perf test: Use sqrtloop workload to test bperf event
Veronika Molnarova (1):
perf test stat_bpf_counter.sh: Stabilize the test results
Xiaomeng Zhang (2):
perf stat: Increase perf_attr_map entries
perf stat: Fix incorrect display of bperf when event count is 0
tools/lib/perf/include/perf/bpf_perf.h | 1 +
tools/perf/builtin-stat.c | 1 +
tools/perf/tests/shell/stat_bpf_counters.sh | 79 ++++++++++-----
tools/perf/util/bpf_counter.c | 61 +++++++++---
tools/perf/util/bpf_skel/bperf_follower.bpf.c | 98 +++++++++++++++++--
tools/perf/util/bpf_skel/bperf_u.h | 5 +
tools/perf/util/target.h | 1 +
7 files changed, 198 insertions(+), 48 deletions(-)
--
2.34.1
2
7
---
.../testing/selftests/xcall_prefetch/Makefile | 37 ++++
.../selftests/xcall_prefetch/echo_client.c | 119 +++++++++++++
.../xcall_prefetch/echo_client_multi | Bin 0 -> 21896 bytes
.../selftests/xcall_prefetch/echo_server.c | 110 ++++++++++++
.../selftests/xcall_prefetch/echo_test.c | 52 ++++++
.../xcall_prefetch/mulit_close_test.c | 48 +++++
.../xcall_prefetch/multi_write_test.c | 77 ++++++++
.../xcall_prefetch/signal_recovery_test.c | 164 ++++++++++++++++++
.../xcall_prefetch/thundering_herd_test.c | 119 +++++++++++++
.../testing/selftests/xcall_prefetch/utils.h | 54 ++++++
.../xcall_prefetch/xcall_prefetch_test.sh | 39 +++++
11 files changed, 819 insertions(+)
create mode 100644 tools/testing/selftests/xcall_prefetch/Makefile
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_client.c
create mode 100755 tools/testing/selftests/xcall_prefetch/echo_client_multi
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_server.c
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/mulit_close_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/multi_write_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/utils.h
create mode 100755 tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
diff --git a/tools/testing/selftests/xcall_prefetch/Makefile b/tools/testing/selftests/xcall_prefetch/Makefile
new file mode 100644
index 000000000000..5bd509df66e0
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/Makefile
@@ -0,0 +1,37 @@
+CFLAGS += -Wall -Wextra -g
+TEST_GEN_FILES := echo_server echo_client echo_test multi_write_test thundering_herd_test mulit_close_test signal_recovery_test
+
+# enable debug
+# echo_client: CFLAGS += -DDEBUG=1
+# echo_server: CFLAGS += -DDEBUG=1
+# multi_write_test: CFLAGS += -DDEBUG=1
+# thundering_herd_test: CFLAGS += -DDEBUG=1
+# mulit_close_test: CFLAGS += -DDEBUG=1
+# signal_recovery_test: CFLAGS += -DDEBUG=1
+
+all: $(TEST_GEN_FILES)
+
+echo_server: echo_server.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_client: echo_client.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_test: echo_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+multi_write_test: multi_write_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+thundering_herd_test: thundering_herd_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+mulit_close_test: mulit_close_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+signal_recovery_test: signal_recovery_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+.PHONY: all
+
+include ../lib.mk
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client.c b/tools/testing/selftests/xcall_prefetch/echo_client.c
new file mode 100644
index 000000000000..2e3c41b2b14e
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_client.c
@@ -0,0 +1,119 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define DEBUG
+
+void *client(void *arg)
+{
+ int thread_id = *(int *)arg;
+ int sock = 0;
+ struct sockaddr_in serv_addr;
+ struct epoll_event ev, events[MAX_EVENTS];
+ const char* test_messages[MAX_MSGS];
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ handle_error("client:%d create socket failed\n", thread_id);
+ }
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(PORT);
+
+ if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
+ close(sock);
+ handle_error("client:%d invalid address\n", thread_id);
+ }
+ if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
+ close(sock);
+ handle_error("client:%d connection failed\n", thread_id);
+ }
+
+ debug_printf("Thread %d connected\n", thread_id);
+
+ int epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("client:%d epoll_create1 failed\n", thread_id);
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = sock;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) == -1) {
+ handle_error("client:%d epoll_ctl add sock failed\n", thread_id);
+ }
+
+ test_messages[0] = "hello world.";
+ test_messages[1] = generate_number_string(100);
+ test_messages[2] = generate_number_string(1024);
+ test_messages[3] = generate_number_string(4096);
+
+
+ for (int i = 0; i < MAX_MSGS; i++) {
+ const char* msg = test_messages[i];
+ ssize_t msg_len = strlen(msg);
+ if (send(sock, msg, msg_len, 0) != msg_len) {
+ handle_error("client:%d send failed\n", thread_id);
+ }
+
+ debug_printf("Client:%d send %s\n", thread_id, msg);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("client:%d epoll_wait failed\n", thread_id);
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == sock) {
+ char buffer[BUFFER_SIZE] = {0};
+ ssize_t read_bytes = read(sock, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ close(sock);
+ if (read_bytes == 0) {
+ handle_error("client:%d server disconnected\n", thread_id);
+ } else {
+ handle_error("client:%d read failed\n", thread_id);
+ }
+ } else {
+ debug_printf("Client:%d received %s\n", thread_id, buffer);
+ if (strncmp(msg, buffer, msg_len) != 0) {
+ handle_error("client:%d error: response does not match sent message\n", thread_id);
+ }
+ }
+ }
+ }
+ }
+
+ close(sock);
+ pthread_exit(NULL);
+}
+
+int main()
+{
+ pthread_t threads[NUM_THREADS];
+ int ret;
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ ret = pthread_create(&threads[i], NULL, client, &i);
+ if (ret != 0) {
+ perror("pthread_create failed");
+ continue;
+ }
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (threads[i] != 0) {
+ pthread_join(threads[i], NULL);
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client_multi b/tools/testing/selftests/xcall_prefetch/echo_client_multi
new file mode 100755
index 0000000000000000000000000000000000000000..36aa08d6e12f6e8ec73b2a7f8eb567225eb0b2f8
GIT binary patch
literal 21896
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
awoFy7Ql!(JO@(L8TPHL=YcsHk?7sjWb7VRI
literal 0
HcmV?d00001
diff --git a/tools/testing/selftests/xcall_prefetch/echo_server.c b/tools/testing/selftests/xcall_prefetch/echo_server.c
new file mode 100644
index 000000000000..49c1ea035788
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_server.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "./utils.h"
+
+static int client_id_counter = 0;
+char buffers[NUM_THREADS][BUFFER_SIZE];
+
+int main() {
+ int server_fd, epoll_fd;
+ struct sockaddr_in address;
+ struct epoll_event ev, events[MAX_EVENTS];
+ struct client_info *clients[MAX_EVENTS] = {0};
+
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
+ handle_error("socket failed\n");
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(PORT);
+
+ if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
+ handle_error("bind failed\n");
+ }
+
+ if (listen(server_fd, 100) < 0) {
+ handle_error("listen failed\n");
+ }
+
+ debug_printf("Server listening on port %d...\n", PORT);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
+ handle_error("epoll_ctl: server_fd\n");
+ }
+
+ while (1) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == server_fd) {
+ int client_fd;
+ socklen_t addr_len = sizeof(address);
+ if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addr_len)) < 0) {
+ debug_printf("accept failed\n");
+ goto fail;
+ }
+
+ struct client_info *info = malloc(sizeof(struct client_info));
+ info->fd = client_fd;
+ info->id = client_id_counter++;
+ info->addr = address;
+
+ clients[client_fd] = info;
+ debug_printf("new connection accepted client:%d\n", info->id);
+
+ int flags = fcntl(client_fd, F_GETFL, 0);
+ fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
+
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
+ debug_printf("epoll_ctl: client_fd\n");
+ goto fail;
+ }
+ } else {
+ int client_fd = events[n].data.fd;
+ // char buffer[BUFFER_SIZE] = {0};
+ struct client_info *info = clients[client_fd];
+ char *buffer = buffers[info->id];
+ memset(buffers[info->id], 0, BUFFER_SIZE);
+ ssize_t read_bytes = read(client_fd, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ if (read_bytes == 0) {
+ debug_printf("client:%d disconnected\n", info->id);
+ continue;
+ } else {
+ debug_printf("read failed\n");
+ }
+ goto fail;
+ } else {
+ debug_printf("Server received client:%d %s\n", info->id, buffer);
+ write(client_fd, buffer, read_bytes);
+ }
+ }
+ }
+ }
+
+fail:
+ close(server_fd);
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_test.c b/tools/testing/selftests/xcall_prefetch/echo_test.c
new file mode 100644
index 000000000000..fc7180869f3c
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_test.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+int main() {
+ pid_t server_pid, client_pid;
+ int server_status, client_status;
+
+ server_pid = fork();
+ if (server_pid == 0) {
+ execl("./echo_server", "./echo_server", NULL);
+ printf("execl echo_server failed\n");
+ exit(EXIT_FAILURE);
+ } else if (server_pid < 0) {
+ printf("fork echo_server failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sleep(1);
+
+ client_pid = fork();
+ if (client_pid == 0) {
+ execl("./echo_client", "./echo_client", NULL);
+ printf("execl client failed\n");
+ exit(EXIT_FAILURE);
+ } else if (client_pid < 0) {
+ printf("fork echo_client failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ waitpid(client_pid, &client_status, 0);
+
+ kill(server_pid, SIGTERM);
+ waitpid(server_pid, &server_status, 0);
+
+ if (WIFEXITED(client_status)) {
+ int exit_code = WEXITSTATUS(client_status);
+ if (exit_code == 0) {
+ printf("echo test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ exit(EXIT_SUCCESS);
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/mulit_close_test.c b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
new file mode 100644
index 000000000000..fae0407e8473
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+
+#include "./utils.h"
+
+int main() {
+ int epoll_fd;
+ struct epoll_event ev, events[1];
+ int ret = -1;
+
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ epoll_fd = epoll_create1(0);
+ ev.events = EPOLLIN | EPOLLHUP;
+ ev.data.fd = fds[0];
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fds[0], &ev);
+
+ if (fork() == 0) {
+ close(fds[1]);
+ exit(0);
+ }
+
+ close(fds[1]);
+
+ int nfds = epoll_wait(epoll_fd, events, 1, 1000);
+
+ if (nfds == 1) {
+ if (events[0].events & EPOLLHUP) {
+ ret = 0;
+ }
+ }
+
+ close(fds[0]);
+ close(epoll_fd);
+ if (!ret) {
+ debug_printf("epoll_wait detected EPOLLHUP!\n");
+ printf("multi close test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ }
+
+ printf("multi close test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/multi_write_test.c b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
new file mode 100644
index 000000000000..0af07b742e73
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+#define NUM_CHILDREN 3
+
+int main() {
+ int epoll_fd, pipe_fd[2];
+ struct epoll_event ev, events[MAX_EVENTS];
+ char buffer[BUFFER_SIZE];
+
+ if (pipe(pipe_fd) == -1) {
+ handle_error("pipe failed\n");
+ }
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = pipe_fd[0];
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fd[0], &ev) == -1) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ sleep(1);
+ pid_t pid = fork();
+ if (pid == 0) {
+ close(pipe_fd[0]);
+ char msg[10];
+ sprintf(msg, "%d %d\n", 2*i, 2*i+1);
+ write(pipe_fd[1], msg, strlen(msg));
+ exit(0);
+ } else if (pid < 0) {
+ handle_error("fork failed\n");
+ }
+ }
+
+ sleep(1);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("epoll_wait returned %d events\n", nfds);
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == pipe_fd[0]) {
+ ssize_t n = read(pipe_fd[0], buffer, BUFFER_SIZE);
+ if (n > 0) {
+ debug_printf("Received: %.*s", (int)n, buffer);
+ }
+ char *expected_msg = "0 1\n2 3\n4 5\n";
+ if (strncmp(expected_msg, buffer, strlen(expected_msg)) != 0) {
+ printf("multi write test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ handle_error("expected msg: %s, buffer: %s", expected_msg, buffer);
+ }
+ }
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ wait(NULL);
+ }
+
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ close(epoll_fd);
+ printf("multi write test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
new file mode 100644
index 000000000000..9645f8ffec1b
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "./utils.h"
+
+
+int epoll_fd;
+int server_fd;
+volatile sig_atomic_t signal_received = 0;
+
+void signal_handler() {
+ signal_received = 1;
+}
+
+void* worker_thread() {
+ struct epoll_event events[MAX_EVENTS];
+
+ while (!signal_received) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ if (errno == EINTR) {
+ debug_printf("epoll_wait interrupted by signal! re-waiting...\n");
+ continue;
+ } else {
+ handle_error("epoll_wait failed\n");
+ }
+ }
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == server_fd) {
+ struct sockaddr_in address;
+ socklen_t addr_len = sizeof(address);
+ int client_fd = accept(server_fd, (struct sockaddr*)&address, &addr_len);
+ if (client_fd < 0) {
+ handle_error("accept failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) {
+ close(client_fd);
+ handle_error("epoll_ctl failed\n");
+ }
+ } else {
+ char buffer[1024];
+ ssize_t n = read(events[i].data.fd, buffer, sizeof(buffer));
+ if (n <= 0) {
+ if (n < 0) {
+ handle_error("read failed\n");
+ }
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
+ close(events[i].data.fd);
+ debug_printf("closing fd %d\n", events[i].data.fd);
+ } else {
+ buffer[n] = '\0';
+ debug_printf("receive: %s\n", buffer);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void* client_thread() {
+ sleep(1);
+
+ int client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in server_addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg = "hello world.";
+ write(client_fd, msg, strlen(msg));
+ close(client_fd);
+
+ sleep(1);
+
+ debug_printf("Sending SIGUSR1 to interrupt epoll_wait...\n");
+ kill(getpid(), SIGUSR1);
+
+ sleep(1);
+ debug_printf("Testing if epoll_wait can still work after signal...\n");
+
+ client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg2 = "hello world again.";
+ if (write(client_fd, msg2, strlen(msg2)) < 0) {
+ goto fail;
+ }
+
+ close(client_fd);
+ return NULL;
+
+fail:
+ close(client_fd);
+ pthread_exit((void *)42);
+}
+
+int main() {
+ pthread_t worker, client;
+
+ signal(SIGUSR1, signal_handler);
+
+ server_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+ bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
+ listen(server_fd, SOMAXCONN);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ pthread_create(&worker, NULL, worker_thread, NULL);
+ pthread_create(&client, NULL, client_thread, NULL);
+
+ void *retval;
+ pthread_join(worker, NULL);
+ pthread_join(client, &retval);
+
+ close(server_fd);
+ close(epoll_fd);
+
+ if (retval != NULL) {
+ printf("signal recovery test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+
+ printf("signal recovery test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
new file mode 100644
index 000000000000..bf98fcf94b6a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define TIMEOUT_MS 1000
+
+int create_client_connection() {
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ return fd;
+}
+
+void set_nonblocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+int main() {
+ int listen_fd, epoll_fd;
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+
+ int shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
+ int tmp_cnt;
+ int *accept_count = (int *)shmat(shm_id, NULL, 0);
+ *accept_count = 0;
+
+ listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ set_nonblocking(listen_fd);
+ int reuse = 1;
+ setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+ bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
+ listen(listen_fd, SOMAXCONN);
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (fork() == 0) {
+ usleep(1000 * i);
+ epoll_fd = epoll_create1(0);
+ struct epoll_event ev = {
+ .events = EPOLLIN | EPOLLET,
+ .data.fd = listen_fd,
+ };
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev);
+
+ debug_printf("Worker %d waiting...\n", getpid());
+
+ struct epoll_event events[MAX_EVENTS];
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT_MS);
+
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("Worker %d: epoll_wait returned %d events\n", getpid(), nfds);
+
+ int client_fd = accept(listen_fd, NULL, NULL);
+ if (client_fd >= 0) {
+ debug_printf("Worker %d accepted a connection!\n", getpid());
+ __sync_fetch_and_add(accept_count, 1);
+ close(client_fd);
+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ debug_printf("accept failed\n");
+ }
+
+ close(epoll_fd);
+ exit(0);
+ }
+ }
+
+ sleep(1);
+
+ debug_printf("Parent creating client connection...\n");
+ int client_fd = create_client_connection();
+ sleep(1);
+ close(client_fd);
+
+ int waited = 0;
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (wait(NULL) < 0 && errno == ECHILD) {
+ break;
+ }
+ waited++;
+ }
+
+ tmp_cnt = *accept_count;
+ debug_printf("Total successful accepts: %d\n", tmp_cnt);
+
+ shmdt(accept_count);
+ shmctl(shm_id, IPC_RMID, NULL);
+ close(listen_fd);
+
+ if (tmp_cnt == 1) {
+ printf("thundering herd test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ } else {
+ printf("thundering herd test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/utils.h b/tools/testing/selftests/xcall_prefetch/utils.h
new file mode 100644
index 000000000000..58959c564119
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/utils.h
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define ANSI_COLOR_GREEN "\x1b[32m"
+#define ANSI_COLOR_RED "\x1b[31m"
+#define ANSI_COLOR_RESET "\x1b[0m"
+
+#define PORT 8080
+#define BUFFER_SIZE 4097
+#define MAX_EVENTS 100
+#define MAX_MSGS 4
+#define NUM_THREADS 4
+
+#ifdef DEBUG
+#define debug_printf(fmt, ...) (printf(fmt, ##__VA_ARGS__))
+#else
+#define debug_printf(fmt, ...) (void)fmt
+#endif
+
+struct client_info {
+ int fd;
+ int id;
+ struct sockaddr_in addr;
+};
+
+void handle_error(const char *format, ...)
+{
+ printf("%s", format);
+ exit(EXIT_FAILURE);
+}
+
+char* generate_number_string(int length)
+{
+ if (length <= 0) {
+ printf("\nnumber string length invalid\n");
+ return NULL;
+ }
+
+ char* result = (char*)malloc((length + 1) * sizeof(char));
+ if (result == NULL) {
+ printf("\nnumber string malloc failed\n");
+ return NULL;
+ }
+
+ for (int i = 0; i < length; i++) {
+ result[i] = '0' + (i % 10);
+ }
+
+ result[length] = '\0';
+
+ return result;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
new file mode 100755
index 000000000000..e9a990dac69a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+RED="\033[31m"
+GREEN="\033[32m"
+RESET="\033[0m"
+
+make clean
+make
+
+if [ -e "/proc/$$/xcall" ]; then
+ echo 22 > "/proc/$$/xcall"
+ echo @22 > "/proc/$$/xcall"
+ echo "enable xcall epoll prefetch, pid is $$."
+else
+ echo "Warnning: not enable xcall."
+fi
+
+./echo_test
+sleep 1
+
+./multi_write_test
+sleep 1
+
+./thundering_herd_test
+sleep 1
+
+./mulit_close_test
+sleep 1
+
+./signal_recovery_test
+sleep 1
+
+if [ $? -eq 0 ]; then
+ echo -e "${GREEN}tests passed successfully.${RESET}"
+ exit 0
+else
+ echo -e "${RED}tests failed.${RESET}"
+ exit 1
+fi
\ No newline at end of file
--
2.34.1
2
1
---
.../testing/selftests/xcall_prefetch/Makefile | 37 ++++
.../selftests/xcall_prefetch/echo_client.c | 119 +++++++++++++
.../xcall_prefetch/echo_client_multi | Bin 0 -> 21896 bytes
.../selftests/xcall_prefetch/echo_server.c | 110 ++++++++++++
.../selftests/xcall_prefetch/echo_test.c | 52 ++++++
.../xcall_prefetch/mulit_close_test.c | 48 +++++
.../xcall_prefetch/multi_write_test.c | 77 ++++++++
.../xcall_prefetch/signal_recovery_test.c | 164 ++++++++++++++++++
.../xcall_prefetch/thundering_herd_test | Bin 0 -> 21000 bytes
.../xcall_prefetch/thundering_herd_test.c | 119 +++++++++++++
.../testing/selftests/xcall_prefetch/utils.h | 54 ++++++
.../xcall_prefetch/xcall_prefetch_test.sh | 39 +++++
12 files changed, 819 insertions(+)
create mode 100644 tools/testing/selftests/xcall_prefetch/Makefile
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_client.c
create mode 100755 tools/testing/selftests/xcall_prefetch/echo_client_multi
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_server.c
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/mulit_close_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/multi_write_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
create mode 100755 tools/testing/selftests/xcall_prefetch/thundering_herd_test
create mode 100644 tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/utils.h
create mode 100755 tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
diff --git a/tools/testing/selftests/xcall_prefetch/Makefile b/tools/testing/selftests/xcall_prefetch/Makefile
new file mode 100644
index 000000000000..5bd509df66e0
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/Makefile
@@ -0,0 +1,37 @@
+CFLAGS += -Wall -Wextra -g
+TEST_GEN_FILES := echo_server echo_client echo_test multi_write_test thundering_herd_test mulit_close_test signal_recovery_test
+
+# enable debug
+# echo_client: CFLAGS += -DDEBUG=1
+# echo_server: CFLAGS += -DDEBUG=1
+# multi_write_test: CFLAGS += -DDEBUG=1
+# thundering_herd_test: CFLAGS += -DDEBUG=1
+# mulit_close_test: CFLAGS += -DDEBUG=1
+# signal_recovery_test: CFLAGS += -DDEBUG=1
+
+all: $(TEST_GEN_FILES)
+
+echo_server: echo_server.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_client: echo_client.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_test: echo_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+multi_write_test: multi_write_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+thundering_herd_test: thundering_herd_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+mulit_close_test: mulit_close_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+signal_recovery_test: signal_recovery_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+.PHONY: all
+
+include ../lib.mk
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client.c b/tools/testing/selftests/xcall_prefetch/echo_client.c
new file mode 100644
index 000000000000..2e3c41b2b14e
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_client.c
@@ -0,0 +1,119 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define DEBUG
+
+void *client(void *arg)
+{
+ int thread_id = *(int *)arg;
+ int sock = 0;
+ struct sockaddr_in serv_addr;
+ struct epoll_event ev, events[MAX_EVENTS];
+ const char* test_messages[MAX_MSGS];
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ handle_error("client:%d create socket failed\n", thread_id);
+ }
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(PORT);
+
+ if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
+ close(sock);
+ handle_error("client:%d invalid address\n", thread_id);
+ }
+ if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
+ close(sock);
+ handle_error("client:%d connection failed\n", thread_id);
+ }
+
+ debug_printf("Thread %d connected\n", thread_id);
+
+ int epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("client:%d epoll_create1 failed\n", thread_id);
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = sock;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) == -1) {
+ handle_error("client:%d epoll_ctl add sock failed\n", thread_id);
+ }
+
+ test_messages[0] = "hello world.";
+ test_messages[1] = generate_number_string(100);
+ test_messages[2] = generate_number_string(1024);
+ test_messages[3] = generate_number_string(4096);
+
+
+ for (int i = 0; i < MAX_MSGS; i++) {
+ const char* msg = test_messages[i];
+ ssize_t msg_len = strlen(msg);
+ if (send(sock, msg, msg_len, 0) != msg_len) {
+ handle_error("client:%d send failed\n", thread_id);
+ }
+
+ debug_printf("Client:%d send %s\n", thread_id, msg);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("client:%d epoll_wait failed\n", thread_id);
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == sock) {
+ char buffer[BUFFER_SIZE] = {0};
+ ssize_t read_bytes = read(sock, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ close(sock);
+ if (read_bytes == 0) {
+ handle_error("client:%d server disconnected\n", thread_id);
+ } else {
+ handle_error("client:%d read failed\n", thread_id);
+ }
+ } else {
+ debug_printf("Client:%d received %s\n", thread_id, buffer);
+ if (strncmp(msg, buffer, msg_len) != 0) {
+ handle_error("client:%d error: response does not match sent message\n", thread_id);
+ }
+ }
+ }
+ }
+ }
+
+ close(sock);
+ pthread_exit(NULL);
+}
+
+int main()
+{
+ pthread_t threads[NUM_THREADS];
+ int ret;
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ ret = pthread_create(&threads[i], NULL, client, &i);
+ if (ret != 0) {
+ perror("pthread_create failed");
+ continue;
+ }
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (threads[i] != 0) {
+ pthread_join(threads[i], NULL);
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client_multi b/tools/testing/selftests/xcall_prefetch/echo_client_multi
new file mode 100755
index 0000000000000000000000000000000000000000..36aa08d6e12f6e8ec73b2a7f8eb567225eb0b2f8
GIT binary patch
literal 21896
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
awoFy7Ql!(JO@(L8TPHL=YcsHk?7sjWb7VRI
literal 0
HcmV?d00001
diff --git a/tools/testing/selftests/xcall_prefetch/echo_server.c b/tools/testing/selftests/xcall_prefetch/echo_server.c
new file mode 100644
index 000000000000..49c1ea035788
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_server.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "./utils.h"
+
+static int client_id_counter = 0;
+char buffers[NUM_THREADS][BUFFER_SIZE];
+
+int main() {
+ int server_fd, epoll_fd;
+ struct sockaddr_in address;
+ struct epoll_event ev, events[MAX_EVENTS];
+ struct client_info *clients[MAX_EVENTS] = {0};
+
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
+ handle_error("socket failed\n");
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(PORT);
+
+ if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
+ handle_error("bind failed\n");
+ }
+
+ if (listen(server_fd, 100) < 0) {
+ handle_error("listen failed\n");
+ }
+
+ debug_printf("Server listening on port %d...\n", PORT);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
+ handle_error("epoll_ctl: server_fd\n");
+ }
+
+ while (1) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == server_fd) {
+ int client_fd;
+ socklen_t addr_len = sizeof(address);
+ if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addr_len)) < 0) {
+ debug_printf("accept failed\n");
+ goto fail;
+ }
+
+ struct client_info *info = malloc(sizeof(struct client_info));
+ info->fd = client_fd;
+ info->id = client_id_counter++;
+ info->addr = address;
+
+ clients[client_fd] = info;
+ debug_printf("new connection accepted client:%d\n", info->id);
+
+ int flags = fcntl(client_fd, F_GETFL, 0);
+ fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
+
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
+ debug_printf("epoll_ctl: client_fd\n");
+ goto fail;
+ }
+ } else {
+ int client_fd = events[n].data.fd;
+ // char buffer[BUFFER_SIZE] = {0};
+ struct client_info *info = clients[client_fd];
+ char *buffer = buffers[info->id];
+ memset(buffers[info->id], 0, BUFFER_SIZE);
+ ssize_t read_bytes = read(client_fd, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ if (read_bytes == 0) {
+ debug_printf("client:%d disconnected\n", info->id);
+ continue;
+ } else {
+ debug_printf("read failed\n");
+ }
+ goto fail;
+ } else {
+ debug_printf("Server received client:%d %s\n", info->id, buffer);
+ write(client_fd, buffer, read_bytes);
+ }
+ }
+ }
+ }
+
+fail:
+ close(server_fd);
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_test.c b/tools/testing/selftests/xcall_prefetch/echo_test.c
new file mode 100644
index 000000000000..fc7180869f3c
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_test.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+int main() {
+ pid_t server_pid, client_pid;
+ int server_status, client_status;
+
+ server_pid = fork();
+ if (server_pid == 0) {
+ execl("./echo_server", "./echo_server", NULL);
+ printf("execl echo_server failed\n");
+ exit(EXIT_FAILURE);
+ } else if (server_pid < 0) {
+ printf("fork echo_server failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sleep(1);
+
+ client_pid = fork();
+ if (client_pid == 0) {
+ execl("./echo_client", "./echo_client", NULL);
+ printf("execl client failed\n");
+ exit(EXIT_FAILURE);
+ } else if (client_pid < 0) {
+ printf("fork echo_client failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ waitpid(client_pid, &client_status, 0);
+
+ kill(server_pid, SIGTERM);
+ waitpid(server_pid, &server_status, 0);
+
+ if (WIFEXITED(client_status)) {
+ int exit_code = WEXITSTATUS(client_status);
+ if (exit_code == 0) {
+ printf("echo test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ exit(EXIT_SUCCESS);
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/mulit_close_test.c b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
new file mode 100644
index 000000000000..fae0407e8473
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+
+#include "./utils.h"
+
+int main() {
+ int epoll_fd;
+ struct epoll_event ev, events[1];
+ int ret = -1;
+
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ epoll_fd = epoll_create1(0);
+ ev.events = EPOLLIN | EPOLLHUP;
+ ev.data.fd = fds[0];
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fds[0], &ev);
+
+ if (fork() == 0) {
+ close(fds[1]);
+ exit(0);
+ }
+
+ close(fds[1]);
+
+ int nfds = epoll_wait(epoll_fd, events, 1, 1000);
+
+ if (nfds == 1) {
+ if (events[0].events & EPOLLHUP) {
+ ret = 0;
+ }
+ }
+
+ close(fds[0]);
+ close(epoll_fd);
+ if (!ret) {
+ debug_printf("epoll_wait detected EPOLLHUP!\n");
+ printf("multi close test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ }
+
+ printf("multi close test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/multi_write_test.c b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
new file mode 100644
index 000000000000..0af07b742e73
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+#define NUM_CHILDREN 3
+
+int main() {
+ int epoll_fd, pipe_fd[2];
+ struct epoll_event ev, events[MAX_EVENTS];
+ char buffer[BUFFER_SIZE];
+
+ if (pipe(pipe_fd) == -1) {
+ handle_error("pipe failed\n");
+ }
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = pipe_fd[0];
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fd[0], &ev) == -1) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ sleep(1);
+ pid_t pid = fork();
+ if (pid == 0) {
+ close(pipe_fd[0]);
+ char msg[10];
+ sprintf(msg, "%d %d\n", 2*i, 2*i+1);
+ write(pipe_fd[1], msg, strlen(msg));
+ exit(0);
+ } else if (pid < 0) {
+ handle_error("fork failed\n");
+ }
+ }
+
+ sleep(1);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("epoll_wait returned %d events\n", nfds);
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == pipe_fd[0]) {
+ ssize_t n = read(pipe_fd[0], buffer, BUFFER_SIZE);
+ if (n > 0) {
+ debug_printf("Received: %.*s", (int)n, buffer);
+ }
+ char *expected_msg = "0 1\n2 3\n4 5\n";
+ if (strncmp(expected_msg, buffer, strlen(expected_msg)) != 0) {
+ printf("multi write test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ handle_error("expected msg: %s, buffer: %s", expected_msg, buffer);
+ }
+ }
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ wait(NULL);
+ }
+
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ close(epoll_fd);
+ printf("multi write test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
new file mode 100644
index 000000000000..9645f8ffec1b
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "./utils.h"
+
+
+int epoll_fd;
+int server_fd;
+volatile sig_atomic_t signal_received = 0;
+
+void signal_handler() {
+ signal_received = 1;
+}
+
+void* worker_thread() {
+ struct epoll_event events[MAX_EVENTS];
+
+ while (!signal_received) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ if (errno == EINTR) {
+ debug_printf("epoll_wait interrupted by signal! re-waiting...\n");
+ continue;
+ } else {
+ handle_error("epoll_wait failed\n");
+ }
+ }
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == server_fd) {
+ struct sockaddr_in address;
+ socklen_t addr_len = sizeof(address);
+ int client_fd = accept(server_fd, (struct sockaddr*)&address, &addr_len);
+ if (client_fd < 0) {
+ handle_error("accept failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) {
+ close(client_fd);
+ handle_error("epoll_ctl failed\n");
+ }
+ } else {
+ char buffer[1024];
+ ssize_t n = read(events[i].data.fd, buffer, sizeof(buffer));
+ if (n <= 0) {
+ if (n < 0) {
+ handle_error("read failed\n");
+ }
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
+ close(events[i].data.fd);
+ debug_printf("closing fd %d\n", events[i].data.fd);
+ } else {
+ buffer[n] = '\0';
+ debug_printf("receive: %s\n", buffer);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void* client_thread() {
+ sleep(1);
+
+ int client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in server_addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg = "hello world.";
+ write(client_fd, msg, strlen(msg));
+ close(client_fd);
+
+ sleep(1);
+
+ debug_printf("Sending SIGUSR1 to interrupt epoll_wait...\n");
+ kill(getpid(), SIGUSR1);
+
+ sleep(1);
+ debug_printf("Testing if epoll_wait can still work after signal...\n");
+
+ client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg2 = "hello world again.";
+ if (write(client_fd, msg2, strlen(msg2)) < 0) {
+ goto fail;
+ }
+
+ close(client_fd);
+ return NULL;
+
+fail:
+ close(client_fd);
+ pthread_exit((void *)42);
+}
+
+int main() {
+ pthread_t worker, client;
+
+ signal(SIGUSR1, signal_handler);
+
+ server_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+ bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
+ listen(server_fd, SOMAXCONN);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ pthread_create(&worker, NULL, worker_thread, NULL);
+ pthread_create(&client, NULL, client_thread, NULL);
+
+ void *retval;
+ pthread_join(worker, NULL);
+ pthread_join(client, &retval);
+
+ close(server_fd);
+ close(epoll_fd);
+
+ if (retval != NULL) {
+ printf("signal recovery test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+
+ printf("signal recovery test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/thundering_herd_test b/tools/testing/selftests/xcall_prefetch/thundering_herd_test
new file mode 100755
index 0000000000000000000000000000000000000000..8121561474f368c05f8108cddd9d80ac8b05379d
GIT binary patch
literal 21000
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
literal 0
HcmV?d00001
diff --git a/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
new file mode 100644
index 000000000000..bf98fcf94b6a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define TIMEOUT_MS 1000
+
+int create_client_connection() {
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ return fd;
+}
+
+void set_nonblocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+int main() {
+ int listen_fd, epoll_fd;
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+
+ int shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
+ int tmp_cnt;
+ int *accept_count = (int *)shmat(shm_id, NULL, 0);
+ *accept_count = 0;
+
+ listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ set_nonblocking(listen_fd);
+ int reuse = 1;
+ setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+ bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
+ listen(listen_fd, SOMAXCONN);
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (fork() == 0) {
+ usleep(1000 * i);
+ epoll_fd = epoll_create1(0);
+ struct epoll_event ev = {
+ .events = EPOLLIN | EPOLLET,
+ .data.fd = listen_fd,
+ };
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev);
+
+ debug_printf("Worker %d waiting...\n", getpid());
+
+ struct epoll_event events[MAX_EVENTS];
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT_MS);
+
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("Worker %d: epoll_wait returned %d events\n", getpid(), nfds);
+
+ int client_fd = accept(listen_fd, NULL, NULL);
+ if (client_fd >= 0) {
+ debug_printf("Worker %d accepted a connection!\n", getpid());
+ __sync_fetch_and_add(accept_count, 1);
+ close(client_fd);
+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ debug_printf("accept failed\n");
+ }
+
+ close(epoll_fd);
+ exit(0);
+ }
+ }
+
+ sleep(1);
+
+ debug_printf("Parent creating client connection...\n");
+ int client_fd = create_client_connection();
+ sleep(1);
+ close(client_fd);
+
+ int waited = 0;
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (wait(NULL) < 0 && errno == ECHILD) {
+ break;
+ }
+ waited++;
+ }
+
+ tmp_cnt = *accept_count;
+ debug_printf("Total successful accepts: %d\n", tmp_cnt);
+
+ shmdt(accept_count);
+ shmctl(shm_id, IPC_RMID, NULL);
+ close(listen_fd);
+
+ if (tmp_cnt == 1) {
+ printf("thundering herd test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ } else {
+ printf("thundering herd test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/utils.h b/tools/testing/selftests/xcall_prefetch/utils.h
new file mode 100644
index 000000000000..58959c564119
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/utils.h
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define ANSI_COLOR_GREEN "\x1b[32m"
+#define ANSI_COLOR_RED "\x1b[31m"
+#define ANSI_COLOR_RESET "\x1b[0m"
+
+#define PORT 8080
+#define BUFFER_SIZE 4097
+#define MAX_EVENTS 100
+#define MAX_MSGS 4
+#define NUM_THREADS 4
+
+#ifdef DEBUG
+#define debug_printf(fmt, ...) (printf(fmt, ##__VA_ARGS__))
+#else
+#define debug_printf(fmt, ...) (void)fmt
+#endif
+
+struct client_info {
+ int fd;
+ int id;
+ struct sockaddr_in addr;
+};
+
+void handle_error(const char *format, ...)
+{
+ printf("%s", format);
+ exit(EXIT_FAILURE);
+}
+
+char* generate_number_string(int length)
+{
+ if (length <= 0) {
+ printf("\nnumber string length invalid\n");
+ return NULL;
+ }
+
+ char* result = (char*)malloc((length + 1) * sizeof(char));
+ if (result == NULL) {
+ printf("\nnumber string malloc failed\n");
+ return NULL;
+ }
+
+ for (int i = 0; i < length; i++) {
+ result[i] = '0' + (i % 10);
+ }
+
+ result[length] = '\0';
+
+ return result;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
new file mode 100755
index 000000000000..e9a990dac69a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+RED="\033[31m"
+GREEN="\033[32m"
+RESET="\033[0m"
+
+make clean
+make
+
+if [ -e "/proc/$$/xcall" ]; then
+ echo 22 > "/proc/$$/xcall"
+ echo @22 > "/proc/$$/xcall"
+ echo "enable xcall epoll prefetch, pid is $$."
+else
+ echo "Warnning: not enable xcall."
+fi
+
+./echo_test
+sleep 1
+
+./multi_write_test
+sleep 1
+
+./thundering_herd_test
+sleep 1
+
+./mulit_close_test
+sleep 1
+
+./signal_recovery_test
+sleep 1
+
+if [ $? -eq 0 ]; then
+ echo -e "${GREEN}tests passed successfully.${RESET}"
+ exit 0
+else
+ echo -e "${RED}tests failed.${RESET}"
+ exit 1
+fi
\ No newline at end of file
--
2.34.1
2
1
Ian Rogers (1):
perf test bpf-counters: Add test for BPF event modifier
Tengda Wu (2):
perf stat: Support inherit events during fork() for bperf
perf test: Use sqrtloop workload to test bperf event
Veronika Molnarova (1):
perf test stat_bpf_counter.sh: Stabilize the test results
Xiaomeng Zhang (2):
perf stat: Increase perf_attr_map entries
perf stat: Fix incorrect display of bperf when event count is 0
tools/lib/perf/include/perf/bpf_perf.h | 1 +
tools/perf/builtin-stat.c | 1 +
tools/perf/tests/shell/stat_bpf_counters.sh | 79 ++++++++++-----
tools/perf/util/bpf_counter.c | 61 +++++++++---
tools/perf/util/bpf_skel/bperf_follower.bpf.c | 98 +++++++++++++++++--
tools/perf/util/bpf_skel/bperf_u.h | 5 +
tools/perf/util/target.h | 1 +
7 files changed, 198 insertions(+), 48 deletions(-)
--
2.34.1
2
7