最新の Windows スケジューラに興味があったので、別のテスト アプリを作成しました。オプションで監視スレッドをスピンアップして、スレッド停止時間を測定するために最善を尽くしました。
// Tested on Windows 10 v1903 with E5-1660 v3 @ 3.00GHz, 8 Core(s), 16 Logical Processor(s)
// Times are (min, average, max) in milliseconds.
threads: 100, iterations: 1, testStop: true
Start(0.1083, 5.3665, 13.7103) - Stop(0.0341, 1.5122, 11.0660)
threads: 32, iterations: 3, testStop: true
Start(0.1349, 1.6423, 3.5561) - Stop(0.0396, 0.2877, 3.5195)
Start(0.1093, 1.4992, 3.3982) - Stop(0.0351, 0.2734, 2.0384)
Start(0.1159, 1.5345, 3.5754) - Stop(0.0378, 0.4938, 3.2216)
threads: 4, iterations: 3, testStop: true
Start(0.2066, 0.3553, 0.4598) - Stop(0.0410, 0.1534, 0.4630)
Start(0.2769, 0.3740, 0.4994) - Stop(0.0414, 0.1028, 0.2581)
Start(0.2342, 0.3602, 0.5650) - Stop(0.0497, 0.2199, 0.3620)
threads: 4, iterations: 3, testStop: false
Start(0.1698, 0.2492, 0.3713)
Start(0.1473, 0.2477, 0.4103)
Start(0.1756, 0.2909, 0.4295)
threads: 1, iterations: 10, testStop: false
Start(0.1910, 0.1910, 0.1910)
Start(0.1685, 0.1685, 0.1685)
Start(0.1564, 0.1564, 0.1564)
Start(0.1504, 0.1504, 0.1504)
Start(0.1389, 0.1389, 0.1389)
Start(0.1234, 0.1234, 0.1234)
Start(0.1550, 0.1550, 0.1550)
Start(0.2800, 0.2800, 0.2800)
Start(0.1587, 0.1587, 0.1587)
Start(0.1877, 0.1877, 0.1877)
ソース:
#include <windows.h>
#include <iostream>
#include <vector>
#include <chrono>
#include <iomanip>
using namespace std::chrono;
struct Test
{
HANDLE Thread = { 0 };
time_point<steady_clock> Creation;
time_point<steady_clock> Started;
time_point<steady_clock> Stopped;
};
DWORD __stdcall ThreadProc(void* lpParamater) {
auto test = (Test*)lpParamater;
test->Started = steady_clock::now();
return 0;
}
DWORD __stdcall TestThreadsEnded(void* lpParamater) {
auto& tests = *(std::vector<Test>*)lpParamater;
std::size_t finished = 0;
while (finished < tests.size())
{
for (auto& test : tests)
{
if (test.Thread != NULL && WaitForSingleObject(test.Thread, 0) == WAIT_OBJECT_0)
{
test.Stopped = steady_clock::now();
test.Thread = NULL;
finished++;
}
}
}
return 0;
}
duration<double, std::milli> diff(time_point<steady_clock> start, time_point<steady_clock> stop)
{
return stop - start;
}
struct Stats
{
double min;
double average;
double max;
};
Stats stats(const std::vector<double>& durations)
{
Stats stats = { 1000, 0, 0 };
for (auto& duration : durations)
{
stats.min = duration < stats.min ? duration : stats.min;
stats.max = duration > stats.max ? duration : stats.max;
stats.average += duration;
}
stats.average /= durations.size();
return stats;
}
void TestScheduler(const int threadCount, const int iterations, const bool testStop)
{
std::cout << "\nthreads: " << threadCount << ", iterations: " << iterations << ", testStop: " << (testStop ? "true" : "false") << "\n";
for (auto i = 0; i < iterations; i++)
{
std::vector<Test> tests(threadCount);
HANDLE testThreadsEnded = NULL;
if (testStop)
{
testThreadsEnded = CreateThread(NULL, 0, TestThreadsEnded, (void*)& tests, 0, NULL);
}
for (auto& test : tests)
{
test.Creation = steady_clock::now();
test.Thread = CreateThread(NULL, 0, ThreadProc, (void*)& test, 0, NULL);
}
if (testStop)
{
WaitForSingleObject(testThreadsEnded, INFINITE);
}
else
{
std::vector<HANDLE> threads;
for (auto& test : tests) threads.push_back(test.Thread);
WaitForMultipleObjects((DWORD)threads.size(), threads.data(), TRUE, INFINITE);
}
std::vector<double> startDurations;
std::vector<double> stopDurations;
for (auto& test : tests)
{
startDurations.push_back(diff(test.Creation, test.Started).count());
stopDurations.push_back(diff(test.Started, test.Stopped).count());
}
auto startStats = stats(startDurations);
auto stopStats = stats(stopDurations);
std::cout << std::fixed << std::setprecision(4);
std::cout << "Start(" << startStats.min << ", " << startStats.average << ", " << startStats.max << ")";
if (testStop)
{
std::cout << " - ";
std::cout << "Stop(" << stopStats.min << ", " << stopStats.average << ", " << stopStats.max << ")";
}
std::cout << "\n";
}
}
int main(void)
{
TestScheduler(100, 1, true);
TestScheduler(32, 3, true);
TestScheduler(4, 3, true);
TestScheduler(4, 3, false);
TestScheduler(1, 10, false);
return 0;
}