summaryrefslogtreecommitdiff
path: root/tools/render-test
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2019-09-23 15:38:25 -0400
committerGitHub <noreply@github.com>2019-09-23 15:38:25 -0400
commit05af41d21d74d24871507e6f8f50574ea08c48a2 (patch)
tree3197b021ed71c40f6035fdfa7d450b4b3b945422 /tools/render-test
parentede0792fd9b4c7bc5c2653092ba1d492e67ca190 (diff)
Simple test profiling (#1062)
* First pass support for performance profiling * Test across all elements * Fix bug - sourceContents is not used, should use rawSource. * * Add ability to get prelude from API. * Allow specifying source language for render-test * Made it possible to compile a test input file as C++ * Special handling for reflection * Added C++ impl to performance-profile.slang * Remove some clang warnings. * Output profile timings on appveyor and other TC. * Remove passing around of StdWriters (can use global). Small comment improvements.
Diffstat (limited to 'tools/render-test')
-rw-r--r--tools/render-test/cpu-compute-util.cpp19
-rw-r--r--tools/render-test/cpu-compute-util.h4
-rw-r--r--tools/render-test/options.cpp50
-rw-r--r--tools/render-test/options.h3
-rw-r--r--tools/render-test/render-test-main.cpp122
-rw-r--r--tools/render-test/shader-input-layout.cpp6
-rw-r--r--tools/render-test/slang-support.cpp25
7 files changed, 195 insertions, 34 deletions
diff --git a/tools/render-test/cpu-compute-util.cpp b/tools/render-test/cpu-compute-util.cpp
index 81325ce80..688e6b254 100644
--- a/tools/render-test/cpu-compute-util.cpp
+++ b/tools/render-test/cpu-compute-util.cpp
@@ -181,7 +181,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
}
else
{
- throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ throw TextFormatException(String("Invalid input syntax at line ") + parser.NextToken().Position.Line);
}
}
@@ -301,7 +301,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
return SLANG_OK;
}
-/* static */SlangResult CPUComputeUtil::calcExecuteInfo(ExecuteStyle style, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out)
+/* static */SlangResult CPUComputeUtil::calcExecuteInfo(ExecuteStyle style, ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out)
{
auto request = compilationAndLayout.output.request;
auto reflection = (slang::ShaderReflection*) spGetReflection(request);
@@ -314,9 +314,6 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
const char* entryPointName = entryPoint->getName();
- ComPtr<ISlangSharedLibrary> sharedLibrary;
- SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(request, 0, 0, sharedLibrary.writeRef()));
-
// Copy dispatch size
for (int i = 0; i < 3; ++i)
{
@@ -334,7 +331,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
StringBuilder groupEntryPointName;
groupEntryPointName << entryPointName << "_Group";
- CPPPrelude::ComputeFunc groupFunc = (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(groupEntryPointName.getBuffer());
+ CPPPrelude::ComputeFunc groupFunc = (CPPPrelude::ComputeFunc)sharedLib->findFuncByName(groupEntryPointName.getBuffer());
if (!groupFunc)
{
return SLANG_FAIL;
@@ -346,7 +343,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
case ExecuteStyle::GroupRange:
{
CPPPrelude::ComputeFunc groupRangeFunc = nullptr;
- groupRangeFunc = (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName);
+ groupRangeFunc = (CPPPrelude::ComputeFunc)sharedLib->findFuncByName(entryPointName);
if (!groupRangeFunc)
{
return SLANG_FAIL;
@@ -359,7 +356,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
StringBuilder threadEntryPointName;
threadEntryPointName << entryPointName << "_Thread";
- CPPPrelude::ComputeThreadFunc threadFunc = (CPPPrelude::ComputeThreadFunc)sharedLibrary->findFuncByName(threadEntryPointName.getBuffer());
+ CPPPrelude::ComputeThreadFunc threadFunc = (CPPPrelude::ComputeThreadFunc)sharedLib->findFuncByName(threadEntryPointName.getBuffer());
if (!threadFunc)
{
return SLANG_FAIL;
@@ -470,7 +467,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
}
-/* static */ SlangResult CPUComputeUtil::checkStyleConsistency(const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout)
+/* static */ SlangResult CPUComputeUtil::checkStyleConsistency(ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout)
{
Context context;
SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context));
@@ -478,7 +475,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
// Run the thread style to test against
{
ExecuteInfo info;
- SLANG_RETURN_ON_FAIL(calcExecuteInfo(ExecuteStyle::Thread, dispatchSize, compilationAndLayout, context, info));
+ SLANG_RETURN_ON_FAIL(calcExecuteInfo(ExecuteStyle::Thread, sharedLib, dispatchSize, compilationAndLayout, context, info));
SLANG_RETURN_ON_FAIL(execute(info));
}
@@ -489,7 +486,7 @@ static CPUComputeUtil::Resource* _newOneTexture2D(int elemCount)
SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, checkContext));
ExecuteInfo info;
- SLANG_RETURN_ON_FAIL(calcExecuteInfo(style, dispatchSize, compilationAndLayout, checkContext, info));
+ SLANG_RETURN_ON_FAIL(calcExecuteInfo(style, sharedLib, dispatchSize, compilationAndLayout, checkContext, info));
SLANG_RETURN_ON_FAIL(execute(info));
// Make sure the out buffers are all the same
diff --git a/tools/render-test/cpu-compute-util.h b/tools/render-test/cpu-compute-util.h
index 1284735c0..9430eb841 100644
--- a/tools/render-test/cpu-compute-util.h
+++ b/tools/render-test/cpu-compute-util.h
@@ -50,11 +50,11 @@ struct CPUComputeUtil
/// Runs code across run styles and makes sure output buffers match
- static SlangResult checkStyleConsistency(const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout);
+ static SlangResult checkStyleConsistency(ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout);
static SlangResult calcBindings(const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& outContext);
- static SlangResult calcExecuteInfo(ExecuteStyle style, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out);
+ static SlangResult calcExecuteInfo(ExecuteStyle style, ISlangSharedLibrary* sharedLib, const uint32_t dispatchSize[3], const ShaderCompilerUtil::OutputAndLayout& compilationAndLayout, Context& context, ExecuteInfo& out);
static SlangResult execute(const ExecuteInfo& info);
diff --git a/tools/render-test/options.cpp b/tools/render-test/options.cpp
index e13a2b88f..3d5df6f62 100644
--- a/tools/render-test/options.cpp
+++ b/tools/render-test/options.cpp
@@ -44,6 +44,32 @@ static SlangResult _setRendererType(RendererType type, const char* arg, Slang::W
return SLANG_OK;
}
+static SlangSourceLanguage _findSourceLanguage(const UnownedStringSlice& text)
+{
+ if (text == "c" || text == "C")
+ {
+ return SLANG_SOURCE_LANGUAGE_C;
+ }
+ else if (text == "cpp" || text == "c++" || text == "C++" || text == "cxx")
+ {
+ return SLANG_SOURCE_LANGUAGE_CPP;
+ }
+ else if (text == "slang")
+ {
+ return SLANG_SOURCE_LANGUAGE_SLANG;
+ }
+ else if (text == "glsl")
+ {
+ return SLANG_SOURCE_LANGUAGE_GLSL;
+ }
+ else if (text == "hlsl")
+ {
+ return SLANG_SOURCE_LANGUAGE_HLSL;
+ }
+ return SLANG_SOURCE_LANGUAGE_UNKNOWN;
+}
+
+
SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper stdError)
{
using namespace Slang;
@@ -169,6 +195,10 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s
arg.value = *argCursor++;
gOptions.compileArgs.add(arg);
}
+ else if (strcmp(arg, "-performance-profile") == 0)
+ {
+ gOptions.performanceProfile = true;
+ }
else if (strcmp(arg, "-adapter") == 0)
{
if (argCursor == argEnd)
@@ -207,6 +237,24 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s
gOptions.computeDispatchSize[i] = v;
}
}
+ else if (strcmp(arg, "-source-language") == 0)
+ {
+ if (argCursor == argEnd)
+ {
+ stdError.print("error: expecting a source language name for '%s'\n", arg);
+ return SLANG_FAIL;
+ }
+ UnownedStringSlice sourceLanguageText(*argCursor++);
+
+ SlangSourceLanguage sourceLanguage = _findSourceLanguage(sourceLanguageText);
+ if (sourceLanguage == SLANG_SOURCE_LANGUAGE_UNKNOWN)
+ {
+ stdError.print("error: expecting unknown source language name '%s' for '%s'\n", String(sourceLanguageText).getBuffer(), arg);
+ return SLANG_FAIL;
+ }
+
+ gOptions.sourceLanguage = sourceLanguage;
+ }
else
{
// Lookup
@@ -228,7 +276,7 @@ SlangResult parseOptions(int argc, const char*const* argv, Slang::WriterHelper s
if (languageRenderType != RendererType::Unknown)
{
gOptions.targetLanguageRendererType = languageRenderType;
- gOptions.inputLanguageID = (argName == "hlsl" || argName == "glsl") ? InputLanguageID::Native : InputLanguageID::Slang;
+ gOptions.inputLanguageID = (argName == "hlsl" || argName == "glsl" || argName == "cpp" || argName == "cxx" || argName == "c") ? InputLanguageID::Native : InputLanguageID::Slang;
continue;
}
}
diff --git a/tools/render-test/options.h b/tools/render-test/options.h
index 67eae6603..1bb4af74c 100644
--- a/tools/render-test/options.h
+++ b/tools/render-test/options.h
@@ -49,6 +49,7 @@ struct Options
/// The set render type
RendererType rendererType = RendererType::Unknown;
InputLanguageID inputLanguageID = InputLanguageID::Slang;
+ SlangSourceLanguage sourceLanguage = SLANG_SOURCE_LANGUAGE_UNKNOWN;
/// Can be used for overriding the profile
const char* profileName = nullptr;
@@ -59,6 +60,8 @@ struct Options
bool useDXIL = false;
bool onlyStartup = false;
+ bool performanceProfile = false;
+
Slang::List<Slang::String> renderFeatures; /// Required render features for this test to run
Slang::List<Slang::CommandLine::Arg> compileArgs;
diff --git a/tools/render-test/render-test-main.cpp b/tools/render-test/render-test-main.cpp
index 3a8871618..13af422a9 100644
--- a/tools/render-test/render-test-main.cpp
+++ b/tools/render-test/render-test-main.cpp
@@ -55,6 +55,13 @@ static const int kVertexCount = SLANG_COUNT_OF(kVertexData);
using namespace Slang;
+static void _outputProfileTime(uint64_t startTicks, uint64_t endTicks)
+{
+ WriterHelper out = StdWriters::getOut();
+ double time = double(endTicks - startTicks) / ProcessUtil::getClockFrequency();
+ out.print("profile-time=%g\n", time);
+}
+
class RenderTestApp : public WindowListener
{
public:
@@ -79,6 +86,8 @@ class RenderTestApp : public WindowListener
/// Called in initialize
Result _initializeShaders(SlangSession* session, Renderer* renderer, Options::ShaderProgramType shaderType, const ShaderCompilerUtil::Input& input);
+ uint64_t m_startTicks;
+
// variables for state to be used for rendering...
uintptr_t m_constantBufferSize, m_computeResultBufferSize;
@@ -232,6 +241,9 @@ void RenderTestApp::runCompute()
auto pipelineType = PipelineType::Compute;
m_renderer->setPipelineState(pipelineType, m_pipelineState);
m_bindingState->apply(m_renderer, pipelineType);
+
+ m_startTicks = ProcessUtil::getClockTick();
+
m_renderer->dispatchCompute(m_options.computeDispatchSize[0], m_options.computeDispatchSize[1], m_options.computeDispatchSize[2]);
}
@@ -314,24 +326,60 @@ Result RenderTestApp::update(Window* window)
}
// If we are in a mode where output is requested, we need to snapshot the back buffer here
- if (m_options.outputPath)
+ if (m_options.outputPath || m_options.performanceProfile)
{
// Submit the work
m_renderer->submitGpuWork();
// Wait until everything is complete
m_renderer->waitForGpu();
- if (gOptions.shaderType == Options::ShaderProgramType::Compute || gOptions.shaderType == Options::ShaderProgramType::GraphicsCompute)
+ if (m_options.performanceProfile)
{
- SLANG_RETURN_ON_FAIL(writeBindingOutput(gOptions.outputPath));
+ // It might not be enough on some APIs to 'waitForGpu' to mean the computation has completed. Let's lock an output
+ // buffer to be sure
+ if (m_bindingState->outputBindings.getCount() > 0)
+ {
+ const auto& binding = m_bindingState->outputBindings[0];
+ auto i = binding.entryIndex;
+ const auto& layoutBinding = m_shaderInputLayout.entries[i];
+
+ assert(layoutBinding.isOutput);
+
+ if (binding.resource && binding.resource->isBuffer())
+ {
+ BufferResource* bufferResource = static_cast<BufferResource*>(binding.resource.Ptr());
+ const size_t bufferSize = bufferResource->getDesc().sizeInBytes;
+ unsigned int* ptr = (unsigned int*)m_renderer->map(bufferResource, MapFlavor::HostRead);
+ if (!ptr)
+ {
+ return SLANG_FAIL;
+ }
+ m_renderer->unmap(bufferResource);
+ }
+ }
+
+ // Note we don't do the same with screen rendering -> as that will do a lot of work, which may swamp any computation
+ // so can only really profile compute shaders at the moment
+
+ const uint64_t endTicks = ProcessUtil::getClockTick();
+
+ _outputProfileTime(m_startTicks, endTicks);
}
- else
+
+ if (gOptions.outputPath)
{
- SlangResult res = writeScreen(gOptions.outputPath);
- if (SLANG_FAILED(res))
+ if (gOptions.shaderType == Options::ShaderProgramType::Compute || gOptions.shaderType == Options::ShaderProgramType::GraphicsCompute)
{
- fprintf(stderr, "ERROR: failed to write screen capture to file\n");
- return res;
+ SLANG_RETURN_ON_FAIL(writeBindingOutput(gOptions.outputPath));
+ }
+ else
+ {
+ SlangResult res = writeScreen(gOptions.outputPath);
+ if (SLANG_FAILED(res))
+ {
+ fprintf(stderr, "ERROR: failed to write screen capture to file\n");
+ return res;
+ }
}
}
// We are done
@@ -343,6 +391,8 @@ Result RenderTestApp::update(Window* window)
return SLANG_OK;
}
+
+
} // namespace renderer_test
SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSession* session, int argcIn, const char*const* argvIn)
@@ -432,6 +482,16 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
break;
}
+ if (gOptions.sourceLanguage != SLANG_SOURCE_LANGUAGE_UNKNOWN)
+ {
+ input.sourceLanguage = gOptions.sourceLanguage;
+
+ if (input.sourceLanguage == SLANG_SOURCE_LANGUAGE_C || input.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP)
+ {
+ input.passThrough = SLANG_PASS_THROUGH_GENERIC_C_CPP;
+ }
+ }
+
// Use the profile name set on options if set
input.profile = gOptions.profileName ? gOptions.profileName : input.profile;
@@ -459,24 +519,52 @@ SLANG_TEST_TOOL_API SlangResult innerMain(Slang::StdWriters* stdWriters, SlangSe
ShaderCompilerUtil::OutputAndLayout compilationAndLayout;
SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.compileArgs, gOptions.shaderType, input, compilationAndLayout));
-
{
+ // Get the shared library -> it contains the executable code, we need to keep around if we recompile
+ ComPtr<ISlangSharedLibrary> sharedLibrary;
+ SLANG_RETURN_ON_FAIL(spGetEntryPointHostCallable(compilationAndLayout.output.request, 0, 0, sharedLibrary.writeRef()));
+
+ // If we are running c/c++ we still need binding information, so compile again as slang source
+ if (gOptions.sourceLanguage == SLANG_SOURCE_LANGUAGE_C || input.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP)
+ {
+ ShaderCompilerUtil::Input slangInput = input;
+ slangInput.sourceLanguage = SLANG_SOURCE_LANGUAGE_SLANG;
+ slangInput.passThrough = SLANG_PASS_THROUGH_NONE;
+ // We just want CPP, so we get suitable reflection
+ slangInput.target = SLANG_CPP_SOURCE;
+
+ SLANG_RETURN_ON_FAIL(ShaderCompilerUtil::compileWithLayout(session, gOptions.sourcePath, gOptions.compileArgs, gOptions.shaderType, slangInput, compilationAndLayout));
+ }
+
+ // calculate binding
CPUComputeUtil::Context context;
SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcBindings(compilationAndLayout, context));
+ // Get the execution info from the lib
CPUComputeUtil::ExecuteInfo info;
- SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcExecuteInfo(CPUComputeUtil::ExecuteStyle::GroupRange, gOptions.computeDispatchSize, compilationAndLayout, context, info));
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::calcExecuteInfo(CPUComputeUtil::ExecuteStyle::GroupRange, sharedLibrary, gOptions.computeDispatchSize, compilationAndLayout, context, info));
+
+ const uint64_t startTicks = ProcessUtil::getClockTick();
+
SLANG_RETURN_ON_FAIL(CPUComputeUtil::execute(info));
-
- // Dump everything out that was written
- SLANG_RETURN_ON_FAIL(CPUComputeUtil::writeBindings(compilationAndLayout.layout, context.buffers, gOptions.outputPath));
- }
- {
- // Check all execution styles produce the same result
- SLANG_RETURN_ON_FAIL(CPUComputeUtil::checkStyleConsistency(gOptions.computeDispatchSize, compilationAndLayout));
+ if (gOptions.performanceProfile)
+ {
+ const uint64_t endTicks = ProcessUtil::getClockTick();
+ _outputProfileTime(startTicks, endTicks);
+ }
+
+ if (gOptions.outputPath)
+ {
+ // Dump everything out that was written
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::writeBindings(compilationAndLayout.layout, context.buffers, gOptions.outputPath));
+
+ // Check all execution styles produce the same result
+ SLANG_RETURN_ON_FAIL(CPUComputeUtil::checkStyleConsistency(sharedLibrary, gOptions.computeDispatchSize, compilationAndLayout));
+ }
}
+
return SLANG_OK;
}
diff --git a/tools/render-test/shader-input-layout.cpp b/tools/render-test/shader-input-layout.cpp
index 0d13e5ca1..b5b65f52d 100644
--- a/tools/render-test/shader-input-layout.cpp
+++ b/tools/render-test/shader-input-layout.cpp
@@ -506,7 +506,7 @@ namespace renderer_test
Token nameToken = parser.ReadToken();
if (nameToken.Type != TokenType::Identifier)
{
- throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ throw TextFormatException(String("Invalid input syntax at line ") + parser.NextToken().Position.Line);
}
builder << nameToken.Content;
@@ -537,7 +537,7 @@ namespace renderer_test
}
else
{
- throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ throw TextFormatException(String("Invalid input syntax at line ") + parser.NextToken().Position.Line);
}
}
@@ -553,7 +553,7 @@ namespace renderer_test
}
catch (TextFormatException)
{
- throw TextFormatException("Invalid input syntax at line " + parser.NextToken().Position.Line);
+ throw TextFormatException(String("Invalid input syntax at line ") + parser.NextToken().Position.Line);
}
}
}
diff --git a/tools/render-test/slang-support.cpp b/tools/render-test/slang-support.cpp
index 515481d4f..9afddc09b 100644
--- a/tools/render-test/slang-support.cpp
+++ b/tools/render-test/slang-support.cpp
@@ -9,6 +9,8 @@
#include <assert.h>
#include <stdio.h>
+#include "../../source/core/slang-string-util.h"
+
namespace renderer_test {
using namespace Slang;
@@ -54,6 +56,12 @@ static const char computeEntryPointName[] = "computeMain";
case SLANG_SOURCE_LANGUAGE_HLSL:
spAddPreprocessorDefine(slangRequest, "__HLSL__", "1");
break;
+ case SLANG_SOURCE_LANGUAGE_C:
+ spAddPreprocessorDefine(slangRequest, "__C__", "1");
+ break;
+ case SLANG_SOURCE_LANGUAGE_CPP:
+ spAddPreprocessorDefine(slangRequest, "__CPP__", "1");
+ break;
default:
assert(!"unexpected");
@@ -240,6 +248,23 @@ static const char computeEntryPointName[] = "computeMain";
List<char> sourceText;
SLANG_RETURN_ON_FAIL(readSource(sourcePath, sourceText));
+ if (input.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP || input.sourceLanguage == SLANG_SOURCE_LANGUAGE_C)
+ {
+ // Add an include of the prelude
+ ComPtr<ISlangBlob> prelude;
+ session->getDownstreamCompilerPrelude(SLANG_PASS_THROUGH_GENERIC_C_CPP, prelude.writeRef());
+
+ String preludeString = StringUtil::getString(prelude);
+
+ // Add the prelude
+ StringBuilder builder;
+ builder << preludeString << "\n";
+ builder << UnownedStringSlice(sourceText.getBuffer(), sourceText.getCount());
+
+ sourceText.setCount(builder.getLength());
+ memcpy(sourceText.getBuffer(), builder.getBuffer(), builder.getLength());
+ }
+
output.sourcePath = sourcePath;
auto& layout = output.layout;