/***********************************************************************************
注意:这个代码是根据我们公司具体情况来写的,测试我们公司业务数据的读写性能(看看有多少数据的读写时间我们不能接受)的。可能与你的实际情况不相符合。
1 该代码仅仅考虑读写速度,不考虑线程间的同步之类的
2 该代码是模拟根据业务数据读写的大小来进行写的,跟具体的读写文件大小有关。
3该代码最终形成的结果值是一个二维表,里面统计了,读写不同字节范围花的时间段的统计。
要点:1预先创建若干个固定大小的文件
2对于每个文件,创建一个线程去写它,写是随机写的,但不能把文件写大
3读线程随机读取已经存在的文件,读取位置也是随机写的。
4对于随机读取的大小也是一定范围内的随机数(这里实际上可以用boost生成正态分布的随机数更好,CSDN上有现成代码)。
**********************************************************************************/
**********************************************************************************/
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include "windows.h"
#include <time.h>
#include <assert.h>
#include <math.h>
#include <fcntl.h>
//二维数组的单维数
#define ARRAY_SIZE
20
#define MAX_THREAD 1024
//全局数据区
/**************************************************************
以下二维表是我们最终要得到的结果表值。
read_time_table,write_time_table数组结构如下:
size(Byte)\time(mic)
[0,10)
[10,20)
[20,40)
[40,80) [80,160) .....
[0,32)
0
0
0
0
0
...
[32,64)
0
0
0
0
0
...
[64,128)
0
0
0
0
0
...
[128,256)
0
0
0
0
0
...
[256,512)
0
0
0
0
0
...
......
...
...
...
...
...
...
***************************************************************/
DWORD read_time_table[ARRAY_SIZE][ARRAY_SIZE];
DWORD
write_time_table[ARRAY_SIZE][ARRAY_SIZE];
//读写数据的缓冲区
char buffer[10240];
//写线程参数结构体声明
typedef struct _THREAD_WRITE_PARAM
{
int i;
//第几个线程
DWORD file_size;
DWORD write_range;
char* dir;
} THREAD_WRITE_PARAM, *LPTHREAD_WRITE_PARAM;
//读线程参数结构体声明
typedef struct _THREAD_READ_PARAM
{
int sum_files;//可供读的文件总数
DWORD file_size;
DWORD read_range;
char* dir;
} THREAD_READ_PARAM, *LPTHREAD_READ_PARAM;
//打印结果线程参数结构体声明
typedef struct _THREAD_RECODE_PARAM
{
char* dir;
char* name;
DWORD time;//每隔多长时间(毫秒)打印一次结果
}THREAD_RECODE_PARAM, *LPTHREAD_RECODE_PARAM;
//函数声明
HANDLE Open_File(char*);
int Close_File(HANDLE);
DWORD CreateRandom(int, int);
int StoreTable(char*, char*, DWORD);
DWORD WINAPI GetTimeTable(LPVOID);
int RecodeTime(int, DWORD, double);
DWORD WINAPI Write_thread(LPVOID);
DWORD WINAPI Read_thread(LPVOID);
int CreateFile(char*, char*, int);
HANDLE Open_File(char*);
int Close_File(HANDLE);
int CreateFile(char*, char*, int);
/********************************************
函数功能:生成[min,max)的整型随机数
*********************************************/
DWORD CreateRandom(int min, int max)
{
return rand()%(max - min) + min;
}
/********************************************
函数功能:在一定时间内将write_time_table,read_time_table信息追加写入文件
参数
which : 0表示存储write_time_table, 1表示存储read_time_table
didd_time:
所花费的时间
size:读或写的大小(单位Bype)
*********************************************/
int StoreTable(char* dir, char* name, DWORD time)
{
int nRet = 0;
DWORD tmp = 0;
char file[128] = {'\0'};
sprintf(file, "%s\\%s", dir, name);
FILE* fd;
if(NULL == (fd = fopen(file, "w+")))
{
printf("error in StoreTable\n");
perror("fopen");
return -1;
}
while(true){
::Sleep(time);
fprintf(fd,"write table\n");
fprintf(fd,"\t\t\t[0,10)
[10,20)
[20,40)
[40,80)
[80,160)
.....\n");
for(int i = 0; i < ARRAY_SIZE ; ++i)
{
if(0 != i){
fprintf(fd, "[%10ld,%10ld)\t", tmp,2*tmp);
tmp = 2*tmp;
}else{
fprintf(fd, "[ 0, 32)\t");
tmp = 32;
}
for(int j = 0; j < ARRAY_SIZE; ++j)
{
nRet = fprintf(fd, "%6d\t", write_time_table[i][j]);
if(nRet < 0)
{
perror("fprintf");
}
}
fprintf(fd, "\n");
}
fprintf(fd,"read table\n");
fprintf(fd,"\t\t\t[0,10)
[10,20)
[20,40)
[40,80)
[80,160)
.....\n");
for(i = 0; i < ARRAY_SIZE ; ++i)
{
if(0 != i){
fprintf(fd, "[%10ld,%10ld)\t", tmp,2*tmp);
tmp = 2*tmp;
}else{
fprintf(fd, "[ 0, 32)\t");
tmp = 32;
}
for(int j = 0; j < ARRAY_SIZE; ++j)
{
nRet = fprintf(fd, "%6d\t", read_time_table[i][j]);
if(nRet < 0)
{
perror("fprintf");
}
}
fprintf(fd, "\n");
}
fprintf(fd,"\n\n");
}
fclose(fd);
return 0;
}
//打印信息线程函数入口
DWORD WINAPI GetTimeTable(LPVOID param)
{
char* dir = ((LPTHREAD_RECODE_PARAM)param)->dir;
char* name = ((LPTHREAD_RECODE_PARAM)param)->name;
DWORD time = ((LPTHREAD_RECODE_PARAM)param)->time;
StoreTable(dir, name, time);
return 0;
}
/***************************************************
函数功能:更新记录
参数
which: 0 write_time_table 1 read_time_table
size:读或写的大小
diff_time:读或写用的时间
******************************************************/
int RecodeTime(int which, DWORD size, double diff_time)
{
int row, list; //row行,list列
if(32 > size)
{
row = 0;
}else{
row = (int)(log10(size)/log10(2) - 4);
}
if(row >= ARRAY_SIZE)
{
row = ARRAY_SIZE-1;
}
if(10.0 > diff_time)
{
list = 0;
}else{
list = (int)(log10(diff_time/10)/log10(2) + 1);
}
if(list >= ARRAY_SIZE)
{
list = ARRAY_SIZE-1;
}
//根据参数判断是更新哪张表(读表或者写表)
if(0 == which)
{
//更新write_time_table
++write_time_table[row][list];
}else if(1 == which){
//更新read_time_table
++read_time_table[row][list];
}else{
printf("error in RecodeTime: param is wrong\n");
}
return 0;
}
//写线程执行函数入口,只写特定的文件
DWORD WINAPI Write_thread(LPVOID param)
{
char file[128] = {0};
DWORD dwWritedDataSize = 0;
int nRet = 0;
DWORD offset = 0;
int num = ((LPTHREAD_WRITE_PARAM)param)->i;
DWORD file_size = ((LPTHREAD_WRITE_PARAM)param)->file_size;
DWORD write_range = ((LPTHREAD_WRITE_PARAM)param)->write_range;
char* dir = ((LPTHREAD_WRITE_PARAM)param)->dir;
sprintf(file,"%s\\%d.txt", dir, ((LPTHREAD_WRITE_PARAM)param)->i);
DWORD write_size;
HANDLE FileHandle;
int count = 0;
int begin_time = 0;
int end_time = 0;
while(true){
count = 2;//写的次数,这个是可变的
write_size = CreateRandom(0,write_range);//写文件的大小,这个是可变的
if(write_size < 0 || write_size >= write_range)
{
assert(0);
continue;
}
offset = CreateRandom(0, file_size-count*write_size-count);
if((offset + count * write_size > file_size)||(offset < 0))
{
assert(0);
}
FileHandle = Open_File(file);//fp指向文件的开始处
if(FileHandle == INVALID_HANDLE_VALUE)
{
printf("Error in CreateFile function, the reason is:[%ld]\n", GetLastError());
::Sleep(2000);
continue;
}
nRet = ::SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
if ( nRet == 0xFFFFFFFF )
{
printf("error in SetFilePointer : reason:%d", GetLastError());
}
begin_time =GetTickCount();
for(int i = 0; i < count; i++)
{
nRet = ::WriteFile(FileHandle, buffer, write_size, &dwWritedDataSize, NULL);
if(!nRet)
{
printf("write data error:%ld\n",GetLastError());
}
}
end_time = ::GetTickCount();
Close_File(FileHandle);
//下面的if语句打印超过10ms的信息到屏幕上,主要用于调试
/*if(10 <= difftime(end_time, begin_time)){
printf("in write thread diff_time%f\n",difftime(end_time, begin_time));
}*/
RecodeTime(0, count*write_size, difftime(end_time, begin_time));
::Sleep(15);
}
return 0;
}
//读线程执行函数入口,随机读已经存在的文件
DWORD WINAPI Read_thread(LPVOID param)
{
//初始化参数
DWORD dwReadedDataSize = 0;
int nRet = 0;
DWORD offset = 0;
int sum_files = ((LPTHREAD_READ_PARAM)param)->sum_files;
DWORD file_size = ((LPTHREAD_READ_PARAM)param)->file_size;
DWORD read_range = ((LPTHREAD_READ_PARAM)param)->read_range;
char* dir = ((LPTHREAD_READ_PARAM)param)->dir;
DWORD read_size = 0;
HANDLE FileHandle;
int count = 0;
int begin_time = 0;
int end_time = 0;
int read_file = 0;//标记正在读的文件
char file[128] = {0};
while(true)
{
count = 2;//这个是可变的,
read_size = CreateRandom(0,read_range);//读文件的大小,这个是可变的
if(0 > file_size-count*read_size)
{
printf("0 > file_size-count*read_size,please adjust the parm\n");
continue;
}
offset = CreateRandom(0, file_size-count*read_size-count);
read_file = CreateRandom(0, sum_files);//随机读取某个存在的文件
memset(file, '\0', sizeof(file));
sprintf(file,"%s\\%d.txt", dir, read_file);
FileHandle = Open_File(file);
if(FileHandle == INVALID_HANDLE_VALUE)
{
printf("Error in CreateFile function, the reason is:[%ld]\n", GetLastError());
::Sleep(2000);
continue;
}
::SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
begin_time = GetTickCount();
for(int i = 0; i < count; ++i)
{
nRet = ::ReadFile(FileHandle, buffer, read_size, &dwReadedDataSize, NULL);
if(!nRet)
{
printf("read data error:%ld\n",GetLastError());
}
}
end_time = ::GetTickCount();
Close_File(FileHandle);
RecodeTime(1, count*read_size, difftime(end_time, begin_time));
::Sleep(15);
}
return 0;
}
/***************************************************
函数功能:创建一个文件
参数:
dir:路径
name:文件名
size:创建文件的大小(Byte)
******************************************************/
int CreateFile(char* dir, char *name, int size)
{
char cmd[1024] = {'\0'};
sprintf(cmd,"fsutil file createnew %s\\%s.txt %d", dir, name, size);
if(0 != system(cmd))
{
return -1;
}
return 0;
}
/***************************************************
函数功能:打开一个文件
参数:
file:文件的路径(包括文件名)
******************************************************/
HANDLE Open_File(char* file)
{
HANDLE m_FileHandle = ::CreateFile(file,
GENERIC_WRITE|GENERIC_READ,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
//打开已经存在的文件。
FILE_ATTRIBUTE_NORMAL,
NULL);
if(m_FileHandle == INVALID_HANDLE_VALUE)
{
int nRet = GetLastError();
printf("Error in CreateFile function, the reason is:[%d]\n", nRet);
::Sleep(2000);
return INVALID_HANDLE_VALUE;
}
return m_FileHandle;
}
/***************************************************
函数功能:关闭一个文件
参数:
HANDLE:文件句柄
******************************************************/
int Close_File(HANDLE mHandle)
{
::CloseHandle(mHandle);
return 0;
}
/***************************************************
函数功能:删除一个文件
参数:
dir:文件的路径
name:文件的名字
******************************************************/
int DelFile(char* dir, char* name)
{
char cmd[1024] = {'\0'};
sprintf(cmd,"del %s\\%s", dir, name);
if(0 != system(cmd))
{
printf("error in DelFile\n");
return -1;
}
return 0;
}
//主函数
int main(int argc, char* argv[])
{
int i;
int nRet = 0;
char name[1024];
HANDLE hThread[MAX_THREAD] = {NULL};
HANDLE hThreadRecode = NULL;
int seq_thread = 0;
char dir[128] = {'\0'};
char result_name[128] = {'\0'};
THREAD_WRITE_PARAM thread_write_param;
THREAD_READ_PARAM thread_read_param;
THREAD_RECODE_PARAM thread_recode_param;
LPTHREAD_WRITE_PARAM pDataWrite = &thread_write_param;
LPTHREAD_READ_PARAM pDataRead = &thread_read_param;
LPTHREAD_RECODE_PARAM pDataRecode = &thread_recode_param;
int save_time = 0;
for(i = 0; i < 1024; i++)
{
buffer[i] = '0' + i % 10;
}
//初始化read_time_table,write_time_table
for(i = 0; i < ARRAY_SIZE; ++i)
for(int j = 0; j < ARRAY_SIZE; ++j)
{
read_time_table[i][j] = 0;
write_time_table[i][j] = 0;
}
//参数检查
if(9 != argc)
{
printf("usage: 程序名
写文件线程数
写文件的范围
读文件的线程数
\
读文件的范围 文件的固定大小 文件的路径 结果文件的名称 多少时间保存一次结果\n");
printf("例如 2 1024 2 1024 20480 x:\\ result241.txt 2000\n");
return -1;
}
int write_count = atol(argv[1]);
DWORD write_range = atol(argv[2]);
int read_count = atol(argv[3]);
DWORD read_range = atol(argv[4]);
DWORD file_size = atol(argv[5]);
strncpy(dir, argv[6], sizeof(dir));
strncpy(result_name, argv[7], sizeof(result_name));
save_time = atol(argv[8]);
char myresult_dir[128] = {"D:\\"};
/*
int write_count = 2;
DWORD write_range = 1024;
int read_count = 2;
DWORD read_range = 1024;
DWORD file_size = 20480;
char dir[128] = "D:\\locattest";//该目录必须是已经存在的。
char result_name[1024] = "result.txt";
save_time = 1000;
*/
//创建写的文件,每个写文件线程单独写一个文件,单位Byte
for(i = 0; i < write_count; i++){
nRet = CreateFile(dir, itoa(i, name, 10), file_size);
if(0 != nRet){
printf("请您删除上次生成的文件(包括结果文件):%ld\n",GetLastError());
return -1;
}
}
//创建打印time_table线程
memset((void *)pDataRecode, '\0', sizeof(THREAD_RECODE_PARAM));
pDataRecode->dir = myresult_dir;
pDataRecode->name = result_name;
pDataRecode->time = save_time;
hThreadRecode = CreateThread(NULL,0,GetTimeTable, pDataRecode,0,NULL);
::Sleep(1000);
//创建写线程
for(i = 0; i < write_count; i++)
{
memset((void *)pDataWrite, '\0', sizeof(THREAD_WRITE_PARAM));
pDataWrite->i = i;
pDataWrite->file_size = file_size;
pDataWrite->write_range = write_range;
pDataWrite->dir = dir;
hThread[seq_thread++] = CreateThread(NULL,0,Write_thread, pDataWrite,0,NULL);
Sleep(1000);
}
//创建读线程
for(i = 0; i < read_count; i++)
{
memset((void *)pDataRead, '\0', sizeof(THREAD_READ_PARAM));
pDataRead->sum_files= write_count;//在这时,有几个写线程,就会有几个文件。
pDataRead->file_size = file_size;
pDataRead->read_range = read_range;
pDataRead->dir = dir;
hThread[seq_thread++] = CreateThread(NULL,0,Read_thread, pDataRead,0,NULL);
::Sleep(1000);
}
//等待所有线程退出
for(i = 0; i < MAX_THREAD; ++i)
{
if(NULL != hThread[i])
{
WaitForSingleObject(hThread[i],-1);
}else
{
break;
}
}
WaitForSingleObject(hThreadRecode,-1);
//这里还要加一些资源的释放操作。
return 0;
}