问题
It seems like CRITICAL_SECTION performance became worse on Windows 8 and higher. (see graphs below)
The test is pretty simple: some concurrent threads do 3 million locks each to access a variable exclusively. You can find the C++ program at the bottom of the question. I run the test on Windows Vista, Windows 7, Windows 8, Windows 10 (x64, VMWare, Intel Core i7-2600 3.40GHz).
The results are on the image below. The X-axis is the number of concurrent threads. The Y-axis is the elapsed time in seconds (lower is better).
What we can see:
SRWLock
performance is approximately the same for all platformsCriticalSection
performance became worse relatively SRWL on Windows 8 and higher
The question is: Can anybody please explain why did CRITICAL_SECTION performance become worse on Win8 and higher?
Some notes:
- The results on real machines are pretty the same - CS is much worse than both std::mutex, std::recursive_mutex and SRWL on Win8 and higher. However I have no chance to run the test on different OSes with the same CPU.
std::mutex
implementation for Windows Vista is based onCRITICAL_SECTION
, but for Win7 and higherstd::mutex
is based on SWRL. It is correct for both MSVS17 and 15 (To make sure search forprimitives.h
file at MSVC++ installation and look forstl_critical_section_vista
andstl_critical_section_win7
classes) This explains the difference between std::mutex performance on Win Vista and others.- As it is said in comments, the
std::mutex
is a wrapper, so the possible explanation for some overhead relatively SRWL may be overhead introduced by the wrapper code.
#include <chrono>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include <Windows.h>
const size_t T = 10;
const size_t N = 3000000;
volatile uint64_t var = 0;
const std::string sep = ";";
namespace WinApi
{
class CriticalSection
{
CRITICAL_SECTION cs;
public:
CriticalSection() { InitializeCriticalSection(&cs); }
~CriticalSection() { DeleteCriticalSection(&cs); }
void lock() { EnterCriticalSection(&cs); }
void unlock() { LeaveCriticalSection(&cs); }
};
class SRWLock
{
SRWLOCK srw;
public:
SRWLock() { InitializeSRWLock(&srw); }
void lock() { AcquireSRWLockExclusive(&srw); }
void unlock() { ReleaseSRWLockExclusive(&srw); }
};
}
template <class M>
void doLock(void *param)
{
M &m = *static_cast<M*>(param);
for (size_t n = 0; n < N; ++n)
{
m.lock();
var += std::rand();
m.unlock();
}
}
template <class M>
void runTest(size_t threadCount)
{
M m;
std::vector<std::thread> thrs(threadCount);
const auto start = std::chrono::system_clock::now();
for (auto &t : thrs) t = std::thread(doLock<M>, &m);
for (auto &t : thrs) t.join();
const auto end = std::chrono::system_clock::now();
const std::chrono::duration<double> diff = end - start;
std::cout << diff.count() << sep;
}
template <class ...Args>
void runTests(size_t threadMax)
{
{
int dummy[] = { (std::cout << typeid(Args).name() << sep, 0)... };
(void)dummy;
}
std::cout << std::endl;
for (size_t n = 1; n <= threadMax; ++n)
{
{
int dummy[] = { (runTest<Args>(n), 0)... };
(void)dummy;
}
std::cout << std::endl;
}
}
int main()
{
std::srand(time(NULL));
runTests<std::mutex, WinApi::CriticalSection, WinApi::SRWLock>(T);
return 0;
}
The test project was built as Windows Console Application on Microsoft Visual Studio 17 (15.8.2) with the folowing settings:
- Use of MFC: Use MFC in a Static Library
- Windows SDK Version: 10.0.17134.0
- Platform Toolset: Visual Studio 2017 (v141)
- Optimization: O2, Oi, Oy-, GL
回答1:
See Windows Critical Section - how to disable spinning completely Starting from Windows 8, Microsoft changed implementation (without even a word in documentation) of default behavior of Critical Section (if you use InitializeCriticalSection(&cs), you will get spinning with undocumented dynamic spin adjustment algorithm enabled). See my comment here: https://randomascii.wordpress.com/2012/06/05/in-praise-of-idleness/#comment-57420
For your test, try using InitializeCriticalSectionAndSpinCount(&cs,1) instead of InitializeCriticalSection(&cs). This should make it behave somewhat similar to Windows 7, though there are plenty of other changes in that area.
来源:https://stackoverflow.com/questions/52170665/why-did-critical-section-performance-become-worse-on-win8