Skip to content

Commit 189fa17

Browse files
feat(test): 添加 pwritev 性能测试程序
1 parent 97e27f9 commit 189fa17

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// ==============================================
2+
//
3+
// 本文件用于测试系统调用 pwritev 在使用
4+
// 大量小块数据写入时的性能表现。
5+
// 重点测试 user_access_len() 函数的开销
6+
//
7+
// ==============================================
8+
9+
#include <fcntl.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <sys/stat.h>
13+
#include <sys/types.h>
14+
#include <sys/uio.h>
15+
#include <unistd.h>
16+
#include <time.h>
17+
#include <string.h>
18+
#include <errno.h>
19+
20+
#define TEST_FILE "pwritev_test.dat"
21+
#define NUM_IOV 1000
22+
#define SMALL_DATA_SIZE 64
23+
#define TOTAL_ITERATIONS 100
24+
25+
// 测试用的小数据块
26+
struct test_iovec {
27+
struct iovec iov[NUM_IOV];
28+
char data[NUM_IOV][SMALL_DATA_SIZE];
29+
};
30+
31+
// 初始化测试数据
32+
void init_test_data(struct test_iovec *test_vec) {
33+
for (int i = 0; i < NUM_IOV; i++) {
34+
// 填充每个小块数据
35+
snprintf(test_vec->data[i], SMALL_DATA_SIZE, "Block_%04d:abcdefghijklmnopqrstuvwxyz", i);
36+
test_vec->iov[i].iov_base = test_vec->data[i];
37+
test_vec->iov[i].iov_len = strlen(test_vec->data[i]);
38+
}
39+
}
40+
41+
// 性能测试函数
42+
double test_pwritev_performance(int fd, struct test_iovec *test_vec, int iterations) {
43+
struct timespec start, end;
44+
45+
clock_gettime(CLOCK_MONOTONIC, &start);
46+
47+
for (int i = 0; i < iterations; i++) {
48+
ssize_t written = pwritev(fd, test_vec->iov, NUM_IOV, 0);
49+
if (written == -1) {
50+
perror("pwritev failed");
51+
exit(EXIT_FAILURE);
52+
}
53+
54+
// 计算总写入字节数
55+
size_t total_bytes = 0;
56+
for (int j = 0; j < NUM_IOV; j++) {
57+
total_bytes += test_vec->iov[j].iov_len;
58+
}
59+
60+
if (written != total_bytes) {
61+
fprintf(stderr, "Partial write: expected %zu, got %zd\n", total_bytes, written);
62+
exit(EXIT_FAILURE);
63+
}
64+
}
65+
66+
clock_gettime(CLOCK_MONOTONIC, &end);
67+
68+
double elapsed = (end.tv_sec - start.tv_sec) +
69+
(end.tv_nsec - start.tv_nsec) / 1e9;
70+
71+
return elapsed;
72+
}
73+
74+
// 对比测试:使用单独的 write 调用
75+
double test_individual_writes_performance(int fd, struct test_iovec *test_vec, int iterations) {
76+
struct timespec start, end;
77+
78+
clock_gettime(CLOCK_MONOTONIC, &start);
79+
80+
for (int i = 0; i < iterations; i++) {
81+
off_t offset = 0;
82+
for (int j = 0; j < NUM_IOV; j++) {
83+
ssize_t written = pwrite(fd, test_vec->iov[j].iov_base,
84+
test_vec->iov[j].iov_len, offset);
85+
if (written == -1) {
86+
perror("pwrite failed");
87+
exit(EXIT_FAILURE);
88+
}
89+
if (written != test_vec->iov[j].iov_len) {
90+
fprintf(stderr, "Partial write in individual test\n");
91+
exit(EXIT_FAILURE);
92+
}
93+
offset += written;
94+
}
95+
}
96+
97+
clock_gettime(CLOCK_MONOTONIC, &end);
98+
99+
double elapsed = (end.tv_sec - start.tv_sec) +
100+
(end.tv_nsec - start.tv_nsec) / 1e9;
101+
102+
return elapsed;
103+
}
104+
105+
106+
int main(void) {
107+
struct test_iovec test_vec;
108+
109+
printf("=== pwritev Performance Test ===\n");
110+
printf("IOV count: %d\n", NUM_IOV);
111+
printf("Small data size: %d bytes\n", SMALL_DATA_SIZE);
112+
printf("Iterations: %d\n", TOTAL_ITERATIONS);
113+
printf("\n");
114+
115+
// 初始化测试数据
116+
init_test_data(&test_vec);
117+
118+
// 计算总数据大小
119+
size_t total_data_size = 0;
120+
for (int i = 0; i < NUM_IOV; i++) {
121+
total_data_size += test_vec.iov[i].iov_len;
122+
}
123+
printf("Total data per pwritev call: %zu bytes\n", total_data_size);
124+
printf("Total data to write: %zu KB\n",
125+
(total_data_size * TOTAL_ITERATIONS) / 1024);
126+
printf("\n");
127+
128+
// 创建测试文件
129+
int fd = open(TEST_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
130+
if (fd == -1) {
131+
perror("Failed to create test file");
132+
exit(EXIT_FAILURE);
133+
}
134+
135+
// 性能测试:pwritev
136+
printf("Testing pwritev performance...\n");
137+
double pwritev_time = test_pwritev_performance(fd, &test_vec, TOTAL_ITERATIONS);
138+
printf("pwritev total time: %.4f seconds\n", pwritev_time);
139+
printf("pwritev average time per call: %.6f ms\n",
140+
(pwritev_time * 1000) / TOTAL_ITERATIONS);
141+
printf("pwritev throughput: %.2f MB/s\n",
142+
(total_data_size * TOTAL_ITERATIONS) / (pwritev_time * 1024 * 1024));
143+
printf("\n");
144+
145+
// 重置文件位置
146+
if (ftruncate(fd, 0) == -1) {
147+
perror("Failed to truncate file");
148+
close(fd);
149+
exit(EXIT_FAILURE);
150+
}
151+
152+
// 性能测试:单独的 write 调用对比
153+
printf("Testing individual pwrite performance (baseline)...\n");
154+
double individual_time = test_individual_writes_performance(fd, &test_vec, TOTAL_ITERATIONS);
155+
printf("Individual pwrite total time: %.4f seconds\n", individual_time);
156+
printf("Individual pwrite average time per call: %.6f ms\n",
157+
(individual_time * 1000) / TOTAL_ITERATIONS);
158+
printf("Individual pwrite throughput: %.2f MB/s\n",
159+
(total_data_size * TOTAL_ITERATIONS) / (individual_time * 1024 * 1024));
160+
printf("\n");
161+
162+
// 性能对比
163+
double speedup = individual_time / pwritev_time;
164+
printf("Performance comparison:\n");
165+
printf("pwritev is %.2fx faster than individual writes\n", speedup);
166+
printf("pwritev saves %.2f%% time\n", (1 - pwritev_time / individual_time) * 100);
167+
printf("\n");
168+
169+
// 清理
170+
close(fd);
171+
if (unlink(TEST_FILE) == -1) {
172+
perror("Failed to remove test file");
173+
}
174+
175+
printf("test_pwritev_perf ok\n");
176+
return 0;
177+
}

0 commit comments

Comments
 (0)