| 558 | } |
| 559 | |
| 560 | void Output(PMTraceSession const* pmSession) |
| 561 | { |
| 562 | SetThreadDescription(GetCurrentThread(), L"PresentMon Output Thread"); |
| 563 | |
| 564 | auto const& args = GetCommandLineArgs(); |
| 565 | |
| 566 | // Structures to track processes and statistics from recorded events. |
| 567 | std::vector<uint64_t> recordingToggleHistory; |
| 568 | std::vector<ProcessEvent> processEvents; |
| 569 | std::vector<std::shared_ptr<PresentEvent>> presentEvents; |
| 570 | processEvents.reserve(128); |
| 571 | presentEvents.reserve(1024); |
| 572 | |
| 573 | for (;;) { |
| 574 | // Read gQuit here, but then check it after processing queued events. |
| 575 | // This ensures that we call Dequeue*() at least once after |
| 576 | // events have stopped being collected so that all events are included. |
| 577 | auto quit = gQuit; |
| 578 | |
| 579 | // Copy recording toggle history from MainThread |
| 580 | bool currentRecordingState = CopyRecordingToggleHistory(&recordingToggleHistory); |
| 581 | |
| 582 | // Copy process events, present events, and lost present events from ConsumerThread. |
| 583 | UpdateProcessEvents(pmSession->mPMConsumer, &processEvents); |
| 584 | pmSession->mPMConsumer->DequeuePresentEvents(presentEvents); |
| 585 | |
| 586 | // Process all the collected events, and update the various tracking |
| 587 | // and statistics data structures. |
| 588 | if (!presentEvents.empty()) { |
| 589 | ProcessEvents(*pmSession, presentEvents, &processEvents, &recordingToggleHistory, currentRecordingState); |
| 590 | presentEvents.clear(); |
| 591 | } |
| 592 | |
| 593 | // Display information to console if requested. If debug build and |
| 594 | // simple console, print a heartbeat if recording. |
| 595 | // |
| 596 | // gIsRecording is the real timeline recording state. Because we're |
| 597 | // just reading it without correlation to gRecordingToggleHistory, we |
| 598 | // don't need the critical section. |
| 599 | switch (args.mConsoleOutput) { |
| 600 | #if _DEBUG |
| 601 | case ConsoleOutput::Simple: |
| 602 | if (currentRecordingState && args.mCSVOutput != CSVOutput::None) { |
| 603 | wprintf(L"."); |
| 604 | } |
| 605 | break; |
| 606 | #endif |
| 607 | case ConsoleOutput::Statistics: |
| 608 | if (BeginConsoleUpdate()) { |
| 609 | for (auto const& pair : gProcesses) { |
| 610 | UpdateConsole(pair.first, pair.second); |
| 611 | } |
| 612 | |
| 613 | if (currentRecordingState && args.mCSVOutput != CSVOutput::None) { |
| 614 | ConsolePrintLn(L"** RECORDING **"); |
| 615 | } |
| 616 | |
| 617 | EndConsoleUpdate(); |
nothing calls this directly
no test coverage detected