//----------------------------------------------------------------------------- /// Constructor where available layers are pushed. //----------------------------------------------------------------------------- DX12LayerManager::DX12LayerManager() : ModernAPILayerManager() , mInterceptor(nullptr) , mbIsInitialized(false) { m_LayerList = (LAYERDESC*) & s_LayerList; m_LayerListSize = sizeof(s_LayerList) / sizeof(s_LayerList[0]); // Start with the object database layer enabled, as we want to track object instances from the start. m_AvailableLayers.push_back(DX12ObjectDatabaseProcessor::Instance()); m_AvailableLayers.push_back(DX12FrameDebuggerLayer::Instance()); m_AvailableLayers.push_back(DX12TraceAnalyzerLayer::Instance()); // If AutoCapture is enabled in the config file, automatically push the TraceAnalyzer to the stack. bool bPushTraceAnalyzer = (SG_GET_INT(OptionTraceType) != kTraceType_None); if (bPushTraceAnalyzer) { // Add the TraceAnalyzer so it can AutoCapture at a specified frame. DX12TraceAnalyzerLayer* traceLayer = DX12TraceAnalyzerLayer::Instance(); PushLayer(*traceLayer, &m_pushLayer); } osFilePath logFilePath; logFilePath.setPath(osFilePath::OS_TEMP_DIRECTORY); char fullPath[PS_MAX_PATH] = {}; sprintf(fullPath, "%s\\%s\\GPS", logFilePath.asString().asASCIICharArray(), GetPerfStudioDirName()); mStreamLog.SetBaseNamePath(fullPath); }
//-------------------------------------------------------------------------- /// 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; }