EDN Admin
Well-known member
We have an application that reads medical image data (DICOM) randomly from file over the network from a regular windows share. For this we use the windows call ReadFile wit and specified offeset to read from a specific position in the file. When moving from VS 2003 to VS 2008 we have noticed a clear increase in reading time. This is especially when a file is read twice or more. In VS 2003 windows will have cached the file and and it is not reread from the share. It is just fetched from some windows cache. When we compile with VS 2008 the file will almost always be read from the share again.
<br/>
I have created some example code which shows the problem. This code reads some data from some files over the network. In VS 2003 it will only actually read the files the firs time. The remaining 4 iterations it will get the data from cache. In VS 2008 it is quite random. Sometimes it will use the cache and sometimes it will reread the files from the share. The total time used on reading files in this code is: 20 sec vs2003 and 20-100 sec using vs2008
<br/>
Has someone experienced this? Are there some flags that can be set to increase the likelihood of the cache being used?
<br/>
<br/>
Example code:
<pre lang=x-cpp>#define _SECURE_SCL 0
#include <iostream>
#include <sstream>
#include <vector>
#include <boost/timer.hpp>
#include <windows.h>
typedef std:
air<size_t,std::string> file_descr;
typedef std::stringstream str_converter;
#define KB 1024
#define MB 1024*1024
/** Simple class to handle opening/closing of file and reading*/
class file_reader
{
public:
file_reader(const std::string &path);
~file_reader(){CloseHandle(m_fid);}
DWORD seek_read(DWORD pos, void* buffer, DWORD count);
private:
HANDLE m_fid;
};
file_reader::file_reader(const std::string &path)
{
str_converter p;
p<<path.c_str();
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength = sizeof( SecurityAttributes );
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = TRUE;
m_fid = CreateFile(p.str().c_str(),
GENERIC_READ,
FILE_SHARE_READ,
&SecurityAttributes,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS ,
NULL );
}
DWORD file_reader::seek_read( DWORD pos, void* buffer, DWORD count )
{
DWORD NumberOfBytesRead; // number of bytes read
OVERLAPPED Overlapped;
Overlapped.Internal = 0;
Overlapped.InternalHigh = 0;
Overlapped.Offset = pos;
Overlapped.OffsetHigh = 0;
Overlapped.hEvent = 0;
BOOL ok = ReadFile(m_fid, buffer, count, &NumberOfBytesRead, &Overlapped);
if (ok) return NumberOfBytesRead;
else return 0;
}
//Read several blocks if data from file
inline DWORD read_blocks(file_reader &fid, file_descr &fd, unsigned char *data)
{
DWORD read = 0;
for (size_t c = 0;c<fd.first;++c)
{
read += fid.seek_read(read, data, 1*MB) + 10*KB;
}
return read;
}
void allocate_some_memory( std::vector<std::vector<unsigned char> > &rubbish )
{
std::cout<<"Allocating some data to fill memory"<<std::endl;
boost::timer t;
const size_t block_nbr = 60000;
rubbish.resize(block_nbr);
for (size_t outer = 0; outer < block_nbr; ++outer)
{
rubbish[outer].resize(10*KB);
for (size_t inner = 0; inner < rubbish[outer].size(); ++inner)
{
rubbish[outer][inner] = unsigned char(inner%250);
}
}
std::cout<<"Done allocating in "<<t.elapsed()<<"s"<<std::endl;
}
int main (int argc, char *argv[])
{
std::vector<std::vector<unsigned char> > rubbish;
//Allocate some memory to make sure the application is of realistic size
allocate_some_memory(rubbish);
std::vector<file_descr> files;
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155315"));
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155314"));
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155313"));
files.push_back(file_descr( 9, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155326"));
files.push_back(file_descr( 7, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155322"));
files.push_back(file_descr( 7, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155318"));
files.push_back(file_descr(10, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155337"));
files.push_back(file_descr(10, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155325"));
files.push_back(file_descr( 9, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155312"));
unsigned char *data = new unsigned char[2*MB];
boost::timer t_outer;
//Read files 5 times
for (size_t i = 0; i < 5; ++i)
{
//Loop through files and data from them
for (size_t f = 0; f < files.size(); ++f)
{
file_reader fid(files[f].second);
boost::timer t_inner;
DWORD read = read_blocks(fid,files[f],data);
std::cout << "Iteration("<<i<<", read "<<read<<" byte from file " << f << ". Total read time:" << t_inner.elapsed()*1000.0 << " ms" << std::endl;
}
}
std::cout <<"Total read time: " << t_outer.elapsed() << " s" << std::endl;
return 0;
}
[/code]
<br/>
View the full article
<br/>
I have created some example code which shows the problem. This code reads some data from some files over the network. In VS 2003 it will only actually read the files the firs time. The remaining 4 iterations it will get the data from cache. In VS 2008 it is quite random. Sometimes it will use the cache and sometimes it will reread the files from the share. The total time used on reading files in this code is: 20 sec vs2003 and 20-100 sec using vs2008
<br/>
Has someone experienced this? Are there some flags that can be set to increase the likelihood of the cache being used?
<br/>
<br/>
Example code:
<pre lang=x-cpp>#define _SECURE_SCL 0
#include <iostream>
#include <sstream>
#include <vector>
#include <boost/timer.hpp>
#include <windows.h>
typedef std:

typedef std::stringstream str_converter;
#define KB 1024
#define MB 1024*1024
/** Simple class to handle opening/closing of file and reading*/
class file_reader
{
public:
file_reader(const std::string &path);
~file_reader(){CloseHandle(m_fid);}
DWORD seek_read(DWORD pos, void* buffer, DWORD count);
private:
HANDLE m_fid;
};
file_reader::file_reader(const std::string &path)
{
str_converter p;
p<<path.c_str();
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength = sizeof( SecurityAttributes );
SecurityAttributes.lpSecurityDescriptor = NULL;
SecurityAttributes.bInheritHandle = TRUE;
m_fid = CreateFile(p.str().c_str(),
GENERIC_READ,
FILE_SHARE_READ,
&SecurityAttributes,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS ,
NULL );
}
DWORD file_reader::seek_read( DWORD pos, void* buffer, DWORD count )
{
DWORD NumberOfBytesRead; // number of bytes read
OVERLAPPED Overlapped;
Overlapped.Internal = 0;
Overlapped.InternalHigh = 0;
Overlapped.Offset = pos;
Overlapped.OffsetHigh = 0;
Overlapped.hEvent = 0;
BOOL ok = ReadFile(m_fid, buffer, count, &NumberOfBytesRead, &Overlapped);
if (ok) return NumberOfBytesRead;
else return 0;
}
//Read several blocks if data from file
inline DWORD read_blocks(file_reader &fid, file_descr &fd, unsigned char *data)
{
DWORD read = 0;
for (size_t c = 0;c<fd.first;++c)
{
read += fid.seek_read(read, data, 1*MB) + 10*KB;
}
return read;
}
void allocate_some_memory( std::vector<std::vector<unsigned char> > &rubbish )
{
std::cout<<"Allocating some data to fill memory"<<std::endl;
boost::timer t;
const size_t block_nbr = 60000;
rubbish.resize(block_nbr);
for (size_t outer = 0; outer < block_nbr; ++outer)
{
rubbish[outer].resize(10*KB);
for (size_t inner = 0; inner < rubbish[outer].size(); ++inner)
{
rubbish[outer][inner] = unsigned char(inner%250);
}
}
std::cout<<"Done allocating in "<<t.elapsed()<<"s"<<std::endl;
}
int main (int argc, char *argv[])
{
std::vector<std::vector<unsigned char> > rubbish;
//Allocate some memory to make sure the application is of realistic size
allocate_some_memory(rubbish);
std::vector<file_descr> files;
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155315"));
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155314"));
files.push_back(file_descr(20, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155313"));
files.push_back(file_descr( 9, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155326"));
files.push_back(file_descr( 7, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155322"));
files.push_back(file_descr( 7, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155318"));
files.push_back(file_descr(10, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155337"));
files.push_back(file_descr(10, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155325"));
files.push_back(file_descr( 9, "\\IMGVAULT5-NOHOR\IV_Archive\2009_09\21\US157243\52155312"));
unsigned char *data = new unsigned char[2*MB];
boost::timer t_outer;
//Read files 5 times
for (size_t i = 0; i < 5; ++i)
{
//Loop through files and data from them
for (size_t f = 0; f < files.size(); ++f)
{
file_reader fid(files[f].second);
boost::timer t_inner;
DWORD read = read_blocks(fid,files[f],data);
std::cout << "Iteration("<<i<<", read "<<read<<" byte from file " << f << ". Total read time:" << t_inner.elapsed()*1000.0 << " ms" << std::endl;
}
}
std::cout <<"Total read time: " << t_outer.elapsed() << " s" << std::endl;
return 0;
}
[/code]
<br/>
View the full article