source: trunk/Utilities/Miscellaneous/EventSynchronizationTest01/EventSynchronizationTest01.cpp

Last change on this file was 203, checked in by roman, 6 years ago
File size: 13.3 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2011
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: EventSynchronizationTest01.cpp 246 2011-03-19 17:24:45Z alax $
6
7#include "stdafx.h"
8#if defined(_DEBUG)
9#include <conio.h>
10#endif // defined(_DEBUG)
11#include <winternl.h>
12#include <atlsync.h>
13
14static const UINT g_nMethod = 4;
15static const SIZE_T g_nSendThreadCount = 3;
16static const ULONG g_nDuration = 60 * 1000; // 60 seconds
17
18#pragma region Internals
19
20namespace Internals
21{
22#if !defined(_WIN64)
23#error The undocumented structures below are only valid for 64-bit code
24#endif // !defined(_WIN64)
25
26        //typedef struct _IO_COUNTERS
27        //{
28        //    ULONG ReadOperationCount;
29        //    ULONG WriteOperationCount;
30        //    ULONG OtherOperationCount;
31        //    ULONGLONG ReadTransferCount;
32        //    ULONGLONG WriteTransferCount;
33        //    ULONGLONG OtherTransferCount;
34        //} IO_COUNTERS;
35
36        typedef struct _VM_COUNTERS
37        {
38                ULONGLONG PeakVirtualSize;
39                ULONGLONG VirtualSize;
40                ULONG PageFaultCount;
41                ULONG Reserved1;
42                ULONGLONG PeakWorkingSetSize;
43                ULONGLONG WorkingSetSize;
44                ULONGLONG QuotaPeakPagedPoolUsage;
45                ULONGLONG QuotaPagedPoolUsage;
46                ULONGLONG QuotaPeakNonPagedPoolUsage;
47                ULONGLONG QuotaNonPagedPoolUsage;
48                ULONGLONG PagefileUsage;
49                ULONGLONG PeakPagefileUsage;
50                ULONGLONG Reserved2;
51        } VM_COUNTERS;
52
53        typedef struct _CLIENT_ID
54        {
55                HANDLE ProcessId; 
56                HANDLE ThreadId; 
57        } CLIENT_ID, *PCLIENT_ID;
58
59        typedef LONG KPRIORITY;
60        typedef LONG KWAIT_REASON;
61
62        typedef struct _SYSTEM_THREAD_INFORMATION {
63                ULONGLONG KernelTime; 
64                ULONGLONG UserTime; 
65                ULONGLONG CreateTime; 
66                ULONG WaitTime; 
67                ULONG Reserved1; 
68                PVOID StartAddress; 
69                CLIENT_ID ClientId; 
70                KPRIORITY Priority; 
71                LONG BasePriority; 
72                ULONG ContextSwitchCount; 
73                ULONG State; 
74                KWAIT_REASON WaitReason;
75        } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
76
77        typedef struct _SYSTEM_PROCESS_INFORMATION {
78                ULONG NextEntryOffset; 
79                ULONG NumberOfThreads; 
80                ULONGLONG Reserved[3]; 
81                ULONGLONG CreateTime; 
82                ULONGLONG UserTime; 
83                ULONGLONG KernelTime; 
84                UNICODE_STRING ImageName; 
85                KPRIORITY BasePriority; 
86                HANDLE ProcessId; 
87                HANDLE InheritedFromProcessId; 
88                ULONG HandleCount; 
89                ULONG Reserved2[2]; 
90                ULONG PrivatePageCount;  // Garbage
91                VM_COUNTERS VirtualMemoryCounters; 
92                IO_COUNTERS IoCounters; 
93                SYSTEM_THREAD_INFORMATION Threads[1];
94        } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
95
96        class CSystemProcessInformation
97        {
98        private:
99                CHeapPtr<BYTE> m_pnData;
100                SIZE_T m_nDataSize;
101
102        public:
103        // CSystemProcessInformation
104                CSystemProcessInformation() :
105                        m_nDataSize(0)
106                {
107                }
108                VOID Initialize()
109                {
110                        static const SIZE_T g_nDataCapacity = 1 << 20; // 1MB
111                        ATLENSURE_THROW(m_pnData.Reallocate(g_nDataCapacity), E_OUTOFMEMORY);
112                        ULONG nDataSize = 0;
113                        typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(__in SYSTEM_INFORMATION_CLASS SystemInformationClass,  __inout PVOID SystemInformation, __in ULONG SystemInformationLength, __out_opt PULONG ReturnLength);
114                        NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQuerySystemInformation");
115                        ATLASSERT(NtQuerySystemInformation);
116                        ATLVERIFY(NtQuerySystemInformation(SystemProcessInformation, m_pnData, (ULONG) g_nDataCapacity, &nDataSize) == 0);
117                        m_nDataSize = nDataSize;
118                }
119                const SYSTEM_PROCESS_INFORMATION* LookupProcess(DWORD nProcessIdentifier = GetCurrentProcessId()) throw()
120                {
121                        if(m_nDataSize)
122                                for(const SYSTEM_PROCESS_INFORMATION* pProcessInformation = (const SYSTEM_PROCESS_INFORMATION*) (const BYTE*) m_pnData; pProcessInformation; pProcessInformation = pProcessInformation->NextEntryOffset ? (const SYSTEM_PROCESS_INFORMATION*) ((const BYTE*) pProcessInformation + pProcessInformation->NextEntryOffset) : NULL)
123                                        if(pProcessInformation->ProcessId == (HANDLE) nProcessIdentifier)
124                                                return pProcessInformation;
125                        return NULL;
126                }
127                static const SYSTEM_THREAD_INFORMATION* LookupThread(const SYSTEM_PROCESS_INFORMATION* pProcessInformation, DWORD nThreadIdentifier = GetCurrentThreadId()) throw()
128                {
129                        if(pProcessInformation)
130                                for(ULONG nThreadIndex = 0; nThreadIndex < pProcessInformation->NumberOfThreads; nThreadIndex++)
131                                {
132                                        const SYSTEM_THREAD_INFORMATION* pThreadInformation = &pProcessInformation->Threads[nThreadIndex];
133                                        ATLASSERT(pThreadInformation->ClientId.ProcessId == pProcessInformation->ProcessId);
134                                        if(pThreadInformation->ClientId.ThreadId == (HANDLE) nThreadIdentifier)
135                                                return pThreadInformation;
136                                }
137                        return NULL;
138                }
139        };
140}
141
142#pragma endregion
143
144class CModule
145{
146private:
147        CEvent m_StartEvent;
148        CEvent m_StopEvent;
149        CComAutoCriticalSection m_CriticalSection;
150        CEvent m_AvailabilityEvent;
151        UINT m_nSendCount;
152        UINT m_nReceiveCount;
153
154        DWORD SendThreadProc()
155        {
156                UINT nRandomValue = (UINT) rand();
157                const HANDLE phObjects[] = { m_StopEvent };
158                ATLVERIFY(WaitForSingleObject(m_StartEvent, INFINITE) == WAIT_OBJECT_0);
159                for(UINT nIteration = 0; ; nIteration++)
160                {
161                        const INT nDelay = (INT) (nRandomValue % 1000) - 998;
162                        nRandomValue = (nRandomValue * 13) ^ ((nRandomValue * 17) << 2) ^ ((nRandomValue * 19) << 4);
163                        if(nDelay > 0)
164                        {
165                                const DWORD nWaitResult = WaitForMultipleObjects(DIM(phObjects), phObjects, FALSE, nDelay);
166                                ATLASSERT(nWaitResult - WAIT_OBJECT_0 < DIM(phObjects) || nWaitResult == WAIT_TIMEOUT);
167                                if(nWaitResult == WAIT_OBJECT_0)
168                                        break;
169                        }
170                        #pragma endregion
171                        switch(g_nMethod)
172                        {
173                        case 1:
174                                {
175                                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_CriticalSection);
176                                        m_nSendCount++;
177                                        ATLVERIFY(m_AvailabilityEvent.Set());
178                                }
179                                break;
180                        case 2:
181                                {
182                                        {
183                                                CComCritSecLock<CComAutoCriticalSection> DataLock(m_CriticalSection);
184                                                m_nSendCount++;
185                                        }
186                                        ATLVERIFY(m_AvailabilityEvent.Set());
187                                }
188                                break;
189                        case 3:
190                        case 4:
191                                {
192                                        //CComCritSecLock<CComAutoCriticalSection> DataLock(m_CriticalSection);
193                                        m_nSendCount++;
194                                        ATLVERIFY(m_AvailabilityEvent.Set());
195                                }
196                                break;
197                        default:
198                                ATLASSUME(FALSE);
199                        }
200                }
201                // NOTE: Master thread will want to query thread performance
202                Sleep(10000);
203                return 0;
204        }
205        DWORD ReceiveThreadProc()
206        {
207                const HANDLE phObjects[] = { m_StopEvent, m_AvailabilityEvent };
208                ATLVERIFY(WaitForSingleObject(m_StartEvent, INFINITE) == WAIT_OBJECT_0);
209                for(UINT nIteration = 0; ; nIteration++)
210                {
211                        const DWORD nWaitResult = WaitForMultipleObjects(DIM(phObjects), phObjects, FALSE, INFINITE);
212                        ATLASSERT(nWaitResult - WAIT_OBJECT_0 < DIM(phObjects) || nWaitResult == WAIT_TIMEOUT);
213                        if(nWaitResult == WAIT_OBJECT_0)
214                                break;
215                        switch(g_nMethod)
216                        {
217                        case 1:
218                        case 2:
219                        case 4:
220                                {
221                                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_CriticalSection);
222                                        m_nReceiveCount++;
223                                        ATLVERIFY(m_AvailabilityEvent.Reset());
224                                }
225                                break;
226                        case 3:
227                                {
228                                        //CComCritSecLock<CComAutoCriticalSection> DataLock(m_CriticalSection);
229                                        m_nReceiveCount++;
230                                        ATLVERIFY(m_AvailabilityEvent.Reset());
231                                }
232                                break;
233                        default:
234                                ATLASSUME(FALSE);
235                        }
236                }
237                // NOTE: Master thread will want to query thread performance
238                Sleep(10000);
239                return 0;
240        }
241        static DWORD STDMETHODCALLTYPE SendThreadProc(CModule* pModule)
242        {
243                return pModule->SendThreadProc();
244        }
245        static DWORD STDMETHODCALLTYPE ReceiveThreadProc(CModule* pModule)
246        {
247                return pModule->ReceiveThreadProc();
248        }
249        static ULONG FileTimesToMilliseconds(const FILETIME& AnchorFileTime, const FILETIME& FileTime) throw()
250        {
251                return (ULONG) ((reinterpret_cast<const ULONGLONG&>(FileTime) - reinterpret_cast<const ULONGLONG&>(AnchorFileTime)) / 10000);
252        }
253        static ULONG FileTimesToMicroseconds(const FILETIME& AnchorFileTime, const FILETIME& FileTime) throw()
254        {
255                return (ULONG) ((reinterpret_cast<const ULONGLONG&>(FileTime) - reinterpret_cast<const ULONGLONG&>(AnchorFileTime)) / 10);
256        }
257        template <typename _Integer>
258        CString FormatIntegerNumber(_Integer nValue)
259        {
260                CString sValue;
261                sValue.Format(_T("%d"), nValue);
262                TCHAR pszValue[32] = { 0 };
263                NUMBERFMT Format = { 0, 1, 3, _T("."), _T(","), 1 };
264                ATLVERIFY(GetNumberFormat(LOCALE_USER_DEFAULT, 0, sValue, &Format, pszValue, DIM(pszValue)));
265                return pszValue;
266        }
267
268public:
269// CModule
270        VOID Run()
271        {
272                srand(1);
273                ATLVERIFY(SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS));
274                ATLVERIFY(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST));
275                _tprintf(_T("Method: %d\n"), g_nMethod);
276                _tprintf(_T("Send Thread Count: %d\n"), g_nSendThreadCount);
277                _tprintf(_T("Duration: %s ms\n"), FormatIntegerNumber(g_nDuration));
278                _tprintf(_T("* * *\n"));
279                m_nSendCount = 0;
280                m_nReceiveCount = 0;
281                ATLENSURE_THROW(m_StartEvent.Create(NULL, TRUE, FALSE, NULL), AtlHresultFromLastError());
282                ATLENSURE_THROW(m_AvailabilityEvent.Create(NULL, TRUE, FALSE, NULL), AtlHresultFromLastError());
283                ATLENSURE_THROW(m_StopEvent.Create(NULL, TRUE, FALSE, NULL), AtlHresultFromLastError());
284                CAtlList<CHandle> SendThreadList;
285                for(SIZE_T nIndex = 0; nIndex < g_nSendThreadCount; nIndex++)
286                {
287                        CHandle& SendThread = SendThreadList.GetAt(SendThreadList.AddTail());
288                        SendThread.Attach(AtlCreateThread(&CModule::SendThreadProc, this));
289                        ATLVERIFY(SetThreadPriority(SendThread, THREAD_PRIORITY_ABOVE_NORMAL));
290                }
291                CHandle& SendThread = SendThreadList.GetHead();
292                CHandle ReceiveThread;
293                ReceiveThread.Attach(AtlCreateThread(&CModule::ReceiveThreadProc, this));
294                ATLVERIFY(SetThreadPriority(ReceiveThread, THREAD_PRIORITY_ABOVE_NORMAL));
295                Sleep(1000);
296                FILETIME SendThreadCreationTime, SendThreadExitTime, AnchorSendThreadKernelTime, AnchorSendThreadUserTime;
297                ATLVERIFY(GetThreadTimes(SendThread, &SendThreadCreationTime, &SendThreadExitTime, &AnchorSendThreadKernelTime, &AnchorSendThreadUserTime));
298                FILETIME ReceiveThreadCreationTime, ReceiveThreadExitTime, AnchorReceiveThreadKernelTime, AnchorReceiveThreadUserTime;
299                ATLVERIFY(GetThreadTimes(ReceiveThread, &ReceiveThreadCreationTime, &ReceiveThreadExitTime, &AnchorReceiveThreadKernelTime, &AnchorReceiveThreadUserTime));
300                FILETIME ProcessCreationTime, ProcessExitTime, AnchorProcessKernelTime, AnchorProcessUserTime;
301                ATLVERIFY(GetProcessTimes(GetCurrentProcess(), &ProcessCreationTime, &ProcessExitTime, &AnchorProcessKernelTime, &AnchorProcessUserTime));
302                ATLVERIFY(m_StartEvent.Set());
303                Sleep(g_nDuration);
304                ATLVERIFY(m_StopEvent.Set());
305                Sleep(1000);
306                #pragma region Performance Statistics
307                FILETIME ProcessKernelTime, ProcessUserTime;
308                ATLVERIFY(GetProcessTimes(GetCurrentProcess(), &ProcessCreationTime, &ProcessExitTime, &ProcessKernelTime, &ProcessUserTime));
309                FILETIME SendThreadKernelTime, SendThreadUserTime;
310                ATLVERIFY(GetThreadTimes(SendThread, &SendThreadCreationTime, &SendThreadExitTime, &SendThreadKernelTime, &SendThreadUserTime));
311                FILETIME ReceiveThreadKernelTime, ReceiveThreadUserTime;
312                ATLVERIFY(GetThreadTimes(ReceiveThread, &ReceiveThreadCreationTime, &ReceiveThreadExitTime, &ReceiveThreadKernelTime, &ReceiveThreadUserTime));
313                _tprintf(_T("Send Count:    %15s\n"), FormatIntegerNumber(m_nSendCount));
314                _tprintf(_T("Receive Count: %15s\n"), FormatIntegerNumber(m_nReceiveCount));
315                _tprintf(_T("\n"));
316                Internals::CSystemProcessInformation SystemProcessInformation;
317                SystemProcessInformation.Initialize();
318                const Internals::SYSTEM_PROCESS_INFORMATION* pProcessInformation = SystemProcessInformation.LookupProcess();
319                const Internals::SYSTEM_THREAD_INFORMATION* pSendThreadInformation = NULL;
320                const Internals::SYSTEM_THREAD_INFORMATION* pReceiveThreadInformation = NULL;
321                if(pProcessInformation)
322                {
323                        //const ::SYSTEM_PROCESS_INFORMATION* pAnotherProcessInformation = (const ::SYSTEM_PROCESS_INFORMATION*) pProcessInformation;
324                        pSendThreadInformation = Internals::CSystemProcessInformation::LookupThread(pProcessInformation, GetThreadId(SendThread));
325                        pReceiveThreadInformation = Internals::CSystemProcessInformation::LookupThread(pProcessInformation, GetThreadId(ReceiveThread));
326                }
327                _tprintf(_T("Process Time:        User %10s ms, Kernel %10s ms\n"), 
328                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorProcessUserTime, ProcessUserTime)),
329                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorProcessKernelTime, ProcessKernelTime)), 
330                        0);
331                _tprintf(_T("Send Thread 0 Time:  User %10s ms, Kernel %10s ms, Context Switches %15s\n"), 
332                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorSendThreadUserTime, SendThreadUserTime)),
333                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorSendThreadKernelTime, SendThreadKernelTime)), 
334                        FormatIntegerNumber(pSendThreadInformation ? pSendThreadInformation->ContextSwitchCount : 0),
335                        0);
336                _tprintf(_T("Receive Thread Time: User %10s ms, Kernel %10s ms, Context Switches %15s\n"), 
337                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorReceiveThreadUserTime, ReceiveThreadUserTime)),
338                        FormatIntegerNumber(FileTimesToMilliseconds(AnchorReceiveThreadKernelTime, ReceiveThreadKernelTime)), 
339                        FormatIntegerNumber(pReceiveThreadInformation ? pReceiveThreadInformation->ContextSwitchCount : 0),
340                        0);
341                #pragma endregion
342        }
343};
344
345int _tmain(int argc, _TCHAR* argv[])
346{
347        _ATLTRY
348        {
349                CModule Module;
350                Module.Run();
351        }
352        _ATLCATCHALL()
353        {
354                _tprintf(_T("Fatal Error\n"));
355        }
356        return 0;
357}
358
Note: See TracBrowser for help on using the repository browser.