Почему производительность CRITICAL_SECTION стала хуже на Win8

Похоже, что производительность CRITICAL_SECTION стала хуже в Windows 8 и выше. (см. графики ниже)

Тест довольно прост: некоторые параллельные потоки делают по 3 миллиона блокировок каждый для доступа исключительно к переменной. Вы можете найти программу на C ++ внизу вопроса. Я запускаю тест на Windows Vista, Windows 7, Windows 8, Windows 10 (x64, VMWare, Intel Core i7-2600 3,40 ГГц).

Результаты на картинке ниже.
Ось X — количество одновременных потоков.
Ось Y — это прошедшее время в секундах (чем ниже, тем лучше).

Результаты теста

Что мы можем увидеть:

  • SRWLock производительность примерно одинакова для всех платформ
  • CriticalSection производительность стала хуже относительно SRWL на Windows 8 и выше

Вопрос в том: Кто-нибудь может объяснить, почему производительность CRITICAL_SECTION стала хуже на Win8 и выше?


Некоторые заметки:

  • Результаты на реальных машинах практически одинаковы — CS гораздо хуже, чем std :: mutex, std :: recursive_mutex и SRWL на Win8 и выше. Однако у меня нет шансов запустить тест на разных ОС с одним и тем же процессором.
  • std::mutex реализация для Windows Vista основана на CRITICAL_SECTION, но для Win7 и выше std::mutex основан на SWRL. Это верно как для MSVS17, так и для 15 (чтобы убедиться, что primitives.h файл при установке MSVC ++ и ищите stl_critical_section_vista а также stl_critical_section_win7 классы) Это объясняет разницу между производительностью std :: mutex в Win Vista и другими.
  • Как сказано в комментариях, std::mutex является оболочкой, поэтому возможное объяснение некоторых издержек относительно SRWL может быть накладными, введенными кодом оболочки.

#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;
}

Тестовый проект был построен как консольное приложение Windows в Microsoft Visual Studio 17 (15.8.2) со следующими настройками:

  • Использование MFC: использование MFC в статической библиотеке
  • Версия Windows SDK: 10.0.17134.0
  • Набор инструментов платформы: Visual Studio 2017 (v141)
  • Оптимизация: O2, Oi, Oy-, GL

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]