Why C++ fread is so different from Windows ReadFile

Greetings,
I write a piece of code to simulate system I/O perf. However the result is so different between fread (IOPS is 5000+) and Windows ReadFile (IOPS 200 ~ 300) for a 7200RPM HDD (it's 180 ~ 190 Random read IOPS by IOMeter). Could you give me a hint where's the problem?

Thanks.

Nai Yan.

Code - Windows ReadFile (with cache)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
DWORD WINAPI FileReadThreadEntry(LPVOID lpThreadParameter)
{
	//File access with cache enabled
	input * in = (input*) lpThreadParameter; 

	LPCTSTR path = (LPCTSTR) in->path;

	HANDLE fp = CreateFile(
		path,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,//|FILE_FLAG_NO_BUFFERING,
		NULL);


	unsigned int sPos = in->starting;

	int * result = in->r;

	if(fp != NULL)
	{
		unsigned long pos;
		bool bRead;

		DWORD bNum;

		for (int i=0; i<length/(threadCount*interval);i++)
		{
			pos = i * interval;

			if ((SetFilePointer(fp,(sPos+pos),NULL,FILE_BEGIN)!=0))
			{
				if ((bRead = ReadFile(fp,&result[sPos/interval + i],512,&bNum,NULL))== true)
				{
					InterlockedIncrement(&completeIOs);
				}
				else
				{
					printf("file read err...\n");
					exit(-1);
				}
			}
		}			
		CloseHandle(fp);
		fp = NULL;
	}

	else
	{
		printf("File open err... \n");
		exit(-1);
	}
}


C++ fread code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
DWORD WINAPI FileReadThreadEntry(LPVOID lpThreadParameter)
{
	input * in = (input*) lpThreadParameter; 

	LPCTSTR path = (LPCTSTR) in->path;

	FILE * fp = fopen(path,"rb");

	int sPos = in->starting;

	int * result = in->r;

	if(fp != NULL)
	{
		fpos_t pos;
		for (int i=0; i<length/(threadCount*interval);i++)
		{
			pos = i * interval;
			fsetpos(fp,&pos);
			if (fread(&result[sPos/interval + i],512,1,fp) ==1)
			{
				InterlockedIncrement(&completeIOs);
			}
			else
			{
				printf("file read err...\n");
				exit(-1);
			}
		}

		fclose(fp);
		fp = NULL;
		}

	else
	{
		printf("File open err... \n");
		exit(-1);
	}
}
ReadFile is a system call, unbuffered.

fread is an ANSI C call, buffered.
Last edited on
I'd be careful about your test for success on your CreateFile() call. While using the C Standard Library fopen() a test such as...

1
2
3
if(fp)
...
...


is OK, it isn't OK with CreateFile. Failures return INVALID_HANDLE_VALUE instead. Here is an example...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int blnSaveSawData(HWND hParent)
{
 MrkData* pMrkData=NULL;
 TCHAR szBuffer[8];
 HANDLE hFile=NULL;
 HWND hCtl=NULL;
 int iNum=0;
 TREE tree;

 pMrkData=(MrkData*)GetWindowLong(hParent,0);
 hFile=CreateFile(pMrkData->ofn.lpstrFile,GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_FLAG_RANDOM_ACCESS,NULL);
 if(hFile==INVALID_HANDLE_VALUE)
    MessageBox(hParent,_T("File Access Problem!  Not Good!"),_T("Can't Open File!"),MB_ICONERROR);
 else
 {
    hCtl=GetDlgItem(hParent,IDC_SAW_SPECIES), GetWindowText(hCtl,szBuffer,4), tree.sp=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_SAW_DBH),     GetWindowText(hCtl,szBuffer,4), tree.dbh=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_SAW_HEIGHT),  GetWindowText(hCtl,szBuffer,4), tree.ht=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_SAW_CULL),    GetWindowText(hCtl,szBuffer,4), tree.cull=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_BLOCK),       GetWindowText(hCtl,szBuffer,4), tree.block=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_BLOCK_CTR),   GetWindowText(hCtl,szBuffer,7), tree.bkctr=(short)_ttoi(szBuffer);
    hCtl=GetDlgItem(hParent,IDC_SAW_NUMBER),  GetWindowText(hCtl,szBuffer,7);
    iNum=_ttoi(szBuffer);
    Put(hFile,iNum,&tree,sizeof(tree));
    CloseHandle(hFile);
    SetWindowLong(hParent,12,0);
 }

 return TRUE;
}


So, with your code as shown, if CreateFile fails, execution will get inside your if (I think INVALID_HANDLE_VALUE = 0xFFFFFFFF or something like that - definitely not zero).
Last edited on
Out of interest, how big a file are you using for your testing? And how many threads?

Also, how are the interval and buffer siz related?

(I should prob reread your post when I'm more awake!)

Andy
Hi Andy,
File size is around 4GB. I tried 32 threads to get this number. Looking forward to your feedback.
Regardind buffer size, neither ReadFile or fread (or ATL CAtlFile, do not tried MFC CFile) accept more than 8192 bytes. std::ifstream seem to not have this limitation.
I think all of them are wrappers around ReadFile internally.
Last edited on
I can assure you, ReadFile is not limited to 8K.
Using windows 7 and sdk 7.0a, using a buffer larger than 8K make ReadFile return 0 and the buffer is not filled. GetLastError returns 0.
Maybe this behavior can be changed using some hidden Microsoft setting.
WriteFile works with any buffer size for me.
hi guys, I'm new to c++ and have completed some studies about the program's syntax, understanding it to some extent , however can't seem to get my hands on a good compiler. I'll be grateful if you can be helpful to recommend a suitable compiler for the platform I'm using; a windows 7 home basic. thanks.
File size is around 4GB. I tried 32 threads to get this number. Looking forward to your feedback.


Are all 32 threads processing the same (4Gb) file?
Topic archived. No new replies allowed.