//-------------------------------------------------------------------------- /// Write a trace's metadata file and return the contenst through the out-param. /// \param inFullResponseString The full response string for a collected linked trace request. /// \param outMetadataXML The XML metadata string to return to the client. /// \returns True if writing the metadata file was successful. //-------------------------------------------------------------------------- bool MultithreadedTraceAnalyzerLayer::WriteTraceAndMetadataFiles(const std::stringstream& inFullResponseString, std::string& outMetadataXML) { bool bWrittenSuccessfully = false; // Empty out the incoming path to the metadata file. We'll know the exact path later. outMetadataXML.assign(""); osModuleArchitecture moduleArchitecture; osRuntimePlatform currentPlatform; gtString executablePath; gtString commandLine; gtString workingDirectory; // Retrieve the name of the instrumented application. Construct a metadata filename which references it. if (osGetProcessLaunchInfo(osGetCurrentProcessId(), moduleArchitecture, currentPlatform, executablePath, commandLine, workingDirectory) == true) { osFilePath executableFilepath; executableFilepath.setFullPathFromString(executablePath); gtString appName; if (executableFilepath.getFileName(appName) == true) { 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 metadataFilename; // ExecutableFilename-YEAR-MM-DD-HOUR-MINUTE-SECOND metadataFilename.appendFormattedString("description-%s-%d-%d-%d-%d-%d-%d.xml", appName.asASCIICharArray(), year, month, day, hour, minute, second); // Build a path to the GPS folder within the Temp directory. osFilePath systemTempDirectory; systemTempDirectory.setPath(osFilePath::OS_TEMP_DIRECTORY); gtString toolDirectory; #ifdef CODEXL_GRAPHICS toolDirectory.fromASCIIString("CodeXL"); #else toolDirectory.fromASCIIString(GetPerfStudioDirName()); #endif // @TODO: Construct a path from the temp + tool directory. systemTempDirectory.appendSubDirectory(toolDirectory); gtList<osFilePath> toolDirectoryPaths; osDirectory d; d.setDirectoryPath(systemTempDirectory); // @TODO: Find a better way to create the "Session" directory. We shouldn't need to search through existing session directories. int maxSessionIndex = 0; bool bGotSubDirectories = d.getSubDirectoriesPaths(osDirectory::SORT_BY_NAME_DESCENDING, toolDirectoryPaths); if (bGotSubDirectories) { // Step through each directory, and look for "Session" folders. gtList<osFilePath>::iterator subdirectoryIter; for (subdirectoryIter = toolDirectoryPaths.begin(); subdirectoryIter != toolDirectoryPaths.end(); ++subdirectoryIter) { gtString subdirString; osFilePath subdir = *subdirectoryIter; subdir.getFileName(subdirString); if (subdir.isDirectory() && subdirString.startsWith(L"Session")) { // Remove the "Session" part of the string. We're only interested in the number at the end. subdirString.replace(L"Session", L"", true); const char* sessionIndexAsString = subdirString.asASCIICharArray(); int thisSessionId = atoi(sessionIndexAsString); if (thisSessionId > maxSessionIndex) { maxSessionIndex = thisSessionId; } } } } gtASCIIString pathToDataDirectory = systemTempDirectory.asString().asASCIICharArray(); // Metadata files will be saved to the temp directory with the following filename scheme: // "%TEMP%/ToolDirectory/Session[Index]/ApplicationBinaryName/Frame[Index]/description.xml" int frameIndex = GetInterceptor()->GetParentLayerManager()->GetFrameCount(); // Generate a "Session" folder with a number at the end. Compute the correct number by looking at the // Session folders that already exist gtASCIIString sessionString; sessionString.appendFormattedString("Session%d", maxSessionIndex + 1); pathToDataDirectory.appendFormattedString("\\%s\\%s\\Frame%d\\", sessionString.asCharArray(), appName.asASCIICharArray(), frameIndex); // Create the data directory if it doesn't already exist. gtString fullPathToDataDirectoryAsGTString; fullPathToDataDirectoryAsGTString.fromASCIIString(pathToDataDirectory.asCharArray()); osDirectory dir; dir.setDirectoryFullPathFromString(fullPathToDataDirectoryAsGTString); if (!dir.exists()) { bool bDirectoryCreated = dir.create(); if (!bDirectoryCreated) { Log(logERROR, "Failed to create data directory for traced frame: '%s'.\n", fullPathToDataDirectoryAsGTString.asASCIICharArray()); } } gtASCIIString pathToMetadataFile = pathToDataDirectory; pathToMetadataFile.appendFormattedString("%s", metadataFilename.asCharArray()); gtString fullMetadataFilepathAsGTString; fullMetadataFilepathAsGTString.fromASCIIString(pathToMetadataFile.asCharArray()); osFile metadataFile(fullMetadataFilepathAsGTString); bool bMetadataFileOpened = metadataFile.open(osChannel::OS_ASCII_TEXT_CHANNEL, osFile::OS_OPEN_TO_WRITE); // If we've successfully opened the metadata file, we'll also attempt to write the trace file. if (bMetadataFileOpened) { osFilePath traceFileDirectory; traceFileDirectory.setPath(osFilePath::OS_TEMP_DIRECTORY); traceFileDirectory.appendSubDirectory(toolDirectory); // Construct a filename for the cached trace response. gtASCIIString fullTraceFilename; fullTraceFilename.appendFormattedString("LinkedTrace-%s-%d-%d-%d-%d-%d-%d.ltr", appName.asASCIICharArray(), year, month, day, hour, minute, second); gtASCIIString fullTraceFilePath = pathToDataDirectory; fullTraceFilePath.appendFormattedString("%s", fullTraceFilename.asCharArray()); gtString fullTraceResponseFilepathGTString; fullTraceResponseFilepathGTString.fromASCIIString(fullTraceFilePath.asCharArray()); // Write the contents of the trace response file. osFile traceResponseFile(fullTraceResponseFilepathGTString); bool bTraceResponseFileOpened = traceResponseFile.open(osChannel::OS_ASCII_TEXT_CHANNEL, osFile::OS_OPEN_TO_WRITE); if (bTraceResponseFileOpened) { // Dump the response into an ASCII string. std::string responseAsString = inFullResponseString.str(); // Now put the ASCII string into a gtString so we can write it to the open file. gtString gtStringResponse; std::wstring wideString; wideString.assign(responseAsString.begin(), responseAsString.end()); gtStringResponse.appendFormattedString(L"%s", wideString.c_str()); traceResponseFile.writeString(gtStringResponse); traceResponseFile.close(); } else { Log(logERROR, "Failed to write trace response to file: '%s'\n", fullTraceResponseFilepathGTString.asASCIICharArray()); } // Write the filename for the associated trace response that was just collected. std::string traceFilepathAsString; traceFilepathAsString.assign(fullTraceResponseFilepathGTString.asASCIICharArray()); TraceMetadata metadata; // Insert the location of the metadata file being written out. metadata.mMetadataFilepath = pathToMetadataFile.asCharArray(); // Insert the path to the cached trace file. metadata.mPathToTraceFile = fullTraceFilePath.asCharArray(); // @TODO: When we have a framebuffer image system working, assign the path-to-image here. metadata.mPathToFrameBufferImage = "UNKNOWNPATH"; ModernAPILayerManager* layerManager = GetInterceptor()->GetParentLayerManager(); FrameInfo frameInfo; layerManager->GetFrameInfo(frameInfo); // Populate the metadata structure with the values stored in the LayerManager. metadata.mFrameInfo = frameInfo; metadata.mFrameIndex = frameIndex; metadata.mArchitecture = moduleArchitecture; // Write the metadata xml into the output file. gtASCIIString metadataXMLString; metadata.WriteToXML(metadataXMLString); gtString metadataXMLAsGTString; metadataXMLAsGTString.fromASCIIString(metadataXMLString.asCharArray()); // Write the metadata XML into the file, and close. metadataFile.writeString(metadataXMLAsGTString); metadataFile.close(); // The client will receive the full metadata XML string to parse. outMetadataXML.assign(metadataXMLString.asCharArray()); bWrittenSuccessfully = true; } else { Log(logERROR, "Failed to open trace metadata file for writing: '%s'\n", metadataFilename); } } else { Log(logERROR, "Failed to retrieve the instrumented process's application filename.\n"); } } else { Log(logERROR, "Failed to retrieve process launch info for target application.\n"); } return bWrittenSuccessfully; }
//-------------------------------------------------------------------------- /// Write a trace's metadata file and return the contenst through the out-param. /// \param inHeaderString The full response string for a collected linked trace request. /// \param inResponseString Response string /// \param outMetadataXML The XML metadata string to return to the client. /// \returns True if writing the metadata file was succesful. //-------------------------------------------------------------------------- bool MultithreadedTraceAnalyzerLayer::WriteTraceAndMetadataFiles(const gtASCIIString& inHeaderString, const gtASCIIString& inResponseString, std::string& outMetadataXML) { bool bWrittenSuccessfully = false; // Empty out the incoming path to the metadata file. We'll know the exact path later. outMetadataXML.assign(""); // Use this object to pass data into and out of the GetSessionManagaerData() method. SessionManagerData smd; smd.frameIndex = GetParentLayerManager()->GetFrameCount(); bool result = SessionManager::Instance()->GetSessionManagerData(smd); if (result == false) { return result; } gtASCIIString pathToMetadataFile = smd.pathToDataDirectory; //pathToDataDirectory; pathToMetadataFile.appendFormattedString("%s", smd.metadataFilename.asCharArray()); gtString fullMetadataFilepathAsGTString; fullMetadataFilepathAsGTString.fromASCIIString(pathToMetadataFile.asCharArray()); osFile metadataFile(fullMetadataFilepathAsGTString); bool bMetadataFileOpened = metadataFile.open(osChannel::OS_ASCII_TEXT_CHANNEL, osFile::OS_OPEN_TO_WRITE); // If we've successfully opened the metadata file, we'll also attempt to write the trace file. if (bMetadataFileOpened == false) { Log(logERROR, "Failed to open trace metadata file for writing: '%s'\n", smd.metadataFilename.asCharArray()); return false; } osFilePath traceFileDirectory; traceFileDirectory.setPath(osFilePath::OS_TEMP_DIRECTORY); traceFileDirectory.appendSubDirectory(smd.toolDirectory); // Construct a filename for the cached trace response. gtASCIIString fullTraceFilename; fullTraceFilename.appendFormattedString("LinkedTrace-%s-%d-%d-%d-%d-%d-%d.ltr", smd.appName.asASCIICharArray(), smd.year, smd.month, smd.day, smd.hour, smd.minute, smd.second); gtASCIIString fullTraceFilePath = smd.pathToDataDirectory; fullTraceFilePath.appendFormattedString("%s", fullTraceFilename.asCharArray()); gtString fullTraceResponseFilepathGTString; fullTraceResponseFilepathGTString.fromASCIIString(fullTraceFilePath.asCharArray()); // Write the contents of the trace response file. osFile traceResponseFile(fullTraceResponseFilepathGTString); bool bTraceResponseFileOpened = traceResponseFile.open(osChannel::OS_ASCII_TEXT_CHANNEL, osFile::OS_OPEN_TO_WRITE); if (bTraceResponseFileOpened) { traceResponseFile.writeString(inHeaderString); traceResponseFile.writeString(inResponseString); traceResponseFile.close(); } else { Log(logERROR, "Failed to write trace response to file: '%s'\n", fullTraceResponseFilepathGTString.asASCIICharArray()); } // Write the filename for the associated trace response that was just collected. std::string traceFilepathAsString; traceFilepathAsString.assign(fullTraceResponseFilepathGTString.asASCIICharArray()); TraceMetadata metadataToWrite; // Insert the location of the metadata file being written out. metadataToWrite.mMetadataFilepath = pathToMetadataFile.asCharArray(); // Insert the path to the cached trace file. metadataToWrite.mPathToTraceFile = fullTraceFilePath.asCharArray(); // Write object files info. It is currently assumed trace and object data will exists simultaneously. metadataToWrite.mPathToObjectTreeFile = smd.pathToDataDirectory.asCharArray(); metadataToWrite.mPathToObjectTreeFile.append("ObjectTree.xml"); metadataToWrite.mPathToObjectDatabaseFile = smd.pathToDataDirectory.asCharArray(); metadataToWrite.mPathToObjectDatabaseFile.append("FullObjectDatabase.xml"); ModernAPIFrameDebuggerLayer* frameDebugger = GetParentLayerManager()->GetFrameDebuggerLayer(); unsigned char* pngData = NULL; unsigned int numBytes = 0; // NOTE: Passing in 0 for the width and height will cause the renderer to render the PNG image at the same resolution as the applications frame buffer (i.e full resolution). bool bCapturedSuccessfully = frameDebugger->CaptureFrameBuffer(0, 0, &pngData, &numBytes, true); if (bCapturedSuccessfully) { gtASCIIString fullImageFilename; fullImageFilename.appendFormattedString("%s_FrameBuffer%d.png", smd.appName.asASCIICharArray(), smd.frameIndex); gtASCIIString imageFilepath = smd.pathToDataDirectory; imageFilepath.appendFormattedString("%s", fullImageFilename.asCharArray()); FILE* frameBufferImageFile = fopen(imageFilepath.asCharArray(), "wb"); if (frameBufferImageFile != NULL) { fwrite(pngData, sizeof(unsigned char), numBytes, frameBufferImageFile); fclose(frameBufferImageFile); // Add the captured image's path into the XML metadata. metadataToWrite.mPathToFrameBufferImage = imageFilepath.asCharArray(); } else { Log(logERROR, "Failed to write frame buffer image file.\n"); } SAFE_DELETE_ARRAY(pngData); } else { metadataToWrite.mPathToFrameBufferImage = "ERROR - Failed to capture frame buffer image."; Log(logERROR, "Failed to capture frame buffer for captured frame.\n"); } // @TODO: This is placeholder for now to get a prototype working. // We should also be able to set this to "Capture". metadataToWrite.mTraceType = kTraceType_Linked; // @TODO: This is temporary until TraceMetadata generation is moved to the LayerManager. FrameInfo frameInfo; frameDebugger->GetFrameInfo(&frameInfo); // Populate the metadata structure with the values stored in the LayerManager. metadataToWrite.mFrameInfo = &frameInfo; metadataToWrite.mArchitecture = smd.moduleArchitecture; metadataToWrite.mAPICallCount = GetNumTracedAPICalls(); metadataToWrite.mDrawCallCount = GetNumTracedDrawCalls(); bool bMetadataWriteSuccessful = WriteMetadataFile(&metadataToWrite, pathToMetadataFile.asCharArray(), outMetadataXML); if (bMetadataWriteSuccessful) { bWrittenSuccessfully = true; } return bWrittenSuccessfully; }