RadeonGpuAnalyzer.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/ShaderCompiler/RadeonGpuAnalyzer.h>
  6. #include <AnKi/Util/File.h>
  7. #include <AnKi/Util/Filesystem.h>
  8. #include <AnKi/Util/Process.h>
  9. #include <AnKi/Util/StringList.h>
  10. namespace anki {
  11. static Atomic<U32> g_nextFileId = {1};
  12. static const Char* kAmdAsic = "gfx1201"; // RDNA4
  13. static CString getPipelineStageString(ShaderType shaderType)
  14. {
  15. CString out;
  16. switch(shaderType)
  17. {
  18. case ShaderType::kVertex:
  19. out = "vert";
  20. break;
  21. case ShaderType::kPixel:
  22. out = "frag";
  23. break;
  24. case ShaderType::kCompute:
  25. out = "comp";
  26. break;
  27. case ShaderType::kMesh:
  28. out = "mesh";
  29. break;
  30. default:
  31. ANKI_ASSERT(!"TODO");
  32. }
  33. return out;
  34. }
  35. Error runRadeonGpuAnalyzer(ConstWeakArray<U8> spirv, ShaderType shaderType, RgaOutput& out)
  36. {
  37. ANKI_ASSERT(spirv.getSize() > 0);
  38. const U32 rand = g_nextFileId.fetchAdd(1) + getCurrentProcessId();
  39. // Store SPIRV
  40. String tmpDir;
  41. ANKI_CHECK(getTempDirectory(tmpDir));
  42. ShaderCompilerString spvFilename;
  43. spvFilename.sprintf("%s/AnKiRgaInput_%u.spv", tmpDir.cstr(), rand);
  44. File spvFile;
  45. ANKI_CHECK(spvFile.open(spvFilename, FileOpenFlag::kWrite | FileOpenFlag::kBinary));
  46. ANKI_CHECK(spvFile.write(&spirv[0], spirv.getSizeInBytes()));
  47. spvFile.close();
  48. CleanupFile spvFileCleanup(spvFilename);
  49. // Call RGA
  50. ShaderCompilerString analysisFilename;
  51. analysisFilename.sprintf("%s/AnKiRgaOutAnalysis_%u.csv", tmpDir.cstr(), rand);
  52. ShaderCompilerString stageStr = "--";
  53. stageStr += getPipelineStageString(shaderType);
  54. Array<CString, 8> args;
  55. args[0] = "-s";
  56. args[1] = "vk-spv-offline";
  57. args[2] = "-c";
  58. args[3] = kAmdAsic;
  59. args[4] = "-a";
  60. args[5] = analysisFilename;
  61. args[6] = stageStr;
  62. args[7] = spvFilename;
  63. I32 exitCode;
  64. #if ANKI_OS_LINUX
  65. CString rgaExecutable = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Linux64/RadeonGpuAnalyzer/rga";
  66. #elif ANKI_OS_WINDOWS
  67. CString rgaExecutable = ANKI_SOURCE_DIRECTORY "/ThirdParty/Bin/Windows64/RadeonDeveloperToolSuite-2025-07-01-1408/rga.exe";
  68. #else
  69. CString rgaExecutable = "nothing";
  70. ANKI_ASSERT(0);
  71. #endif
  72. ShaderCompilerString argsStr;
  73. for(CString a : args)
  74. {
  75. argsStr += a;
  76. argsStr += " ";
  77. }
  78. ANKI_SHADER_COMPILER_LOGV("Calling RGA: %s %s", rgaExecutable.cstr(), argsStr.cstr());
  79. ANKI_CHECK(Process::callProcess(rgaExecutable, args, nullptr, nullptr, exitCode));
  80. if(exitCode != 0)
  81. {
  82. ANKI_SHADER_COMPILER_LOGE("RGA failed with exit code %d", exitCode);
  83. return Error::kFunctionFailed;
  84. }
  85. // Construct the output filename
  86. ShaderCompilerString outFilename;
  87. outFilename.sprintf("%s/%s_AnKiRgaOutAnalysis_%u_%s.csv", tmpDir.cstr(), kAmdAsic, rand, getPipelineStageString(shaderType).cstr());
  88. CleanupFile rgaFileCleanup(outFilename);
  89. // Read the file
  90. File analysisFile;
  91. ANKI_CHECK(analysisFile.open(outFilename, FileOpenFlag::kRead));
  92. ShaderCompilerString analysisText;
  93. ANKI_CHECK(analysisFile.readAllText(analysisText));
  94. analysisText.replaceAll("\r", "");
  95. analysisFile.close();
  96. // Parse the text
  97. ShaderCompilerStringList lines;
  98. lines.splitString(analysisText, '\n');
  99. if(lines.getSize() != 2)
  100. {
  101. ANKI_SHADER_COMPILER_LOGE("Error parsing RGA analysis file");
  102. return Error::kFunctionFailed;
  103. }
  104. ShaderCompilerStringList tokens;
  105. tokens.splitString(lines.getFront(), ',');
  106. ShaderCompilerStringList values;
  107. values.splitString(*(lines.getBegin() + 1), ',');
  108. if(tokens.getSize() != tokens.getSize())
  109. {
  110. ANKI_SHADER_COMPILER_LOGE("Error parsing RGA analysis file");
  111. return Error::kFunctionFailed;
  112. }
  113. out.m_vgprCount = kMaxU32;
  114. out.m_sgprCount = kMaxU32;
  115. out.m_isaSize = kMaxU32;
  116. auto valuesIt = values.getBegin();
  117. for(const ShaderCompilerString& token : tokens)
  118. {
  119. if(token.find("USED_VGPRs") != String::kNpos)
  120. {
  121. ANKI_CHECK((*valuesIt).toNumber(out.m_vgprCount));
  122. }
  123. else if(token.find("USED_SGPRs") != String::kNpos)
  124. {
  125. ANKI_CHECK((*valuesIt).toNumber(out.m_sgprCount));
  126. }
  127. else if(token.find("ISA_SIZE") != String::kNpos)
  128. {
  129. ANKI_CHECK((*valuesIt).toNumber(out.m_isaSize));
  130. }
  131. ++valuesIt;
  132. }
  133. if(out.m_vgprCount == kMaxU32 || out.m_sgprCount == kMaxU32 || out.m_isaSize == kMaxU32)
  134. {
  135. ANKI_SHADER_COMPILER_LOGE("Error parsing RGA analysis file");
  136. return Error::kFunctionFailed;
  137. }
  138. return Error::kNone;
  139. }
  140. } // end namespace anki