Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

828 lines
23 KiB

  1. /*++
  2. Copyright 2000 Microsoft Corporation
  3. Module Name:
  4. dsperf.c
  5. Abstract:
  6. This module contains the implementation of the DShow performance counter
  7. provider. It acts as a WMI event tracing controller and consumer and exposes
  8. standard NT performance counters.
  9. Author:
  10. Arthur Zwiegincew (arthurz) 05-Oct-00
  11. Revision History:
  12. 05-Oct-00 - Created
  13. --*/
  14. #include <windows.h>
  15. #include <winperf.h>
  16. #include <stdio.h>
  17. #include <wmistr.h>
  18. #include <evntrace.h>
  19. #include <initguid.h>
  20. #include <math.h>
  21. #include "dscounters.h"
  22. #define WMIPERF
  23. #include <perfstruct.h>
  24. typedef LONG LOGICAL;
  25. GUID KmixerGuid =
  26. { 0xe5a43a19, 0x6de0, 0x44f8, 0xb0, 0xd7, 0x77, 0x2d, 0xbd, 0xe4, 0x6c, 0xc0 };
  27. GUID PortclsGuid =
  28. { 0x9d447297, 0xc576, 0x4015, 0x87, 0xb5, 0xa5, 0xa6, 0x98, 0xfd, 0x4d, 0xd1 };
  29. GUID UsbaudioGuid =
  30. { 0xd6464a84, 0xa358, 0x4013, 0xa1, 0xe8, 0x6e, 0x2f, 0xb4, 0x8a, 0xab, 0x93 };
  31. //
  32. // Video glitch threshold. When abs(PresentationTime - RenderTime) > this value,
  33. // we consider the event a glitch.
  34. //
  35. #define GLITCH_THRESHOLD 30 /* ms */ * 10000 /* 1 ms / 100 ns */
  36. //
  37. // Performance data.
  38. //
  39. ULONG VideoGlitches;
  40. ULONG VideoGlitchesPerSec;
  41. ULONG VideoFrameRate;
  42. ULONG VideoJitter;
  43. ULONG DsoundGlitches;
  44. ULONG KmixerGlitches;
  45. ULONG PortclsGlitches;
  46. ULONG UsbaudioGlitches;
  47. ULONG VideoGlitchesSinceLastMeasurement;
  48. ULONG FramesRendered;
  49. ULONGLONG LastMeasurementTime;
  50. #define JITTER_HISTORY_BUFFER_SIZE 200
  51. LONGLONG FrameJitterHistory[JITTER_HISTORY_BUFFER_SIZE];
  52. ULONG NextJitterEntry;
  53. //
  54. // DSHOW WMI provider GUID.
  55. //
  56. GUID ControlGuid = GUID_DSHOW_CTL;
  57. //
  58. // Event tracing-related globals.
  59. //
  60. HANDLE MonitorThread;
  61. HANDLE ResetThread;
  62. TRACEHANDLE LoggerHandle;
  63. TRACEHANDLE ConsumerHandle;
  64. EVENT_TRACE_LOGFILE Logfile;
  65. ULONGLONG LastBufferFlushTime;
  66. //
  67. // Performance monitoring structures.
  68. //
  69. typedef struct _DSHOW_PERF_DATA_DEFINITION {
  70. PERF_OBJECT_TYPE ObjectType;
  71. PERF_COUNTER_DEFINITION VideoGlitches;
  72. PERF_COUNTER_DEFINITION VideoGlitchesPerSec;
  73. PERF_COUNTER_DEFINITION VideoFrameRate;
  74. PERF_COUNTER_DEFINITION VideoJitter;
  75. PERF_COUNTER_DEFINITION DsoundGlitches;
  76. PERF_COUNTER_DEFINITION KmixerGlitches;
  77. PERF_COUNTER_DEFINITION PortclsGlitches;
  78. PERF_COUNTER_DEFINITION UsbaudioGlitches;
  79. } DSHOW_PERF_DATA_DEFINITION, *PDSHOW_PERF_DATA_DEFINITION;
  80. typedef struct _DSHOW_PERF_COUNTERS {
  81. PERF_COUNTER_BLOCK CounterBlock;
  82. ULONG Pad;
  83. ULONG VideoGlitches;
  84. ULONG VideoGlitchesPerSec;
  85. ULONG VideoFrameRate;
  86. ULONG VideoJitter;
  87. ULONG DsoundGlitches;
  88. ULONG KmixerGlitches;
  89. ULONG PortclsGlitches;
  90. ULONG UsbaudioGlitches;
  91. //ULONG Pad2;
  92. //ULONG Pad3;
  93. } DSHOW_PERF_COUNTERS, *PDSHOW_PERF_COUNTERS;
  94. //
  95. // Perfmon-related globals.
  96. //
  97. DSHOW_PERF_DATA_DEFINITION DshowPerfDataDefinition;
  98. LONG OpenCount = 0; // Keeps track of how many threads have open ds counters.
  99. LOGICAL Initialized = 0; // Fixes an initialization race condition.
  100. //
  101. // Function prototypes.
  102. //
  103. PM_OPEN_PROC PerfOpen;
  104. PM_CLOSE_PROC PerfClose;
  105. PM_COLLECT_PROC PerfCollect;
  106. DWORD
  107. WINAPI
  108. MonitorThreadProc (
  109. LPVOID Param
  110. );
  111. DWORD
  112. WINAPI
  113. ResetThreadProc (
  114. LPVOID Param
  115. );
  116. VOID
  117. TerminateLogging (
  118. VOID
  119. );
  120. ////////////////////////////////////////////////////////////////////////////
  121. ULONG
  122. APIENTRY
  123. PerfOpen (
  124. LPWSTR DevNames
  125. )
  126. /*++
  127. Routine Description:
  128. This routine initializes data collection.
  129. Arguments:
  130. DevNames - Supplies a REG_MULTISZ of object IDs of the devices to be opened.
  131. Return Value:
  132. ERROR_SUCCESS - OK.
  133. <multiple failure codes> - initialization failed.
  134. Note:
  135. On remote connections, this function may be called more than once
  136. by multiple threads.
  137. --*/
  138. {
  139. PDSHOW_PERF_DATA_DEFINITION Def = &DshowPerfDataDefinition;
  140. ULONG FirstCounter;
  141. ULONG FirstHelp;
  142. HKEY PerfKey;
  143. LOGICAL WasInitialized;
  144. ULONG Type;
  145. ULONG Size;
  146. LONG status;
  147. //
  148. // Initialize counters.
  149. //
  150. VideoGlitches = 0;
  151. VideoGlitchesSinceLastMeasurement = 0;
  152. VideoFrameRate = 0;
  153. DsoundGlitches = 0;
  154. KmixerGlitches = 0;
  155. PortclsGlitches = 0;
  156. UsbaudioGlitches = 0;
  157. FramesRendered = 0;
  158. NextJitterEntry = 0;
  159. GetSystemTimeAsFileTime ((FILETIME*)&LastMeasurementTime);
  160. //
  161. // Since WinLogon is multithreaded and will call this routine in order to
  162. // service remote performance queries, this library must keep track of how
  163. // many threads have accessed it). The registry routines will limit access
  164. // to the initialization routine to only one thread at a time.
  165. //
  166. WasInitialized = InterlockedCompareExchange (&Initialized, 0, 0);
  167. if (!WasInitialized) {
  168. //
  169. // Create the monitor thread.
  170. //
  171. MonitorThread = CreateThread (NULL, 0, MonitorThreadProc, 0, 0, NULL);
  172. if (MonitorThread == NULL) {
  173. return GetLastError();
  174. }
  175. //
  176. // Create the reset thread.
  177. //
  178. ResetThread = CreateThread (NULL, 0, ResetThreadProc, 0, 0, NULL);
  179. if (ResetThread == NULL) {
  180. return GetLastError();
  181. }
  182. //
  183. // Get counter and help index base values from the registry.
  184. //
  185. status = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  186. "SYSTEM\\CurrentControlSet\\Services\\DSPerf\\Performance",
  187. 0L, KEY_READ, &PerfKey);
  188. if (status != ERROR_SUCCESS) {
  189. return status;
  190. }
  191. Size = sizeof (ULONG);
  192. status = RegQueryValueEx (PerfKey, "First Counter", 0L, &Type,
  193. (LPBYTE) &FirstCounter, &Size);
  194. if (status != ERROR_SUCCESS) {
  195. RegCloseKey (PerfKey);
  196. return status;
  197. }
  198. Size = sizeof (ULONG);
  199. status = RegQueryValueEx (PerfKey, "First Help", 0L, &Type,
  200. (LPBYTE) &FirstHelp, &Size);
  201. if (status != ERROR_SUCCESS) {
  202. RegCloseKey (PerfKey);
  203. return status;
  204. }
  205. RegCloseKey (PerfKey);
  206. //
  207. // Fill the data definition structure.
  208. //
  209. Def->ObjectType.TotalByteLength = sizeof (DSHOW_PERF_DATA_DEFINITION) +
  210. sizeof (DSHOW_PERF_COUNTERS);
  211. Def->ObjectType.DefinitionLength = sizeof (DSHOW_PERF_DATA_DEFINITION);
  212. Def->ObjectType.HeaderLength = sizeof (PERF_OBJECT_TYPE);
  213. Def->ObjectType.ObjectNameTitleIndex = DSHOWPERF_OBJ + FirstCounter;
  214. Def->ObjectType.ObjectNameTitle = NULL;
  215. Def->ObjectType.ObjectHelpTitleIndex = DSHOWPERF_OBJ + FirstHelp;
  216. Def->ObjectType.ObjectHelpTitle = NULL;
  217. Def->ObjectType.DetailLevel = PERF_DETAIL_NOVICE;
  218. Def->ObjectType.NumCounters = (sizeof (DSHOW_PERF_DATA_DEFINITION) -
  219. sizeof (PERF_OBJECT_TYPE)) /
  220. sizeof (PERF_COUNTER_DEFINITION);
  221. Def->ObjectType.DefaultCounter = -1;
  222. Def->ObjectType.NumInstances = PERF_NO_INSTANCES;
  223. Def->ObjectType.CodePage = 0;
  224. Def->ObjectType.PerfFreq.QuadPart = 10000000;
  225. ///
  226. Def->VideoGlitches.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  227. Def->VideoGlitches.CounterNameTitleIndex = DSHOWPERF_VIDEO_GLITCHES + FirstCounter;
  228. Def->VideoGlitches.CounterNameTitle = NULL;
  229. Def->VideoGlitches.CounterHelpTitleIndex = DSHOWPERF_VIDEO_GLITCHES + FirstHelp;
  230. Def->VideoGlitches.CounterHelpTitle = NULL;
  231. Def->VideoGlitches.DefaultScale = -1;
  232. Def->VideoGlitches.DetailLevel = PERF_DETAIL_NOVICE;
  233. Def->VideoGlitches.CounterType = PERF_COUNTER_RAWCOUNT;
  234. Def->VideoGlitches.CounterSize = sizeof (ULONG);
  235. Def->VideoGlitches.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, VideoGlitches);
  236. ///
  237. Def->VideoGlitchesPerSec.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  238. Def->VideoGlitchesPerSec.CounterNameTitleIndex = DSHOWPERF_VIDEO_GLITCHES_SEC + FirstCounter;
  239. Def->VideoGlitchesPerSec.CounterNameTitle = NULL;
  240. Def->VideoGlitchesPerSec.CounterHelpTitleIndex = DSHOWPERF_VIDEO_GLITCHES_SEC + FirstHelp;
  241. Def->VideoGlitchesPerSec.CounterHelpTitle = NULL;
  242. Def->VideoGlitchesPerSec.DefaultScale = 0;
  243. Def->VideoGlitchesPerSec.DetailLevel = PERF_DETAIL_NOVICE;
  244. Def->VideoGlitchesPerSec.CounterType = PERF_COUNTER_RAWCOUNT;
  245. Def->VideoGlitchesPerSec.CounterSize = sizeof (ULONG);
  246. Def->VideoGlitchesPerSec.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, VideoGlitchesPerSec);
  247. ///
  248. Def->VideoFrameRate.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  249. Def->VideoFrameRate.CounterNameTitleIndex = DSHOWPERF_FRAME_RATE + FirstCounter;
  250. Def->VideoFrameRate.CounterNameTitle = NULL;
  251. Def->VideoFrameRate.CounterHelpTitleIndex = DSHOWPERF_FRAME_RATE + FirstHelp;
  252. Def->VideoFrameRate.CounterHelpTitle = NULL;
  253. Def->VideoFrameRate.DefaultScale = 0;
  254. Def->VideoFrameRate.DetailLevel = PERF_DETAIL_NOVICE;
  255. Def->VideoFrameRate.CounterType = PERF_COUNTER_RAWCOUNT;
  256. Def->VideoFrameRate.CounterSize = sizeof (ULONG);
  257. Def->VideoFrameRate.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, VideoFrameRate);
  258. ///
  259. Def->VideoJitter.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  260. Def->VideoJitter.CounterNameTitleIndex = DSHOWPERF_JITTER + FirstCounter;
  261. Def->VideoJitter.CounterNameTitle = NULL;
  262. Def->VideoJitter.CounterHelpTitleIndex = DSHOWPERF_JITTER + FirstHelp;
  263. Def->VideoJitter.CounterHelpTitle = NULL;
  264. Def->VideoJitter.DefaultScale = 1;
  265. Def->VideoJitter.DetailLevel = PERF_DETAIL_NOVICE;
  266. Def->VideoJitter.CounterType = PERF_COUNTER_RAWCOUNT;
  267. Def->VideoJitter.CounterSize = sizeof (ULONG);
  268. Def->VideoJitter.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, VideoJitter);
  269. ///
  270. Def->DsoundGlitches.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  271. Def->DsoundGlitches.CounterNameTitleIndex = DSHOWPERF_DSOUND_GLITCHES + FirstCounter;
  272. Def->DsoundGlitches.CounterNameTitle = NULL;
  273. Def->DsoundGlitches.CounterHelpTitleIndex = DSHOWPERF_DSOUND_GLITCHES + FirstHelp;
  274. Def->DsoundGlitches.CounterHelpTitle = NULL;
  275. Def->DsoundGlitches.DefaultScale = -1;
  276. Def->DsoundGlitches.DetailLevel = PERF_DETAIL_NOVICE;
  277. Def->DsoundGlitches.CounterType = PERF_COUNTER_RAWCOUNT;
  278. Def->DsoundGlitches.CounterSize = sizeof (ULONG);
  279. Def->DsoundGlitches.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, DsoundGlitches);
  280. ///
  281. Def->KmixerGlitches.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  282. Def->KmixerGlitches.CounterNameTitleIndex = DSHOWPERF_KMIXER_GLITCHES + FirstCounter;
  283. Def->KmixerGlitches.CounterNameTitle = NULL;
  284. Def->KmixerGlitches.CounterHelpTitleIndex = DSHOWPERF_KMIXER_GLITCHES + FirstHelp;
  285. Def->KmixerGlitches.CounterHelpTitle = NULL;
  286. Def->KmixerGlitches.DefaultScale = -1;
  287. Def->KmixerGlitches.DetailLevel = PERF_DETAIL_NOVICE;
  288. Def->KmixerGlitches.CounterType = PERF_COUNTER_RAWCOUNT;
  289. Def->KmixerGlitches.CounterSize = sizeof (ULONG);
  290. Def->KmixerGlitches.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, KmixerGlitches);
  291. ///
  292. Def->PortclsGlitches.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  293. Def->PortclsGlitches.CounterNameTitleIndex = DSHOWPERF_PORTCLS_GLITCHES + FirstCounter;
  294. Def->PortclsGlitches.CounterNameTitle = NULL;
  295. Def->PortclsGlitches.CounterHelpTitleIndex = DSHOWPERF_PORTCLS_GLITCHES + FirstHelp;
  296. Def->PortclsGlitches.CounterHelpTitle = NULL;
  297. Def->PortclsGlitches.DefaultScale = -1;
  298. Def->PortclsGlitches.DetailLevel = PERF_DETAIL_NOVICE;
  299. Def->PortclsGlitches.CounterType = PERF_COUNTER_RAWCOUNT;
  300. Def->PortclsGlitches.CounterSize = sizeof (ULONG);
  301. Def->PortclsGlitches.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, PortclsGlitches);
  302. ///
  303. Def->UsbaudioGlitches.ByteLength = sizeof (PERF_COUNTER_DEFINITION);
  304. Def->UsbaudioGlitches.CounterNameTitleIndex = DSHOWPERF_USBAUDIO_GLITCHES + FirstCounter;
  305. Def->UsbaudioGlitches.CounterNameTitle = NULL;
  306. Def->UsbaudioGlitches.CounterHelpTitleIndex = DSHOWPERF_USBAUDIO_GLITCHES + FirstHelp;
  307. Def->UsbaudioGlitches.CounterHelpTitle = NULL;
  308. Def->UsbaudioGlitches.DefaultScale = -1;
  309. Def->UsbaudioGlitches.DetailLevel = PERF_DETAIL_NOVICE;
  310. Def->UsbaudioGlitches.CounterType = PERF_COUNTER_RAWCOUNT;
  311. Def->UsbaudioGlitches.CounterSize = sizeof (ULONG);
  312. Def->UsbaudioGlitches.CounterOffset = FIELD_OFFSET (DSHOW_PERF_COUNTERS, UsbaudioGlitches);
  313. }
  314. InterlockedExchange (&Initialized, 1);
  315. InterlockedIncrement (&OpenCount);
  316. return ERROR_SUCCESS;
  317. }
  318. ////////////////////////////////////////////////////////////////////////////
  319. ULONG
  320. APIENTRY
  321. PerfClose (
  322. VOID
  323. )
  324. /*++
  325. Routine Description:
  326. This routine cleans up after data collection.
  327. Arguments:
  328. None.
  329. Return Value:
  330. ERROR_SUCCESS.
  331. Note:
  332. On remote connections, this function may be called more than once
  333. by multiple threads.
  334. --*/
  335. {
  336. ULONG NewOpenCount;
  337. NewOpenCount = InterlockedDecrement (&OpenCount);
  338. if (NewOpenCount == 0) {
  339. //
  340. // Last thread has closed the counter. Perform cleanup here.
  341. //
  342. TerminateLogging();
  343. }
  344. return ERROR_SUCCESS;
  345. }
  346. ////////////////////////////////////////////////////////////////////////////
  347. ULONG
  348. APIENTRY
  349. PerfCollect (
  350. IN LPWSTR ValueName,
  351. IN OUT LPVOID* PData,
  352. IN OUT LPDWORD TotalBytes,
  353. OUT LPDWORD NumObjectTypes
  354. )
  355. /*++
  356. Routine Description:
  357. This routine provides perf mon data.
  358. Arguments:
  359. ValueName - Supplies a string specified by the performance monitor program
  360. in a call to the RegQueryValueEx function.
  361. PData - Supplies the address of the buffer to receive the completed
  362. PERF_DATA_BLOCK and subordinate structures. This routine will
  363. append its data to the buffer starting at the point referenced
  364. by *PData.
  365. Receives the pointer to the first byte after the data structure
  366. added by this routine.
  367. TotalBytes - Supplies the size in bytes of the buffer referenced by PData.
  368. Receives the number of bytes added by this routine.
  369. NumObjectTypes - Receives the number of objects added by this routine.
  370. Return Value:
  371. ERROR_MORE_DATA - if the buffer passed is too small to hold data.
  372. ERROR_SUCCESS - if success or any other error.
  373. Errors are also reported to the event log. AZFIX
  374. --*/
  375. {
  376. PDSHOW_PERF_DATA_DEFINITION PerfDataDefinition;
  377. PDSHOW_PERF_COUNTERS PerfCounters;
  378. FILETIME FileTime;
  379. ULONG SpaceNeeded;
  380. SpaceNeeded = sizeof (DSHOW_PERF_DATA_DEFINITION) +
  381. sizeof (DSHOW_PERF_COUNTERS);
  382. if (!Initialized) {
  383. *TotalBytes = 0;
  384. *NumObjectTypes = 0;
  385. return ERROR_SUCCESS; // This is OK.
  386. }
  387. if (*TotalBytes < SpaceNeeded) {
  388. *TotalBytes = 0;
  389. *NumObjectTypes = 0;
  390. return ERROR_MORE_DATA;
  391. }
  392. //
  393. // Copy the object and counter definitions.
  394. //
  395. PerfDataDefinition = (PDSHOW_PERF_DATA_DEFINITION)(*PData);
  396. RtlMoveMemory (PerfDataDefinition, &DshowPerfDataDefinition,
  397. sizeof (DSHOW_PERF_DATA_DEFINITION));
  398. GetSystemTimeAsFileTime (&FileTime);
  399. RtlCopyMemory (&PerfDataDefinition->ObjectType.PerfTime.QuadPart,
  400. &FileTime, sizeof (LONGLONG));
  401. PerfDataDefinition->ObjectType.NumInstances = -1;
  402. PerfDataDefinition->ObjectType.TotalByteLength = SpaceNeeded;
  403. //
  404. // Fill in counter data.
  405. //
  406. PerfCounters = (PDSHOW_PERF_COUNTERS)(PerfDataDefinition + 1);
  407. PerfCounters->CounterBlock.ByteLength = sizeof (DSHOW_PERF_COUNTERS);
  408. PerfCounters->VideoGlitches = VideoGlitches;
  409. PerfCounters->VideoGlitchesPerSec = VideoGlitchesPerSec;
  410. PerfCounters->VideoFrameRate = VideoFrameRate;
  411. PerfCounters->VideoJitter = VideoJitter;
  412. PerfCounters->DsoundGlitches = DsoundGlitches;
  413. PerfCounters->KmixerGlitches = KmixerGlitches;
  414. PerfCounters->PortclsGlitches = PortclsGlitches;
  415. PerfCounters->UsbaudioGlitches = UsbaudioGlitches;
  416. //
  417. // Update out parameters.
  418. //
  419. *PData = (PVOID)(PerfCounters + 1);
  420. *TotalBytes = SpaceNeeded;
  421. *NumObjectTypes = 1;
  422. return ERROR_SUCCESS;
  423. }
  424. ////////////////////////////////////////////////////////////////////////////
  425. VOID
  426. TerminateLogging (
  427. VOID
  428. )
  429. {
  430. ULONG status;
  431. int i;
  432. struct EVENT_TRACE_INFO {
  433. EVENT_TRACE_PROPERTIES TraceProperties;
  434. char Logger[256];
  435. char LogFileName[256];
  436. } Info;
  437. ZeroMemory (&Info, sizeof (Info));
  438. Info.TraceProperties.LoggerNameOffset = sizeof (EVENT_TRACE_PROPERTIES);
  439. Info.TraceProperties.LogFileNameOffset = sizeof (EVENT_TRACE_PROPERTIES) + 256;
  440. Info.TraceProperties.Wnode.BufferSize = sizeof (Info);
  441. ControlTrace (0, "DSPerf", &Info.TraceProperties, EVENT_TRACE_CONTROL_QUERY);
  442. ControlTraceA (LoggerHandle, NULL, &Info.TraceProperties, EVENT_TRACE_CONTROL_STOP);
  443. if (MonitorThread != NULL) {
  444. EnableTrace (FALSE, 0, 0, &ControlGuid, LoggerHandle);
  445. TerminateThread (MonitorThread, 0);
  446. }
  447. if (ResetThread != NULL) {
  448. TerminateThread (ResetThread, 0);
  449. }
  450. for (i = 0; i < 100; i += 1) {
  451. Sleep (50);
  452. status = CloseTrace (ConsumerHandle);
  453. if (status == ERROR_SUCCESS) {
  454. break;
  455. }
  456. }
  457. EnableTrace (FALSE, 0, 0, &ControlGuid, LoggerHandle);
  458. }
  459. ////////////////////////////////////////////////////////////////////////////
  460. VOID
  461. WINAPI
  462. EventCallback (
  463. IN PEVENT_TRACE Event
  464. )
  465. {
  466. PPERFINFO_DSHOW_AVREND PerfInfoAvRend;
  467. PPERFINFO_DSHOW_AUDIOGLITCH PerfInfoAudioGlitch;
  468. ULONG i;
  469. LONGLONG PresentationDelta;
  470. if (IsEqualGUID (Event->Header.Guid, GUID_VIDEOREND)) {
  471. FramesRendered += 1;
  472. PerfInfoAvRend = (PPERFINFO_DSHOW_AVREND)Event->MofData;
  473. PresentationDelta = PerfInfoAvRend->dshowClock - PerfInfoAvRend->sampleTime;
  474. FrameJitterHistory[NextJitterEntry] = PresentationDelta;
  475. if (NextJitterEntry < JITTER_HISTORY_BUFFER_SIZE - 1) {
  476. NextJitterEntry += 1;
  477. }
  478. if (labs ((int)PresentationDelta) > GLITCH_THRESHOLD) {
  479. //
  480. // Video glitch.
  481. //
  482. VideoGlitches += 1;
  483. VideoGlitchesSinceLastMeasurement += 1;
  484. }
  485. }
  486. else if (IsEqualGUID (Event->Header.Guid, GUID_DSOUNDGLITCH)) {
  487. PerfInfoAudioGlitch = (PPERFINFO_DSHOW_AUDIOGLITCH)Event->MofData;
  488. if (PerfInfoAudioGlitch->glitchType == 1) {
  489. DsoundGlitches += 1;
  490. }
  491. }
  492. else if (IsEqualGUID (Event->Header.Guid, KmixerGuid)) {
  493. PerfInfoAudioGlitch = (PPERFINFO_DSHOW_AUDIOGLITCH)Event->MofData;
  494. KmixerGlitches += 1;
  495. }
  496. else if (IsEqualGUID (Event->Header.Guid, PortclsGuid)) {
  497. PerfInfoAudioGlitch = (PPERFINFO_DSHOW_AUDIOGLITCH)Event->MofData;
  498. PortclsGlitches += 1;
  499. }
  500. else if (IsEqualGUID (Event->Header.Guid, UsbaudioGuid)) {
  501. PerfInfoAudioGlitch = (PPERFINFO_DSHOW_AUDIOGLITCH)Event->MofData;
  502. UsbaudioGlitches += 1;
  503. }
  504. }
  505. ////////////////////////////////////////////////////////////////////////////
  506. ULONG
  507. WINAPI
  508. BufferCallback (
  509. PEVENT_TRACE_LOGFILE Log
  510. )
  511. {
  512. ULONGLONG CurrentTime;
  513. double TimeDelta;
  514. double JitterMean;
  515. double Jitter;
  516. double x;
  517. ULONG i;
  518. //
  519. // Extend the reset timer (indirectly).
  520. //
  521. GetSystemTimeAsFileTime ((FILETIME*)&LastBufferFlushTime);
  522. //
  523. // Calculate rates.
  524. //
  525. GetSystemTimeAsFileTime ((FILETIME*)&CurrentTime);
  526. TimeDelta = (double)(CurrentTime - LastMeasurementTime) / 10000000.0L;
  527. if (CurrentTime > LastMeasurementTime) {
  528. VideoGlitchesPerSec = (ULONG)((double)VideoGlitchesSinceLastMeasurement / TimeDelta);
  529. VideoFrameRate = (ULONG)((double)FramesRendered / TimeDelta);
  530. }
  531. else {
  532. VideoGlitchesPerSec = 0;
  533. VideoFrameRate = 0;
  534. }
  535. //
  536. // Calculate jitter.
  537. //
  538. if (NextJitterEntry > 1) {
  539. JitterMean = 0.0L;
  540. for (i = 0; i < NextJitterEntry; i += 1) {
  541. JitterMean += (double)FrameJitterHistory[i];
  542. }
  543. JitterMean /= (double)NextJitterEntry;
  544. Jitter = 0.0L;
  545. for (i = 0; i < NextJitterEntry; i += 1) {
  546. x = (double)FrameJitterHistory[i] - JitterMean;
  547. Jitter += (x * x);
  548. }
  549. Jitter /= (double)(NextJitterEntry - 1);
  550. Jitter = sqrt (Jitter) / 10000.0L;
  551. VideoJitter = (ULONG)Jitter;
  552. }
  553. else {
  554. VideoJitter = 0;
  555. }
  556. LastMeasurementTime = CurrentTime;
  557. VideoGlitchesSinceLastMeasurement = 0;
  558. FramesRendered = 0;
  559. NextJitterEntry = 0;
  560. return TRUE;
  561. }
  562. ////////////////////////////////////////////////////////////////////////////
  563. DWORD
  564. WINAPI
  565. MonitorThreadProc (
  566. LPVOID Param
  567. )
  568. {
  569. struct EVENT_TRACE_INFO {
  570. EVENT_TRACE_PROPERTIES TraceProperties;
  571. char Logger[256];
  572. } Info;
  573. UNREFERENCED_PARAMETER (Param);
  574. ULONG status;
  575. //
  576. // Start the controller.
  577. //
  578. ZeroMemory (&Info, sizeof (Info));
  579. Info.TraceProperties.Wnode.BufferSize = sizeof (Info);
  580. Info.TraceProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  581. Info.TraceProperties.Wnode.Guid = ControlGuid;
  582. Info.TraceProperties.BufferSize = 4096;
  583. Info.TraceProperties.MinimumBuffers = 8;
  584. Info.TraceProperties.MaximumBuffers = 16;
  585. Info.TraceProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
  586. Info.TraceProperties.FlushTimer = 1;
  587. Info.TraceProperties.EnableFlags = 1;
  588. Info.TraceProperties.AgeLimit = 1;
  589. Info.TraceProperties.LoggerNameOffset = sizeof (Info.TraceProperties);
  590. strcpy (Info.Logger, "DSPerf");
  591. status = StartTrace (&LoggerHandle, "DSPerf", &Info.TraceProperties);
  592. if (status != ERROR_SUCCESS) {
  593. return 0;
  594. }
  595. status = EnableTrace (TRUE, 0x1f, 0, &ControlGuid, LoggerHandle);
  596. if (status != ERROR_SUCCESS) {
  597. return 0;
  598. }
  599. //
  600. // Start the consumer.
  601. //
  602. ZeroMemory (&Logfile, sizeof (Logfile));
  603. Logfile.LoggerName = "DSPerf";
  604. Logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
  605. Logfile.BufferCallback = BufferCallback;
  606. Logfile.EventCallback = EventCallback;
  607. ConsumerHandle = OpenTrace (&Logfile);
  608. if (ConsumerHandle == (TRACEHANDLE)INVALID_HANDLE_VALUE) {
  609. return 0;
  610. }
  611. //
  612. // Consume. This call returns when logging is stopped.
  613. //
  614. status = ProcessTrace (&ConsumerHandle, 1, NULL, NULL);
  615. if (status != ERROR_SUCCESS) {
  616. return 1;
  617. }
  618. return 1;
  619. }
  620. ////////////////////////////////////////////////////////////////////////////
  621. DWORD
  622. WINAPI
  623. ResetThreadProc (
  624. LPVOID Param
  625. )
  626. {
  627. ULONGLONG Time;
  628. for (;;) {
  629. Sleep (500);
  630. GetSystemTimeAsFileTime ((FILETIME*)&Time);
  631. if (Time - LastBufferFlushTime > 15000000I64) {
  632. FramesRendered = 0;
  633. NextJitterEntry = 0;
  634. VideoGlitchesPerSec = 0;
  635. VideoFrameRate = 0;
  636. VideoJitter = 0;
  637. }
  638. }
  639. }