diff options
| author | kaizhangNV <149626564+kaizhangNV@users.noreply.github.com> | 2024-06-13 13:02:12 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-13 13:02:12 -0700 |
| commit | f0d40ad5e1d0a0dec39fe8a141d3f81d88fc576a (patch) | |
| tree | 210a0a9b5bb2aea0e64776527c4ce04266709a43 /source | |
| parent | ecc6ecb3a25a28eb5e85cfdb2bf170448ab9a4e7 (diff) | |
capture/replay: implement infrastructure for capture (#4372)
* Define api call ID for each being captured methods
* Add parameter encoder interface
* Add outputStream and capture manager
Add infrastructure for output stream
This is the interface to record the method and parameter, and also
provide functionality to write all the serialized data into file.
Add capture manager:
Capture manager is associated to global session object, it will
provide the functionality to actual record all the APIs.
Implement some of parameter encoder functions.
* Fix some Windows & cmake build error
* remove unused headers
Diffstat (limited to 'source')
| -rw-r--r-- | source/core/slang-stream.h | 5 | ||||
| -rw-r--r-- | source/slang-capture-replay/api_callId.h | 147 | ||||
| -rw-r--r-- | source/slang-capture-replay/capture-manager.cpp | 53 | ||||
| -rw-r--r-- | source/slang-capture-replay/capture-manager.h | 30 | ||||
| -rw-r--r-- | source/slang-capture-replay/output-stream.cpp | 52 | ||||
| -rw-r--r-- | source/slang-capture-replay/output-stream.h | 46 | ||||
| -rw-r--r-- | source/slang-capture-replay/parameter-encoder.cpp | 72 | ||||
| -rw-r--r-- | source/slang-capture-replay/parameter-encoder.h | 51 | ||||
| -rw-r--r-- | source/slang-capture-replay/slang-global-session.cpp | 13 | ||||
| -rw-r--r-- | source/slang-capture-replay/slang-global-session.h | 13 |
10 files changed, 479 insertions, 3 deletions
diff --git a/source/core/slang-stream.h b/source/core/slang-stream.h index 9f405dbb0..a62c18838 100644 --- a/source/core/slang-stream.h +++ b/source/core/slang-stream.h @@ -138,7 +138,10 @@ public: void setContent(const void* contents, size_t contentsSize) { m_ownedContents.setCount(contentsSize); - ::memcpy(m_ownedContents.getBuffer(), contents, contentsSize); + if (contentsSize > 0) + { + ::memcpy(m_ownedContents.getBuffer(), contents, contentsSize); + } _setContents(m_ownedContents.getBuffer(), m_ownedContents.getCount()); } diff --git a/source/slang-capture-replay/api_callId.h b/source/slang-capture-replay/api_callId.h new file mode 100644 index 000000000..0a96ef4a7 --- /dev/null +++ b/source/slang-capture-replay/api_callId.h @@ -0,0 +1,147 @@ +#ifndef API_CALL_ID_H +#define API_CALL_ID_H + +#include <cstdint> + +namespace SlangCapture +{ + constexpr uint32_t makeApiCallId(uint16_t classId, uint16_t memberFunctionId) + { + return ((static_cast<uint32_t>(classId) << 16) & 0xffff0000) | (static_cast<uint32_t>(memberFunctionId) & 0x0000ffff); + } + + constexpr uint16_t getClassId(uint32_t callId) + { + return static_cast<uint16_t>((callId >> 16) & 0x0000ffff); + } + + constexpr uint16_t getMemberFunctionId(uint32_t callId) + { + return static_cast<uint16_t>(callId & 0x0000ffff); + } + + enum ApiClassId : uint16_t + { + GlobalFunction = 1, + Class_IGlobalSession = 2, + Class_ISession = 3, + Class_IModule = 4, + Class_IEntryPoint = 5, + Class_ICompositeComponentType = 6, + Class_ITypeConformance = 7, + }; + + typedef uint64_t AddressFormat; + + constexpr uint64_t g_globalFunctionHandle = 0; + + enum ApiCallId : uint32_t + { + InvalidCallId = 0x00000000, + ICreateGlobalSession = makeApiCallId(GlobalFunction, 0x0000), + IGlobalSession_createSession = makeApiCallId(Class_IGlobalSession, 0x0001), + IGlobalSession_findProfile = makeApiCallId(Class_IGlobalSession, 0x0002), + IGlobalSession_setDownstreamCompilerPath = makeApiCallId(Class_IGlobalSession, 0x0003), + IGlobalSession_setDownstreamCompilerPrelude = makeApiCallId(Class_IGlobalSession, 0x0004), + IGlobalSession_getDownstreamCompilerPrelude = makeApiCallId(Class_IGlobalSession, 0x0005), + IGlobalSession_getBuildTagString = makeApiCallId(Class_IGlobalSession, 0x0006), + IGlobalSession_setDefaultDownstreamCompiler = makeApiCallId(Class_IGlobalSession, 0x0007), + IGlobalSession_getDefaultDownstreamCompiler = makeApiCallId(Class_IGlobalSession, 0x0008), + IGlobalSession_setLanguagePrelude = makeApiCallId(Class_IGlobalSession, 0x0009), + IGlobalSession_getLanguagePrelude = makeApiCallId(Class_IGlobalSession, 0x000A), + IGlobalSession_createCompileRequest = makeApiCallId(Class_IGlobalSession, 0x000B), + IGlobalSession_addBuiltins = makeApiCallId(Class_IGlobalSession, 0x000C), + IGlobalSession_setSharedLibraryLoader = makeApiCallId(Class_IGlobalSession, 0x000D), + IGlobalSession_getSharedLibraryLoader = makeApiCallId(Class_IGlobalSession, 0x000E), + IGlobalSession_checkCompileTargetSupport = makeApiCallId(Class_IGlobalSession, 0x000F), + IGlobalSession_checkPassThroughSupport = makeApiCallId(Class_IGlobalSession, 0x0010), + IGlobalSession_compileStdLib = makeApiCallId(Class_IGlobalSession, 0x0011), + IGlobalSession_loadStdLib = makeApiCallId(Class_IGlobalSession, 0x0012), + IGlobalSession_saveStdLib = makeApiCallId(Class_IGlobalSession, 0x0013), + IGlobalSession_findCapability = makeApiCallId(Class_IGlobalSession, 0x0014), + IGlobalSession_setDownstreamCompilerForTransition = makeApiCallId(Class_IGlobalSession, 0x0015), + IGlobalSession_getDownstreamCompilerForTransition = makeApiCallId(Class_IGlobalSession, 0x0016), + IGlobalSession_getCompilerElapsedTime = makeApiCallId(Class_IGlobalSession, 0x0017), + IGlobalSession_setSPIRVCoreGrammar = makeApiCallId(Class_IGlobalSession, 0x0018), + IGlobalSession_parseCommandLineArguments = makeApiCallId(Class_IGlobalSession, 0x0019), + IGlobalSession_getSessionDescDigest = makeApiCallId(Class_IGlobalSession, 0x001A), + + ISession_getGlobalSession = makeApiCallId(Class_ISession, 0x0001), + ISession_loadModule = makeApiCallId(Class_ISession, 0x0002), + ISession_loadModuleFromBlob = makeApiCallId(Class_ISession, 0x0003), + ISession_loadModuleFromIRBlob = makeApiCallId(Class_ISession, 0x0004), + ISession_loadModuleFromSource = makeApiCallId(Class_ISession, 0x0005), + ISession_loadModuleFromSourceString = makeApiCallId(Class_ISession, 0x0006), + ISession_createCompositeComponentType = makeApiCallId(Class_ISession, 0x0007), + ISession_specializeType = makeApiCallId(Class_ISession, 0x0008), + ISession_getTypeLayout = makeApiCallId(Class_ISession, 0x0009), + ISession_getContainerType = makeApiCallId(Class_ISession, 0x000A), + ISession_getDynamicType = makeApiCallId(Class_ISession, 0x000B), + ISession_getTypeRTTIMangledName = makeApiCallId(Class_ISession, 0x000C), + ISession_getTypeConformanceWitnessMangledName = makeApiCallId(Class_ISession, 0x000D), + ISession_getTypeConformanceWitnessSequentialID = makeApiCallId(Class_ISession, 0x000E), + ISession_createTypeConformanceComponentType = makeApiCallId(Class_ISession, 0x000F), + ISession_createCompileRequest = makeApiCallId(Class_ISession, 0x0010), + ISession_getLoadedModuleCount = makeApiCallId(Class_ISession, 0x0011), + ISession_getLoadedModule = makeApiCallId(Class_ISession, 0x0012), + ISession_isBinaryModuleUpToDate = makeApiCallId(Class_ISession, 0x0013), + + IModule_findEntryPointByName = makeApiCallId(Class_IModule, 0x0001), + IModule_getDefinedEntryPointCount = makeApiCallId(Class_IModule, 0x0002), + IModule_getDefinedEntryPoint = makeApiCallId(Class_IModule, 0x0003), + IModule_serialize = makeApiCallId(Class_IModule, 0x0004), + IModule_writeToFile = makeApiCallId(Class_IModule, 0x0005), + IModule_getName = makeApiCallId(Class_IModule, 0x0006), + IModule_getFilePath = makeApiCallId(Class_IModule, 0x0007), + IModule_getUniqueIdentity = makeApiCallId(Class_IModule, 0x0008), + IModule_findAndCheckEntryPoint = makeApiCallId(Class_IModule, 0x0009), + IModule_getSession = makeApiCallId(Class_IModule, 0x000A), + IModule_getLayout = makeApiCallId(Class_IModule, 0x000B), + IModule_getSpecializationParamCount = makeApiCallId(Class_IModule, 0x000C), + IModule_getEntryPointCode = makeApiCallId(Class_IModule, 0x000D), + IModule_getResultAsFileSystem = makeApiCallId(Class_IModule, 0x000E), + IModule_getEntryPointHash = makeApiCallId(Class_IModule, 0x000F), + IModule_specialize = makeApiCallId(Class_IModule, 0x0010), + IModule_link = makeApiCallId(Class_IModule, 0x0011), + IModule_getEntryPointHostCallable = makeApiCallId(Class_IModule, 0x0012), + IModule_renameEntryPoint = makeApiCallId(Class_IModule, 0x0013), + IModule_linkWithOptions = makeApiCallId(Class_IModule, 0x0014), + + IEntryPoint_getSession = makeApiCallId(Class_IEntryPoint, 0x0001), + IEntryPoint_getLayout = makeApiCallId(Class_IEntryPoint, 0x0002), + IEntryPoint_getSpecializationParamCount = makeApiCallId(Class_IEntryPoint, 0x0003), + IEntryPoint_getEntryPointCode = makeApiCallId(Class_IEntryPoint, 0x0004), + IEntryPoint_getResultAsFileSystem = makeApiCallId(Class_IEntryPoint, 0x0005), + IEntryPoint_getEntryPointHash = makeApiCallId(Class_IEntryPoint, 0x0006), + IEntryPoint_specialize = makeApiCallId(Class_IEntryPoint, 0x0007), + IEntryPoint_link = makeApiCallId(Class_IEntryPoint, 0x0008), + IEntryPoint_getEntryPointHostCallable = makeApiCallId(Class_IEntryPoint, 0x0009), + IEntryPoint_renameEntryPoint = makeApiCallId(Class_IEntryPoint, 0x000A), + IEntryPoint_linkWithOptions = makeApiCallId(Class_IEntryPoint, 0x000B), + + ICompositeComponentType_getSession = makeApiCallId(Class_ICompositeComponentType, 0x0001), + ICompositeComponentType_getLayout = makeApiCallId(Class_ICompositeComponentType, 0x0002), + ICompositeComponentType_getSpecializationParamCount = makeApiCallId(Class_ICompositeComponentType, 0x0003), + ICompositeComponentType_getEntryPointCode = makeApiCallId(Class_ICompositeComponentType, 0x0004), + ICompositeComponentType_getResultAsFileSystem = makeApiCallId(Class_ICompositeComponentType, 0x0005), + ICompositeComponentType_getEntryPointHash = makeApiCallId(Class_ICompositeComponentType, 0x0006), + ICompositeComponentType_specialize = makeApiCallId(Class_ICompositeComponentType, 0x0007), + ICompositeComponentType_link = makeApiCallId(Class_ICompositeComponentType, 0x0008), + ICompositeComponentType_getEntryPointHostCallable = makeApiCallId(Class_ICompositeComponentType, 0x0009), + ICompositeComponentType_renameEntryPoint = makeApiCallId(Class_ICompositeComponentType, 0x000A), + ICompositeComponentType_linkWithOptions = makeApiCallId(Class_ICompositeComponentType, 0x000B), + + ITypeConformance_getSession = makeApiCallId(Class_ITypeConformance, 0x0001), + ITypeConformance_getLayout = makeApiCallId(Class_ITypeConformance, 0x0002), + ITypeConformance_getSpecializationParamCount = makeApiCallId(Class_ITypeConformance, 0x0003), + ITypeConformance_getEntryPointCode = makeApiCallId(Class_ITypeConformance, 0x0004), + ITypeConformance_getResultAsFileSystem = makeApiCallId(Class_ITypeConformance, 0x0005), + ITypeConformance_getEntryPointHash = makeApiCallId(Class_ITypeConformance, 0x0006), + ITypeConformance_specialize = makeApiCallId(Class_ITypeConformance, 0x0007), + ITypeConformance_link = makeApiCallId(Class_ITypeConformance, 0x0008), + ITypeConformance_getEntryPointHostCallable = makeApiCallId(Class_ITypeConformance, 0x0009), + ITypeConformance_renameEntryPoint = makeApiCallId(Class_ITypeConformance, 0x000A), + ITypeConformance_linkWithOptions = makeApiCallId(Class_ITypeConformance, 0x000B) + }; +} +#endif diff --git a/source/slang-capture-replay/capture-manager.cpp b/source/slang-capture-replay/capture-manager.cpp new file mode 100644 index 000000000..be5615e00 --- /dev/null +++ b/source/slang-capture-replay/capture-manager.cpp @@ -0,0 +1,53 @@ + +#include <string> +#include <sstream> +#include <thread> +#include "capture-manager.h" + +namespace SlangCapture +{ + CaptureManager::CaptureManager(uint64_t globalSessionHandle) + : m_encoder(&m_memoryStream) + { + std::stringstream ss; + ss << "gs-"<< globalSessionHandle <<"t-"<<std::this_thread::get_id() << ".cap"; + m_fileStream = std::make_unique<FileOutputStream>(ss.str()); + } + + void CaptureManager::clearWithHeader(const ApiCallId& callId, uint64_t handleId) + { + m_memoryStream.flush(); + FunctionHeader header {}; + header.callId = callId; + header.handleId = handleId; + + // write header to memory stream + m_memoryStream.write(&header, sizeof(FunctionHeader)); + } + + ParameterEncoder* CaptureManager::beginMethodCapture(const ApiCallId& callId, uint64_t handleId) + { + clearWithHeader(callId, handleId); + return &m_encoder; + } + + void CaptureManager::endMethodCapture() + { + FunctionHeader* pHeader = const_cast<FunctionHeader*>( + reinterpret_cast<const FunctionHeader*>(m_memoryStream.getData())); + + pHeader->dataSizeInBytes = m_memoryStream.getSizeInBytes() - sizeof(FunctionHeader); + + std::hash<std::thread::id> hasher; + pHeader->threadId = hasher(std::this_thread::get_id()); + + // write capture data to file + m_fileStream->write(m_memoryStream.getData(), m_memoryStream.getSizeInBytes()); + + // take effect of the write + m_fileStream->flush(); + + // clear the memory stream + m_memoryStream.flush(); + } +} diff --git a/source/slang-capture-replay/capture-manager.h b/source/slang-capture-replay/capture-manager.h new file mode 100644 index 000000000..55d42c458 --- /dev/null +++ b/source/slang-capture-replay/capture-manager.h @@ -0,0 +1,30 @@ +#ifndef CAPTURE_MANAGER_H +#define CAPTURE_MANAGER_H + +#include "parameter-encoder.h" +#include "api_callId.h" +namespace SlangCapture +{ + class CaptureManager + { + public: + CaptureManager(uint64_t globalSessionHandle); + ParameterEncoder* beginMethodCapture(const ApiCallId& callId, uint64_t handleId); + void endMethodCapture(); + private: + void clearWithHeader(const ApiCallId& callId, uint64_t handleId); + + struct FunctionHeader + { + ApiCallId callId {InvalidCallId}; + uint64_t handleId {0}; + uint64_t dataSizeInBytes {0}; + uint64_t threadId {0}; + }; + + MemoryStream m_memoryStream; + std::unique_ptr<FileOutputStream> m_fileStream; + ParameterEncoder m_encoder; + }; +} // namespace SlangCapture +#endif // CAPTURE_MANAGER_H diff --git a/source/slang-capture-replay/output-stream.cpp b/source/slang-capture-replay/output-stream.cpp new file mode 100644 index 000000000..acde6fbf1 --- /dev/null +++ b/source/slang-capture-replay/output-stream.cpp @@ -0,0 +1,52 @@ +#include "output-stream.h" +#include "capture_utility.h" + +namespace SlangCapture +{ + FileOutputStream::FileOutputStream(const std::string& filename, bool append) + { + Slang::String path(filename.c_str()); + Slang::FileMode fileMode = append ? Slang::FileMode::Append : Slang::FileMode::Create; + Slang::FileAccess fileAccess = Slang::FileAccess::Write; + Slang::FileShare fileShare = Slang::FileShare::None; + + SlangResult res = m_fileStream.init(path, fileMode, fileAccess, fileShare); + + if (res != SLANG_OK) + { + SlangCapture::slangCaptureLog(SlangCapture::LogLevel::Error, "Failed to open file %s\n", filename.c_str()); + std::abort(); + } + } + + FileOutputStream::~FileOutputStream() + { + m_fileStream.close(); + } + + void FileOutputStream::write(const void* data, size_t len) + { + SLANG_CAPTURE_ASSERT(m_fileStream.write(data, len)); + } + + MemoryStream::MemoryStream() + : m_memoryStream(Slang::FileAccess::Write) + { } + + void FileOutputStream::flush() + { + SLANG_CAPTURE_ASSERT(m_fileStream.flush()); + } + + void MemoryStream::write(const void* data, size_t len) + { + SLANG_CAPTURE_ASSERT(m_memoryStream.write(data, len)); + } + + void MemoryStream::flush() + { + // This call will reset the underlying buffer to size 0, + // and reset the write position to 0. + m_memoryStream.setContent(nullptr, 0); + } +} diff --git a/source/slang-capture-replay/output-stream.h b/source/slang-capture-replay/output-stream.h new file mode 100644 index 000000000..1f2c882b0 --- /dev/null +++ b/source/slang-capture-replay/output-stream.h @@ -0,0 +1,46 @@ +#ifndef OUTPUT_STREAM_H +#define OUTPUT_STREAM_H + +#include <string> +#include "../core/slang-stream.h" + +namespace SlangCapture +{ + class OutputStream + { + public: + virtual ~OutputStream() {} + virtual void write(const void* data, size_t len) = 0; + virtual void flush() {} + }; + + class FileOutputStream : public OutputStream + { + public: + FileOutputStream(const std::string& filename, bool append = false); + virtual ~FileOutputStream() override; + virtual void write(const void* data, size_t len) override; + virtual void flush() override; + + private: + Slang::FileStream m_fileStream; + }; + + // The reason we inherit from OwnedMemoryStream instead of declaring it + // as a member is because OwnedMemoryStream lacks some of the functionality + // of operating on the underlying buffer directly. + class MemoryStream : public OutputStream + { + public: + MemoryStream(); + virtual ~MemoryStream() { } + virtual void write(const void* data, size_t len) override; + virtual void flush() override; + const void* getData() { return m_memoryStream.getContents().getBuffer(); } + size_t getSizeInBytes() { return m_memoryStream.getContents().getCount(); } + + private: + Slang::OwnedMemoryStream m_memoryStream; + }; +} // namespace SlangCapture +#endif // OUTPUT_STREAM_H diff --git a/source/slang-capture-replay/parameter-encoder.cpp b/source/slang-capture-replay/parameter-encoder.cpp new file mode 100644 index 000000000..5167cc2ab --- /dev/null +++ b/source/slang-capture-replay/parameter-encoder.cpp @@ -0,0 +1,72 @@ +#include "parameter-encoder.h" + +namespace SlangCapture +{ + void ParameterEncoder::encodeStruct(slang::SessionDesc const& desc) + { + encodeUint64(desc.structureSize); + encodeInt64(desc.targetCount); + + for (SlangInt i = 0; i < desc.targetCount; i++) + { + encodeStruct(desc.targets[i]); + } + + encodeUint32(desc.flags); + encodeUint32(desc.defaultMatrixLayoutMode); + encodeInt64(desc.searchPathCount); + for (SlangInt i = 0; i < desc.searchPathCount; i++) + { + encodeString(desc.searchPaths[i]); + } + + encodeInt64(desc.preprocessorMacroCount); + for (SlangInt i = 0; i < desc.preprocessorMacroCount; i++) + { + encodeStruct(desc.preprocessorMacros[i]); + } + + encodeBool(desc.enableEffectAnnotations); + encodeBool(desc.allowGLSLSyntax); + + encodeUint32(desc.compilerOptionEntryCount); + for (uint32_t i = 0; i < desc.compilerOptionEntryCount; i++) + { + encodeStruct(desc.compilerOptionEntries[i]); + } + } + + void ParameterEncoder::encodeStruct(slang::PreprocessorMacroDesc const& desc) + { + encodeString(desc.name); + encodeString(desc.value); + } + + void ParameterEncoder::encodeStruct(slang::CompilerOptionEntry const& entry) + { + encodeInt32((int32_t)(entry.name)); + encodeStruct(entry.value); + } + + void ParameterEncoder::encodeStruct(slang::CompilerOptionValue const& value) + { + (void)value; + } + + void ParameterEncoder::encodeStruct(slang::TargetDesc const& targetDesc) + { + (void)targetDesc; + } + + void ParameterEncoder::encodePointer(const void* value, bool omitData, size_t size) + { + (void)value; + (void)omitData; + (void)size; + } + // first 4-bytes is the length of the string + void ParameterEncoder::encodeString(const char* value) + { + (void)value; + } +} diff --git a/source/slang-capture-replay/parameter-encoder.h b/source/slang-capture-replay/parameter-encoder.h new file mode 100644 index 000000000..c7c2d959a --- /dev/null +++ b/source/slang-capture-replay/parameter-encoder.h @@ -0,0 +1,51 @@ +#ifndef PARAMETER_ENCODER_H +#define PARAMETER_ENCODER_H + +#include <cstdio> +#include <cinttypes> +#include <cstdint> + +#include "output-stream.h" + +namespace SlangCapture +{ + class ParameterEncoder + { + public: + ParameterEncoder(OutputStream* stream) : m_stream(stream) {}; + void encodeInt8(int8_t value) { encodeValue(value); } + void encodeUint8(uint8_t value) { encodeValue(value); } + void encodeInt16(int16_t value) { encodeValue(value); } + void encodeUint16(uint16_t value) { encodeValue(value); } + void encodeInt32(int32_t value) { encodeValue(value); } + void encodeUint32(uint32_t value) { encodeValue(value); } + void encodeInt64(int64_t value) { encodeValue(value); } + void encodeUint64(uint64_t value) { encodeValue(value); } + void encodeFloat(float value) { encodeValue(value); } + void encodeDouble(double value) { encodeValue(value); } + void encodeBool(bool value) { encodeValue(value); } + + template<typename T> + void encodeEnumValue(T value) { encodeValue(static_cast<uint32_t>(value)); } + + void encodeString(const char* value); + void encodePointer(const void* value, bool omitData = false, size_t size = 0); + void encodeAddress(const void* value) { encodeValue(reinterpret_cast<uint64_t>(value)); } + + void encodeStruct(slang::SessionDesc const& desc); + void encodeStruct(slang::PreprocessorMacroDesc const& desc); + void encodeStruct(slang::CompilerOptionEntry const& entry); + void encodeStruct(slang::CompilerOptionValue const& value); + void encodeStruct(slang::TargetDesc const& targetDesc); + + private: + template <typename T> + void encodeValue(T value) + { + m_stream->write(&value, sizeof(T)); + } + OutputStream* m_stream; + }; +} // namespace SlangCapture + +#endif // PARAMETER_ENCODER_H diff --git a/source/slang-capture-replay/slang-global-session.cpp b/source/slang-capture-replay/slang-global-session.cpp index 05a2b93ec..45ea0b58d 100644 --- a/source/slang-capture-replay/slang-global-session.cpp +++ b/source/slang-capture-replay/slang-global-session.cpp @@ -1,5 +1,3 @@ - -#include <vector> #include "slang-global-session.h" #include "slang-session.h" #include "slang-filesystem.h" @@ -8,10 +6,21 @@ namespace SlangCapture { + // constructor is called in slang_createGlobalSession GlobalSessionCapture::GlobalSessionCapture(slang::IGlobalSession* session): m_actualGlobalSession(session) { SLANG_CAPTURE_ASSERT(m_actualGlobalSession != nullptr); + + m_thisHandle = reinterpret_cast<SlangCapture::AddressFormat>(this); + m_captureManager = std::make_unique<CaptureManager>(m_thisHandle); + + // We will use the address of the global session as the filename for the capture manager + // to make it unique for each global session. + // capture slang::createGlobalSession + ParameterEncoder* encoder = m_captureManager->beginMethodCapture(ApiCallId::ICreateGlobalSession, g_globalFunctionHandle); + encoder->encodeAddress(m_actualGlobalSession); + m_captureManager->endMethodCapture(); } GlobalSessionCapture::~GlobalSessionCapture() diff --git a/source/slang-capture-replay/slang-global-session.h b/source/slang-capture-replay/slang-global-session.h index 52260ba21..6923ddf11 100644 --- a/source/slang-capture-replay/slang-global-session.h +++ b/source/slang-capture-replay/slang-global-session.h @@ -5,6 +5,7 @@ #include "../../slang.h" #include "../../slang-com-helper.h" #include "../core/slang-smart-pointer.h" +#include "capture-manager.h" namespace SlangCapture { @@ -58,6 +59,8 @@ namespace SlangCapture SLANG_NO_THROW SlangResult SLANG_MCALL getSessionDescDigest(slang::SessionDesc* sessionDesc, ISlangBlob** outBlob) override; + CaptureManager* getCaptureManager() { return m_captureManager.get(); } + private: SLANG_FORCE_INLINE slang::IGlobalSession* asExternal(GlobalSessionCapture* session) { @@ -65,6 +68,16 @@ namespace SlangCapture } Slang::ComPtr<slang::IGlobalSession> m_actualGlobalSession; + + // we will create one capture file per IGlobalSession. + // We don't try to reproduce the user application's threading model, because it requires lots of effort and it's not necessary. + // Instead, we record all the compilation jobs associated with the session in the same capture file, so that during replay, + // those jobs will be executed sequentially. This might violate the user application's threading model, because those jobs might + // be executed in different threads. But it's not a big problem, because slang doesn't allow multiple threads to access the same + // session at the same time. So even if there is one session used by multiple threads, those threads will execute the compile jobs + // sequentially. + std::unique_ptr<CaptureManager> m_captureManager; + uint64_t m_thisHandle = 0; }; } // namespace Slang |
