DragonOS/user/apps/c_unitest/test_pwritev_perf.c

177 lines
5.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==============================================
//
// 本文件用于测试系统调用 pwritev 在使用
// 大量小块数据写入时的性能表现。
// 重点测试 user_access_len() 函数的开销
//
// ==============================================
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#define TEST_FILE "pwritev_test.dat"
#define NUM_IOV 1000
#define SMALL_DATA_SIZE 64
#define TOTAL_ITERATIONS 100
// 测试用的小数据块
struct test_iovec {
struct iovec iov[NUM_IOV];
char data[NUM_IOV][SMALL_DATA_SIZE];
};
// 初始化测试数据
void init_test_data(struct test_iovec *test_vec) {
for (int i = 0; i < NUM_IOV; i++) {
// 填充每个小块数据
snprintf(test_vec->data[i], SMALL_DATA_SIZE, "Block_%04d:abcdefghijklmnopqrstuvwxyz", i);
test_vec->iov[i].iov_base = test_vec->data[i];
test_vec->iov[i].iov_len = strlen(test_vec->data[i]);
}
}
// 性能测试函数
double test_pwritev_performance(int fd, struct test_iovec *test_vec, int iterations) {
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < iterations; i++) {
ssize_t written = pwritev(fd, test_vec->iov, NUM_IOV, 0);
if (written == -1) {
perror("pwritev failed");
exit(EXIT_FAILURE);
}
// 计算总写入字节数
size_t total_bytes = 0;
for (int j = 0; j < NUM_IOV; j++) {
total_bytes += test_vec->iov[j].iov_len;
}
if (written != total_bytes) {
fprintf(stderr, "Partial write: expected %zu, got %zd\n", total_bytes, written);
exit(EXIT_FAILURE);
}
}
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
return elapsed;
}
// 对比测试:使用单独的 write 调用
double test_individual_writes_performance(int fd, struct test_iovec *test_vec, int iterations) {
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < iterations; i++) {
off_t offset = 0;
for (int j = 0; j < NUM_IOV; j++) {
ssize_t written = pwrite(fd, test_vec->iov[j].iov_base,
test_vec->iov[j].iov_len, offset);
if (written == -1) {
perror("pwrite failed");
exit(EXIT_FAILURE);
}
if (written != test_vec->iov[j].iov_len) {
fprintf(stderr, "Partial write in individual test\n");
exit(EXIT_FAILURE);
}
offset += written;
}
}
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_nsec - start.tv_nsec) / 1e9;
return elapsed;
}
int main(void) {
struct test_iovec test_vec;
printf("=== pwritev Performance Test ===\n");
printf("IOV count: %d\n", NUM_IOV);
printf("Small data size: %d bytes\n", SMALL_DATA_SIZE);
printf("Iterations: %d\n", TOTAL_ITERATIONS);
printf("\n");
// 初始化测试数据
init_test_data(&test_vec);
// 计算总数据大小
size_t total_data_size = 0;
for (int i = 0; i < NUM_IOV; i++) {
total_data_size += test_vec.iov[i].iov_len;
}
printf("Total data per pwritev call: %zu bytes\n", total_data_size);
printf("Total data to write: %zu KB\n",
(total_data_size * TOTAL_ITERATIONS) / 1024);
printf("\n");
// 创建测试文件
int fd = open(TEST_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror("Failed to create test file");
exit(EXIT_FAILURE);
}
// 性能测试pwritev
printf("Testing pwritev performance...\n");
double pwritev_time = test_pwritev_performance(fd, &test_vec, TOTAL_ITERATIONS);
printf("pwritev total time: %.4f seconds\n", pwritev_time);
printf("pwritev average time per call: %.6f ms\n",
(pwritev_time * 1000) / TOTAL_ITERATIONS);
printf("pwritev throughput: %.2f MB/s\n",
(total_data_size * TOTAL_ITERATIONS) / (pwritev_time * 1024 * 1024));
printf("\n");
// 重置文件位置
if (ftruncate(fd, 0) == -1) {
perror("Failed to truncate file");
close(fd);
exit(EXIT_FAILURE);
}
// 性能测试:单独的 write 调用对比
printf("Testing individual pwrite performance (baseline)...\n");
double individual_time = test_individual_writes_performance(fd, &test_vec, TOTAL_ITERATIONS);
printf("Individual pwrite total time: %.4f seconds\n", individual_time);
printf("Individual pwrite average time per call: %.6f ms\n",
(individual_time * 1000) / TOTAL_ITERATIONS);
printf("Individual pwrite throughput: %.2f MB/s\n",
(total_data_size * TOTAL_ITERATIONS) / (individual_time * 1024 * 1024));
printf("\n");
// 性能对比
double speedup = individual_time / pwritev_time;
printf("Performance comparison:\n");
printf("pwritev is %.2fx faster than individual writes\n", speedup);
printf("pwritev saves %.2f%% time\n", (1 - pwritev_time / individual_time) * 100);
printf("\n");
// 清理
close(fd);
if (unlink(TEST_FILE) == -1) {
perror("Failed to remove test file");
}
printf("test_pwritev_perf ok\n");
return 0;
}