diff --git a/cryptest.dsp b/cryptest.dsp index 31c21ba3..33bbe2a5 100644 --- a/cryptest.dsp +++ b/cryptest.dsp @@ -188,10 +188,6 @@ SOURCE=.\diamond.dat # End Source File # Begin Source File -SOURCE=.\digest.dat -# End Source File -# Begin Source File - SOURCE=.\dsa1024.dat # End Source File # Begin Source File diff --git a/hrtimer.cpp b/hrtimer.cpp index 52458419..9c8da7df 100644 --- a/hrtimer.cpp +++ b/hrtimer.cpp @@ -21,9 +21,10 @@ NAMESPACE_BEGIN(CryptoPP) word64 Timer::GetCurrentTimerValue() { #if defined(CRYPTOPP_WIN32_AVAILABLE) - FILETIME now; - GetSystemTimeAsFileTime(&now); - return now.dwLowDateTime + ((word64)now.dwHighDateTime << 32); + LARGE_INTEGER now; + if (!QueryPerformanceCounter(&now)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError())); + return now.QuadPart; #elif defined(CRYPTOPP_UNIX_AVAILABLE) timeval now; gettimeofday(&now, NULL); @@ -35,20 +36,33 @@ word64 Timer::GetCurrentTimerValue() #endif } -unsigned long Timer::ConvertTo(word64 t, Unit unit) +word64 Timer::TicksPerSecond() { - switch (unit) +#if defined(CRYPTOPP_WIN32_AVAILABLE) + static LARGE_INTEGER freq; + if (freq.QuadPart == 0) { - case SECONDS: - return (unsigned long)(t / (TicksPerMillisecond() * 1000)); - case MILLISECONDS: - return (unsigned long)(t / TicksPerMillisecond()); - case MICROSECONDS: - assert(TicksPerMillisecond() % 1000 == 0); - return (unsigned long)(t / (TicksPerMillisecond() / 1000)); + if (!QueryPerformanceFrequency(&freq)) + throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError())); } - assert(false); - return 0; + return freq.QuadPart; +#elif defined(CRYPTOPP_UNIX_AVAILABLE) || defined(macintosh) + return 1000000; +#endif +} + +word64 Timer::ConvertTo(word64 t, Unit unit) +{ + static unsigned long unitsPerSecondTable[] = {1, 1000, 1000*1000, 1000*1000*1000}; + + assert(unit < sizeof(unitsPerSecondTable) / sizeof(unitsPerSecondTable[0])); + unsigned long unitsPerSecond = unitsPerSecondTable[unit]; + const word64 freq = TicksPerSecond(); + + if (freq % unitsPerSecond == 0) + return t / (freq / unitsPerSecond); + else + return word64((double)t * unitsPerSecond / freq); } void Timer::StartTimer() @@ -57,7 +71,7 @@ void Timer::StartTimer() m_started = true; } -unsigned long Timer::ElapsedTime() +word64 Timer::ElapsedTimeInWord64() { if (m_stuckAtZero) return 0; @@ -70,6 +84,13 @@ unsigned long Timer::ElapsedTime() } } +unsigned long Timer::ElapsedTime() +{ + word64 elapsed = ElapsedTimeInWord64(); + assert(elapsed <= ULONG_MAX); + return (unsigned long)elapsed; +} + NAMESPACE_END #endif diff --git a/hrtimer.h b/hrtimer.h index d05dfd10..1e513923 100644 --- a/hrtimer.h +++ b/hrtimer.h @@ -11,23 +11,16 @@ NAMESPACE_BEGIN(CryptoPP) class Timer { public: - enum Unit {SECONDS, MILLISECONDS, MICROSECONDS}; + enum Unit {SECONDS = 0, MILLISECONDS, MICROSECONDS, NANOSECONDS}; Timer(Unit unit, bool stuckAtZero = false) : m_timerUnit(unit), m_stuckAtZero(stuckAtZero), m_started(false) {} static word64 GetCurrentTimerValue(); // GetCurrentTime is a macro in MSVC 6.0 - static unsigned long ConvertTo(word64 t, Unit unit); - - // this is not the resolution, just a conversion factor into milliseconds - static inline unsigned int TicksPerMillisecond() - { -#if defined(CRYPTOPP_WIN32_AVAILABLE) - return 10000; -#elif defined(CRYPTOPP_UNIX_AVAILABLE) || defined(macintosh) - return 1000; -#endif - } + static word64 ConvertTo(word64 t, Unit unit); + // this is not the resolution, just a conversion factor into seconds + static word64 TicksPerSecond(); void StartTimer(); + word64 ElapsedTimeInWord64(); unsigned long ElapsedTime(); private: diff --git a/network.cpp b/network.cpp index f7705a70..ab495da9 100644 --- a/network.cpp +++ b/network.cpp @@ -4,6 +4,8 @@ #include "network.h" #include "wait.h" +#define CRYPTOPP_TRACE_NETWORK 0 + NAMESPACE_BEGIN(CryptoPP) unsigned int NonblockingSource::PumpMessages2(unsigned int &messageCount, bool blocking) @@ -78,6 +80,9 @@ unsigned int NetworkSource::GeneralPump2(unsigned long &byteCount, bool blocking break; unsigned int recvResult = receiver.GetReceiveResult(); +#if CRYPTOPP_TRACE_NETWORK + OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str()); +#endif m_dataEnd += recvResult; m_waitingForResult = false; @@ -102,11 +107,17 @@ ReceiveNoWait: m_waitingForResult = true; // call Receive repeatedly as long as data is immediately available, // because some receivers tend to return data in small pieces +#if CRYPTOPP_TRACE_NETWORK + OutputDebugString((IntToString((unsigned int)this) + ": Receiving " + IntToString(m_buf.size()-m_dataEnd) + " bytes\n").c_str()); +#endif while (receiver.Receive(m_buf+m_dataEnd, m_buf.size()-m_dataEnd)) { unsigned int recvResult = receiver.GetReceiveResult(); +#if CRYPTOPP_TRACE_NETWORK + OutputDebugString((IntToString((unsigned int)this) + ": Received " + IntToString(recvResult) + " bytes\n").c_str()); +#endif m_dataEnd += recvResult; - if (receiver.EofReceived() || m_dataEnd == m_buf.size()) + if (receiver.EofReceived() || m_dataEnd > m_buf.size() /2) { m_waitingForResult = false; break; @@ -154,33 +165,56 @@ DoOutput: // ************************************************************* -NetworkSink::NetworkSink(unsigned int maxBufferSize, bool autoFlush) - : m_maxBufferSize(maxBufferSize), m_autoFlush(autoFlush) - , m_needSendResult(false), m_buffer(STDMIN(16U*1024U, maxBufferSize)), m_blockedBytes(0) +NetworkSink::NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound) + : m_maxBufferSize(maxBufferSize), m_autoFlushBound(autoFlushBound) + , m_needSendResult(false), m_wasBlocked(false) + , m_buffer(STDMIN(16U*1024U+256, maxBufferSize)), m_skipBytes(0) + , m_speedTimer(Timer::MILLISECONDS), m_byteCountSinceLastTimerReset(0) + , m_currentSpeed(0), m_maxObservedSpeed(0) { } +float NetworkSink::ComputeCurrentSpeed() +{ + if (m_speedTimer.ElapsedTime() > 1000) + { + m_currentSpeed = m_byteCountSinceLastTimerReset * 1000 / m_speedTimer.ElapsedTime(); + m_maxObservedSpeed = STDMAX(m_currentSpeed, m_maxObservedSpeed * 0.98f); + m_byteCountSinceLastTimerReset = 0; + m_speedTimer.StartTimer(); +// OutputDebugString(("max speed: " + IntToString((int)m_maxObservedSpeed) + " current speed: " + IntToString((int)m_currentSpeed) + "\n").c_str()); + } + return m_currentSpeed; +} + unsigned int NetworkSink::Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking) { - if (m_blockedBytes) + if (m_skipBytes) { - assert(length >= m_blockedBytes); - inString += length - m_blockedBytes; - length = m_blockedBytes; + assert(length >= m_skipBytes); + inString += m_skipBytes; + length -= m_skipBytes; } LazyPutter lp(m_buffer, inString, length); + if (!blocking || m_buffer.CurrentSize() > m_autoFlushBound) + TimedFlush(0, 0); + unsigned int targetSize = messageEnd ? 0 : m_maxBufferSize; - TimedFlush(blocking ? INFINITE_TIME : 0, m_autoFlush ? 0 : targetSize); + if (blocking) + TimedFlush(INFINITE_TIME, targetSize); if (m_buffer.CurrentSize() > targetSize) { assert(!blocking); - m_blockedBytes = STDMIN(m_buffer.CurrentSize() - targetSize, (unsigned long)length); - m_buffer.UndoLazyPut(m_blockedBytes); - return STDMAX(m_blockedBytes, 1U); + unsigned int blockedBytes = STDMIN(m_buffer.CurrentSize() - targetSize, (unsigned long)length); + m_buffer.UndoLazyPut(blockedBytes); + m_wasBlocked = true; + m_skipBytes += length - blockedBytes; + return STDMAX(blockedBytes, 1U); } - m_blockedBytes = 0; + m_wasBlocked = false; + m_skipBytes = 0; if (messageEnd) AccessSender().SendEof(); @@ -206,6 +240,9 @@ unsigned int NetworkSink::TimedFlush(unsigned long maxTime, unsigned int targetS break; unsigned int sendResult = sender.GetSendResult(); +#if CRYPTOPP_TRACE_NETWORK + OutputDebugString((IntToString((unsigned int)this) + ": Sent " + IntToString(sendResult) + " bytes\n").c_str()); +#endif m_buffer.Skip(sendResult); totalFlushSize += sendResult; m_needSendResult = false; @@ -221,6 +258,9 @@ unsigned int NetworkSink::TimedFlush(unsigned long maxTime, unsigned int targetS unsigned int contiguousSize = 0; const byte *block = m_buffer.Spy(contiguousSize); +#if CRYPTOPP_TRACE_NETWORK + OutputDebugString((IntToString((unsigned int)this) + ": Sending " + IntToString(contiguousSize) + " bytes\n").c_str()); +#endif sender.Send(block, contiguousSize); m_needSendResult = true; @@ -228,6 +268,9 @@ unsigned int NetworkSink::TimedFlush(unsigned long maxTime, unsigned int targetS break; // once time limit is reached, return even if there is more data waiting } + m_byteCountSinceLastTimerReset += totalFlushSize; + ComputeCurrentSpeed(); + return totalFlushSize; } diff --git a/network.h b/network.h index 1af4e650..a02e9ed7 100644 --- a/network.h +++ b/network.h @@ -51,8 +51,20 @@ public: virtual bool EofReceived() const =0; }; +class CRYPTOPP_NO_VTABLE NonblockingSinkInfo +{ +public: + virtual ~NonblockingSinkInfo() {} + virtual unsigned int GetMaxBufferSize() const =0; + virtual unsigned int GetCurrentBufferSize() const =0; + //! compute the current speed of this sink in bytes per second + virtual float ComputeCurrentSpeed() =0; + //! get the maximum observed speed of this sink in bytes per second + virtual float GetMaxObservedSpeed() const =0; +}; + //! a Sink class that queues input and can flush to a device for a specified amount of time. -class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink +class CRYPTOPP_NO_VTABLE NonblockingSink : public Sink, public NonblockingSinkInfo { public: bool IsolatedFlush(bool hardFlush, bool blocking); @@ -70,10 +82,8 @@ public: virtual unsigned int TimedFlush(unsigned long maxTime, unsigned int targetSize = 0) =0; virtual void SetMaxBufferSize(unsigned int maxBufferSize) =0; - virtual void SetAutoFlush(bool autoFlush = true) =0; - - virtual unsigned int GetMaxBufferSize() const =0; - virtual unsigned int GetCurrentBufferSize() const =0; + //! set a bound which will cause sink to flush if exceeded by GetCurrentBufferSize() + virtual void SetAutoFlushBound(unsigned int bound) =0; }; //! Network Sender @@ -116,32 +126,39 @@ private: class CRYPTOPP_NO_VTABLE NetworkSink : public NonblockingSink { public: - NetworkSink(unsigned int maxBufferSize, bool autoFlush); + NetworkSink(unsigned int maxBufferSize, unsigned int autoFlushBound); unsigned int GetMaxWaitObjectCount() const {return GetSender().GetMaxWaitObjectCount();} void GetWaitObjects(WaitObjectContainer &container) - {if (m_blockedBytes || !m_buffer.IsEmpty()) AccessSender().GetWaitObjects(container);} + {if (m_wasBlocked || !m_buffer.IsEmpty()) AccessSender().GetWaitObjects(container);} unsigned int Put2(const byte *inString, unsigned int length, int messageEnd, bool blocking); unsigned int TimedFlush(unsigned long maxTime, unsigned int targetSize = 0); void SetMaxBufferSize(unsigned int maxBufferSize) {m_maxBufferSize = maxBufferSize;} - void SetAutoFlush(bool autoFlush = true) {m_autoFlush = autoFlush;} + void SetAutoFlushBound(unsigned int bound) {m_autoFlushBound = bound;} unsigned int GetMaxBufferSize() const {return m_maxBufferSize;} unsigned int GetCurrentBufferSize() const {return m_buffer.CurrentSize();} + //! compute the current speed of this sink in bytes per second + float ComputeCurrentSpeed(); + //! get the maximum observed speed of this sink in bytes per second + float GetMaxObservedSpeed() const {return m_maxObservedSpeed;} + protected: virtual NetworkSender & AccessSender() =0; const NetworkSender & GetSender() const {return const_cast(this)->AccessSender();} private: - unsigned int m_maxBufferSize; - bool m_autoFlush, m_needSendResult; + unsigned int m_maxBufferSize, m_autoFlushBound; + bool m_needSendResult, m_wasBlocked; ByteQueue m_buffer; - unsigned int m_blockedBytes; + unsigned int m_skipBytes; + Timer m_speedTimer; + float m_byteCountSinceLastTimerReset, m_currentSpeed, m_maxObservedSpeed; }; #endif // #ifdef HIGHRES_TIMER_AVAILABLE diff --git a/queue.cpp b/queue.cpp index 976bb0c5..16de7720 100644 --- a/queue.cpp +++ b/queue.cpp @@ -234,9 +234,15 @@ void ByteQueue::LazyPut(const byte *inString, unsigned int size) { if (m_lazyLength > 0) FinalizeLazyPut(); - m_lazyString = const_cast(inString); - m_lazyLength = size; - m_lazyStringModifiable = false; + + if (inString == m_tail->buf+m_tail->m_tail) + Put(inString, size); + else + { + m_lazyString = const_cast(inString); + m_lazyLength = size; + m_lazyStringModifiable = false; + } } void ByteQueue::LazyPutModifiable(byte *inString, unsigned int size) diff --git a/simple.h b/simple.h index 99bc0906..1727d381 100644 --- a/simple.h +++ b/simple.h @@ -68,7 +68,7 @@ public: Unflushable() {} Unflushable(BufferedTransformation *q) : T(q) {} bool Flush(bool completeFlush, int propagation=-1, bool blocking=true) - {return ChannelFlush(NULL_CHANNEL, completeFlush, propagation);} + {return ChannelFlush(NULL_CHANNEL, completeFlush, propagation, blocking);} bool IsolatedFlush(bool hardFlush, bool blocking) {assert(false); return false;} bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) diff --git a/socketft.h b/socketft.h index e8baef0f..96f54124 100644 --- a/socketft.h +++ b/socketft.h @@ -200,8 +200,8 @@ private: class SocketSink : public NetworkSink, public Socket { public: - SocketSink(socket_t s = INVALID_SOCKET, unsigned int maxBufferSize=0, bool autoFlush=false) - : NetworkSink(maxBufferSize, autoFlush), Socket(s), m_sender(*this) {} + SocketSink(socket_t s=INVALID_SOCKET, unsigned int maxBufferSize=0, unsigned int autoFlushBound=16*1024) + : NetworkSink(maxBufferSize, autoFlushBound), Socket(s), m_sender(*this) {} void SendEof() {ShutDown(SD_SEND);} diff --git a/wait.cpp b/wait.cpp index e4da6121..b468bc76 100644 --- a/wait.cpp +++ b/wait.cpp @@ -13,6 +13,12 @@ #include #endif +#define TRACE_WAIT 0 + +#if TRACE_WAIT +#include "hrtimer.h" +#endif + NAMESPACE_BEGIN(CryptoPP) unsigned int WaitObjectContainer::MaxWaitObjects() @@ -25,9 +31,8 @@ unsigned int WaitObjectContainer::MaxWaitObjects() } WaitObjectContainer::WaitObjectContainer() -#ifndef NDEBUG - : m_sameResultCount(0) - , m_timer(Timer::MILLISECONDS) +#if CRYPTOPP_DETECT_NO_WAIT + : m_sameResultCount(0), m_timer(Timer::MILLISECONDS) #endif { Clear(); @@ -45,6 +50,19 @@ void WaitObjectContainer::Clear() m_noWait = false; } +void WaitObjectContainer::SetNoWait() +{ +#if CRYPTOPP_DETECT_NO_WAIT + if (-1 == m_lastResult && m_timer.ElapsedTime() > 1000) + { + if (m_sameResultCount > m_timer.ElapsedTime()) + try {throw 0;} catch (...) {} // possible no-wait loop, break in debugger + m_timer.StartTimer(); + } +#endif + m_noWait = true; +} + #ifdef USE_WINDOWS_STYLE_SOCKETS struct WaitingThreadData @@ -90,7 +108,7 @@ WaitObjectContainer::~WaitObjectContainer() void WaitObjectContainer::AddHandle(HANDLE handle) { -#ifndef NDEBUG +#if CRYPTOPP_DETECT_NO_WAIT if (m_handles.size() == m_lastResult && m_timer.ElapsedTime() > 1000) { if (m_sameResultCount > m_timer.ElapsedTime()) @@ -165,7 +183,18 @@ void WaitObjectContainer::CreateThreads(unsigned int count) bool WaitObjectContainer::Wait(unsigned long milliseconds) { if (m_noWait || m_handles.empty()) + { +#if CRYPTOPP_DETECT_NO_WAIT + if (-1 == m_lastResult) + m_sameResultCount++; + else + { + m_lastResult = -1; + m_sameResultCount = 0; + } +#endif return true; + } if (m_handles.size() > MAXIMUM_WAIT_OBJECTS) { @@ -211,10 +240,23 @@ bool WaitObjectContainer::Wait(unsigned long milliseconds) } else { +#if TRACE_WAIT + static Timer t(Timer::MICROSECONDS); + static unsigned long lastTime = 0; + unsigned long timeBeforeWait = t.ElapsedTime(); +#endif DWORD result = ::WaitForMultipleObjects(m_handles.size(), &m_handles[0], FALSE, milliseconds); +#if TRACE_WAIT + if (milliseconds > 0) + { + unsigned long timeAfterWait = t.ElapsedTime(); + OutputDebugString(("Handles " + IntToString(m_handles.size()) + ", Woke up by " + IntToString(result-WAIT_OBJECT_0) + ", Busied for " + IntToString(timeBeforeWait-lastTime) + " us, Waited for " + IntToString(timeAfterWait-timeBeforeWait) + " us, max " + IntToString(milliseconds) + "ms\n").c_str()); + lastTime = timeAfterWait; + } +#endif if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + m_handles.size()) { -#ifndef NDEBUG +#if CRYPTOPP_DETECT_NO_WAIT if (result == m_lastResult) m_sameResultCount++; else diff --git a/wait.h b/wait.h index 2951efe1..7adcdd7d 100644 --- a/wait.h +++ b/wait.h @@ -14,7 +14,13 @@ #include #endif -#ifndef NDEBUG +#ifdef NDEBUG +#define CRYPTOPP_DETECT_NO_WAIT 0 +#else +#define CRYPTOPP_DETECT_NO_WAIT 1 +#endif + +#if CRYPTOPP_DETECT_NO_WAIT #include "hrtimer.h" #endif @@ -38,7 +44,7 @@ public: WaitObjectContainer(); void Clear(); - void SetNoWait() {m_noWait = true;} + void SetNoWait(); bool Wait(unsigned long milliseconds); #ifdef USE_WINDOWS_STYLE_SOCKETS @@ -62,7 +68,7 @@ private: #endif bool m_noWait; -#ifndef NDEBUG +#if CRYPTOPP_DETECT_NO_WAIT #ifdef USE_WINDOWS_STYLE_SOCKETS DWORD m_lastResult; #else diff --git a/winpipes.h b/winpipes.h index 29a3717a..a02005b9 100644 --- a/winpipes.h +++ b/winpipes.h @@ -123,8 +123,8 @@ private: class WindowsPipeSink : public WindowsHandle, public NetworkSink, public WindowsPipeSender { public: - WindowsPipeSink(HANDLE h=INVALID_HANDLE_VALUE, unsigned int maxBufferSize=0, bool autoFlush=false) - : WindowsHandle(h), NetworkSink(maxBufferSize, autoFlush) {} + WindowsPipeSink(HANDLE h=INVALID_HANDLE_VALUE, unsigned int maxBufferSize=0, unsigned int autoFlushBound=16*1024) + : WindowsHandle(h), NetworkSink(maxBufferSize, autoFlushBound) {} NetworkSink::GetMaxWaitObjectCount; NetworkSink::GetWaitObjects;