//-------------------------------------------------------------------------- /// EndFrame is used to signal the end of a rendered frame and to stop/send /// the captured results that were logged during the frame render. /// \return Nothing. //-------------------------------------------------------------------------- void MultithreadedTraceAnalyzerLayer::EndFrame() { // Check again which trace type is active at the end of the frame. Need to match how it was started. int autotraceFlags = GetTraceTypeFlags(); // If the linked trace was requested, return all of the results through a single response. bool bLinkedTraceRequested = (mCmdLinkedTrace.IsActive() || mCmdLinkedTraceWithSave.IsActive()) || (autotraceFlags == kTraceType_Linked); // Will we be required to dump the trace response to a file on disk? bool bSaveResponseToFile = mCmdLinkedTraceWithSave.IsActive(); // If we want a linked trace, we'll need responses from all trace types. bool bAPITraceResponseNeeded = m_apiTraceTXT.IsActive() || bLinkedTraceRequested || (autotraceFlags & kTraceType_API); bool bGPUTraceResponseNeeded = m_cmdGPUTrace.IsActive() || bLinkedTraceRequested || (autotraceFlags & kTraceType_GPU); if (bAPITraceResponseNeeded || bGPUTraceResponseNeeded) { // We're done collecting, so turn off the interception and profiler switch. InterceptorBase* interceptor = GetInterceptor(); interceptor->SetCollectTrace(false); interceptor->SetProfilingEnabled(false); AfterAPITrace(); AfterGPUTrace(); std::string apiTraceResponseString, gpuTraceResponseString; if (bAPITraceResponseNeeded) { mbCollectingApiTrace = false; apiTraceResponseString.assign(GetAPITraceTXT().c_str()); } if (bGPUTraceResponseNeeded) { mbGPUTraceAlreadyCollected = false; gpuTraceResponseString.assign(GetGPUTraceTXT().c_str()); } std::stringstream fullResponseString; if (bAPITraceResponseNeeded) { #if !defined(CODEXL_GRAPHICS) // In Linked trace mode, insert a separator indicating the split between response types. if (bLinkedTraceRequested) { fullResponseString << "//Type:API" << std::endl; } #endif fullResponseString << apiTraceResponseString.c_str() << std::endl; } if (bGPUTraceResponseNeeded) { #if !defined(CODEXL_GRAPHICS) // In Linked trace mode, insert a separator indicating the split between response types. if (bLinkedTraceRequested) { fullResponseString << "//Type:GPU" << std::endl; } #endif fullResponseString << gpuTraceResponseString.c_str() << std::endl; } // If the autotrace flags are anything besides "None," we'll just store the trace log internally so the client can pick it up later. bool bShouldCacheForAutotrace = (autotraceFlags != kTraceType_None); if (bShouldCacheForAutotrace) { // Don't send the response back through a command yet. // The client will know to pick it up through a special AutoCapture command. mCachedTraceResponse.assign(fullResponseString.str()); mbWaitingForAutocaptureClient = true; } else { // Send the response string back to the server through a specific request command. if (bLinkedTraceRequested) { HandleLinkedTraceResponse(fullResponseString, bSaveResponseToFile); } else { if (bAPITraceResponseNeeded) { m_apiTraceTXT.Send(apiTraceResponseString.c_str()); } else if (bGPUTraceResponseNeeded) { m_cmdGPUTrace.Send(gpuTraceResponseString.c_str()); } } } } // When AutoCapture is enabled, we need to delay rendering so the user has time to retrieve the cached response. if (mbWaitingForAutocaptureClient) { // For AutoCapture the client will send the separate request below to collect the cached trace response. if (mCmdAutoCaptureCachedTrace.IsActive()) { // We're done waiting to send the cached response to the client. Move on with playback. mbWaitingForAutocaptureClient = false; mCmdAutoCaptureCachedTrace.Send(mCachedTraceResponse.c_str()); mCachedTraceResponse.clear(); } else { // Sleep to give the user a chance to connect during playback. osSleep(500); } } if (mRetrieveCachedTraceResponse.IsActive()) { const char* pathToTraceMetadata = mRetrieveCachedTraceResponse.GetValue(); if (strlen(pathToTraceMetadata) > 0) { // Read the metadata file and store the contents in a structure. TraceMetadata traceMetadata; bool bReadMetadataFileSuccessfully = ReadTraceMetadataFile(pathToTraceMetadata, traceMetadata); if (bReadMetadataFileSuccessfully) { gtASCIIString traceContents; bool bReadTraceSuccessfully = LoadTraceFile(traceMetadata.mPathToTraceFile, traceContents); if (bReadTraceSuccessfully) { // At this point the full trace response text should be loaded into our string and ready to be sent back to the client. mRetrieveCachedTraceResponse.Send(traceContents.asCharArray()); } else { Log(logERROR, "Failed to read trace file at '%s'.", traceMetadata.mPathToTraceFile.c_str()); } } else { Log(logERROR, "Failed to read metadata file at '%s'.", pathToTraceMetadata); } } else { Log(logERROR, "Failed to locate valid path to trace metadata file."); } } }
//-------------------------------------------------------------------------- /// Handle what happens when a Linked Trace is requested. We can either: /// 1. Return the trace response as normal. /// 2. Cache the response to disk, and generate a "trace metadata" file used to retrieve the trace later. /// \param inFullResponseString The response string built by tracing the application. /// \param inbSaveResponseToFile A switch used to determine which response method to use. //-------------------------------------------------------------------------- void MultithreadedTraceAnalyzerLayer::HandleLinkedTraceResponse(gtASCIIString& inFullResponseString, bool inbSaveResponseToFile) { ModernAPILayerManager* parentLayerManager = GetParentLayerManager(); if (parentLayerManager->InCapturePlayer()) { const std::string& metadataFile = parentLayerManager->GetPathToTargetMetadataFile(); if (metadataFile.length() > 0) { // Read the metadata file and store the contents in a structure. TraceMetadata traceMetadata; traceMetadata.mFrameInfo = new FrameInfo; bool bReadMetadataFileSuccessfully = ReadMetadataFile(metadataFile, &traceMetadata); if (bReadMetadataFileSuccessfully) { gtASCIIString traceContents; bool bReadTraceSuccessfully = LoadTraceFile(traceMetadata.mPathToTraceFile, traceContents); if (bReadTraceSuccessfully) { // At this point the full trace response text should be loaded into our string and ready to be sent back to the client. mCmdLinkedTrace.Send(traceContents.asCharArray()); } else { Log(logERROR, "Failed to read trace file at '%s'.", traceMetadata.mPathToTraceFile.c_str()); } } else { Log(logERROR, "Failed to read metadata file at '%s'.", metadataFile.c_str()); } // Destroy the FrameInfo instance that was created above. SAFE_DELETE(traceMetadata.mFrameInfo); } else { Log(logERROR, "Failed to locate valid path to trace metadata file."); } } else { gtASCIIString traceHeaderBlock; bool bBuiltHeaderSuccessfully = GenerateLinkedTraceHeader(traceHeaderBlock); if (bBuiltHeaderSuccessfully) { bool bKeypressTrigger = parentLayerManager->IsTraceTriggeredByKeypress(); // Collect a trace and generate the trace metadata string. Write the trace and metadata files to disk. std::string metadataXMLString; bool bWriteMetadataSuccessful = WriteTraceAndMetadataFiles(traceHeaderBlock, inFullResponseString, metadataXMLString); // If the trace wasn't triggered by a keypress, we'll need to send a response back through either of the following commands. CommandResponse& frameCaptureWithSaveResponse = (inbSaveResponseToFile == true) ? parentLayerManager->mCmdFrameCaptureWithSave : mCmdLinkedTrace; if (bWriteMetadataSuccessful) { // We only need to send the response back through a request if the client triggered collection. if (!bKeypressTrigger) { // Check if we want to cache the response to disk, or return it as-is. if (inbSaveResponseToFile) { if (bWriteMetadataSuccessful) { // Send a response back to the client indicating which trace metadata file was written to disk. frameCaptureWithSaveResponse.Send(metadataXMLString.c_str()); } else { Log(logERROR, "Failed to write trace metadata XML.\n"); frameCaptureWithSaveResponse.Send("Failed"); } } else { // Send a response containing the API and GPU trace text. frameCaptureWithSaveResponse.Send(inFullResponseString.asCharArray()); } } else { Log(logMESSAGE, "Successfully traced frame %d.\n", parentLayerManager->GetFrameCount()); } } else { Log(logERROR, "Failed to write trace metadata XML.\n"); // If a failed trace collection was triggered by a command, we need to respond with an error message. if (!bKeypressTrigger) { frameCaptureWithSaveResponse.Send("Failed"); } } } } }