知识关系
所属体系: 工程工具与自动化 / 工程工具链 主题节点: C++编写fio测试工具 | C++写脚本,我在发疯 推荐前置: 服务器稳定性及基准测试方法 相关主题: 记录初学Python开发fio测试工具 原始来源:
source/_posts/cpp编写fio测试工具,我在发疯.md从旧博客迁移;已按知识图谱结构重新归档。
我有病,拿C++写测试工具
仓库地址:https://github.com/1949hacker/studycplusplus
fio.hpp
main.cpp
fio.cpp
长文预警
fio.hpp代码
// fio.hpp
#ifndef FIO_HPP
#define FIO_HPP
// 设置测试参数
void setConfig();
// 创建预读文件
void init_read();
// 顺序写
void fio_seq_write();
// 顺序读
void fio_seq_read();
// 随机写
void fio_rand_write();
// 随机读
void fio_rand_read();
// 随机读写测试
void fio_randrw();
// 输出结果
void runReport();
#endif // FIO_HPPmain.cpp代码
#include "fio.hpp"
#include <ctime>
#include <fstream>
#include <iostream>
#include <memory>
#include <streambuf>
#include <termios.h>
#include <unistd.h>
// Linux/macOS 下的 getch() 实现
int getch() {
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
using namespace std;
// 自定义流缓冲区类,将输出内容同时写入控制台和日志文件
class TeeBuf : public streambuf {
public:
TeeBuf(streambuf *consoleBuf, streambuf *fileBuf)
: consoleBuf(consoleBuf), fileBuf(fileBuf) {}
protected:
virtual int overflow(int c) override {
if (c == EOF) {
return !EOF;
} else {
if (consoleBuf->sputc(c) == EOF)
return EOF;
if (fileBuf->sputc(c) == EOF)
return EOF;
return c;
}
}
virtual int sync() override {
if (consoleBuf->pubsync() == -1)
return -1;
if (fileBuf->pubsync() == -1)
return -1;
return 0;
}
private:
streambuf *consoleBuf;
streambuf *fileBuf;
};
int main() {
// 日志目录初始化
int result = system("mkdir -p /var/log/fio_tool");
if (result == 0) {
std::cout << "\033[32m日志存储目录 /var/log/fio_tool 已成功创建。\033[0m"
<< std::endl;
} else {
std::cerr << "\033[31m创建目录 /var/log/fio_tool "
"时出现错误。请检查当前用户的运行权限!\033[0m"
<< std::endl;
return 0;
}
// 获取时间并格式化文件名
time_t log_time = time(nullptr);
tm *localTime = localtime(&log_time);
char timeStr[20];
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d-%H-%M-%S", localTime);
string fileName = "/var/log/fio_tool/" + string(timeStr) + ".log";
// 创建日志文件流
ofstream logFile(fileName, ios::app);
if (!logFile) {
cerr << "\033[31m无法创建日志文件!\033[0m" << endl;
return 1;
} else {
cout << "\033[32m成功创建日志文件:\033[0m" << fileName << endl;
}
// 重定向 cout 输出到日志文件和控制台
TeeBuf teeBuf(cout.rdbuf(), logFile.rdbuf());
streambuf *originalCoutBuf = cout.rdbuf(&teeBuf);
cout << "\033[36m欢迎使用fio测试工具\n日志和输出的fio."
"csv默认保存到/var/log/fio_tool/"
"\n日志不会自行清除,运行前请自行清理日志文件和检查是否残留有测试文件"
"\n输出的数据统一为KiB/s单位,iops无单位\n请<按键>"
"选择你的测试内容:\n"
<< "1. 顺序写测试\n"
<< "2. 随机写测试\n\n\n"
<< "\033[31m-------分割线-------\n"
<< "进行读测试之前需要先创建预读文件,固定为测试路径下的init_read.[0-15]"
<< ".0共16个文件\n"
<< "请自行根据测试情况判断是否需要重新生成,如需重新生成,请删除后按<r>"
<< "进行预读文件创建\n"
<< "如无需创建预读文件则直接按键开始测试即可!\n\n"
<< "测试完成后记得清理干净测试残留的文件和日志文件\n"
<< "-------分割线-------\033[36m\n\n\n"
<< "3. 顺序读测试\n"
<< "4. 随机读测试\n"
<< "5. 4k随机50%混合读写测试\n"
<< "r. 创建预读文件\n"
<< "f. Fullauto全自动测试"
<< "q. 退出程序\n"
<< "s. 你想骚一下?\033[0m" << endl;
char choice;
while (true) {
choice = getch(); // Linux/macOS 下使用自定义 getch()
cout << choice << endl; // 打印选项
switch (choice) {
case '1':
setConfig();
fio_seq_write();
return 0;
case '2':
setConfig();
fio_rand_write();
return 0;
case '3':
setConfig();
fio_seq_read();
return 0;
case '4':
setConfig();
fio_rand_read();
return 0;
case '5':
setConfig();
fio_randrw();
return 0;
case 'r':
setConfig();
init_read();
return 0;
case 'f':
setConfig();
fio_seq_write();
fio_rand_write();
init_read();
fio_seq_read();
fio_rand_read();
fio_randrw();
return 0;
case 'q':
cout << "程序已退出。" << endl;
return 0;
case 's':
while (true) {
cout << "骚个鸡儿啊,正事儿不干?我不懒得写炸机代码?" << endl;
}
return 0;
default:
cout << "\033[31m无效选项,请重新输入。\033[0m" << endl;
}
}
// 恢复 cout 的原始缓冲区
cout.rdbuf(originalCoutBuf);
return 0;
}
fio.cpp代码
#include <array>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
using namespace std;
// 全局参数
int bwMin, bwMax, bwAvg, iopsMin, iopsMax, iopsAvg, bw[] = {0, 0, 0, 0, 0, 0},
iops[] = {0, 0, 0, 0, 0, 0};
string dir, fsize, ioengine, name, fio_cmd, runtime, direct, line;
stringstream fio_output;
vector<vector<string>> run_report;
vector<string> row;
vector<int> values, bw_int, iops_int;
// 参数设置
void setConfig() {
cout << "\033[36m测试路径(完整输入,带/结尾,如/mnt/iotest/):";
cin >> dir;
cout << "测试文件大小,需要略大于内存大小,仅输入数字单位为G,size=";
cin >> fsize;
cout << "运行时长,至少30秒,仅输入数字单位为秒,runtime=";
cin >> runtime;
cout << "io测试引擎,Linux(NAS)输入libaio,ioengine=";
cin >> ioengine;
cout << "设置是否经过系统缓存,1不缓存,0操作系统缓存,direct=\033[0m";
cin >> direct;
}
// 删除测试文件
void rm_file(string name) {
string rm_command = "rm -rf " + dir + name;
system(rm_command.c_str()); // 删除 /iopsTest 目录下的所有文件
cout << "\033[32m临时文件已删除\033[0m" << endl;
}
void run_cmd(const string &cmd) {
// 重置变量
fio_output.str("");
fio_output.clear();
FILE *fp = popen(cmd.c_str(), "r");
if (fp == nullptr) {
cerr << "\033[31mError opening pipe!\033[0m" << endl;
return;
}
// 从fio输出中获取数据
char buffer[128];
while (fgets(buffer, sizeof(buffer), fp) != nullptr) {
fio_output << buffer;
}
fclose(fp);
// DEBUG:显示fio的输出内容
// cout << fio_output.str();
}
// 分析fio输出
void format(const int &i) {
vector<string> bw_num, iops_num;
while (getline(fio_output, line)) {
if (line.find("samples") != string::npos) {
cout << "\033[32;1m筛选成功,原始数据:\033[0m" << line << endl;
if (line.find("bw ") != string::npos) {
if (line.find("MiB/s") != string::npos) {
cout << "\033[32;1m检测到单位MiB/s,将转换为KiB/s\033[0m" << endl;
// 提取带宽数字
regex bw_regex(R"(\d+\.\d+|\d+)");
smatch match;
while (regex_search(line, match, bw_regex)) {
// 检测到单位是MiB,则转换为KiB
float bw_value_kib = stof(match.str());
bw_value_kib *= 1024;
int bw_value_bytes = static_cast<int>(bw_value_kib); // 转为整数
bw_num.push_back(to_string(bw_value_bytes));
line = match.suffix();
}
} else if (line.find("KiB/s") != string::npos) {
cout << "\033[32;1m检测到单位KiB/s,直接提取\033[0m" << endl;
// 提取带宽数字
regex bw_regex(R"(\d+\.\d+|\d+)");
smatch match;
while (regex_search(line, match, bw_regex)) {
bw_num.push_back(match.str());
line = match.suffix();
}
}
}
if (line.find("iops") != string::npos) {
// 提取IOPS数字
regex iops_regex(R"(\d+\.\d+|\d+)");
smatch match;
while (regex_search(line, match, iops_regex)) {
iops_num.push_back(match.str());
line = match.suffix();
}
}
}
}
// 转换为整数
for (const string &s : bw_num) {
bw_int.push_back(static_cast<int>(stof(s)));
}
for (const string &s : iops_num) {
iops_int.push_back(static_cast<int>(stof(s)));
}
// DEBUG: 检查原始数据是否正常
// for (int a : bw_int) {
// cout << "bw:" << a << endl;
// }
// for (int a : iops_int) {
// cout << "iops:" << a << endl;
// }
if (bw_int.size() > 7) {
// 混合读写
cout << "\033[32;1m" << name << " | 第" << i << "次带宽运行<读>结果:"
<< "min:" << bw_int[0] << "KiB/s max:" << bw_int[1]
<< "KiB/s avg:" << bw_int[3] << "KiB/s\n"
<< name << " | 第" << i << "次次IOPS运行<读>结果:"
<< "min:" << iops_int[0] << " max:" << iops_int[1]
<< " avg:" << iops_int[2] << endl;
cout << name << " | 第" << i << "次带宽运行<写>结果:"
<< "min:" << bw_int[6] << "KiB/s max:" << bw_int[7]
<< "KiB/s avg:" << bw_int[9] << "KiB/s\n"
<< name << " | 第" << i << "次次IOPS运行<写>结果:"
<< "min:" << iops_int[5] << " max:" << iops_int[6]
<< " avg:" << iops_int[7] << "\033[0m" << endl;
// 整理带宽和IOPS数据
bw[0] += bw_int[0];
bw[1] += bw_int[1];
bw[2] += bw_int[3];
bw[3] = bw_int[6];
bw[4] += bw_int[7];
bw[5] += bw_int[9];
iops[0] += iops_int[0];
iops[1] += iops_int[1];
iops[2] += iops_int[2];
iops[3] += iops_int[5];
iops[4] += iops_int[6];
iops[5] += iops_int[7];
} else {
cout << "\033[32;1m" << name << " | 第" << i << "次带宽运行结果:"
<< "min:" << bw_int[0] << "KiB/s max:" << bw_int[1]
<< "KiB/s avg:" << bw_int[3] << "KiB/s\n"
<< name << " | 第" << i << "次次IOPS运行结果:"
<< "min:" << iops_int[0] << " max:" << iops_int[1]
<< " avg:" << iops_int[2] << "\033[0m" << endl;
// 整理带宽和IOPS数据
bw[0] += bw_int[0];
bw[1] += bw_int[1];
bw[2] += bw_int[3];
iops[0] += iops_int[0];
iops[1] += iops_int[1];
iops[2] += iops_int[2];
}
}
void fio_sum(const string &name) {
if (bw[3] != 0) {
// 针对混合读写处理
// 计算最小、最大和平均值
int RbwMin = bw[0] / 3;
int RbwMax = bw[1] / 3;
int RbwAvg = bw[2] / 3;
int RiopsMin = iops[0] / 3;
int RiopsMax = iops[1] / 3;
int RiopsAvg = iops[2] / 3;
int WbwMin = bw[3] / 3;
int WbwMax = bw[4] / 3;
int WbwAvg = bw[5] / 3;
int WiopsMin = iops[3] / 3;
int WiopsMax = iops[4] / 3;
int WiopsAvg = iops[5] / 3;
// 将结果存储到数据表中,第一列是 名称,后面是6个值
values = {RbwMin, RbwMax, RbwAvg, RiopsMin, RiopsMax, RiopsAvg,
WbwMin, WbwMax, WbwAvg, WiopsMin, WiopsMax, WiopsAvg};
row = {name};
for (int val : values) {
row.push_back(to_string(val)); // 将每个值转换为字符串并添加到行中
}
run_report.push_back(row); // 将这行添加到数据中
} else {
// 计算最小、最大和平均值
int bwMin = bw[0] / 3;
int bwMax = bw[1] / 3;
int bwAvg = bw[2] / 3;
int iopsMin = iops[0] / 3;
int iopsMax = iops[1] / 3;
int iopsAvg = iops[2] / 3;
// 将结果存储到数据表中,第一列是 名称,后面是6个值
values = {bwMin, bwMax, bwAvg, iopsMin, iopsMax, iopsAvg};
row = {name};
for (int val : values) {
row.push_back(to_string(val)); // 将每个值转换为字符串并添加到行中
}
run_report.push_back(row); // 将这行添加到数据中
// 重置
values.clear();
row.clear();
}
// 重置数据
fill(begin(bw), end(bw), 0);
fill(begin(iops), end(iops), 0);
}
void runReport() {
// 打开文件用于追加写入
ofstream outputFile("/var/log/fio_tool/fio.csv", ios::app);
if (outputFile.is_open()) {
// 如果文件为空,先写入表头(假设表头只在文件为空时写入一次)
if (outputFile.tellp() == 0) {
outputFile
<< "测试类型,带宽最小值,带宽最大值,带宽均值,IOPS最小值,"
"IOPS最大值,IOPS均值,写带宽最小值,写带宽最大值,写带宽均值,"
"写IOPS最小值,"
"写IOPS最大值,写IOPS均值,(前6列数据在混合读写中作为读的数据)"
<< endl;
}
for (const auto &row : run_report) {
for (const auto &cell : row) {
outputFile << cell << ",";
}
outputFile << endl;
}
// 关闭文件
outputFile.close();
cout << "\033[32;1m数据已成功追加到fio.csv文件。\033[0m" << endl;
} else {
cerr << "\033[31;1m无法打开fio.csv文件进行追加写入。\033[0m" << endl;
}
cout << "\033[32;1m已重置run_report\033[0m" << endl;
// 重置run_report
run_report.clear();
}
// ---创建预读文件 start---
void init_read() {
cout << "\033[32;1m预读文件的大小与测试文件一致,自动从之前的测试中获取\033["
"0m\n";
cout << "\033[31;1m正在为读取测试创建预读文件,请稍后..."
"\n创建完毕后会出现提示,创建的文件数量为最大numjobs数量:16个,每个"
"大小为" +
fsize + "G"
<< "\033[0m" << endl;
fio_cmd = "fio -name=init_read -size=" + fsize +
"G -bs=1m -direct=1 -rw=write -ioengine=" + ioengine +
" -numjobs=16 -group_reporting -iodepth=1 -directory=" + dir;
run_cmd(fio_cmd);
cout << "\033[32;"
"1m预读文件创建完毕!!!\n预读文件创建完毕!!!\n预读文件创建完毕!"
"!"
"!\n\033[0m"
<< endl;
}
// ---创建预读文件 end---
// --- 顺序写start ---
void fio_seq_write() {
// 重置数据
bw_int.clear();
iops_int.clear();
// 文件
cout << "\033[31;1m顺序写测试,共计50项,每项3次,每次 " << runtime
<< " 秒,共计 " << to_string((stoi(runtime) + 5) * 50 * 3) << " 秒,约 "
<< setprecision(2) << fixed
<< (double)(stoi(runtime) + 5) * 50 * 3 / 60 / 60
<< " 小时\n进行中...\033[0m" << endl;
// 文件/文件夹
string DorF[] = {"filename", "directory"};
for (string dorf : DorF) {
if (dorf.find("file") != string::npos) { // 如果是单文件
// numjobs=1
string numjobs[] = {"1"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=512/1024
string bs_group[] = {"512", "1024"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "write";
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
// 重复运行3次
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "fio -name=" + name + " -size=" + fsize +
"G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + to_string(i);
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
rm_file(to_string(i)); //"rm -rf " + dir + ? rm -rf /mnt/?
}
fio_sum(name);
}
runReport();
}
}
} else if (dorf.find("directory") != string::npos) {
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"128", "256", "512", "1024"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
string rw = "write";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "mkdir -p " + dir + "dir_" + to_string(i) + "/" +
" && fio -name=" + name + " -size=" + fsize +
"G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + "dir_" + to_string(i) + "/";
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
rm_file("dir_" + to_string(i));
}
fio_sum(name);
}
runReport();
}
}
}
}
}
// --- 顺序写end ---
// --- 顺序读start ---
void fio_seq_read() {
// 重置数据
bw_int.clear();
iops_int.clear();
// 文件
cout << "\033[31;1m顺序读测试,共计50项,每项3次,每次预热5秒,每次测试" +
runtime + "秒,共计" + to_string((stoi(runtime) + 5) * 50 * 3) +
"秒,约 "
<< setprecision(2) << fixed
<< (double)(stoi(runtime) + 5) * 50 * 3 / 60 / 60
<< "小时\n进行中...\033[0m" << endl;
// 文件/文件夹
string DorF[] = {"filename", "directory"};
for (string dorf : DorF) {
if (dorf.find("file") != string::npos) { // 如果是单文件
// numjobs=1
string numjobs[] = {"1"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=512/1024
string bs_group[] = {"512", "1024"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
string rw = "read";
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
// 重复运行3次
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime +
"s -time_base -bs=" + bs + "k -direct=" + direct +
" -rw=" + rw + " -ioengine=" + ioengine +
" -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + "init_read.0.0";
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
} else if (dorf.find("directory") != string::npos) {
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"128", "256", "512", "1024"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "read";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime +
"s -time_base -bs=" + bs + "k -direct=" + direct +
" -rw=" + rw + " -ioengine=" + ioengine +
" -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir;
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
}
}
}
// --- 顺序读end ---
// --- 随机读start ---
void fio_rand_read() {
// 重置数据
bw_int.clear();
iops_int.clear();
// 文件
cout << "\033[31;1m随机读测试,共计15项,每项3次,每次预热5秒,每次测试" +
runtime + "秒,共计" + to_string((stoi(runtime) + 5) * 15 * 3) +
"秒,约 "
<< setprecision(2) << fixed
<< (double)(stoi(runtime) + 5) * 15 * 3 / 60 / 60
<< "小时\n进行中...\033[0m" << endl;
// 文件/文件夹
string DorF[] = {"filename", "directory"};
for (string dorf : DorF) {
if (dorf.find("file") != string::npos) { // 如果是单文件
// numjobs=1
string numjobs[] = {"1"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=512/1024
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
string rw = "randread";
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
// 重复运行3次
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd =
"echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -readrepeat=0 -iodepth=" +
iodepth + " -" + dorf + "=" + dir + "init_read.0.0";
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
} else if (dorf.find("directory") != string::npos) {
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "randread";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd =
"echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -readrepeat=0 -iodepth=" +
iodepth + " -" + dorf + "=" + dir;
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
}
}
}
// --- 随机读end ---
// --- 随机写开始 ---
void fio_rand_write() {
// 重置数据
bw_int.clear();
iops_int.clear();
cout << "\033[31;1m随机写测试,共计15项,每项3次,每次预热5秒,每次测试" +
runtime + "秒,共计" + to_string((stoi(runtime) + 5) * 15 * 3) +
"秒,约 "
<< setprecision(2) << fixed
<< (double)(stoi(runtime) + 5) * 15 * 3 / 60 / 60
<< "小时\n进行中...\033[0m" << endl;
// 文件/文件夹
string DorF[] = {"filename", "directory"};
for (string dorf : DorF) {
if (dorf.find("file") != string::npos) { // 如果是单文件
// numjobs=8/16
string numjobs[] = {"1"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "randwrite";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "fio -name=" + name + " -size=" + fsize +
"G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + to_string(i);
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
rm_file(to_string(i));
}
fio_sum(name);
}
runReport();
}
}
} else if (dorf.find("directory") != string::npos) {
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "randwrite";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "mkdir -p " + dir + "dir_" + to_string(i) + "/" +
" && fio -name=" + name + " -size=" + fsize +
"G -runtime=" + runtime + "s -time_base -bs=" + bs +
"k -direct=" + direct + " -rw=" + rw +
" -ioengine=" + ioengine + " -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + "dir_" + to_string(i) + "/";
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
rm_file("dir_" + to_string(i));
}
fio_sum(name);
}
runReport();
}
}
}
}
}
// --- 随机写结束 ---
// --- 4k随机读写开始 ---
void fio_randrw() {
// 重置数据
bw_int.clear();
iops_int.clear();
// 文件
cout << "\033[31;1m50%随机读写测试,共计15项,每项3次,每次" + runtime +
"秒,共计" + to_string((stoi(runtime) + 5) * 15 * 3) + "秒,约"
<< setprecision(2) << fixed
<< (double)(stoi(runtime) + 5) * 15 * 3 / 60 / 60
<< "小时\n进行中...\033[0m" << endl;
// 文件/文件夹
string DorF[] = {"filename", "directory"};
for (string dorf : DorF) {
if (dorf.find("file") != string::npos) { // 如果是单文件
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "randrw";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime +
"s -time_base -bs=" + bs + "k -direct=" + direct +
" -rw=" + rw + " -ioengine=" + ioengine +
" -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir + "init_read.0.0";
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
} else if (dorf.find("directory") != string::npos) {
// numjobs=8/16
string numjobs[] = {"8", "16"}; // 用数组配置numjobs
for (string numjob : numjobs) {
// bs=4k
string bs_group[] = {"4"}; // 用数组配置bs块大小
for (string bs : bs_group) {
string iodepth_group[] = {"1", "2", "8", "16",
"32"}; // 用数组配置iodepth循环
// iodepth=1/2/8/16/32
for (string iodepth : iodepth_group) {
// 先写后读
string rw = "randrw";
// 重复运行3次
name = rw + "_" + dorf + "_numjobs=" + numjob +
"_iodepth=" + iodepth + "_bs=" + bs + "k";
for (int i = 1; i <= 3; i++) {
// 构建文件夹fio命令
fio_cmd = "echo 3 > /proc/sys/vm/drop_caches && fio "
"-name=init_read -size=" +
fsize + "G -runtime=" + runtime +
"s -time_base -bs=" + bs + "k -direct=" + direct +
" -rw=" + rw + " -ioengine=" + ioengine +
" -numjobs=" + numjob +
" -group_reporting -ramp_time=5 -iodepth=" + iodepth +
" -" + dorf + "=" + dir;
// 输出本次运行的命令以便排障
cout << "\033[36;1m第" << i << "次运行的命令是:" << fio_cmd
<< "\033[0m" << endl;
run_cmd(fio_cmd);
format(i);
// 重置数据
bw_int.clear();
iops_int.clear();
}
fio_sum(name);
}
runReport();
}
}
}
}
}
// --- 4k随机读写结束 ---