diff options
Diffstat (limited to 'library/binary.cpp')
-rw-r--r-- | library/binary.cpp | 112 |
1 files changed, 101 insertions, 11 deletions
diff --git a/library/binary.cpp b/library/binary.cpp index 409b024a..8b8fd2ec 100644 --- a/library/binary.cpp +++ b/library/binary.cpp @@ -5,32 +5,122 @@ // ************************************************************************** // #include "binary.h" -#include <boost/scoped_array.hpp> #include "../shared/fileIO.h" +#include <vector> +#include <wx/stopwatch.h> -bool FreeFileSync::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback) +inline +void setMinSize(std::vector<char>& buffer, size_t minSize) +{ + if (buffer.size() < minSize) //this is similar to reserve(), but be need a "properly initialized" array here + buffer.resize(minSize); +} + + +namespace { - const size_t BUFFER_SIZE = 512 * 1024; //512 kb seems to be the perfect buffer size - static boost::scoped_array<unsigned char> memory1(new unsigned char[BUFFER_SIZE]); - static boost::scoped_array<unsigned char> memory2(new unsigned char[BUFFER_SIZE]); +class BufferSize +{ +public: + BufferSize() : bufSize(BUFFER_SIZE_START) {} + + void inc() + { + if (bufSize < BUFFER_SIZE_MAX) + bufSize *= 2; + } + + void dec() + { + if (bufSize > BUFFER_SIZE_MIN) + bufSize /= 2; + } + + operator size_t() const + { + return bufSize; + } + +private: + static const size_t BUFFER_SIZE_MIN = 128 * 1024; + static const size_t BUFFER_SIZE_START = 512 * 1024; //512 kb seems to be a reasonable initial buffer size + static const size_t BUFFER_SIZE_MAX = 16 * 1024 * 1024; + + /*Tests on Win7 x64 show that buffer size does NOT matter if files are located on different physical disks! + Impact of buffer size when files are on same disk: + + buffer MB/s + ------------ + 64 10 + 128 19 + 512 40 + 1024 48 + 2048 56 + 4096 56 + 8192 56 + */ + size_t bufSize; +}; +} + + +bool FreeFileSync::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback) +{ FileInput file1(filename1); //throw FileError() FileInput file2(filename2); //throw FileError() + BufferSize bufferSize; + + static std::vector<char> memory1; + static std::vector<char> memory2; + wxLongLong bytesCompared; + + wxLongLong lastDelayViolation = wxGetLocalTimeMillis(); + do { - const size_t length1 = file1.read(memory1.get(), BUFFER_SIZE); //returns actual number of bytes read; throw FileError() - const size_t length2 = file2.read(memory2.get(), BUFFER_SIZE); // + setMinSize(memory1, bufferSize); + setMinSize(memory2, bufferSize); - if (length1 != length2 || ::memcmp(memory1.get(), memory2.get(), length1) != 0) + const wxLongLong startTime = wxGetLocalTimeMillis(); + + const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError() + const size_t length2 = file2.read(&memory2[0], bufferSize); // + + const wxLongLong stopTime = wxGetLocalTimeMillis(); + + //-------- dynamically set buffer size to keep callback interval between 200 - 500ms --------------------- + const wxLongLong loopTime = stopTime - startTime; + if (loopTime < 200 && stopTime - lastDelayViolation > 2000) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 300 ms, but second one will be 0ms! + { + lastDelayViolation = stopTime; + bufferSize.inc(); //practically no costs! + } + else if (loopTime > 500) + { + lastDelayViolation = stopTime; + bufferSize.dec(); // + } + //------------------------------------------------------------------------------------------------ + +//#warning +// static wxLongLong blorg = wxGetLocalTimeMillis(); +// if (wxGetLocalTimeMillis() - blorg > 5000) +// { +// blorg = wxGetLocalTimeMillis(); +// wxMessageBox(numberToZstring<size_t>(bufferSize).c_str()); +// } + + + + if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0) return false; bytesCompared += length1 * 2; - - //send progress updates - callback.updateCompareStatus(bytesCompared); + callback.updateCompareStatus(bytesCompared); //send progress updates } while (!file1.eof()); |