#include #include #include #include #pragma comment(lib, "winmm.lib") #pragma comment(lib, "synchronization.lib") #define N 10000 #define DELAY_MS 50 const char *ExperimentName; void(*ExperimentWait)(void); void(*ExperimentWake)(void); LARGE_INTEGER StartTime; double Dt[N]; volatile int BarrierA; volatile int BarrierB; DWORD __stdcall ThreadA(void *parameter) { (void)parameter; for (int i = 0; i < N; ++i) { ++BarrierA; while (BarrierB != i + 1); ExperimentWait(); LARGE_INTEGER endTime; QueryPerformanceCounter(&endTime); LARGE_INTEGER qpf; QueryPerformanceFrequency(&qpf); double dt = (endTime.QuadPart - StartTime.QuadPart) / (double)qpf.QuadPart; Dt[i] = dt; } } DWORD __stdcall ThreadB(void *parameter) { (void)parameter; for (int i = 0; i < N; ++i) { ++BarrierB; while (BarrierA != i + 1); Sleep(DELAY_MS); QueryPerformanceCounter(&StartTime); ExperimentWake(); } } int Compare(const void *a, const void *b) { double A = *(double *)a; double B = *(double *)b; if (A < B) return -1; else if (A > B) return +1; else return 0; } void Run(void) { BarrierA = 0; BarrierB = 0; HANDLE a = CreateThread(NULL, 0, ThreadA, NULL, 0, NULL); HANDLE b = CreateThread(NULL, 0, ThreadB, NULL, 0, NULL); HANDLE threads[2] = { a, b }; WaitForMultipleObjects(2, threads, TRUE, INFINITE); qsort(Dt, N, sizeof Dt[0], Compare); double avg = 0; double min = 1e99; double max = 0; double med = Dt[N / 2]; for (int i = 0; i < N; ++i) { avg += Dt[i]; if (Dt[i] < min) min = Dt[i]; if (Dt[i] > max) max = Dt[i]; } avg /= N; double sdev = 0; for (int i = 0; i < N; ++i) { double dev = Dt[i] - avg; sdev += dev * dev; } sdev = sqrt(sdev / N); printf("%s avg: %.2f sdev: %.2f min: %.1f max: %.1f median: %.1f us\n", ExperimentName, avg * 1e6, sdev * 1e6, min * 1e6, max * 1e6, med * 1e6); } volatile long Spin; void SpinWait(void) { while (!Spin); Spin = FALSE; } void SpinWake(void) { Spin = TRUE; } volatile long Atomic; void AtomicWait(void) { long notYet = FALSE; while (!Atomic) WaitOnAddress(&Atomic, ¬Yet, sizeof(long), INFINITE); Atomic = FALSE; } void AtomicWake(void) { Atomic = TRUE; WakeByAddressSingle((void *)&Atomic); } HANDLE Event; void EventWait(void) { WaitForSingleObject(Event, INFINITE); } void EventWake(void) { SetEvent(Event); } volatile long SleepVar; void SleepWait(void) { while (!SleepVar) Sleep(1); SleepVar = FALSE; } void SleepWake(void) { SleepVar = TRUE; } int main(void) { timeBeginPeriod(1); Event = CreateEvent(NULL, FALSE, FALSE, NULL); ExperimentName = "Spin"; ExperimentWait = SpinWait; ExperimentWake = SpinWake; Run(); ExperimentName = "Atomic wait"; ExperimentWait = AtomicWait; ExperimentWake = AtomicWake; Run(); ExperimentName = "Event"; ExperimentWait = EventWait; ExperimentWake = EventWake; Run(); ExperimentName = "Sleep"; ExperimentWait = SleepWait; ExperimentWake = SleepWake; Run(); }