From bb6e0678a9032354c3f2aae0b55e850143f16b08 Mon Sep 17 00:00:00 2001 From: shouyeliu Date: Tue, 23 Dec 2025 11:03:22 +0800 Subject: [PATCH] =?UTF-8?q?testcase:=20=E6=96=B0=E5=A2=9Elmbench=E3=80=81M?= =?UTF-8?q?LC=E3=80=81STREAM=E5=92=8Csysbench=E5=86=85=E5=AD=98=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B=E5=B9=B6=E6=B7=BB=E5=8A=A0MLC?= =?UTF-8?q?=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增内存性能测试用例,共44个测试用例,78个性能指标 - lmbench lat_mem_rd: 2个用例,8个指标 - 测试L1、L2、L3内存读延迟 - 参数: -P 1 1000 128 - prefetch-on/off两种模式 - MLC: 5个用例,11个指标 - idle-latency: 空闲内存延迟测试(1个指标) - loaded-latency: 负载内存延迟测试(2个指标:min/max) - latency-matrix: NUMA节点间延迟矩阵(4个指标:同/异NUMA min/max) - bandwidth-matrix: NUMA节点间带宽矩阵(4个指标:同/异NUMA min/max) - peak-bandwidth: 峰值带宽测试(4个指标:全读、3:1、2:1、1:1读写比) - STREAM: 6个用例,24个指标 - single/max/thread-4/8/16/32六种线程配置 - 每个配置4个指标:Add、Copy、Scale、Triad - 参数: warmup=0, run_loop=40, result_select_percent=70 - sysbench memory: 2个用例,2个指标 - thread-1/thread-max两种配置 - 参数: --time=300 - lmbench带宽测试: 4个用例,4个指标 - bw_mem测试:fwr、cp、fcp、bcopy - libmicro内存操作: 8个用例,8个指标 - memcpy: 1k/100k - memset: 10k/100k - malloc: 1k/1m - strcpy: 1k - strchr: 10 - 已有sysbench memory块测试: 17个用例,17个指标(已存在) 2. 新增性能测试适配类(lib/ts_common.py) - PerfStream: STREAM内存带宽测试 - PerfMLC: Intel MLC内存延迟测试 - PerfLMbench: lmbench延迟测试 3. 添加MLC工具 - 工具路径: tools/mlc/mlc - 构建脚本: tools/mlc/tst-build.sh 4. 更新配置文件 - base/base.json: 添加新用例配置 - templates/tperf.csv: 更新权重配置 - templates/tperf_mem_add.csv: 新增内存测试模板,临时使用 --- base/base.json | 1664 +++++++++++++++++ lib/ts_common.py | 568 +++++- templates/tperf.csv | 78 + testcase/tperf-libmicro-malloc_1k.py | 55 + testcase/tperf-libmicro-malloc_1m.py | 55 + testcase/tperf-libmicro-memcpy_100k.py | 55 + testcase/tperf-libmicro-memcpy_1k.py | 55 + testcase/tperf-libmicro-memset_100k.py | 55 + testcase/tperf-libmicro-memset_10k.py | 55 + testcase/tperf-libmicro-strchr_10.py | 55 + testcase/tperf-libmicro-strcpy_1k.py | 55 + testcase/tperf-lmbench-bw_mem-bcopy.py | 54 + testcase/tperf-lmbench-bw_mem-cp.py | 54 + testcase/tperf-lmbench-bw_mem-fcp.py | 54 + testcase/tperf-lmbench-bw_mem-fwr.py | 54 + .../tperf-lmbench-lat_mem_rd-prefetch-off.py | 57 + .../tperf-lmbench-lat_mem_rd-prefetch-on.py | 57 + testcase/tperf-mlc-bandwidth-matrix.py | 51 + testcase/tperf-mlc-idle-latency.py | 51 + testcase/tperf-mlc-latency-matrix.py | 51 + testcase/tperf-mlc-loaded-latency.py | 51 + testcase/tperf-mlc-peak-bandwidth.py | 51 + testcase/tperf-stream-max.py | 57 + testcase/tperf-stream-single.py | 4 + testcase/tperf-stream-thread-16.py | 55 + testcase/tperf-stream-thread-32.py | 55 + testcase/tperf-stream-thread-4.py | 55 + testcase/tperf-stream-thread-8.py | 55 + ...sbench-memory-block-256k-size-10g-rndwr.py | 2 +- ...ysbench-memory-block-64k-size-10g-rndrd.py | 2 +- testcase/tperf-sysbench-memory-thread-1.py | 53 + testcase/tperf-sysbench-memory-thread-max.py | 58 + ...ysbench-threads-16-locks-16-yields-1000.py | 0 ...sbench-threads-16-locks-16-yields-10000.py | 0 ...ysbench-threads-16-locks-16-yields-5000.py | 0 ...ysbench-threads-16-locks-32-yields-1000.py | 0 ...sbench-threads-16-locks-32-yields-10000.py | 0 ...ysbench-threads-16-locks-32-yields-5000.py | 0 ...ysbench-threads-16-locks-48-yields-5000.py | 0 ...sysbench-threads-16-locks-8-yields-1000.py | 0 ...ysbench-threads-16-locks-8-yields-10000.py | 0 ...sysbench-threads-16-locks-8-yields-5000.py | 0 ...ysbench-threads-16-locks-96-yields-5000.py | 0 ...ysbench-threads-32-locks-16-yields-1000.py | 0 ...sbench-threads-32-locks-16-yields-10000.py | 0 ...ysbench-threads-32-locks-16-yields-5000.py | 0 ...ysbench-threads-32-locks-32-yields-1000.py | 0 ...sbench-threads-32-locks-32-yields-10000.py | 0 ...ysbench-threads-32-locks-32-yields-5000.py | 0 ...ysbench-threads-32-locks-48-yields-5000.py | 0 ...sysbench-threads-32-locks-8-yields-1000.py | 0 ...ysbench-threads-32-locks-8-yields-10000.py | 0 ...sysbench-threads-32-locks-8-yields-5000.py | 0 ...ysbench-threads-32-locks-96-yields-5000.py | 0 ...sysbench-threads-8-locks-16-yields-5000.py | 0 ...sysbench-threads-8-locks-32-yields-5000.py | 0 ...sysbench-threads-8-locks-48-yields-1000.py | 0 ...ysbench-threads-8-locks-48-yields-10000.py | 0 ...sysbench-threads-8-locks-48-yields-5000.py | 0 ...-sysbench-threads-8-locks-8-yields-5000.py | 0 ...sysbench-threads-8-locks-96-yields-1000.py | 0 ...sysbench-threads-8-locks-96-yields-5000.py | 0 tools/mlc/mlc | Bin 0 -> 221120 bytes tools/mlc/tst-build.sh | 58 + 64 files changed, 3763 insertions(+), 26 deletions(-) create mode 100755 testcase/tperf-libmicro-malloc_1k.py create mode 100755 testcase/tperf-libmicro-malloc_1m.py create mode 100755 testcase/tperf-libmicro-memcpy_100k.py create mode 100755 testcase/tperf-libmicro-memcpy_1k.py create mode 100755 testcase/tperf-libmicro-memset_100k.py create mode 100755 testcase/tperf-libmicro-memset_10k.py create mode 100755 testcase/tperf-libmicro-strchr_10.py create mode 100755 testcase/tperf-libmicro-strcpy_1k.py create mode 100755 testcase/tperf-lmbench-bw_mem-bcopy.py create mode 100755 testcase/tperf-lmbench-bw_mem-cp.py create mode 100755 testcase/tperf-lmbench-bw_mem-fcp.py create mode 100755 testcase/tperf-lmbench-bw_mem-fwr.py create mode 100755 testcase/tperf-lmbench-lat_mem_rd-prefetch-off.py create mode 100755 testcase/tperf-lmbench-lat_mem_rd-prefetch-on.py create mode 100755 testcase/tperf-mlc-bandwidth-matrix.py create mode 100755 testcase/tperf-mlc-idle-latency.py create mode 100755 testcase/tperf-mlc-latency-matrix.py create mode 100755 testcase/tperf-mlc-loaded-latency.py create mode 100755 testcase/tperf-mlc-peak-bandwidth.py create mode 100755 testcase/tperf-stream-max.py create mode 100755 testcase/tperf-stream-thread-16.py create mode 100755 testcase/tperf-stream-thread-32.py create mode 100755 testcase/tperf-stream-thread-4.py create mode 100755 testcase/tperf-stream-thread-8.py create mode 100755 testcase/tperf-sysbench-memory-thread-1.py create mode 100755 testcase/tperf-sysbench-memory-thread-max.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-16-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-16-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-16-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-32-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-32-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-32-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-48-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-8-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-8-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-8-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-16-locks-96-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-16-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-16-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-16-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-32-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-32-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-32-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-48-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-8-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-8-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-8-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-32-locks-96-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-16-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-32-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-48-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-48-yields-10000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-48-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-8-yields-5000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-96-yields-1000.py mode change 100644 => 100755 testcase/tperf-sysbench-threads-8-locks-96-yields-5000.py create mode 100755 tools/mlc/mlc create mode 100755 tools/mlc/tst-build.sh diff --git a/base/base.json b/base/base.json index 41657a4..093868e 100644 --- a/base/base.json +++ b/base/base.json @@ -15986,6 +15986,88 @@ } } }, + "tperf-stream-max": { + "status": "PASS", + "duration": 121.58, + "result": { + "stream-max-thread-Copy": { + "name": "stream-max-thread-Copy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "stream-max-thread-Scale": { + "name": "stream-max-thread-Scale", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "stream-max-thread-Add": { + "name": "stream-max-thread-Add", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "stream-max-thread-Triad": { + "name": "stream-max-thread-Triad", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + } + } + }, "tperf-sysbench-threads-16-locks-24-yields-1000": { "status": "PASS", "duration": 20.13, @@ -20333,5 +20415,1587 @@ } } } + }, + "tperf-sysbench-memory-thread-max": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-thread-max": { + "name": "tperf-sysbench-memory-thread-max", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-1k-size-1g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-1k-size-1g-seqrd": { + "name": "tperf-sysbench-memory-block-1k-size-1g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-2k-size-1g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-2k-size-1g-seqrd": { + "name": "tperf-sysbench-memory-block-2k-size-1g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-4k-size-1g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-4k-size-1g-seqrd": { + "name": "tperf-sysbench-memory-block-4k-size-1g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-16k-size-1g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-16k-size-1g-seqrd": { + "name": "tperf-sysbench-memory-block-16k-size-1g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-32k-size-1g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-32k-size-1g-seqrd": { + "name": "tperf-sysbench-memory-block-32k-size-1g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-32k-size-1g-seqwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-32k-size-1g-seqwr": { + "name": "tperf-sysbench-memory-block-32k-size-1g-seqwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-32k-size-1g-rndrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-32k-size-1g-rndrd": { + "name": "tperf-sysbench-memory-block-32k-size-1g-rndrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-32k-size-1g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-32k-size-1g-rndwr": { + "name": "tperf-sysbench-memory-block-32k-size-1g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-64k-size-10g-rndrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-64k-size-10g-rndrd": { + "name": "tperf-sysbench-memory-block-64k-size-10g-rndrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-64k-size-10g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-64k-size-10g-rndwr": { + "name": "tperf-sysbench-memory-block-64k-size-10g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-128k-size-10g-seqrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-128k-size-10g-seqrd": { + "name": "tperf-sysbench-memory-block-128k-size-10g-seqrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-128k-size-10g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-128k-size-10g-rndwr": { + "name": "tperf-sysbench-memory-block-128k-size-10g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-256k-size-10g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-256k-size-10g-rndwr": { + "name": "tperf-sysbench-memory-block-256k-size-10g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-512k-size-10g-seqwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-512k-size-10g-seqwr": { + "name": "tperf-sysbench-memory-block-512k-size-10g-seqwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-512k-size-10g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-512k-size-10g-rndwr": { + "name": "tperf-sysbench-memory-block-512k-size-10g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-1g-size-10g-rndrd": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-1g-size-10g-rndrd": { + "name": "tperf-sysbench-memory-block-1g-size-10g-rndrd", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-block-1g-size-10g-rndwr": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-block-1g-size-10g-rndwr": { + "name": "tperf-sysbench-memory-block-1g-size-10g-rndwr", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-sysbench-memory-thread-1": { + "status": "PASS", + "duration": 0, + "result": { + "tperf-sysbench-memory-thread-1": { + "name": "tperf-sysbench-memory-thread-1", + "type": "HIB", + "key": "avg", + "unit": "MiB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 0 + } + } + }, + "tperf-mlc-idle-latency": { + "status": "PASS", + "duration": 0, + "result": { + "mlc_idle_latency_result-idle_latency": { + "name": "mlc_idle_latency_result-idle_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-mlc-peak-bandwidth": { + "status": "PASS", + "duration": 0, + "result": { + "mlc_peak_injection_bandwidth_result-all_read": { + "name": "mlc_peak_injection_bandwidth_result-all_read", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_peak_injection_bandwidth_result-3:1_read_write": { + "name": "mlc_peak_injection_bandwidth_result-3:1_read_write", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_peak_injection_bandwidth_result-2:1_read_write": { + "name": "mlc_peak_injection_bandwidth_result-2:1_read_write", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_peak_injection_bandwidth_result-1:1_read_write": { + "name": "mlc_peak_injection_bandwidth_result-1:1_read_write", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-mlc-loaded-latency": { + "status": "PASS", + "duration": 0, + "result": { + "mlc_loaded_latency_result-loaded_latency_min": { + "name": "mlc_loaded_latency_result-loaded_latency_min", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_loaded_latency_result-loaded_latency_max": { + "name": "mlc_loaded_latency_result-loaded_latency_max", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-mlc-latency-matrix": { + "status": "PASS", + "duration": 0, + "result": { + "mlc_latency_matrix_result-samenuma_latency_max": { + "name": "mlc_latency_matrix_result-samenuma_latency_max", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_latency_matrix_result-samenuma_latency_min": { + "name": "mlc_latency_matrix_result-samenuma_latency_min", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_latency_matrix_result-difnuma_latency_max": { + "name": "mlc_latency_matrix_result-difnuma_latency_max", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_latency_matrix_result-difnuma_latency_min": { + "name": "mlc_latency_matrix_result-difnuma_latency_min", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-mlc-bandwidth-matrix": { + "status": "PASS", + "duration": 0, + "result": { + "mlc_bandwidth_matrix_result-samenuma_bandwidth_max": { + "name": "mlc_bandwidth_matrix_result-samenuma_bandwidth_max", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_bandwidth_matrix_result-samenuma_bandwidth_min": { + "name": "mlc_bandwidth_matrix_result-samenuma_bandwidth_min", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_bandwidth_matrix_result-difnuma_bandwidth_max": { + "name": "mlc_bandwidth_matrix_result-difnuma_bandwidth_max", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "mlc_bandwidth_matrix_result-difnuma_bandwidth_min": { + "name": "mlc_bandwidth_matrix_result-difnuma_bandwidth_min", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-lmbench-lat_mem_rd-prefetch-on": { + "status": "PASS", + "duration": 125.721, + "result": { + "tperf-lmbench-lat_mem_rd-prefetch-on-l1_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-on-l1_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-on-l2_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-on-l2_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-on-l3_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-on-l3_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-on-mem_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-on-mem_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + } + } + }, + "tperf-lmbench-lat_mem_rd-prefetch-off": { + "status": "PASS", + "duration": 129.739, + "result": { + "tperf-lmbench-lat_mem_rd-prefetch-off-l1_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-off-l1_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-off-l2_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-off-l2_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-off-l3_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-off-l3_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + }, + "tperf-lmbench-lat_mem_rd-prefetch-off-mem_latency": { + "name": "tperf-lmbench-lat_mem_rd-prefetch-off-mem_latency", + "type": "LIB", + "key": "avg", + "unit": "ns", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0.0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50.0 + } + } + }, + "tperf-libmicro-memcpy_1k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-memcpy_1k": { + "name": "tperf-libmicro-memcpy_1k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-libmicro-memcpy_100k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-memcpy_100k": { + "name": "tperf-libmicro-memcpy_100k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-libmicro-memset_10k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-memset_10k": { + "name": "tperf-libmicro-memset_10k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-libmicro-memset_100k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-memset_100k": { + "name": "tperf-libmicro-memset_100k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-libmicro-malloc_1k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-malloc_1k": { + "name": "tperf-libmicro-malloc_1k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 30 + } + } + }, + "tperf-libmicro-malloc_1m": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-malloc_1m": { + "name": "tperf-libmicro-malloc_1m", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 30 + } + } + }, + "tperf-lmbench-bw_mem-fwr": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-lmbench-bw_mem-fwr": { + "name": "tperf-lmbench-bw_mem-fwr", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-lmbench-bw_mem-cp": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-lmbench-bw_mem-cp": { + "name": "tperf-lmbench-bw_mem-cp", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-lmbench-bw_mem-fcp": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-lmbench-bw_mem-fcp": { + "name": "tperf-lmbench-bw_mem-fcp", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-lmbench-bw_mem-bcopy": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-lmbench-bw_mem-bcopy": { + "name": "tperf-lmbench-bw_mem-bcopy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-stream-thread-4": { + "status": "PASS", + "duration": 1, + "result": { + "stream-thread-4-Add": { + "name": "stream-thread-4-Add", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-4-Copy": { + "name": "stream-thread-4-Copy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-4-Scale": { + "name": "stream-thread-4-Scale", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-4-Triad": { + "name": "stream-thread-4-Triad", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-stream-thread-8": { + "status": "PASS", + "duration": 1, + "result": { + "stream-thread-8-Add": { + "name": "stream-thread-8-Add", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-8-Copy": { + "name": "stream-thread-8-Copy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-8-Scale": { + "name": "stream-thread-8-Scale", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-8-Triad": { + "name": "stream-thread-8-Triad", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-stream-thread-16": { + "status": "PASS", + "duration": 1, + "result": { + "stream-thread-16-Add": { + "name": "stream-thread-16-Add", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-16-Copy": { + "name": "stream-thread-16-Copy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-16-Scale": { + "name": "stream-thread-16-Scale", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-16-Triad": { + "name": "stream-thread-16-Triad", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-stream-thread-32": { + "status": "PASS", + "duration": 1, + "result": { + "stream-thread-32-Add": { + "name": "stream-thread-32-Add", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-32-Copy": { + "name": "stream-thread-32-Copy", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-32-Scale": { + "name": "stream-thread-32-Scale", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + }, + "stream-thread-32-Triad": { + "name": "stream-thread-32-Triad", + "type": "HIB", + "key": "avg", + "unit": "MB/s", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 50 + } + } + }, + "tperf-libmicro-strcpy_1k": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-strcpy_1k": { + "name": "tperf-libmicro-strcpy_1k", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 80 + } + } + }, + "tperf-libmicro-strchr_10": { + "status": "PASS", + "duration": 1, + "result": { + "tperf-libmicro-strchr_10": { + "name": "tperf-libmicro-strchr_10", + "type": "LIB", + "key": "avg", + "unit": "usecs/call", + "label": "L0:内存", + "value": 1, + "statistics": { + "max": 1, + "min": 1, + "avg": 1, + "mid": 1, + "sd": 0 + }, + "L0": "内存", + "L1": "", + "L2": "", + "weight": 80 + } + } } } \ No newline at end of file diff --git a/lib/ts_common.py b/lib/ts_common.py index e893356..152c74f 100644 --- a/lib/ts_common.py +++ b/lib/ts_common.py @@ -2,6 +2,7 @@ # coding: utf-8 # Desc: 测试套公共模块 import abc +import bisect import json import multiprocessing import os.path @@ -14,6 +15,7 @@ import subprocess import sys import time from typing import Union +import numpy as np tperf_top_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(tperf_top_dir) @@ -686,6 +688,412 @@ class PerfStream(TSTPerf): return result +class PerfMLC(TSTPerf): + """Intel Memory Latency Checker (MLC) 性能测试工具适配类 + + MLC 支持以下测试模式: + - idle_latency: 空闲内存延迟 + - loaded_latency: 负载内存延迟 + - peak_injection_bandwidth: 峰值注入带宽 + - latency_matrix: 延迟矩阵(跨NUMA节点) + - bandwidth_matrix: 带宽矩阵(跨NUMA节点) + """ + + # 支持的测试模式 + SUPPORTED_MODES = [ + "idle_latency", + "loaded_latency", + "peak_injection_bandwidth", + "latency_matrix", + "bandwidth_matrix", + ] + + def __init__( + self, + name: str, + test_mode: str = "", + label: str = "", + general_opt: str = "", + ): + """初始化 MLC 测试 + + Args: + name: 测试名称 + test_mode: 测试模式,支持 idle_latency, loaded_latency, peak_injection_bandwidth, + latency_matrix, bandwidth_matrix + label: 标签 + general_opt: 额外的命令行参数 + """ + super().__init__() + self.name = name + self.label = label + self.test_mode = test_mode + self.general_opt = general_opt + + if test_mode not in self.SUPPORTED_MODES: + raise ValueError( + f"不支持的测试模式: {test_mode},支持的模式: {self.SUPPORTED_MODES}" + ) + + self.mlc = os.path.join(tperf_top_dir, "tools/mlc.install/mlc") + self.command = f"{self.mlc} --{test_mode} {general_opt if general_opt else ''}" + self.outs = "" + self.errs = "" + + def prepare(self): + """prepare before run testcase""" + if not os.path.isfile(self.mlc): + fail_dir = os.path.join(tperf_top_dir, "tools/mlc.install.fail") + if os.path.isdir(fail_dir): + raise FileNotFoundError(f"mlc may compile fail: {fail_dir}") + self.log("compile mlc") + command(cmd=f"{os.path.join(tperf_top_dir, 'tools/mlc/tst-build.sh')}") + if not os.path.isfile(self.mlc): + raise FileNotFoundError(f"mlc tool compile fail: {self.mlc}") + + def benchmark(self): + """执行性能测试""" + self.log(f"COMMAND: {self.command}") + proc = subprocess.Popen( + self.command, + shell=True, + encoding="utf-8", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + self.outs, self.errs = proc.communicate() + self.log(f"outs: {self.outs}") + self.log(f"errs: {self.errs}") + + def parse_test_data(self) -> Union[list, PerfData]: + """执行benchmark性能测试后,对测试结果进行解析,返回 PerfData 或其 list 性能测试结果""" + if not self.outs: + raise Exception("test output is empty") + + if self.test_mode == "idle_latency": + return self._parse_idle_latency() + elif self.test_mode == "loaded_latency": + return self._parse_loaded_latency() + elif self.test_mode == "peak_injection_bandwidth": + return self._parse_peak_injection_bandwidth() + elif self.test_mode == "latency_matrix": + return self._parse_latency_matrix() + elif self.test_mode == "bandwidth_matrix": + return self._parse_bandwidth_matrix() + else: + raise Exception(f"unknown test mode {self.test_mode}") + + def _parse_idle_latency(self) -> PerfData: + """解析 idle_latency 测试结果 + 输出格式示例: + Each iteration took 256.5 base frequency clocks ( 128.2 ns) + + 输出指标: + --idle_latency: 内存空闲延迟 (80.3ns) + """ + result = PerfData( + name="mlc_idle_latency_result-idle_latency", + value_type=ValueType.LIB, # 延迟越低越好 + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + for line in self.outs.splitlines(): + if "Each iteration took" in line and "ns)" in line: + # 提取延迟值 (ns) + match = re.search(r"\(\s*([\d.]+)\s*ns\)", line) + if match: + latency = float(match.group(1)) + result.set_key_value(value=latency) + break + return result + + def _parse_loaded_latency(self) -> list: + """解析 loaded_latency 测试结果 + 输出格式示例: + Inject Latency Bandwidth + Delay (ns) MB/sec + ========================== + 00000 982.13 54708.4 + + 输出指标: + --loaded_latency_min: 注入延迟最小值 + --loaded_latency_max: 注入延迟最大值 + """ + result_list = [] + # 返回最低延迟和最高延迟 + min_latency = float("inf") + max_latency = 0 + + in_data_section = False + for line in self.outs.splitlines(): + if "====" in line: + in_data_section = True + continue + if in_data_section and line.strip(): + parts = line.split() + if len(parts) >= 3: + try: + latency = float(parts[1]) + if latency < min_latency: + min_latency = latency + if latency > max_latency: + max_latency = latency + except (ValueError, IndexError): + continue + + # 最低延迟结果 + result_min_lat = PerfData( + name="mlc_loaded_latency_result-loaded_latency_min", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result_min_lat.set_key_value(value=min_latency if min_latency != float("inf") else 0) + result_list.append(result_min_lat) + + # 最高延迟结果 + result_max_lat = PerfData( + name="mlc_loaded_latency_result-loaded_latency_max", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result_max_lat.set_key_value(value=max_latency) + result_list.append(result_max_lat) + + return result_list + + def _parse_peak_injection_bandwidth(self) -> list: + """解析 peak_injection_bandwidth 测试结果 + 输出格式示例: + ALL Reads : 56361.9 + 3:1 Reads-Writes : 54526.2 + + 输出指标: + --all_read: 峰值内存带宽测试——全读 + --3:1_read_write: 峰值内存带宽测试——读写3:1 + --2:1_read_write: 峰值内存带宽测试——读写2:1 + --1:1_read_write: 峰值内存带宽测试——读写1:1 + """ + result_list = [] + bandwidth_types = { + "ALL Reads": "all_read", + "3:1 Reads-Writes": "3:1_read_write", + "2:1 Reads-Writes": "2:1_read_write", + "1:1 Reads-Writes": "1:1_read_write", + } + + for line in self.outs.splitlines(): + for pattern, suffix in bandwidth_types.items(): + if pattern in line and ":" in line: + parts = line.split(":") + if len(parts) >= 2: + try: + bandwidth = float(parts[-1].strip()) + result = PerfData( + name=f"mlc_peak_injection_bandwidth_result-{suffix}", + value_type=ValueType.HIB, + key_item=KeyItem.avg, + unit="MB/s", + label=self.label, + ) + result.set_key_value(value=bandwidth) + result_list.append(result) + except ValueError: + continue + break + + if not result_list: + raise Exception("Failed to parse peak_injection_bandwidth results") + + return result_list + + def _parse_latency_matrix(self) -> list: + """解析 latency_matrix 测试结果 + 输出格式示例: + Numa node + Numa node 0 1 + 0 125.9 162.2 + 1 186.3 101.8 + + 输出指标: + --samenuma_latency_max: 同NUMA时延最大值 (80.7) + --samenuma_latency_min: 同NUMA时延最小值 (80.6) + --difnuma_latency_max: 不同NUMA时延最大值 (140.0) + --difnuma_latency_min: 不同NUMA时延最小值 (139.8) + """ + result_list = [] + in_data_section = False + header_found = False + + # 收集同NUMA和不同NUMA的延迟值 + samenuma_latencies = [] + difnuma_latencies = [] + + for line in self.outs.splitlines(): + if "Numa node" in line and not header_found: + header_found = True + continue + if header_found and "Numa node" not in line: + in_data_section = True + if in_data_section and line.strip(): + parts = line.split() + if len(parts) >= 2: + try: + src_node = int(parts[0]) + for dst_idx, value in enumerate(parts[1:]): + latency = float(value) + if src_node == dst_idx: + samenuma_latencies.append(latency) + else: + difnuma_latencies.append(latency) + except (ValueError, IndexError): + continue + + # 同NUMA时延最大值 + if samenuma_latencies: + result = PerfData( + name="mlc_latency_matrix_result-samenuma_latency_max", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=max(samenuma_latencies)) + result_list.append(result) + + result = PerfData( + name="mlc_latency_matrix_result-samenuma_latency_min", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=min(samenuma_latencies)) + result_list.append(result) + + # 不同NUMA时延最大值和最小值 + if difnuma_latencies: + result = PerfData( + name="mlc_latency_matrix_result-difnuma_latency_max", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=max(difnuma_latencies)) + result_list.append(result) + + result = PerfData( + name="mlc_latency_matrix_result-difnuma_latency_min", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=min(difnuma_latencies)) + result_list.append(result) + + if not result_list: + raise Exception("Failed to parse latency_matrix results") + + return result_list + + def _parse_bandwidth_matrix(self) -> list: + """解析 bandwidth_matrix 测试结果 + 输出格式类似 latency_matrix + + 输出指标: + --samenuma_bandwidth_max: 同NUMA带宽最大值 (123556.8) + --samenuma_bandwidth_min: 同NUMA带宽最小值 (123280.2) + --difnuma_bandwidth_max: 不同NUMA带宽最大值 (34261.4) + --difnuma_bandwidth_min: 不同NUMA带宽最小值 (34131.5) + """ + result_list = [] + in_data_section = False + header_found = False + + # 收集同NUMA和不同NUMA的带宽值 + samenuma_bandwidths = [] + difnuma_bandwidths = [] + + for line in self.outs.splitlines(): + if "Numa node" in line and not header_found: + header_found = True + continue + if header_found and "Numa node" not in line: + in_data_section = True + if in_data_section and line.strip(): + parts = line.split() + if len(parts) >= 2: + try: + src_node = int(parts[0]) + for dst_idx, value in enumerate(parts[1:]): + bandwidth = float(value) + if src_node == dst_idx: + samenuma_bandwidths.append(bandwidth) + else: + difnuma_bandwidths.append(bandwidth) + except (ValueError, IndexError): + continue + + # 同NUMA带宽最大值和最小值 + if samenuma_bandwidths: + result = PerfData( + name="mlc_bandwidth_matrix_result-samenuma_bandwidth_max", + value_type=ValueType.HIB, + key_item=KeyItem.avg, + unit="MB/s", + label=self.label, + ) + result.set_key_value(value=max(samenuma_bandwidths)) + result_list.append(result) + + result = PerfData( + name="mlc_bandwidth_matrix_result-samenuma_bandwidth_min", + value_type=ValueType.HIB, + key_item=KeyItem.avg, + unit="MB/s", + label=self.label, + ) + result.set_key_value(value=min(samenuma_bandwidths)) + result_list.append(result) + + # 不同NUMA带宽最大值和最小值 + if difnuma_bandwidths: + result = PerfData( + name="mlc_bandwidth_matrix_result-difnuma_bandwidth_max", + value_type=ValueType.HIB, + key_item=KeyItem.avg, + unit="MB/s", + label=self.label, + ) + result.set_key_value(value=max(difnuma_bandwidths)) + result_list.append(result) + + result = PerfData( + name="mlc_bandwidth_matrix_result-difnuma_bandwidth_min", + value_type=ValueType.HIB, + key_item=KeyItem.avg, + unit="MB/s", + label=self.label, + ) + result.set_key_value(value=min(difnuma_bandwidths)) + result_list.append(result) + + if not result_list: + raise Exception("Failed to parse bandwidth_matrix results") + + return result_list + + def cleanup(self): + """性能测试完成后cleanup""" + pass + + class PerfUnixbench(TSTPerf): def __init__( self, @@ -878,7 +1286,7 @@ class PerfLMbench(TSTPerf): elif self.name == "lat_ctx": result.append(self.parse_result_ctx()) elif self.name == "lat_mem_rd": - result.append(self.parse_result_mem_rd()) + result.extend(self.parse_result_mem_rd()) elif self.name == "lat_fs": result.append(self.parse_result_fs()) elif self.name == "lat_ops": @@ -934,31 +1342,143 @@ class PerfLMbench(TSTPerf): return result def parse_result_mem_rd(self): - result = PerfData( - name=self.testname, - value_type=ValueType.LIB, - key_item=KeyItem.avg, - unit="ns", - label=self.label, - ) + """解析 lat_mem_rd 测试结果 + 输出格式示例: + "stride=128 + 0.00098 1.234 + 0.00195 1.345 + ... + 0.12500 5.678 + ... + 8.00000 89.012 + + 输出指标: + --l1_latency: L1缓存延迟 (约1KB数组大小) + --l2_latency: L2缓存延迟 (约128KB数组大小) + --l3_latency: L3缓存延迟 (约2-8MB数组大小) + --mem_latency: 主内存延迟 (最大数组大小) + """ + # 新版本的完整解析:返回所有缓存级别的延迟 + result_list = [] + # 解析所有数据点 + data_points = [] + size_list = [] + lat_list = [] lines = self.outs.splitlines() - if "l1" in self.testname: - last_line = lines[2] - mean = float(last_line.split()[-1]) - result.set_key_value(value=mean) - return result - elif "l2" in self.testname: - last_line = lines[25] - mean = float(last_line.split()[-1]) - result.set_key_value(value=mean) - return result - else: - last_line = lines[-2] - print(last_line) - mean = float(last_line.split()[-1]) - result.set_key_value(value=mean) - return result + + for line in lines: + line = line.strip() + if not line or line.startswith('"'): + continue + + parts = line.split() + if len(parts) >= 2: + try: + size_mb = float(parts[0]) + latency_ns = float(parts[1]) + data_points.append((size_mb, latency_ns)) + size_list.append(size_mb) + lat_list.append(latency_ns) + except (ValueError, IndexError): + continue + + if not data_points: + # 没有数据点 + return result_list + + # 使用参考代码中的算法:基于实际缓存大小识别缓存级别 + # 获取系统缓存大小信息(如果可用) + cache_range = self._get_cache_sizes() + + # 如果没有获取到缓存大小信息,使用默认的缓存大小估计 + if not cache_range: + # 默认缓存大小估计(MB) + cache_range = [0.032, 1.024, 36.608] # L1: ~32KB, L2: ~1MB, L3: ~36MB + + # 使用二分查找定位缓存边界 + size_list.sort() + lat_list.sort() + + # 查找每个缓存级别对应的索引位置 + index_list = [bisect.bisect_left(size_list, cr) for cr in cache_range] + index_list.insert(0, 0) # 添加起始索引 + index_list.append(len(lat_list)) # 添加结束索引 + + # 计算每个缓存级别的延迟(使用中位数) + result_list_values = [] + for i in range(1, len(index_list)): + sub_list = lat_list[index_list[i - 1]:index_list[i]] + if sub_list: + median_latency = round(np.median(sub_list), 3) + result_list_values.append(median_latency) + else: + result_list_values.append(None) + self.log(f"警告: 缓存级别 {i} 没有数据点") + + # 主内存延迟使用最后一个数据点 + mem_latency = lat_list[-1] if lat_list else None + + # 根据检测到的缓存级别数量分配延迟值 + l1_latency = result_list_values[0] if len(result_list_values) > 0 else None + l2_latency = result_list_values[1] if len(result_list_values) > 1 else None + l3_latency = result_list_values[2] if len(result_list_values) > 2 else None + + # 打印调试信息 + self.log(f"检测到缓存级别: L1={l1_latency}ns, L2={l2_latency}ns, L3={l3_latency}ns, 内存={mem_latency}ns") + + # 创建各级缓存的 PerfData 对象 + if l1_latency is not None: + result = PerfData( + name=f"{self.testname}-l1_latency", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=l1_latency) + result_list.append(result) + + if l2_latency is not None: + result = PerfData( + name=f"{self.testname}-l2_latency", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=l2_latency) + result_list.append(result) + + if l3_latency is not None: + result = PerfData( + name=f"{self.testname}-l3_latency", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=l3_latency) + result_list.append(result) + + if mem_latency is not None: + result = PerfData( + name=f"{self.testname}-mem_latency", + value_type=ValueType.LIB, + key_item=KeyItem.avg, + unit="ns", + label=self.label, + ) + result.set_key_value(value=mem_latency) + result_list.append(result) + + return result_list + + def _get_cache_sizes(self): + """获取系统缓存大小信息""" + # 这里可以扩展为从系统信息获取实际缓存大小 + # 目前返回空列表,使用默认估计值 + return [] def parse_result_bandwidth(self): result = PerfData( diff --git a/templates/tperf.csv b/templates/tperf.csv index de668eb..a229c92 100644 --- a/templates/tperf.csv +++ b/templates/tperf.csv @@ -1011,3 +1011,81 @@ tperf-qperf-udp-len-60000-bw,tperf-qperf-udp-len-60000-bw-udp_bw,网络,,,40 tperf-qperf-udp-len-60000-lat,tperf-qperf-udp-len-60000-lat-udp_lat,网络,,,40 tperf-qperf-udp-len-64-bw,tperf-qperf-udp-len-64-bw-udp_bw,网络,,,40 tperf-qperf-udp-len-64-lat,tperf-qperf-udp-len-64-lat-udp_lat,网络,,,40 +tperf-sysbench-memory-thread-1,tperf-sysbench-memory-thread-1,内存,,,50 +tperf-sysbench-memory-thread-max,tperf-sysbench-memory-thread-max,内存,,,50 +tperf-sysbench-memory-block-1k-size-1g-seqrd,tperf-sysbench-memory-block-1k-size-1g-seqrd,内存,,,30 +tperf-sysbench-memory-block-2k-size-1g-seqrd,tperf-sysbench-memory-block-2k-size-1g-seqrd,内存,,,30 +tperf-sysbench-memory-block-4k-size-1g-seqrd,tperf-sysbench-memory-block-4k-size-1g-seqrd,内存,,,30 +tperf-sysbench-memory-block-16k-size-1g-seqrd,tperf-sysbench-memory-block-16k-size-1g-seqrd,内存,,,30 +tperf-sysbench-memory-block-32k-size-1g-seqrd,tperf-sysbench-memory-block-32k-size-1g-seqrd,内存,,,40 +tperf-sysbench-memory-block-32k-size-1g-seqwr,tperf-sysbench-memory-block-32k-size-1g-seqwr,内存,,,40 +tperf-sysbench-memory-block-32k-size-1g-rndrd,tperf-sysbench-memory-block-32k-size-1g-rndrd,内存,,,40 +tperf-sysbench-memory-block-32k-size-1g-rndwr,tperf-sysbench-memory-block-32k-size-1g-rndwr,内存,,,40 +tperf-sysbench-memory-block-64k-size-10g-rndrd,tperf-sysbench-memory-block-64k-size-10g-rndrd,内存,,,40 +tperf-sysbench-memory-block-64k-size-10g-rndwr,tperf-sysbench-memory-block-64k-size-10g-rndwr,内存,,,40 +tperf-sysbench-memory-block-128k-size-10g-seqrd,tperf-sysbench-memory-block-128k-size-10g-seqrd,内存,,,40 +tperf-sysbench-memory-block-128k-size-10g-rndwr,tperf-sysbench-memory-block-128k-size-10g-rndwr,内存,,,40 +tperf-sysbench-memory-block-256k-size-10g-rndwr,tperf-sysbench-memory-block-256k-size-10g-rndwr,内存,,,40 +tperf-sysbench-memory-block-512k-size-10g-seqwr,tperf-sysbench-memory-block-512k-size-10g-seqwr,内存,,,40 +tperf-sysbench-memory-block-512k-size-10g-rndwr,tperf-sysbench-memory-block-512k-size-10g-rndwr,内存,,,40 +tperf-sysbench-memory-block-1g-size-10g-rndrd,tperf-sysbench-memory-block-1g-size-10g-rndrd,内存,,,50 +tperf-sysbench-memory-block-1g-size-10g-rndwr,tperf-sysbench-memory-block-1g-size-10g-rndwr,内存,,,50 +tperf-stream-single,stream-single-thread-Add,内存,,,50 +,stream-single-thread-Copy,内存,,,50 +,stream-single-thread-Scale,内存,,,50 +,stream-single-thread-Triad,内存,,,50 +tperf-stream-max,stream-max-thread-Add,内存,,,50 +,stream-max-thread-Copy,内存,,,50 +,stream-max-thread-Scale,内存,,,50 +,stream-max-thread-Triad,内存,,,50 +tperf-lmbench-lat_mem_rd-prefetch-on,tperf-lmbench-lat_mem_rd-prefetch-on-l1_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-on-l2_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-on-l3_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-on-mem_latency,内存,,,50 +tperf-lmbench-lat_mem_rd-prefetch-off,tperf-lmbench-lat_mem_rd-prefetch-off-l1_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-off-l2_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-off-l3_latency,内存,,,50 +,tperf-lmbench-lat_mem_rd-prefetch-off-mem_latency,内存,,,50 +tperf-mlc-idle-latency,mlc_idle_latency_result-idle_latency,内存,,,50 +tperf-mlc-peak-bandwidth,mlc_peak_injection_bandwidth_result-all_read,内存,,,50 +,mlc_peak_injection_bandwidth_result-3:1_read_write,内存,,,50 +,mlc_peak_injection_bandwidth_result-2:1_read_write,内存,,,50 +,mlc_peak_injection_bandwidth_result-1:1_read_write,内存,,,50 +tperf-mlc-loaded-latency,mlc_loaded_latency_result-loaded_latency_min,内存,,,50 +,mlc_loaded_latency_result-loaded_latency_max,内存,,,50 +tperf-mlc-bandwidth-matrix,mlc_bandwidth_matrix_result-samenuma_bandwidth_max,内存,,,50 +,mlc_bandwidth_matrix_result-samenuma_bandwidth_min,内存,,,50 +,mlc_bandwidth_matrix_result-difnuma_bandwidth_max,内存,,,50 +,mlc_bandwidth_matrix_result-difnuma_bandwidth_min,内存,,,50 +tperf-libmicro-memcpy_1k,tperf-libmicro-memcpy_1k,内存,,,50 +tperf-libmicro-memcpy_100k,tperf-libmicro-memcpy_100k,内存,,,50 +tperf-libmicro-memset_10k,tperf-libmicro-memset_10k,内存,,,50 +tperf-libmicro-memset_100k,tperf-libmicro-memset_100k,内存,,,50 +tperf-libmicro-malloc_1k,tperf-libmicro-malloc_1k,内存,,,30 +tperf-libmicro-malloc_1m,tperf-libmicro-malloc_1m,内存,,,30 +tperf-lmbench-bw_mem-fwr,tperf-lmbench-bw_mem-fwr,内存,,,50 +tperf-lmbench-bw_mem-cp,tperf-lmbench-bw_mem-cp,内存,,,50 +tperf-lmbench-bw_mem-fcp,tperf-lmbench-bw_mem-fcp,内存,,,50 +tperf-lmbench-bw_mem-bcopy,tperf-lmbench-bw_mem-bcopy,内存,,,50 +tperf-stream-thread-4,stream-thread-4-Add,内存,,,50 +,stream-thread-4-Copy,内存,,,50 +,stream-thread-4-Scale,内存,,,50 +,stream-thread-4-Triad,内存,,,50 +tperf-stream-thread-8,stream-thread-8-Add,内存,,,50 +,stream-thread-8-Copy,内存,,,50 +,stream-thread-8-Scale,内存,,,50 +,stream-thread-8-Triad,内存,,,50 +tperf-stream-thread-16,stream-thread-16-Add,内存,,,50 +,stream-thread-16-Copy,内存,,,50 +,stream-thread-16-Scale,内存,,,50 +,stream-thread-16-Triad,内存,,,50 +tperf-stream-thread-32,stream-thread-32-Add,内存,,,50 +,stream-thread-32-Copy,内存,,,50 +,stream-thread-32-Scale,内存,,,50 +,stream-thread-32-Triad,内存,,,50 +tperf-mlc-latency-matrix,mlc_latency_matrix_result-samenuma_latency_min,内存,,,50 +,mlc_latency_matrix_result-samenuma_latency_max,内存,,,50 +,mlc_latency_matrix_result-difnuma_latency_min,内存,,,50 +,mlc_latency_matrix_result-difnuma_latency_max,内存,,,50 +tperf-libmicro-strcpy_1k,tperf-libmicro-strcpy_1k,内存,,,80 +tperf-libmicro-strchr_10,tperf-libmicro-strchr_10,内存,,,80 diff --git a/testcase/tperf-libmicro-malloc_1k.py b/testcase/tperf-libmicro-malloc_1k.py new file mode 100755 index 0000000..77c77c7 --- /dev/null +++ b/testcase/tperf-libmicro-malloc_1k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000105 + @用例名称: tperf-libmicro-malloc_1k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N malloc_1k -s 1k -g 10 -I 100 -B 100", + tool_path="tools/libmicro.install/build/malloc" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-malloc_1m.py b/testcase/tperf-libmicro-malloc_1m.py new file mode 100755 index 0000000..84cce53 --- /dev/null +++ b/testcase/tperf-libmicro-malloc_1m.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000106 + @用例名称: tperf-libmicro-malloc_1m + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N malloc_1m -s 1m -g 10 -I 2000 -B 100", + tool_path="tools/libmicro.install/build/malloc" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-memcpy_100k.py b/testcase/tperf-libmicro-memcpy_100k.py new file mode 100755 index 0000000..dd05da1 --- /dev/null +++ b/testcase/tperf-libmicro-memcpy_100k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000101 + @用例名称: tperf-libmicro-memcpy_100k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N memcpy_100k -s 100k -I 1000 -B 100", + tool_path="tools/libmicro.install/build/memcpy" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-memcpy_1k.py b/testcase/tperf-libmicro-memcpy_1k.py new file mode 100755 index 0000000..c556c1c --- /dev/null +++ b/testcase/tperf-libmicro-memcpy_1k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000102 + @用例名称: tperf-libmicro-memcpy_1k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N memcpy_1k -s 1k -I 500 -B 100", + tool_path="tools/libmicro.install/build/memcpy" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-memset_100k.py b/testcase/tperf-libmicro-memset_100k.py new file mode 100755 index 0000000..6452b05 --- /dev/null +++ b/testcase/tperf-libmicro-memset_100k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000104 + @用例名称: tperf-libmicro-memset_100k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N memset_100k -s 100k -I 1000 -B 100", + tool_path="tools/libmicro.install/build/memset", + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-memset_10k.py b/testcase/tperf-libmicro-memset_10k.py new file mode 100755 index 0000000..64c3c26 --- /dev/null +++ b/testcase/tperf-libmicro-memset_10k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000103 + @用例名称: tperf-libmicro-memset_10k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N memset_10k -s 10k -I 800 -B 100", + tool_path="tools/libmicro.install/build/memset", + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-strchr_10.py b/testcase/tperf-libmicro-strchr_10.py new file mode 100755 index 0000000..3598925 --- /dev/null +++ b/testcase/tperf-libmicro-strchr_10.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000502 + @用例名称: tperf-libmicro-strchr_10 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N strchr_10 -s 10 -I 100 -B 100", + tool_path="tools/libmicro.install/build/strchr" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-libmicro-strcpy_1k.py b/testcase/tperf-libmicro-strcpy_1k.py new file mode 100755 index 0000000..7abe60e --- /dev/null +++ b/testcase/tperf-libmicro-strcpy_1k.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLibMicro # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000501 + @用例名称: tperf-libmicro-strcpy_1k + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用libmicro测试系统性能 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统启动 + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 使用使用libmicro测试系统性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLibMicro( + name=self.tc_name, + label="L0:内存", + test_opt="-E -C 2000 -L -S -W -N strcpy_1k -s 1k -I 200 -B 100", + tool_path="tools/libmicro.install/build/strcpy" + ) + perf.run(warmup=1, run_loop=20, result_select_percent=80) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-lmbench-bw_mem-bcopy.py b/testcase/tperf-lmbench-bw_mem-bcopy.py new file mode 100755 index 0000000..6a419ca --- /dev/null +++ b/testcase/tperf-lmbench-bw_mem-bcopy.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import pathlib +import subprocess +import sys +from typing import List + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000204 + @用例名称: tperf-lmbench-bw_mem-bcopy + @用例级别: 3 + @用例标签: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存带宽-bcopy模式 + """ + + def tc_setup(self, *args): + # @预置条件: + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试lmbench性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLMbench( + name="bw_mem", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 4096m bcopy" + ) + perf.run() + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == '__main__': + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-lmbench-bw_mem-cp.py b/testcase/tperf-lmbench-bw_mem-cp.py new file mode 100755 index 0000000..e56eb57 --- /dev/null +++ b/testcase/tperf-lmbench-bw_mem-cp.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import pathlib +import subprocess +import sys +from typing import List + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000202 + @用例名称: tperf-lmbench-bw_mem-cp + @用例级别: 3 + @用例标签: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存带宽-cp模式 + """ + + def tc_setup(self, *args): + # @预置条件: + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试lmbench性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLMbench( + name="bw_mem", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 4096m cp" + ) + perf.run() + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == '__main__': + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-lmbench-bw_mem-fcp.py b/testcase/tperf-lmbench-bw_mem-fcp.py new file mode 100755 index 0000000..eb0356e --- /dev/null +++ b/testcase/tperf-lmbench-bw_mem-fcp.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import pathlib +import subprocess +import sys +from typing import List + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000203 + @用例名称: tperf-lmbench-bw_mem-fcp + @用例级别: 3 + @用例标签: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存带宽-fcp模式 + """ + + def tc_setup(self, *args): + # @预置条件: + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试lmbench性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLMbench( + name="bw_mem", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 4096m fcp" + ) + perf.run() + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == '__main__': + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-lmbench-bw_mem-fwr.py b/testcase/tperf-lmbench-bw_mem-fwr.py new file mode 100755 index 0000000..d695da9 --- /dev/null +++ b/testcase/tperf-lmbench-bw_mem-fwr.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import pathlib +import subprocess +import sys +from typing import List + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000201 + @用例名称: tperf-lmbench-bw_mem-fwr + @用例级别: 3 + @用例标签: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存带宽-fwr模式 + """ + + def tc_setup(self, *args): + # @预置条件: + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试lmbench性能 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfLMbench( + name="bw_mem", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 4096m fwr" + ) + perf.run() + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == '__main__': + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-lmbench-lat_mem_rd-prefetch-off.py b/testcase/tperf-lmbench-lat_mem_rd-prefetch-off.py new file mode 100755 index 0000000..1614fe6 --- /dev/null +++ b/testcase/tperf-lmbench-lat_mem_rd-prefetch-off.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-200000-000000002 + @用例名称: tperf-lmbench-lat_mem_rd-prefetch-off + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存读取延迟(关闭硬件预取)- 同NUMA节点 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存读取延迟(关闭硬件预取) + # @预期结果: 测试正常,性能数据采集正常 + # 注意:-t 参数用于关闭硬件预取,测试同NUMA节点内存延迟 + # 命令格式: numactl --cpunodebind=0 --membind=0 lat_mem_rd -P 1 -t 8000 128 + perf = PerfLMbench( + name="lat_mem_rd", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 -t 8000 128" + ) + # 修改命令以添加numactl前缀 + perf.command = f"numactl --cpunodebind=0 --membind=0 {perf.command}" + perf.run(warmup=0, run_loop=1) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) + diff --git a/testcase/tperf-lmbench-lat_mem_rd-prefetch-on.py b/testcase/tperf-lmbench-lat_mem_rd-prefetch-on.py new file mode 100755 index 0000000..e861d0e --- /dev/null +++ b/testcase/tperf-lmbench-lat_mem_rd-prefetch-on.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfLMbench # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-200000-000000001 + @用例名称: tperf-lmbench-lat_mem_rd-prefetch-on + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用lmbench测试内存读取延迟(开启硬件预取)- 同NUMA节点 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存读取延迟(开启硬件预取) + # @预期结果: 测试正常,性能数据采集正常 + # 注意:使用numactl绑定到NUMA节点0,测试同NUMA节点内存延迟 + # 命令格式: numactl --cpunodebind=0 --membind=0 lat_mem_rd -P 1 8000 128 + perf = PerfLMbench( + name="lat_mem_rd", + testname=self.tc_name, + label="L0:内存", + general_opt="-P 1 8000 128" + ) + # 修改命令以添加numactl前缀 + perf.command = f"numactl --cpunodebind=0 --membind=0 {perf.command}" + perf.run(warmup=0, run_loop=1) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) + diff --git a/testcase/tperf-mlc-bandwidth-matrix.py b/testcase/tperf-mlc-bandwidth-matrix.py new file mode 100755 index 0000000..eabe65a --- /dev/null +++ b/testcase/tperf-mlc-bandwidth-matrix.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfMLC # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-194800-029667980 + @用例名称: tperf-mlc-bandwidth-matrix + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用Intel MLC测试NUMA节点间带宽矩阵 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试NUMA节点间带宽矩阵 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfMLC( + name="mlc-bandwidth-matrix", + test_mode="bandwidth_matrix", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=1, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-mlc-idle-latency.py b/testcase/tperf-mlc-idle-latency.py new file mode 100755 index 0000000..d3519b3 --- /dev/null +++ b/testcase/tperf-mlc-idle-latency.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfMLC # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-194800-029667976 + @用例名称: tperf-mlc-idle-latency + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用Intel MLC测试空闲内存延迟 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试空闲内存延迟 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfMLC( + name="mlc-idle", + test_mode="idle_latency", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=1, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-mlc-latency-matrix.py b/testcase/tperf-mlc-latency-matrix.py new file mode 100755 index 0000000..693dd03 --- /dev/null +++ b/testcase/tperf-mlc-latency-matrix.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfMLC # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000401 + @用例名称: tperf-mlc-latency-matrix + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用Intel MLC测试NUMA延迟矩阵 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试NUMA延迟矩阵 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfMLC( + name="mlc-latency-matrix", + test_mode="latency_matrix", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=1, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-mlc-loaded-latency.py b/testcase/tperf-mlc-loaded-latency.py new file mode 100755 index 0000000..6b34723 --- /dev/null +++ b/testcase/tperf-mlc-loaded-latency.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfMLC # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-194800-029667978 + @用例名称: tperf-mlc-loaded-latency + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用Intel MLC测试负载内存延迟和带宽 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试负载内存延迟和带宽 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfMLC( + name="mlc-loaded", + test_mode="loaded_latency", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=1, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-mlc-peak-bandwidth.py b/testcase/tperf-mlc-peak-bandwidth.py new file mode 100755 index 0000000..7159e37 --- /dev/null +++ b/testcase/tperf-mlc-peak-bandwidth.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfMLC # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-194800-029667977 + @用例名称: tperf-mlc-peak-bandwidth + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用Intel MLC测试峰值注入带宽 + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试峰值注入带宽 + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfMLC( + name="mlc-peak", + test_mode="peak_injection_bandwidth", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=1, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-stream-max.py b/testcase/tperf-stream-max.py new file mode 100755 index 0000000..f89e2b7 --- /dev/null +++ b/testcase/tperf-stream-max.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import multiprocessing +import os +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfStream # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-100000-599002773 + @用例名称: tperf-stream-max + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用stream测试内存性能(整机线程数) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + # 设置线程数为CPU核心数 + cpu_count = multiprocessing.cpu_count() + os.environ["OMP_NUM_THREADS"] = str(cpu_count) + self.msg(f"Set OMP_NUM_THREADS={cpu_count}") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存性能(整机线程数) + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfStream( + name="stream-max-thread", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=40, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-stream-single.py b/testcase/tperf-stream-single.py index 67f2073..97cc8c4 100755 --- a/testcase/tperf-stream-single.py +++ b/testcase/tperf-stream-single.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # coding: utf-8 +import os import os.path import stat import sys @@ -29,6 +30,9 @@ class PythonTestCase(MyTestCase): def tc_setup(self, *args): self.msg("this is tc_setup") + # 设置线程数为1,确保单线程运行 + os.environ["OMP_NUM_THREADS"] = "1" + self.msg("Set OMP_NUM_THREADS=1") def do_test(self, *args): self.msg("this is do_test") diff --git a/testcase/tperf-stream-thread-16.py b/testcase/tperf-stream-thread-16.py new file mode 100755 index 0000000..081fed3 --- /dev/null +++ b/testcase/tperf-stream-thread-16.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfStream # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000303 + @用例名称: tperf-stream-thread-16 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用stream测试内存性能(16线程) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + # 设置线程数为16 + os.environ["OMP_NUM_THREADS"] = "16" + self.msg("Set OMP_NUM_THREADS=16") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存性能(16线程) + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfStream( + name="stream-thread-16", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=40, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-stream-thread-32.py b/testcase/tperf-stream-thread-32.py new file mode 100755 index 0000000..0f50b40 --- /dev/null +++ b/testcase/tperf-stream-thread-32.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfStream # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000304 + @用例名称: tperf-stream-thread-32 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用stream测试内存性能(32线程) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + # 设置线程数为32 + os.environ["OMP_NUM_THREADS"] = "32" + self.msg("Set OMP_NUM_THREADS=32") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存性能(32线程) + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfStream( + name="stream-thread-32", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=40, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-stream-thread-4.py b/testcase/tperf-stream-thread-4.py new file mode 100755 index 0000000..3a5e444 --- /dev/null +++ b/testcase/tperf-stream-thread-4.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfStream # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000301 + @用例名称: tperf-stream-thread-4 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用stream测试内存性能(4线程) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + # 设置线程数为4 + os.environ["OMP_NUM_THREADS"] = "4" + self.msg("Set OMP_NUM_THREADS=4") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存性能(4线程) + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfStream( + name="stream-thread-4", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=40, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-stream-thread-8.py b/testcase/tperf-stream-thread-8.py new file mode 100755 index 0000000..a7723d9 --- /dev/null +++ b/testcase/tperf-stream-thread-8.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import os.path +import stat +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfStream # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251223-170001-000000302 + @用例名称: tperf-stream-thread-8 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用stream测试内存性能(8线程) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + # 设置线程数为8 + os.environ["OMP_NUM_THREADS"] = "8" + self.msg("Set OMP_NUM_THREADS=8") + + def do_test(self, *args): + self.msg("this is do_test") + + # @测试步骤: 测试内存性能(8线程) + # @预期结果: 测试正常,性能数据采集正常 + perf = PerfStream( + name="stream-thread-8", + label="L0:内存", + ) + perf.run(warmup=0, run_loop=40, result_select_percent=70) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-sysbench-memory-block-256k-size-10g-rndwr.py b/testcase/tperf-sysbench-memory-block-256k-size-10g-rndwr.py index c20a879..150d857 100755 --- a/testcase/tperf-sysbench-memory-block-256k-size-10g-rndwr.py +++ b/testcase/tperf-sysbench-memory-block-256k-size-10g-rndwr.py @@ -36,7 +36,7 @@ class PythonTestCase(MyTestCase): # @测试步骤: 使用sysbench执行memory性能测试 # @预期结果: 性能测试正常并且可以获取到性能数据 perf = PerfSysBench( - name="tperf-sysbench-memory-block-2568k-size-10g-rndwr", + name="tperf-sysbench-memory-block-256k-size-10g-rndwr", testname="memory", label="L0:内存", general_opt="--memory-block-size=256k --memory-total-size=10G --memory-oper=write --memory-access-mode=rnd", diff --git a/testcase/tperf-sysbench-memory-block-64k-size-10g-rndrd.py b/testcase/tperf-sysbench-memory-block-64k-size-10g-rndrd.py index 14c67af..5c0b4e0 100755 --- a/testcase/tperf-sysbench-memory-block-64k-size-10g-rndrd.py +++ b/testcase/tperf-sysbench-memory-block-64k-size-10g-rndrd.py @@ -36,7 +36,7 @@ class PythonTestCase(MyTestCase): # @测试步骤: 使用sysbench执行memory性能测试 # @预期结果: 性能测试正常并且可以获取到性能数据 perf = PerfSysBench( - name="tperf-sysbench-memory-block-64k-size-10g-rndwr", + name="tperf-sysbench-memory-block-64k-size-10g-rndrd", testname="memory", label="L0:内存", general_opt="--memory-block-size=64k --memory-total-size=10G --memory-oper=read --memory-access-mode=rnd", diff --git a/testcase/tperf-sysbench-memory-thread-1.py b/testcase/tperf-sysbench-memory-thread-1.py new file mode 100755 index 0000000..4c3df65 --- /dev/null +++ b/testcase/tperf-sysbench-memory-thread-1.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfSysBench # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-100001-100000001 + @用例名称: tperf-sysbench-memory-thread-1 + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用sysbench工具测试内存带宽性能(单线程) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统正常启动 + + def do_test(self, *args): + self.msg("this is do_test") + # @测试步骤: 使用sysbench执行内存性能测试(单线程) + # @预期结果: 性能测试正常并且可以获取到内存带宽数据 + perf = PerfSysBench( + name="tperf-sysbench-memory-thread-1", + testname="memory", + label="L0:内存", + general_opt="--threads=1 --time=300", + ) + perf.run(warmup=1, run_loop=1, result_select_percent=90) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-sysbench-memory-thread-max.py b/testcase/tperf-sysbench-memory-thread-max.py new file mode 100755 index 0000000..4c41218 --- /dev/null +++ b/testcase/tperf-sysbench-memory-thread-max.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +import os +import os.path +import sys + +_suite_top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") +while _suite_top_dir != "/": + if os.path.isfile(os.path.join(_suite_top_dir, "tsuite")): + break + _suite_top_dir = os.path.dirname(_suite_top_dir) +sys.path.append(_suite_top_dir) +from lib.ts_common import MyTestCase, PerfSysBench # noqa: E402 + + +class PythonTestCase(MyTestCase): + """ + @用例ID: 20251217-100002-100000002 + @用例名称: tperf-sysbench-memory-thread-max + @用例级别: 3 + @用例标签: + @扩展属性: + @用例类型: 性能测试 + @自动化: 1 + @超时时间: 0 + @用例描述: 使用sysbench工具测试内存带宽性能(最大线程数) + """ + + def tc_setup(self, *args): + self.msg("this is tc_setup") + + # @预置条件: 系统正常启动 + + def do_test(self, *args): + self.msg("this is do_test") + # @测试步骤: 使用sysbench执行内存性能测试(最大线程数) + # @预期结果: 性能测试正常并且可以获取到内存带宽数据 + + # 获取系统CPU核心数作为最大线程数 + max_threads = os.cpu_count() or 1 + + perf = PerfSysBench( + name="tperf-sysbench-memory-thread-max", + testname="memory", + label="L0:内存", + general_opt=f"--threads={max_threads} --time=300", + ) + perf.run(warmup=1, run_loop=1, result_select_percent=90) + perf.report(testcase=self) + self.assert_true(len(perf.results) > 0) + + def tc_teardown(self, *args): + self.msg("this is tc_teardown") + + +if __name__ == "__main__": + PythonTestCase().tst_main(sys.argv) diff --git a/testcase/tperf-sysbench-threads-16-locks-16-yields-1000.py b/testcase/tperf-sysbench-threads-16-locks-16-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-16-yields-10000.py b/testcase/tperf-sysbench-threads-16-locks-16-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-16-yields-5000.py b/testcase/tperf-sysbench-threads-16-locks-16-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-32-yields-1000.py b/testcase/tperf-sysbench-threads-16-locks-32-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-32-yields-10000.py b/testcase/tperf-sysbench-threads-16-locks-32-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-32-yields-5000.py b/testcase/tperf-sysbench-threads-16-locks-32-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-48-yields-5000.py b/testcase/tperf-sysbench-threads-16-locks-48-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-8-yields-1000.py b/testcase/tperf-sysbench-threads-16-locks-8-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-8-yields-10000.py b/testcase/tperf-sysbench-threads-16-locks-8-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-8-yields-5000.py b/testcase/tperf-sysbench-threads-16-locks-8-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-16-locks-96-yields-5000.py b/testcase/tperf-sysbench-threads-16-locks-96-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-16-yields-1000.py b/testcase/tperf-sysbench-threads-32-locks-16-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-16-yields-10000.py b/testcase/tperf-sysbench-threads-32-locks-16-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-16-yields-5000.py b/testcase/tperf-sysbench-threads-32-locks-16-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-32-yields-1000.py b/testcase/tperf-sysbench-threads-32-locks-32-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-32-yields-10000.py b/testcase/tperf-sysbench-threads-32-locks-32-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-32-yields-5000.py b/testcase/tperf-sysbench-threads-32-locks-32-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-48-yields-5000.py b/testcase/tperf-sysbench-threads-32-locks-48-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-8-yields-1000.py b/testcase/tperf-sysbench-threads-32-locks-8-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-8-yields-10000.py b/testcase/tperf-sysbench-threads-32-locks-8-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-8-yields-5000.py b/testcase/tperf-sysbench-threads-32-locks-8-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-32-locks-96-yields-5000.py b/testcase/tperf-sysbench-threads-32-locks-96-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-16-yields-5000.py b/testcase/tperf-sysbench-threads-8-locks-16-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-32-yields-5000.py b/testcase/tperf-sysbench-threads-8-locks-32-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-48-yields-1000.py b/testcase/tperf-sysbench-threads-8-locks-48-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-48-yields-10000.py b/testcase/tperf-sysbench-threads-8-locks-48-yields-10000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-48-yields-5000.py b/testcase/tperf-sysbench-threads-8-locks-48-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-8-yields-5000.py b/testcase/tperf-sysbench-threads-8-locks-8-yields-5000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-96-yields-1000.py b/testcase/tperf-sysbench-threads-8-locks-96-yields-1000.py old mode 100644 new mode 100755 diff --git a/testcase/tperf-sysbench-threads-8-locks-96-yields-5000.py b/testcase/tperf-sysbench-threads-8-locks-96-yields-5000.py old mode 100644 new mode 100755 diff --git a/tools/mlc/mlc b/tools/mlc/mlc new file mode 100755 index 0000000000000000000000000000000000000000..8e90526f0300d438d89e4d85739cc09251541fa7 GIT binary patch literal 221120 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 | tee "${g_install_dir}/tst-build.log" + if [ "${PIPESTATUS[0]}" -eq 0 ]; then + echo "build $g_tool_dir success, dir $g_install_dir" + return 0 + else + [ -e "${g_install_dir}.fail" ] && rm -rf "${g_install_dir}.fail" + mv "$g_install_dir" "${g_install_dir}.fail" + echo "build $g_tool_dir fail, dir $g_install_dir" + return 1 + fi +} + +main "$@" -- Gitee