Skip to content

Commit

Permalink
capture/replay: implement infrastructure for capture (#4372)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
kaizhangNV committed Jun 13, 2024
1 parent ecc6ecb commit f0d40ad
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 3 deletions.
7 changes: 7 additions & 0 deletions build/visual-studio/slang/slang.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,11 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\slang.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\api_callId.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\capture-manager.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\capture_utility.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\output-stream.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\parameter-encoder.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\slang-composite-component-type.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\slang-entrypoint.h" />
<ClInclude Include="..\..\..\source\slang-capture-replay\slang-filesystem.h" />
Expand Down Expand Up @@ -546,7 +550,10 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla
<ClCompile Include="..\..\..\prelude\slang-cuda-prelude.h.cpp" />
<ClCompile Include="..\..\..\prelude\slang-hlsl-prelude.h.cpp" />
<ClCompile Include="..\..\..\prelude\slang-torch-prelude.h.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\capture-manager.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\capture_utility.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\output-stream.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\parameter-encoder.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\slang-composite-component-type.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\slang-entrypoint.cpp" />
<ClCompile Include="..\..\..\source\slang-capture-replay\slang-filesystem.cpp" />
Expand Down
21 changes: 21 additions & 0 deletions build/visual-studio/slang/slang.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,21 @@
<ClInclude Include="..\..\..\slang.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\api_callId.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\capture-manager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\capture_utility.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\output-stream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\parameter-encoder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\slang-capture-replay\slang-composite-component-type.h">
<Filter>Header Files</Filter>
</ClInclude>
Expand Down Expand Up @@ -722,9 +734,18 @@
<ClCompile Include="..\..\..\prelude\slang-torch-prelude.h.cpp">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\slang-capture-replay\capture-manager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\slang-capture-replay\capture_utility.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\slang-capture-replay\output-stream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\slang-capture-replay\parameter-encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\slang-capture-replay\slang-composite-component-type.cpp">
<Filter>Source Files</Filter>
</ClCompile>
Expand Down
5 changes: 4 additions & 1 deletion source/core/slang-stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@ class OwnedMemoryStream : public MemoryStreamBase
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());
}

Expand Down
147 changes: 147 additions & 0 deletions source/slang-capture-replay/api_callId.h
Original file line number Diff line number Diff line change
@@ -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
53 changes: 53 additions & 0 deletions source/slang-capture-replay/capture-manager.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
}
30 changes: 30 additions & 0 deletions source/slang-capture-replay/capture-manager.h
Original file line number Diff line number Diff line change
@@ -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
52 changes: 52 additions & 0 deletions source/slang-capture-replay/output-stream.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading

0 comments on commit f0d40ad

Please sign in to comment.