//-------------------------------------------------------------------------- /// 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(std::stringstream& inFullResponseString, bool inbSaveResponseToFile) { // If we're building for use with CodeXL, insert extra metadata into the response before returning. #if defined(CODEXL_GRAPHICS) // The response should include a header when connected to CodeXL Graphics. gtASCIIString headerBuilder; headerBuilder.appendFormattedString("//AMD CodeXL Frame Trace\n"); osModuleArchitecture moduleArchitecture; osRuntimePlatform currentPlatform; gtString executablePath; gtString commandLine; gtString workingDirectory; if (osGetProcessLaunchInfo(osGetCurrentProcessId(), moduleArchitecture, currentPlatform, executablePath, commandLine, workingDirectory) == true) { headerBuilder.appendFormattedString("//ProcessExe=%s\n", executablePath.asASCIICharArray()); // Build a timestamp. osTime currentTime; currentTime.setFromCurrentTime(); tm timeStruct; currentTime.timeAsTmStruct(timeStruct, osTime::LOCAL); // Need to add 1900, since tm contains "years since 1900". int year = timeStruct.tm_year + 1900; // Need to add 1, since tm contains "months since January". int month = timeStruct.tm_mon + 1; int day = timeStruct.tm_mday; int hour = timeStruct.tm_hour; int minute = timeStruct.tm_min; int second = timeStruct.tm_sec; gtASCIIString timestampBuilder; timestampBuilder.appendFormattedString("%d/%d/%d %d:%d:%d", month, day, year, hour, minute, second); headerBuilder.appendFormattedString("//TraceDateTime=%s\n", timestampBuilder.asCharArray()); headerBuilder.appendFormattedString("//TraceFileVersion=%d\n", 1); headerBuilder.appendFormattedString("//ApplicationArgs=%s\n", commandLine.asASCIICharArray()); headerBuilder.appendFormattedString("//WorkingDirectory=%s\n", workingDirectory.asASCIICharArray()); } else { Log(logERROR, "Failed to retrieve process info when building response header.\n"); } // Build a system information header string. std::string systemInfo; OSWrappers::WriteSystemInfoString(systemInfo); headerBuilder.appendFormattedString("\n%s\n", systemInfo.c_str()); // Store the response temporarily. std::string headerString = headerBuilder.asCharArray(); std::string responseString = inFullResponseString.str(); // Clear the response string stream. inFullResponseString.str(std::string()); inFullResponseString.clear(); // Write the header and response chunks into the final response. inFullResponseString << headerString; inFullResponseString << responseString; #endif // Check if we want to cache the response to disk, or return it as-is. if (inbSaveResponseToFile) { std::string metadataXMLString; bool bWriteMetadataSuccessful = WriteTraceAndMetadataFiles(inFullResponseString, metadataXMLString); if (bWriteMetadataSuccessful) { // Send a response back to the client indicating which trace metadata file was written to disk. mCmdLinkedTraceWithSave.Send(metadataXMLString.c_str()); } else { Log(logERROR, "Failed to write trace metadata XML.\n"); mCmdLinkedTraceWithSave.Send("Failed"); } } else { // Return the normal trace response string. // Send a response containing the API and GPU trace text. mCmdLinkedTrace.Send(std::string(inFullResponseString.str()).c_str()); } }
//-------------------------------------------------------------------------- /// 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"); } } } } }