Skip to content

Commit 0a1b924

Browse files
authored
Add Perfetto tracing and a test output directory option (#2742)
This PR adds a new `MaterialXTrace` module with optional Perfetto tracing infrastructure, plus a configurable test output directory, laying the groundwork for performance analysis and optimization work.
1 parent 6d0e937 commit 0a1b924

File tree

18 files changed

+899
-52
lines changed

18 files changed

+899
-52
lines changed

.github/workflows/main.yml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
compiler: gcc
3232
compiler_version: "14"
3333
python: 3.13
34+
extended_build_perfetto: ON
3435

3536
- name: Linux_GCC_14_Python314
3637
os: ubuntu-24.04
@@ -206,6 +207,9 @@ jobs:
206207
if [ "${{ matrix.extended_build_mdl_sdk }}" == "ON" -a "${{ runner.os }}" == "Windows" ]; then
207208
EXTENDED_BUILD_CONFIG="$EXTENDED_BUILD_CONFIG -DVCPKG_TARGET_TRIPLET=x64-windows-release -DMATERIALX_MDL_SDK_DIR=C:/vcpkg/installed/x64-windows-release"
208209
fi
210+
if [ "${{ matrix.extended_build_perfetto }}" == "ON" ]; then
211+
EXTENDED_BUILD_CONFIG="$EXTENDED_BUILD_CONFIG -DMATERIALX_BUILD_PERFETTO_TRACING=ON"
212+
fi
209213
fi
210214
TEST_RENDER_CONFIG="-DMATERIALX_TEST_RENDER=OFF"
211215
if [ "${{ matrix.test_render }}" == "ON" ]; then
@@ -266,7 +270,7 @@ jobs:
266270
run: |
267271
sudo apt-get install gcovr
268272
mkdir coverage
269-
gcovr --html --html-details --output coverage/index.html --exclude .*\/External\/.* --root .. .
273+
gcovr --html --html-details --output coverage/index.html --exclude .*\/External\/.* --exclude .*perfetto.* --root .. .
270274
working-directory: build
271275

272276
- name: Static Analysis Tests
@@ -277,7 +281,7 @@ jobs:
277281
else
278282
brew install cppcheck
279283
fi
280-
cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=normalCheckLevelMaxBranches --suppress=*:*/External/* --suppress=*:*/NanoGUI/*
284+
cppcheck --project=build/compile_commands.json --error-exitcode=1 --suppress=normalCheckLevelMaxBranches --suppress=*:*/External/* --suppress=*:*/NanoGUI/* --suppress=*:*perfetto*
281285
282286
- name: Setup Rendering Environment (Linux)
283287
if: matrix.test_render == 'ON' && runner.os == 'Linux'
@@ -358,6 +362,14 @@ jobs:
358362
name: MaterialX_Coverage
359363
path: build/coverage
360364

365+
- name: Upload Perfetto Traces
366+
uses: actions/upload-artifact@v4
367+
if: matrix.extended_build_perfetto == 'ON' && env.IS_EXTENDED_BUILD == 'true'
368+
with:
369+
name: Traces_${{ matrix.name }}
370+
path: build/**/*.perfetto-trace
371+
if-no-files-found: ignore
372+
361373
javascript:
362374
name: JavaScript
363375
runs-on: ubuntu-latest

CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ option(MATERIALX_BUILD_OCIO "Build OpenColorIO support for shader generators." O
5151
option(MATERIALX_BUILD_TESTS "Build unit tests." OFF)
5252
option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF)
5353
option(MATERIALX_BUILD_OSOS "Build OSL .oso's of standard library shaders for the OSL Network generator" OFF)
54+
option(MATERIALX_BUILD_PERFETTO_TRACING "Build with Perfetto tracing support for performance analysis." OFF)
5455

5556
option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF)
5657
option(MATERIALX_BUILD_DATA_LIBRARY "Build generated products from the MaterialX data library." OFF)
@@ -228,6 +229,41 @@ mark_as_advanced(MATERIALX_MDL_BINARY_TESTRENDER)
228229
mark_as_advanced(MATERIALX_MDL_MODULE_PATHS)
229230
mark_as_advanced(MATERIALX_MDL_SDK_DIR)
230231
mark_as_advanced(MATERIALX_SLANG_RHI_SOURCE_DIR)
232+
mark_as_advanced(MATERIALX_BUILD_PERFETTO_TRACING)
233+
234+
# Perfetto tracing support
235+
if(MATERIALX_BUILD_PERFETTO_TRACING)
236+
include(FetchContent)
237+
FetchContent_Declare(
238+
perfetto
239+
GIT_REPOSITORY https://android.googlesource.com/platform/external/perfetto
240+
GIT_TAG v43.0
241+
GIT_SHALLOW TRUE
242+
)
243+
# Only fetch the SDK, not the full Perfetto source
244+
set(PERFETTO_SDK_INCLUDE_DIR "${CMAKE_BINARY_DIR}/_deps/perfetto-src/sdk")
245+
FetchContent_MakeAvailable(perfetto)
246+
add_definitions(-DMATERIALX_BUILD_PERFETTO_TRACING)
247+
248+
# Define compile flags for perfetto.cc (Perfetto SDK triggers various warnings)
249+
# These variables are used in source/CMakeLists.txt (monolithic) and MaterialXTrace (non-monolithic)
250+
# Note: set_source_files_properties is directory-scoped, so we define variables here
251+
# but apply them in the directories where targets are created.
252+
if(MSVC)
253+
set(MATERIALX_PERFETTO_COMPILE_DEFINITIONS "NOMINMAX;WIN32_LEAN_AND_MEAN" CACHE INTERNAL "")
254+
# /bigobj: perfetto.cc has too many sections for default MSVC object format
255+
# /W0: disable all warnings for third-party Perfetto SDK code
256+
# /WX-: disable warnings-as-errors (overrides project-level /WX)
257+
set(MATERIALX_PERFETTO_COMPILE_FLAGS "/bigobj /W0 /WX-" CACHE INTERNAL "")
258+
else()
259+
set(MATERIALX_PERFETTO_COMPILE_DEFINITIONS "" CACHE INTERNAL "")
260+
# -Wno-error: Don't treat warnings as errors (Perfetto has shadowing issues)
261+
# -Wno-shadow: Suppress shadow warnings (kDevNull shadows global)
262+
set(MATERIALX_PERFETTO_COMPILE_FLAGS "-Wno-error -Wno-shadow" CACHE INTERNAL "")
263+
endif()
264+
265+
message(STATUS "Perfetto tracing support enabled")
266+
endif()
231267

232268
if (MATERIALX_BUILD_USE_CCACHE)
233269
# Setup CCache for C/C++ compilation
@@ -491,6 +527,9 @@ endif()
491527
# Add core subdirectories
492528
add_subdirectory(source/MaterialXCore)
493529
add_subdirectory(source/MaterialXFormat)
530+
if(MATERIALX_BUILD_PERFETTO_TRACING)
531+
add_subdirectory(source/MaterialXTrace)
532+
endif()
494533

495534
# Add shader generation subdirectories
496535
add_subdirectory(source/MaterialXGenShader)

resources/Materials/TestSuite/_options.mtlx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,19 @@
7070
but requiring a more powerful GPU and longer CPU render times.
7171
-->
7272
<input name="enableReferenceQuality" type="boolean" value="false" />
73+
74+
<!-- Base directory for all test output artifacts (shaders, images, logs).
75+
If empty (default), artifacts are written to their default locations
76+
(CWD for logs, alongside source materials for shaders/images).
77+
Supports absolute paths or paths relative to the test working directory.
78+
The directory will be created if it doesn't exist.
79+
-->
80+
<input name="outputDirectory" type="string" value="" />
81+
82+
<!-- Enable Perfetto tracing during render tests (requires MATERIALX_BUILD_TRACING).
83+
When enabled, generates .perfetto-trace files in outputDirectory.
84+
Default is false to avoid overhead when not profiling.
85+
-->
86+
<input name="enableTracing" type="boolean" value="true" />
7387
</nodedef>
7488
</materialx>

source/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ if (MATERIALX_BUILD_MONOLITHIC)
55
# such that the individual module would have been built if not in monolithic build mode
66
add_library(${MATERIALX_MODULE_NAME} "" "" )
77

8+
# Apply Perfetto compile flags for monolithic builds
9+
# (set_source_files_properties is directory-scoped, must be called here)
10+
if(MATERIALX_BUILD_PERFETTO_TRACING)
11+
set_source_files_properties("${perfetto_SOURCE_DIR}/sdk/perfetto.cc"
12+
PROPERTIES
13+
COMPILE_DEFINITIONS "${MATERIALX_PERFETTO_COMPILE_DEFINITIONS}"
14+
COMPILE_FLAGS "${MATERIALX_PERFETTO_COMPILE_FLAGS}")
15+
endif()
16+
817
set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
918
set_target_properties(${MATERIALX_MODULE_NAME} PROPERTIES CMAKE_VISIBILITY_INLINES_HIDDEN 1)
1019

source/MaterialXTest/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ add_subdirectory(MaterialXCore)
4040
target_link_libraries(MaterialXTest MaterialXCore)
4141
add_subdirectory(MaterialXFormat)
4242
target_link_libraries(MaterialXTest MaterialXFormat)
43+
if(MATERIALX_BUILD_PERFETTO_TRACING)
44+
target_link_libraries(MaterialXTest MaterialXTrace)
45+
endif()
4346

4447
add_subdirectory(MaterialXGenShader)
4548
target_link_libraries(MaterialXTest MaterialXGenShader)

source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
#include <MaterialXCore/Material.h>
2424
#include <MaterialXCore/Unit.h>
2525

26+
#include <MaterialXTrace/Tracing.h>
27+
2628
#include <iostream>
29+
#include <optional>
2730

2831
namespace mx = MaterialX;
2932

@@ -652,24 +655,36 @@ void ShaderGeneratorTester::registerLights(mx::DocumentPtr doc, const std::vecto
652655

653656
void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, const std::string& optionsFilePath)
654657
{
655-
// Start logging
656-
_logFile.open(_logFilePath);
657-
658-
// Check for an option file
658+
// Check for an option file first (before opening log) so we can use outputDirectory
659659
TestSuiteOptions options;
660660
if (!options.readOptions(optionsFilePath))
661661
{
662-
_logFile << "Cannot read options file: " << optionsFilePath << ". Skipping test." << std::endl;
663-
_logFile.close();
662+
std::cerr << "Cannot read options file: " << optionsFilePath << ". Skipping test." << std::endl;
664663
return;
665664
}
666665
// Test has been turned off so just do nothing.
667666
if (!runTest(options))
668667
{
669-
_logFile << "Target: " << _targetString << " not set to run. Skipping test." << std::endl;
670-
_logFile.close();
668+
std::cerr << "Target: " << _targetString << " not set to run. Skipping test." << std::endl;
671669
return;
672670
}
671+
672+
#ifdef MATERIALX_BUILD_PERFETTO_TRACING
673+
// Set up Perfetto tracing if enabled
674+
std::optional<mx::Tracing::Dispatcher::ShutdownGuard> tracingGuard;
675+
if (options.enableTracing)
676+
{
677+
mx::FilePath tracePath = options.resolveOutputPath(_shaderGenerator->getTarget() + "_gen_trace.perfetto-trace");
678+
mx::Tracing::Dispatcher::getInstance().setSink(
679+
mx::Tracing::createPerfettoSink(tracePath.asString()));
680+
tracingGuard.emplace();
681+
}
682+
#endif
683+
684+
// Start logging - use outputDirectory if set
685+
mx::FilePath logPath = options.resolveOutputPath(_logFilePath);
686+
_logFile.open(logPath.asString());
687+
673688
options.print(_logFile);
674689

675690
// Add files to override the files in the test suite to be examined.
@@ -839,7 +854,11 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
839854
_logFile << "------------ Run validation with element: " << namePath << "------------" << std::endl;
840855

841856
mx::StringVec sourceCode;
842-
const bool generatedCode = generateCode(context, elementName, element, _logFile, _testStages, sourceCode);
857+
bool generatedCode = false;
858+
{
859+
MX_TRACE_SCOPE(mx::Tracing::Category::ShaderGen, elementName.c_str());
860+
generatedCode = generateCode(context, elementName, element, _logFile, _testStages, sourceCode);
861+
}
843862

844863
// Record implementations tested
845864
if (options.checkImplCount)
@@ -879,6 +898,17 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
879898
path = searchPath.isEmpty() ? mx::FilePath() : searchPath[0];
880899
}
881900

901+
// Redirect to outputDirectory if set
902+
if (!options.outputDirectory.isEmpty())
903+
{
904+
mx::FilePath materialDir = path.getBaseName();
905+
path = options.outputDirectory / materialDir;
906+
if (!path.exists())
907+
{
908+
path.createDirectory();
909+
}
910+
}
911+
882912
std::vector<mx::FilePath> sourceCodePaths;
883913
if (sourceCode.size() > 1)
884914
{
@@ -939,6 +969,12 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
939969
{
940970
_logFile.close();
941971
}
972+
973+
// Print effective output directory for easy access (clickable in terminals)
974+
if (!options.outputDirectory.isEmpty())
975+
{
976+
std::cout << std::endl << "Test artifacts written to: " << options.outputDirectory.asString() << std::endl;
977+
}
942978
}
943979

944980
void TestSuiteOptions::print(std::ostream& output) const
@@ -968,6 +1004,8 @@ void TestSuiteOptions::print(std::ostream& output) const
9681004
output << "\tExtra library paths: " << extraLibraryPaths.asString() << std::endl;
9691005
output << "\tRender test paths: " << renderTestPaths.asString() << std::endl;
9701006
output << "\tEnable Reference Quality: " << enableReferenceQuality << std::endl;
1007+
output << "\tOutput Directory: " << (outputDirectory.isEmpty() ? "(default)" : outputDirectory.asString()) << std::endl;
1008+
output << "\tEnable Tracing: " << enableTracing << std::endl;
9711009
}
9721010

9731011
bool TestSuiteOptions::readOptions(const std::string& optionFile)
@@ -993,6 +1031,8 @@ bool TestSuiteOptions::readOptions(const std::string& optionFile)
9931031
const std::string EXTRA_LIBRARY_PATHS("extraLibraryPaths");
9941032
const std::string RENDER_TEST_PATHS("renderTestPaths");
9951033
const std::string ENABLE_REFERENCE_QUALITY("enableReferenceQuality");
1034+
const std::string OUTPUT_DIRECTORY_STRING("outputDirectory");
1035+
const std::string ENABLE_TRACING_STRING("enableTracing");
9961036

9971037
overrideFiles.clear();
9981038
dumpGeneratedCode = false;
@@ -1091,6 +1131,23 @@ bool TestSuiteOptions::readOptions(const std::string& optionFile)
10911131
{
10921132
enableReferenceQuality = val->asA<bool>();
10931133
}
1134+
else if (name == OUTPUT_DIRECTORY_STRING)
1135+
{
1136+
std::string dirPath = p->getValueString();
1137+
if (!dirPath.empty())
1138+
{
1139+
outputDirectory = mx::FilePath(dirPath);
1140+
// Create the directory if it doesn't exist
1141+
if (!outputDirectory.exists())
1142+
{
1143+
outputDirectory.createDirectory();
1144+
}
1145+
}
1146+
}
1147+
else if (name == ENABLE_TRACING_STRING)
1148+
{
1149+
enableTracing = val->asA<bool>();
1150+
}
10941151
}
10951152
}
10961153
}

source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ class TestSuiteOptions
118118
// Enable reference quality rendering. Default is false.
119119
bool enableReferenceQuality;
120120

121+
// Base directory for all test output artifacts (shaders, images, logs).
122+
// If empty, use default locations. If set, all artifacts go to this directory.
123+
mx::FilePath outputDirectory;
124+
125+
// Enable Perfetto tracing during render tests (requires MATERIALX_BUILD_PERFETTO_TRACING).
126+
// Default is false to avoid overhead when not profiling.
127+
bool enableTracing = false;
128+
129+
// Helper to resolve output path for an artifact.
130+
// If outputDirectory is set, returns outputDirectory/filename.
131+
// Otherwise returns the original path unchanged.
132+
mx::FilePath resolveOutputPath(const mx::FilePath& path) const
133+
{
134+
if (outputDirectory.isEmpty())
135+
{
136+
return path;
137+
}
138+
// Extract just the filename and place it in outputDirectory
139+
return outputDirectory / path.getBaseName();
140+
}
141+
121142
// Bake parameters
122143
struct BakeSetting
123144
{

0 commit comments

Comments
 (0)