Example #1
0
//-----------------------------------------------------------------------------
/// 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;
}