Migrate amdgpu-windows-interop to rocm-systems (#808)
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddLegacyDefs.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Macros for conditional language support.
|
||||
#ifdef _MSVC_LANG
|
||||
#define DD_CPLUSPLUS _MSVC_LANG
|
||||
#else
|
||||
#define DD_CPLUSPLUS __cplusplus
|
||||
#endif
|
||||
// Denotes versions of the C++ standard from __cplusplus.
|
||||
#define CPP98 (199711L)
|
||||
#define CPP11 (201103L)
|
||||
#define CPP14 (201402L)
|
||||
#define CPP17 (201703L)
|
||||
#define CPP20 (202002L)
|
||||
#define DD_CPLUSPLUS_SUPPORTS(x) (DD_CPLUSPLUS >= (x))
|
||||
|
||||
static_assert(DD_CPLUSPLUS_SUPPORTS(CPP11), "C++11 is required to build devdriver.");
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define DD_ALIGNAS(x)__declspec(align(x))
|
||||
#if _MSC_VER < 1900
|
||||
#define DD_STATIC_CONST static const
|
||||
#else
|
||||
#define DD_STATIC_CONST static constexpr
|
||||
#endif
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DD_STATIC_CONST)
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
#define DD_STATIC_CONST static constexpr
|
||||
#else
|
||||
#define DD_STATIC_CONST static const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DD_CPLUSPLUS_SUPPORTS(CPP14)
|
||||
#define DD_CPP14_CONSTEXPR_FN constexpr
|
||||
#define DD_CPP14_STATIC_ASSERT(a, b) static_assert(a, b)
|
||||
#else
|
||||
#define DD_CPP14_CONSTEXPR_FN inline
|
||||
#define DD_CPP14_STATIC_ASSERT(a, b)
|
||||
#endif
|
||||
|
||||
#if !defined(DD_ALIGNAS)
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
#define DD_ALIGNAS(x) alignas(x)
|
||||
#else
|
||||
static_assert(false, "Error: unsupported compiler detected. Support is required to build.");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// Remove the __FILE__ macro for release builds
|
||||
#ifndef DD_FILE
|
||||
#ifdef NDEBUG
|
||||
#define DD_FILE ""
|
||||
#else
|
||||
#define DD_FILE __FILE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Creates a structure with the specified name and alignment.
|
||||
#define DD_ALIGNED_STRUCT(name, alignment) struct DD_ALIGNAS(alignment) name
|
||||
|
||||
// Creates a structure with the specified alignment, and mark it as final to ensure it cannot be used as a parent class
|
||||
#define DD_NETWORK_STRUCT(name, alignment) struct DD_ALIGNAS(alignment) name final
|
||||
|
||||
#define DD_CHECK_SIZE(x, size) static_assert(sizeof(x) == size_t(size), "sizeof(" # x ") should be " # size " bytes but has changed recently")
|
||||
|
||||
#define DD_UNUSED(x) (static_cast<void>(x))
|
||||
|
||||
#define _DD_STRINGIFY(str) #str
|
||||
#define DD_STRINGIFY(x) _DD_STRINGIFY(x)
|
||||
|
||||
#if DD_CPLUSPLUS_SUPPORTS(CPP17)
|
||||
// Require that a function's return value, or an entire type, be used.
|
||||
#define DD_NODISCARD [[nodiscard]]
|
||||
|
||||
// Do not warn about switch statement cases falling through. Place this macro as the case body, e.g.
|
||||
// switch (x)
|
||||
// {
|
||||
// case 0: DD_FALLTHROUGH();
|
||||
// case 1: DD_FALLTHROUGH();
|
||||
// case 2:
|
||||
// printf("0, 1, or 2");
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
#define DD_FALLTHROUGH() [[fallthrough]]
|
||||
#else
|
||||
// Require that a function's return value, or an entire type, be used.
|
||||
// This option is aggressive enough that we do not enable it when C++17 is not enabled
|
||||
#define DD_NODISCARD
|
||||
|
||||
// Do not warn about switch statement cases falling through. Place this macro as the case body, e.g.
|
||||
// switch (x)
|
||||
// {
|
||||
// case 0: DD_FALLTHROUGH();
|
||||
// case 1: DD_FALLTHROUGH();
|
||||
// case 2:
|
||||
// printf("0, 1, or 2");
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
#if defined(__clang__)
|
||||
#define DD_FALLTHROUGH() [[clang::fallthrough]]
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ >= 7
|
||||
// gnu::fallthrough isn't supported until GCC 7+
|
||||
#define DD_FALLTHROUGH() [[gnu::fallthrough]]
|
||||
#else
|
||||
// Not supported on older versions of GCC
|
||||
#define DD_FALLTHROUGH()
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
// Not supported on MSVC - who doesn't warn about this issue in the first place.
|
||||
#define DD_FALLTHROUGH()
|
||||
#else
|
||||
// We don't know what compiler this is, so just no-op the macro.
|
||||
#define DD_FALLTHROUGH()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Include in the private section of a class declaration in order to disallow use of the copy and assignment operator
|
||||
#define DD_DISALLOW_COPY_AND_ASSIGN(_typename) \
|
||||
_typename(const _typename&); \
|
||||
_typename& operator =(const _typename&);
|
||||
|
||||
// Include in the private section of a class declaration in order to disallow use of the default constructor
|
||||
#define DD_DISALLOW_DEFAULT_CTOR(_typename) \
|
||||
_typename();
|
||||
|
||||
// Detect the CPU architecture for the target.
|
||||
// These are often evaluated during the preprocessor stage, so it's important that we don't rely on things like sizeof.
|
||||
#if UINTPTR_MAX == 0xFFFFFFFF
|
||||
#define DEVDRIVER_ARCHITECTURE_BITS 32
|
||||
#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF
|
||||
#define DEVDRIVER_ARCHITECTURE_BITS 64
|
||||
#else
|
||||
static_assert(false, "Unknown or unsupported target architecture.");
|
||||
#endif
|
||||
static_assert(DEVDRIVER_ARCHITECTURE_BITS == (8 * sizeof(void*)), // Assume 8-bits-per-byte.
|
||||
"DEVDRIVER_ARCHITECTURE_BITS does not match sizeof(void*).");
|
||||
|
||||
// Add a detailed function name macro
|
||||
// These vary across platforms, so we'll just pick the first one that's defined
|
||||
#if defined(__FUNCSIG__)
|
||||
#define DD_FUNCTION_NAME __FUNCSIG__
|
||||
#elif defined(__PRETTY_FUNCTION__)
|
||||
#define DD_FUNCTION_NAME __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define DD_FUNCTION_NAME __FUNCTION__
|
||||
#endif
|
||||
|
||||
// Common Typedefs
|
||||
// These types are shared between all platforms,
|
||||
// and need to be defined before including a specific platform header.
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
|
||||
typedef int8_t int8; ///< 8-bit integer.
|
||||
typedef int16_t int16; ///< 16-bit integer.
|
||||
typedef int32_t int32; ///< 32-bit integer.
|
||||
typedef int64_t int64; ///< 64-bit integer.
|
||||
typedef uint8_t uint8; ///< Unsigned 8-bit integer.
|
||||
typedef uint16_t uint16; ///< Unsigned 16-bit integer.
|
||||
typedef uint32_t uint32; ///< Unsigned 32-bit integer.
|
||||
typedef uint64_t uint64; ///< Unsigned 64-bit integer.
|
||||
|
||||
typedef uint32_t ProcessId;
|
||||
typedef uint32_t Size;
|
||||
typedef uint64_t Handle;
|
||||
|
||||
DD_STATIC_CONST Handle kNullPtr = 0;
|
||||
DD_STATIC_CONST Handle kInvalidHandle = 0;
|
||||
|
||||
////////////////////////////
|
||||
// Common result codes
|
||||
enum struct Result : uint32
|
||||
{
|
||||
//// Generic Result Code ////
|
||||
Success = 0,
|
||||
Error = 1,
|
||||
NotReady = 2,
|
||||
VersionMismatch = 3,
|
||||
Unavailable = 4,
|
||||
Rejected = 5,
|
||||
EndOfStream = 6,
|
||||
Aborted = 7,
|
||||
InsufficientMemory = 8,
|
||||
InvalidParameter = 9,
|
||||
InvalidClientId = 10,
|
||||
ConnectionExists = 11,
|
||||
FileNotFound = 12,
|
||||
FunctionNotFound = 13,
|
||||
InterfaceNotFound = 14,
|
||||
EntryExists = 15,
|
||||
FileAccessError = 16,
|
||||
FileIoError = 17,
|
||||
LimitReached = 18,
|
||||
MemoryOverLimit = 19,
|
||||
|
||||
//// URI PROTOCOL ////
|
||||
UriServiceRegistrationError = 1000,
|
||||
UriStringParseError = 1001,
|
||||
UriInvalidParameters = 1002,
|
||||
UriInvalidPostDataBlock = 1003,
|
||||
UriInvalidPostDataSize = 1004,
|
||||
UriFailedToAcquirePostBlock = 1005,
|
||||
UriFailedToOpenResponseBlock = 1006,
|
||||
UriRequestFailed = 1007,
|
||||
UriPendingRequestError = 1008,
|
||||
UriInvalidChar = 1009,
|
||||
UriInvalidJson = 1010,
|
||||
|
||||
//// Settings URI Service ////
|
||||
SettingsUriInvalidComponent = 2000,
|
||||
SettingsUriInvalidSettingName = 2001,
|
||||
SettingsUriInvalidSettingValue = 2002,
|
||||
SettingsUriInvalidSettingValueSize = 2003,
|
||||
|
||||
//// Info URI Service ////
|
||||
InfoUriSourceNameInvalid = 3000,
|
||||
InfoUriSourceCallbackInvalid = 3001,
|
||||
InfoUriSourceAlreadyRegistered = 3002,
|
||||
InfoUriSourceWriteFailed = 3003,
|
||||
|
||||
//// Settings Service ////
|
||||
SettingsInvalidComponent = 4000,
|
||||
SettingsInvalidSettingName = 4001,
|
||||
SettingsInvalidSettingValue = 4002,
|
||||
SettingsInsufficientValueSize = 4003,
|
||||
SettingsInvalidSettingValueSize = 4004,
|
||||
};
|
||||
|
||||
} // namespace DevDriver
|
||||
+824
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
// <new> can not be used in the kernel
|
||||
#if !DD_PLATFORM_IS_KM
|
||||
#include <new>
|
||||
#endif
|
||||
|
||||
#include <ddDefs.h>
|
||||
#include <ddTemplate.h>
|
||||
|
||||
#define DD_CACHE_LINE_BYTES 64
|
||||
|
||||
#define DD_MALLOC(size, alignment, allocCb) allocCb.Alloc(size, alignment, false)
|
||||
#define DD_CALLOC(size, alignment, allocCb) allocCb.Alloc(size, alignment, true)
|
||||
#define DD_FREE(memory, allocCb) allocCb.Free(memory)
|
||||
|
||||
#define DD_NEW(className, allocCb) new(allocCb, alignof(className), true, DD_FILE, __LINE__, __FUNCTION__) className
|
||||
#define DD_DELETE(memory, allocCb) DevDriver::Platform::Destructor(memory); DD_FREE(memory, allocCb)
|
||||
|
||||
#define DD_NEW_ARRAY(className, numElements, allocCb) DevDriver::Platform::NewArray<className>(numElements, allocCb)
|
||||
#define DD_DELETE_ARRAY(memory, allocCb) DevDriver::Platform::DeleteArray(memory, allocCb)
|
||||
|
||||
// Always enable asserts in Debug builds
|
||||
#if !defined(NDEBUG)
|
||||
#if !defined(DD_OPT_ASSERTS_ENABLE)
|
||||
#define DD_OPT_ASSERTS_ENABLE
|
||||
#endif
|
||||
#if !defined(DD_OPT_ASSERTS_DEBUGBREAK)
|
||||
#define DD_OPT_ASSERTS_DEBUGBREAK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DD_PTR_TO_HANDLE(x) ((DevDriver::Handle)(uintptr_t)(x))
|
||||
|
||||
#define DD_SANITIZE_RESULT(x) ((x != Result::Success) ? Result::Error : x)
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
|
||||
////////////////////////////
|
||||
// Common logging levels
|
||||
enum struct LogLevel : uint8
|
||||
{
|
||||
Debug = 0,
|
||||
Verbose,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
Always,
|
||||
Count,
|
||||
|
||||
// Backwards compatibility for old alert log level
|
||||
Alert = Warn,
|
||||
|
||||
Never = 0xFF
|
||||
};
|
||||
|
||||
typedef void*(*AllocFunc)(void* pUserdata, size_t size, size_t alignment, bool zero);
|
||||
typedef void(*FreeFunc)(void* pUserdata, void* pMemory);
|
||||
|
||||
struct AllocCb
|
||||
{
|
||||
void* pUserdata;
|
||||
AllocFunc pfnAlloc;
|
||||
FreeFunc pfnFree;
|
||||
|
||||
void* Alloc(size_t size, size_t alignment, bool zero) const;
|
||||
void* Alloc(size_t size, bool zero) const;
|
||||
void Free(void* pMemory) const;
|
||||
};
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
|
||||
// Used by the Platform::Thread implementation.
|
||||
typedef void (*ThreadFunction)(void* pThreadParameter);
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
} // namespace DevDriver
|
||||
|
||||
#if defined(DD_PLATFORM_WINDOWS_UM)
|
||||
#include <platforms/ddWinPlatform.h>
|
||||
#elif defined(DD_PLATFORM_WINDOWS_KM)
|
||||
#include <platforms/ddWinKernelPlatform.h>
|
||||
#elif defined(DD_PLATFORM_DARWIN_UM)
|
||||
#include <platforms/ddPosixPlatform.h>
|
||||
#elif defined(DD_PLATFORM_LINUX_UM)
|
||||
#include <platforms/ddPosixPlatform.h>
|
||||
#else
|
||||
// Legacy system for Ati Make
|
||||
#if defined(_WIN32) && !defined(_KERNEL_MODE)
|
||||
#define DD_PLATFORM_WINDOWS_UM
|
||||
#include <platforms/ddWinPlatform.h>
|
||||
#elif defined(__linux__)
|
||||
#define DD_PLATFORM_LINUX_UM
|
||||
#include <platforms/ddPosixPlatform.h>
|
||||
#else
|
||||
#error "Unknown Platform - please configure your build system"
|
||||
#endif
|
||||
|
||||
#if __x86_64__
|
||||
#define DD_ARCH_BITS 64
|
||||
#else
|
||||
#define DD_ARCH_BITS 32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DD_RESTRICT)
|
||||
#error "DD_RESTRICT not defined by platform!"
|
||||
#endif
|
||||
|
||||
#if !defined(DD_DEBUG_BREAK)
|
||||
#error "DD_DEBUG_BREAK not defined by platform!"
|
||||
#endif
|
||||
|
||||
// This only exists for 32bit Windows to specificy callbacks as __stdcall.
|
||||
#if !defined(DD_APIENTRY)
|
||||
#define DD_APIENTRY
|
||||
#endif
|
||||
|
||||
// TODO: remove this and make kDebugLogLevel DD_STATIC_CONST when we use a version of visual studio that supports it
|
||||
#ifdef DD_OPT_LOG_LEVEL
|
||||
#define DD_OPT_LOG_LEVEL_VALUE static_cast<LogLevel>(DD_OPT_LOG_LEVEL)
|
||||
#else
|
||||
#if defined(NDEBUG)
|
||||
// In non-debug builds, default to printing asserts, Error, and Always log messages
|
||||
#define DD_OPT_LOG_LEVEL_VALUE LogLevel::Error
|
||||
#else
|
||||
// In debug builds, default to more messages
|
||||
#define DD_OPT_LOG_LEVEL_VALUE LogLevel::Verbose
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DD_WILL_PRINT(lvl) ((lvl >= DD_OPT_LOG_LEVEL_VALUE) && (lvl < DevDriver::LogLevel::Count))
|
||||
#define DD_PRINT(lvl, ...) DevDriver::LogString<lvl>(__VA_ARGS__)
|
||||
|
||||
#if defined(DD_OPT_ASSERTS_DEBUGBREAK)
|
||||
#define DD_ASSERT_DEBUG_BREAK() DD_DEBUG_BREAK()
|
||||
#else
|
||||
#define DD_ASSERT_DEBUG_BREAK()
|
||||
#endif
|
||||
|
||||
#include <dd_crc32.h>
|
||||
|
||||
// Calling `check_expr_is_bool(x)` when `x` is not exactly a bool will create a compile error.
|
||||
// When it is a bool, it's a no-op.
|
||||
// This allows us to enforce bool arguments to DD_ASSERT() macros
|
||||
namespace DevDriver
|
||||
{
|
||||
inline void check_expr_is_bool(bool) {}
|
||||
|
||||
template <typename T>
|
||||
void check_expr_is_bool(const T&) = delete;
|
||||
}
|
||||
|
||||
#if !defined(DD_OPT_ASSERTS_ENABLE)
|
||||
#define DD_WARN(statement) DD_UNUSED(0)
|
||||
#define DD_WARN_REASON(reason) DD_UNUSED(0)
|
||||
|
||||
#ifndef DD_ASSERT
|
||||
#define DD_ASSERT(statement) DD_UNUSED(0)
|
||||
#endif
|
||||
|
||||
#define DD_ASSERT_REASON(reason) DD_UNUSED(0)
|
||||
#else
|
||||
#define DD_WARN(statement) do \
|
||||
{ \
|
||||
DevDriver::check_expr_is_bool(statement); \
|
||||
if (!(statement)) \
|
||||
{ \
|
||||
DD_PRINT(DevDriver::LogLevel::Warn, "%s (%d): Warning triggered in %s: %s", \
|
||||
DD_FILE, __LINE__, __func__, DD_STRINGIFY(statement)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DD_WARN_REASON(reason) do \
|
||||
{ \
|
||||
DD_PRINT(DevDriver::LogLevel::Warn, "%s (%d): Warning triggered in %s: %s", \
|
||||
DD_FILE, __LINE__, __func__, reason); \
|
||||
} while (0)
|
||||
|
||||
#ifndef DD_ASSERT
|
||||
#define DD_ASSERT(statement) do \
|
||||
{ \
|
||||
DevDriver::check_expr_is_bool(statement); \
|
||||
if (!(statement)) \
|
||||
{ \
|
||||
DD_PRINT(DevDriver::LogLevel::Error, "%s (%d): Assertion failed in %s: %s", \
|
||||
DD_FILE, __LINE__, __func__, DD_STRINGIFY(statement)); \
|
||||
DD_ASSERT_DEBUG_BREAK(); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define DD_ASSERT_REASON(reason) do \
|
||||
{ \
|
||||
DD_PRINT(DevDriver::LogLevel::Error, "%s (%d): Assertion failed in %s: %s", \
|
||||
DD_FILE, __LINE__, __func__, reason); \
|
||||
DD_ASSERT_DEBUG_BREAK(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/// Convenience macro that always warns.
|
||||
#define DD_WARN_ALWAYS() DD_WARN_REASON("Unconditional Warning")
|
||||
|
||||
/// Convenience macro that always asserts.
|
||||
#define DD_ASSERT_ALWAYS() DD_ASSERT_REASON("Unconditional Assertion")
|
||||
|
||||
/// Convenience macro that asserts if something has not been implemented.
|
||||
#define DD_NOT_IMPLEMENTED() DD_ASSERT_REASON("Code not implemented!")
|
||||
|
||||
/// Convenience macro that asserts if an area of code that shouldn't be executed is reached.
|
||||
#define DD_UNREACHABLE() DD_ASSERT_REASON("Unreachable code has been reached!")
|
||||
|
||||
// Backwards compatibility for old alert macro
|
||||
#define DD_ALERT(statement) DD_WARN(statement)
|
||||
#define DD_ALERT_REASON(reason) DD_WARN_REASON(reason)
|
||||
#define DD_ALERT_ALWAYS() DD_WARN_ALWAYS()
|
||||
|
||||
// Debug utility to log an expression
|
||||
//
|
||||
// This works by taking the format specifier for a local variable, and an expression.
|
||||
// The expression is evaluated once.
|
||||
// It then prints that expression and its value:
|
||||
// ```cpp
|
||||
// int x = 5;
|
||||
// int y = 10;
|
||||
// int z = 0xf0;
|
||||
// DD_DBG("0x%x", x + y + z); // Prints: foo/file.cpp:5 "x + y + z" == 0xff
|
||||
// ```
|
||||
#define DD_DBG(level, fmt, expr) DD_PRINT( \
|
||||
level, \
|
||||
"%s:%d:\t\"" DD_STRINGIFY(expr) "\" == " fmt, \
|
||||
DD_FILE, \
|
||||
__LINE__, \
|
||||
(expr) \
|
||||
)
|
||||
|
||||
// Allocates memory using an AllocCb.
|
||||
// This overload is declared noexcept, and will correctly handle AllocCb::pfnAlloc() returning NULL.
|
||||
void* operator new(
|
||||
size_t size,
|
||||
const DevDriver::AllocCb& allocCb,
|
||||
size_t align,
|
||||
bool zero,
|
||||
const char* pFilename,
|
||||
int lineNumber,
|
||||
const char* pFunction
|
||||
) noexcept;
|
||||
|
||||
#if DD_PLATFORM_IS_KM
|
||||
// Provide a placement new function if <new> is not available
|
||||
inline void* operator new(size_t size, void *pMemory)
|
||||
{
|
||||
return pMemory;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Overload of operator delete that matches the previously declared operator new.
|
||||
// The compiler can call this version automatically in the case of exceptions thrown in the Constructor
|
||||
// ... even though we turn them off?
|
||||
// Compilers are fussy.
|
||||
void operator delete(
|
||||
void* pObject,
|
||||
const DevDriver::AllocCb& allocCb,
|
||||
size_t align,
|
||||
bool zero,
|
||||
const char* pFilename,
|
||||
int lineNumber,
|
||||
const char* pFunction
|
||||
) noexcept;
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline void static Destructor(T* p)
|
||||
{
|
||||
if (p != nullptr)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* NewArray(size_t numElements, const AllocCb& allocCb)
|
||||
{
|
||||
size_t allocSize = (sizeof(T) * numElements) + DD_CACHE_LINE_BYTES;
|
||||
size_t allocAlign = DD_CACHE_LINE_BYTES;
|
||||
|
||||
T* pMem = reinterpret_cast<T*>(DD_MALLOC(allocSize, allocAlign, allocCb));
|
||||
if (pMem != nullptr)
|
||||
{
|
||||
pMem = reinterpret_cast<T*>(reinterpret_cast<char*>(pMem) + DD_CACHE_LINE_BYTES);
|
||||
size_t* pNumElements = reinterpret_cast<size_t*>(reinterpret_cast<char*>(pMem) - sizeof(size_t));
|
||||
*pNumElements = numElements;
|
||||
T* pCurrentElement = pMem;
|
||||
for (size_t elementIndex = 0; elementIndex < numElements; ++elementIndex)
|
||||
{
|
||||
new(pCurrentElement) T;
|
||||
++pCurrentElement;
|
||||
}
|
||||
}
|
||||
|
||||
return pMem;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void DeleteArray(T* pElements, const AllocCb& allocCb)
|
||||
{
|
||||
if (pElements != nullptr)
|
||||
{
|
||||
size_t numElements = *reinterpret_cast<size_t*>(reinterpret_cast<char*>(pElements) - sizeof(size_t));
|
||||
T* pCurrentElement = pElements;
|
||||
for (size_t elementIndex = 0; elementIndex < numElements; ++elementIndex)
|
||||
{
|
||||
pCurrentElement->~T();
|
||||
++pCurrentElement;
|
||||
}
|
||||
|
||||
pElements = reinterpret_cast<T*>(reinterpret_cast<char*>(pElements) - DD_CACHE_LINE_BYTES);
|
||||
}
|
||||
|
||||
DD_FREE(pElements, allocCb);
|
||||
}
|
||||
|
||||
// Get the number of elements in a statically sized array
|
||||
// Usage:
|
||||
// char buffer[1024];
|
||||
// size_t size = ArraySize(buffer); // size == 1024
|
||||
//
|
||||
// With a cast:
|
||||
// char buffer[1024];
|
||||
// uint32 size = ArraySize<uint32>(buffer);
|
||||
//
|
||||
template <
|
||||
typename SizeT = size_t, // Type to return
|
||||
typename T, // Inferred type of array elements - you should not need to supply this argument
|
||||
size_t Size // Inferred length of array (in elements) - you should not need to supply this argument
|
||||
>
|
||||
constexpr SizeT ArraySize(const T(&)[Size])
|
||||
{
|
||||
return static_cast<SizeT>(Size);
|
||||
}
|
||||
|
||||
// Log to consoles and attached debuggers
|
||||
void DebugPrint(LogLevel lvl, const char* pFormat, ...);
|
||||
|
||||
// Platform-specific loggers, this is called from DebugPrint.
|
||||
void PlatformDebugPrint(LogLevel lvl, const char* pString);
|
||||
|
||||
/// Get the absolute path to a file or directory that already exists
|
||||
/// If ppAbsPathFilePart is non-NULL, *ppAbsPathFilePart will point into absPath at the beginning of the Filename
|
||||
/// This is recommended to do whenever you need to display a path to a user.
|
||||
Result GetAbsPathName(
|
||||
const char* pPath,
|
||||
char (&absPath)[256]
|
||||
);
|
||||
|
||||
/* platform functions for performing atomic operations */
|
||||
|
||||
int32 AtomicIncrement(Atomic* pVariable);
|
||||
int32 AtomicDecrement(Atomic* pVariable);
|
||||
int32 AtomicAdd(Atomic* pVariable, int32 num);
|
||||
int32 AtomicSubtract(Atomic* pVariable, int32 num);
|
||||
|
||||
int64 AtomicIncrement(Atomic64* pVariable);
|
||||
int64 AtomicDecrement(Atomic64* pVariable);
|
||||
int64 AtomicAdd(Atomic64* pVariable, int64 num);
|
||||
int64 AtomicSubtract(Atomic64* pVariable, int64 num);
|
||||
|
||||
// A generic AllocCb that defers allocation to Platform::AllocateMemory()
|
||||
// Suitable for memory allocation if you don't care about it.
|
||||
extern AllocCb GenericAllocCb;
|
||||
|
||||
void* AllocateMemory(size_t size, size_t alignment, bool zero);
|
||||
void FreeMemory(void* pMemory);
|
||||
|
||||
/* fast locks */
|
||||
class AtomicLock
|
||||
{
|
||||
public:
|
||||
AtomicLock() : m_lock(0) {};
|
||||
~AtomicLock() {};
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
bool IsLocked() { return (m_lock != 0); };
|
||||
private:
|
||||
Atomic m_lock;
|
||||
};
|
||||
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
private:
|
||||
MutexStorage m_mutex;
|
||||
};
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
explicit Semaphore(uint32 initialCount, uint32 maxCount);
|
||||
~Semaphore();
|
||||
Result Signal();
|
||||
Result Wait(uint32 millisecTimeout);
|
||||
private:
|
||||
SemaphoreStorage m_semaphore;
|
||||
};
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
explicit Event(bool signaled);
|
||||
~Event();
|
||||
void Clear();
|
||||
void Signal();
|
||||
Result Wait(uint32 timeoutInMs);
|
||||
private:
|
||||
EventStorage m_event;
|
||||
};
|
||||
|
||||
class Thread
|
||||
{
|
||||
public:
|
||||
Thread() = default;
|
||||
|
||||
Thread(Thread&& other) noexcept = default;
|
||||
Thread& operator=(Thread&& other) noexcept = default;
|
||||
|
||||
// Copying a thread doesn't make sense
|
||||
Thread(const Thread&) = delete;
|
||||
Thread& operator= (const Thread& other) = delete;
|
||||
|
||||
~Thread();
|
||||
|
||||
Result Start(ThreadFunction pFnThreadFunc, void* pThreadParameter);
|
||||
|
||||
// Set the user-visible name for the thread using printf-style formatters
|
||||
// This should only be called on valid thread objects. (Threads that have been started)
|
||||
// This function will return Result::Error if it's called on an invalid thread.
|
||||
// Note: This change is global to the thread and can be changed by other means
|
||||
// Treat this as an aid for people
|
||||
Result SetName(const char* pFmt, ...);
|
||||
|
||||
Result Join(uint32 timeoutInMs);
|
||||
|
||||
bool IsJoinable() const;
|
||||
|
||||
private:
|
||||
static ThreadReturnType DD_APIENTRY ThreadShim(void* pShimParam);
|
||||
|
||||
// Reset our object to a default state
|
||||
void Reset()
|
||||
{
|
||||
pFnFunction = nullptr;
|
||||
pParameter = nullptr;
|
||||
hThread = kInvalidThreadHandle;
|
||||
|
||||
onExit.Clear();
|
||||
}
|
||||
|
||||
// Set the thread name to a hard-coded string.
|
||||
// The thread name passed to this function must be no larger than kThreadNameMaxLength including the NULL byte.
|
||||
// If a larger string is passed, errors may occur on some platforms.
|
||||
Result SetNameRaw(const char* pThreadName);
|
||||
|
||||
ThreadFunction pFnFunction = nullptr;
|
||||
void* pParameter = nullptr;
|
||||
ThreadHandle hThread = kInvalidThreadHandle;
|
||||
Event onExit = Event(false); // Start unsignaled
|
||||
};
|
||||
|
||||
class Random
|
||||
{
|
||||
public:
|
||||
// Algorithm Constants
|
||||
static constexpr uint64 kModulus = (uint64(1) << 48);
|
||||
static constexpr uint64 kMultiplier = 0X5DEECE66Dull;
|
||||
static constexpr uint16 kIncrement = 0xB;
|
||||
|
||||
Random();
|
||||
Random(uint64 seed)
|
||||
{
|
||||
Reseed(seed);
|
||||
}
|
||||
~Random() {}
|
||||
|
||||
uint32 Generate();
|
||||
void Reseed(uint64 seed);
|
||||
private:
|
||||
uint64 m_prevState = 0;
|
||||
|
||||
// Sanity checks.
|
||||
static_assert(0 < kModulus, "Invalid modulus");
|
||||
static_assert(0 < kMultiplier, "Invalid multiplier");
|
||||
static_assert(kMultiplier < kModulus, "Invalid multiplier");
|
||||
static_assert(kIncrement < kModulus, "Invalid increment");
|
||||
};
|
||||
|
||||
class Library
|
||||
{
|
||||
public:
|
||||
Library() : m_hLib(nullptr) { }
|
||||
~Library() { Close(); }
|
||||
|
||||
Result Load(const char* pLibraryName);
|
||||
|
||||
void Close();
|
||||
|
||||
bool IsLoaded() const { return (m_hLib != nullptr); }
|
||||
|
||||
void Swap(Library* pLibrary)
|
||||
{
|
||||
m_hLib = pLibrary->m_hLib;
|
||||
pLibrary->m_hLib = nullptr;
|
||||
}
|
||||
|
||||
// Retrieve a function address from the dynamic library object. Returns true if successful, false otherwise.
|
||||
template <typename Func_t>
|
||||
bool GetFunction(const char* pName, Func_t* ppfnFunc) const
|
||||
{
|
||||
(*ppfnFunc) = reinterpret_cast<Func_t>(GetFunctionHelper(pName));
|
||||
return ((*ppfnFunc) != nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
void* GetFunctionHelper(const char* pName) const;
|
||||
|
||||
LibraryHandle m_hLib;
|
||||
|
||||
DD_DISALLOW_COPY_AND_ASSIGN(Library);
|
||||
};
|
||||
|
||||
enum struct MkdirStatus
|
||||
{
|
||||
Unknown,
|
||||
Created,
|
||||
Existed,
|
||||
};
|
||||
|
||||
// Create a directory with default permissions
|
||||
// On Windows, this uses NULL for LPSECURITY_ATTRIBUTES
|
||||
// On Unix, this uses 0777 for the mode.
|
||||
// When pStatus is non-NULL, *pStatus is set to
|
||||
// MkdirStatus::Created if the directory did not exist and was created
|
||||
// MkdirStatus::Existed if the directory already existed
|
||||
// Returns:
|
||||
// - Result::Success, if the directory already exists or was created
|
||||
// - Result::FileIoError, if the directory failed to be created
|
||||
Result Mkdir(const char* pDir, MkdirStatus* pStatus = nullptr);
|
||||
|
||||
ProcessId GetProcessId();
|
||||
|
||||
uint64 GetCurrentTimeInMs();
|
||||
|
||||
uint64 QueryTimestampFrequency();
|
||||
uint64 QueryTimestamp();
|
||||
|
||||
// Todo: Remove Sleep() entirely from our platform API. It cannot be used in the KMD and should not be used
|
||||
// anywhere else either.
|
||||
void Sleep(uint32 millisecTimeout);
|
||||
|
||||
void GetProcessName(char* buffer, size_t bufferSize);
|
||||
|
||||
void Strncpy(char* pDst, const char* pSrc, size_t dstSize);
|
||||
|
||||
template <size_t DstSize>
|
||||
void Strncpy(char(&dst)[DstSize], const char* pSrc)
|
||||
{
|
||||
Strncpy(dst, pSrc, DstSize);
|
||||
}
|
||||
|
||||
char* Strtok(char* pDst, const char* pDelimiter, char** ppContext);
|
||||
|
||||
void Strncat(char* pDst, const char* pSrc, size_t dstSize);
|
||||
|
||||
template <size_t DstSize>
|
||||
void Strncat(char(&dst)[DstSize], const char* pSrc)
|
||||
{
|
||||
Strncat(dst, pSrc, DstSize);
|
||||
}
|
||||
|
||||
int32 Strcmpi(const char* pSrc1, const char* pSrc2);
|
||||
|
||||
int32 Snprintf(char* pDst, size_t dstSize, const char* pFormat, ...);
|
||||
int32 Vsnprintf(char* pDst, size_t dstSize, const char* pFormat, va_list args);
|
||||
|
||||
template <size_t DstSize, typename... Args>
|
||||
int32 Snprintf(char(&dst)[DstSize], const char* pFormat, Args&&... args)
|
||||
{
|
||||
return Snprintf(dst, DstSize, pFormat, args...);
|
||||
}
|
||||
|
||||
struct OsInfo
|
||||
{
|
||||
DD_STATIC_CONST const char* kOsTypeWindows = "Windows";
|
||||
DD_STATIC_CONST const char* kOsTypeLinux = "Linux";
|
||||
DD_STATIC_CONST const char* kOsTypeDarwin = "Darwin";
|
||||
|
||||
char type[16]; /// The type of the OS, either "Windows", "Linux", or "Darwin".
|
||||
|
||||
char name[32]; /// A human-readable string to identify the version of the OS running
|
||||
char description[256]; /// A human-readable string to identify the detailed version of the OS running
|
||||
char hostname[128]; /// The hostname for the machine
|
||||
|
||||
struct UserInfo {
|
||||
char name[32]; /// Username for the current user
|
||||
char homeDir[128]; /// Path to the current user's home directory
|
||||
//< This is typically stored in $HOME or %HOMEPATH% and looks like one of:
|
||||
//< C:\Users\BobMarley
|
||||
//< /home/bob_ross
|
||||
//< /Users/BobTheBuilder
|
||||
} user;
|
||||
|
||||
uint64 physMemory; /// Total amount of memory available on host in bytes
|
||||
uint64 swapMemory; /// Total amount of swap memory available on host in bytes
|
||||
};
|
||||
|
||||
Result QueryOsInfo(OsInfo* pInfo);
|
||||
|
||||
struct EtwSupportInfo
|
||||
{
|
||||
bool isSupported; ///< If true, indicates that the OS platform supports system monitoring, false otherwise.
|
||||
bool hasPermission; ///< If true, indicates the account has the required permissions, false otherwise.
|
||||
uint32 statusCode; ///< The status result returned when attempting to open a monitoring session.
|
||||
char statusDescription[256]; ///< The textual status result returned when attempting to open a monitoring.
|
||||
};
|
||||
|
||||
Result QueryEtwInfo(EtwSupportInfo* pInfo);
|
||||
|
||||
} // Platform
|
||||
|
||||
#ifndef DD_PRINT_FUNC
|
||||
#define DD_PRINT_FUNC Platform::DebugPrint
|
||||
#else
|
||||
void DD_PRINT_FUNC(LogLevel logLevel, const char* format, ...);
|
||||
#endif
|
||||
|
||||
template <LogLevel logLevel = LogLevel::Info, class ...Ts>
|
||||
inline void LogString(const char *format, Ts&&... args)
|
||||
{
|
||||
if (DD_WILL_PRINT(logLevel))
|
||||
{
|
||||
DD_PRINT_FUNC(logLevel, format, Platform::Forward<Ts>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// Increments a const pointer by numBytes by first casting it to a const uint8*.
|
||||
DD_NODISCARD
|
||||
constexpr const void* VoidPtrInc(
|
||||
const void* pPtr,
|
||||
size_t numBytes)
|
||||
{
|
||||
return (static_cast<const uint8*>(pPtr) + numBytes);
|
||||
}
|
||||
|
||||
// Increments a pointer by numBytes by first casting it to a uint8*.
|
||||
DD_NODISCARD
|
||||
constexpr void* VoidPtrInc(
|
||||
void* pPtr,
|
||||
size_t numBytes)
|
||||
{
|
||||
return (static_cast<uint8*>(pPtr) + numBytes);
|
||||
}
|
||||
|
||||
// Decrements a const pointer by numBytes by first casting it to a const uint8*.
|
||||
DD_NODISCARD
|
||||
constexpr const void* VoidPtrDec(
|
||||
const void* pPtr,
|
||||
size_t numBytes)
|
||||
{
|
||||
return (static_cast<const uint8*>(pPtr) - numBytes);
|
||||
}
|
||||
|
||||
// Decrements a pointer by numBytes by first casting it to a uint8*.
|
||||
DD_NODISCARD
|
||||
constexpr void* VoidPtrDec(
|
||||
void* pPtr,
|
||||
size_t numBytes)
|
||||
{
|
||||
return (static_cast<uint8*>(pPtr) - numBytes);
|
||||
}
|
||||
|
||||
/// Convert a `DevDriver::Result` into a human recognizable string.
|
||||
static inline const char* ResultToString(Result result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
//// Generic Result Code ////
|
||||
case Result::Success: return "Success";
|
||||
case Result::Error: return "Error";
|
||||
case Result::NotReady: return "NotReady";
|
||||
case Result::VersionMismatch: return "VersionMismatch";
|
||||
case Result::Unavailable: return "Unavailable";
|
||||
case Result::Rejected: return "Rejected";
|
||||
case Result::EndOfStream: return "EndOfStream";
|
||||
case Result::Aborted: return "Aborted";
|
||||
case Result::InsufficientMemory: return "InsufficientMemory";
|
||||
case Result::InvalidParameter: return "InvalidParameter";
|
||||
case Result::InvalidClientId: return "InvalidClientId";
|
||||
case Result::ConnectionExists: return "ConnectionExists";
|
||||
case Result::FileNotFound: return "FileNotFound";
|
||||
case Result::FunctionNotFound: return "FunctionNotFound";
|
||||
case Result::InterfaceNotFound: return "InterfaceNotFound";
|
||||
case Result::EntryExists: return "EntryExists";
|
||||
case Result::FileAccessError: return "FileAccessError";
|
||||
case Result::FileIoError: return "FileIoError";
|
||||
case Result::LimitReached: return "LimitReached";
|
||||
case Result::MemoryOverLimit: return "MemoryOverLimit";
|
||||
|
||||
//// URI PROTOCOL ////
|
||||
case Result::UriServiceRegistrationError: return "UriServiceRegistrationError";
|
||||
case Result::UriStringParseError: return "UriStringParseError";
|
||||
case Result::UriInvalidParameters: return "UriInvalidParameters";
|
||||
case Result::UriInvalidPostDataBlock: return "UriInvalidPostDataBlock";
|
||||
case Result::UriInvalidPostDataSize: return "UriInvalidPostDataSize";
|
||||
case Result::UriFailedToAcquirePostBlock: return "UriFailedToAcquirePostBlock";
|
||||
case Result::UriFailedToOpenResponseBlock: return "UriFailedToOpenResponseBlock";
|
||||
case Result::UriRequestFailed: return "UriRequestFailed";
|
||||
case Result::UriPendingRequestError: return "UriPendingRequestError";
|
||||
case Result::UriInvalidChar: return "UriInvalidChar";
|
||||
case Result::UriInvalidJson: return "UriInvalidJson";
|
||||
|
||||
//// Settings URI Service ////
|
||||
case Result::SettingsUriInvalidComponent: return "SettingsUriInvalidComponent";
|
||||
case Result::SettingsUriInvalidSettingName: return "SettingsUriInvalidSettingName";
|
||||
case Result::SettingsUriInvalidSettingValue: return "SettingsUriInvalidSettingValue";
|
||||
case Result::SettingsUriInvalidSettingValueSize: return "SettingsUriInvalidSettingValueSize";
|
||||
|
||||
//// Info URI Service ////
|
||||
case Result::InfoUriSourceNameInvalid: return "InfoUriSourceNameInvalid";
|
||||
case Result::InfoUriSourceCallbackInvalid: return "InfoUriSourceCallbackInvalid";
|
||||
case Result::InfoUriSourceAlreadyRegistered: return "InfoUriSourceAlreadyRegistered";
|
||||
case Result::InfoUriSourceWriteFailed: return "InfoUriSourceWriteFailed";
|
||||
|
||||
//// Settings Service ////
|
||||
case Result::SettingsInvalidComponent: return "SettingsInvalidComponent";
|
||||
case Result::SettingsInvalidSettingName: return "SettingsInvalidSettingName";
|
||||
case Result::SettingsInvalidSettingValue: return "SettingsInvalidSettingValue";
|
||||
case Result::SettingsInsufficientValueSize: return "SettingsInsufficientValueSize";
|
||||
case Result::SettingsInvalidSettingValueSize: return "SettingsInvalidSettingValueSize";
|
||||
}
|
||||
|
||||
DD_PRINT(LogLevel::Warn, "Result code %u is not handled", static_cast<uint32>(result));
|
||||
return "Unrecognized DevDriver::Result";
|
||||
}
|
||||
|
||||
// Helper function for converting bool values into Result enums
|
||||
// Useful for cases where Results and bools are interleaved in logic
|
||||
static inline Result BoolToResult(bool value)
|
||||
{
|
||||
return (value ? Result::Success : Result::Error);
|
||||
}
|
||||
|
||||
// Use this macro to mark Result values that have not been or cannot be handled correctly.
|
||||
#define DD_UNHANDLED_RESULT(x) DevDriver::MarkUnhandledResultImpl((x), DD_STRINGIFY(x), DD_FILE, __LINE__, __func__)
|
||||
|
||||
// Implementation for DD_UNHANDLED_RESULT.
|
||||
// This is a specialized assert that should be used through the macro, and not called directly.
|
||||
// This is implemented in ddPlatform.h, so that it has access to DD_ASSERT.
|
||||
static inline void MarkUnhandledResultImpl(
|
||||
Result result,
|
||||
const char* pExpr,
|
||||
const char* pFile,
|
||||
int lineNumber,
|
||||
const char* pFunc)
|
||||
{
|
||||
#if defined(DD_OPT_ASSERTS_ENABLE)
|
||||
if (result != Result::Success)
|
||||
{
|
||||
DD_PRINT(DevDriver::LogLevel::Error,
|
||||
"%s (%d): Unchecked Result in %s: \"%s\" == \"%s\" (0x%X)\n",
|
||||
pFile,
|
||||
lineNumber,
|
||||
pFunc,
|
||||
pExpr,
|
||||
ResultToString(result),
|
||||
result);
|
||||
}
|
||||
#else
|
||||
DD_UNUSED(result);
|
||||
DD_UNUSED(pExpr);
|
||||
DD_UNUSED(pFile);
|
||||
DD_UNUSED(lineNumber);
|
||||
DD_UNUSED(pFunc);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // DevDriver
|
||||
+378
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
/// Templated LockGuard class. Works with any type that implements Lock() and Unlock()
|
||||
template <typename T>
|
||||
class LockGuard
|
||||
{
|
||||
public:
|
||||
explicit LockGuard(T &lock) : m_lock(lock) { lock.Lock(); }
|
||||
~LockGuard() { m_lock.Unlock(); }
|
||||
private:
|
||||
T &m_lock;
|
||||
};
|
||||
|
||||
/// Computes the base-2 logarithm of an unsigned 64-bit integer.
|
||||
///
|
||||
/// If the given integer is not a power of 2, this function will not provide an exact answer.
|
||||
///
|
||||
/// @returns log_2(u)
|
||||
template<typename T>
|
||||
inline uint32 Log2(T u) ///< Value to compute the logarithm of.
|
||||
{
|
||||
uint32 logValue = 0;
|
||||
|
||||
while (u > 1)
|
||||
{
|
||||
++logValue;
|
||||
u >>= 1;
|
||||
}
|
||||
return logValue;
|
||||
}
|
||||
|
||||
/// Computes the base-2 logarithm of an unsigned 64-bit integer.
|
||||
///
|
||||
/// If the given integer is not a power of 2, this function will not provide an exact answer.
|
||||
///
|
||||
/// @returns log_2(u)
|
||||
template<typename T>
|
||||
inline constexpr uint32 _ConstLog2(T u, uint32 logValue) ///< Value to compute the logarithm of.
|
||||
{
|
||||
return (u > 1) ? _ConstLog2(u >> 1, logValue + 1) : logValue;
|
||||
}
|
||||
|
||||
/// Computes the base-2 logarithm of an unsigned 64-bit integer.
|
||||
///
|
||||
/// If the given integer is not a power of 2, this function will not provide an exact answer.
|
||||
///
|
||||
/// @returns log_2(u)
|
||||
template<typename T>
|
||||
inline constexpr uint32 ConstLog2(T u) ///< Value to compute the logarithm of.
|
||||
{
|
||||
return _ConstLog2(u, 0);
|
||||
}
|
||||
|
||||
static_assert(ConstLog2(1) == 0, "ConstLog2 failure");
|
||||
static_assert(ConstLog2(2) == 1, "ConstLog2 failure");
|
||||
static_assert(ConstLog2(128) == 7, "ConstLog2 failure");
|
||||
static_assert(ConstLog2(255) == 7, "ConstLog2 failure");
|
||||
|
||||
/// Computes 2 ^ value provided
|
||||
///
|
||||
/// @returns 2 ^ (u)
|
||||
template<typename T>
|
||||
inline constexpr T Pow2(T u)
|
||||
{
|
||||
return ((T)1 << u);
|
||||
}
|
||||
|
||||
static_assert(Pow2(0) == 1, "Pow2 failure");
|
||||
static_assert(Pow2(1) == 2, "Pow2 failure");
|
||||
static_assert(Pow2(7) == 128, "Pow2 failure");
|
||||
|
||||
/// Determines if a value is a power of two.
|
||||
///
|
||||
/// @returns True if it is a power of two, false otherwise.
|
||||
inline constexpr bool IsPowerOfTwo(uint64 value)
|
||||
{
|
||||
return (value == 0) ? false : ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
/// Rounds the specified uint 'value' up to the nearest value meeting the specified 'alignment'. Only power of 2
|
||||
/// alignments are supported by this function.
|
||||
///
|
||||
/// returns Aligned value.
|
||||
template<typename T>
|
||||
inline constexpr T Pow2Align(
|
||||
T value, ///< Value to align.
|
||||
uint64 alignment) ///< Desired alignment (must be a power of 2).
|
||||
{
|
||||
return ((value + static_cast<T>(alignment) - 1) & ~(static_cast<T>(alignment) - 1));
|
||||
}
|
||||
|
||||
/// Rounds the specified uint 'value' up to the nearest power of 2
|
||||
///
|
||||
/// @returns Power of 2 padded value.
|
||||
template<typename T>
|
||||
inline T Pow2Pad(T value) ///< Value to pad.
|
||||
{
|
||||
T ret = 1;
|
||||
if (IsPowerOfTwo(value))
|
||||
{
|
||||
ret = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ret < value)
|
||||
{
|
||||
ret <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Rounds the specified uint 'value' up to the nearest power of 2. Constexpr varient.
|
||||
///
|
||||
/// @returns Power of 2 padded value.
|
||||
template<typename T>
|
||||
inline constexpr T _ConstPow2Pad(T value, T padded) ///< Value to pad.
|
||||
{
|
||||
return (padded < value) ? _ConstPow2Pad(value, padded << 1) : padded;
|
||||
}
|
||||
|
||||
/// Rounds the specified uint 'value' up to the nearest power of 2. Constexpr varient.
|
||||
///
|
||||
/// @returns Power of 2 padded value.
|
||||
template<typename T>
|
||||
inline constexpr T ConstPow2Pad(T value) ///< Value to pad.
|
||||
{
|
||||
return (IsPowerOfTwo(value)) ? value : _ConstPow2Pad(value, (T)1);
|
||||
}
|
||||
|
||||
static_assert(ConstPow2Pad(512) == 512, "ConstPow2Pad failure");
|
||||
static_assert(ConstPow2Pad(511) == 512, "ConstPow2Pad failure");
|
||||
static_assert(ConstPow2Pad(257) == 512, "ConstPow2Pad failure");
|
||||
|
||||
/// Finds the smallest of two values
|
||||
///
|
||||
/// @returns a if a < b, otherwise b.
|
||||
template <typename T>
|
||||
inline constexpr T Min(const T &a, const T &b)
|
||||
{
|
||||
return ((a < b) ? a : b);
|
||||
}
|
||||
|
||||
/// Finds the larger of two values
|
||||
///
|
||||
/// @returns a if a > b, otherwise b.
|
||||
template <typename T>
|
||||
inline constexpr T Max(const T &a, const T &b)
|
||||
{
|
||||
return ((a > b) ? a : b);
|
||||
}
|
||||
|
||||
// Given a type T, set Type equal to T
|
||||
template <typename T>
|
||||
struct RemoveRef
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
// Given a type T&, set Type equal to T
|
||||
template <typename T>
|
||||
struct RemoveRef<T &>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
// Given a type T&&, set Type equal to T
|
||||
template <typename T>
|
||||
struct RemoveRef<T &&>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
// std::move equivalent
|
||||
template <typename T>
|
||||
inline typename RemoveRef<T>::Type&& Move(T&& obj)
|
||||
{
|
||||
return static_cast<typename RemoveRef<T>::Type&&>(obj);
|
||||
}
|
||||
|
||||
// std::forward equivalent
|
||||
template <typename T>
|
||||
inline T&& Forward(typename RemoveRef<T>::Type&& args)
|
||||
{
|
||||
return static_cast<T&&>(args);
|
||||
}
|
||||
|
||||
// std::forward equivalent
|
||||
template <typename T>
|
||||
inline T&& Forward(typename RemoveRef<T>::Type& args)
|
||||
{
|
||||
return static_cast<T&&>(args);
|
||||
}
|
||||
|
||||
// Returns the contents of Value in a new variable, and assign newValue into the memory occupied by value.
|
||||
template <typename T, typename U = T>
|
||||
inline T Exchange(T& value, U&& newValue)
|
||||
{
|
||||
T oldValue = Move(value);
|
||||
value = Forward<U>(newValue);
|
||||
return (oldValue);
|
||||
}
|
||||
|
||||
// Convenience structure that defined Value as either true or false, and Type as either TrueType or FalseType
|
||||
template <bool value>
|
||||
struct BoolType
|
||||
{
|
||||
static const bool Value = value;
|
||||
using Type = BoolType<value>;
|
||||
};
|
||||
|
||||
using FalseType = BoolType<false>;
|
||||
using TrueType = BoolType<true>;
|
||||
|
||||
// Struct whose ::Type member is undefined if the first condition is not true
|
||||
template<bool Enable,
|
||||
class Type = void>
|
||||
struct EnableIf
|
||||
{
|
||||
};
|
||||
|
||||
// Struct whose ::Type member is equal to T if the first condition is true.
|
||||
template<class T>
|
||||
struct EnableIf<true, T>
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct IsPointer : FalseType
|
||||
{
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct IsPointer<T*> : TrueType
|
||||
{
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// If we are building with MSVC we want to use the compiler intrinsics here. This is primarily because building with
|
||||
// the /kernel precludes the use of the C++ type traits library. For all other compilers we simply implement this
|
||||
// using the standard C++ library.
|
||||
|
||||
// Struct whose ::Value member is equal to true if you can cast from T to U, and false otherwise.
|
||||
template <class T, class U>
|
||||
struct IsConvertible : BoolType<__is_convertible_to(T, U)>
|
||||
{
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if you can construct an object of type T using the arguments
|
||||
// provided.
|
||||
template<typename T, typename... Args>
|
||||
struct IsConstructible : BoolType<__is_constructible(T, Args...)>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an abstract class, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsAbstract : BoolType<__is_abstract(T)>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an abstract class, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsPod : BoolType<__is_pod(T)>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is has a standard layout, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsStandardLayout : BoolType<__is_standard_layout(T)>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is trivially destructable, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsTriviallyDestructible : BoolType<__is_trivially_destructible(T)>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an enumeration type, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsEnum : BoolType<__is_enum(T)>
|
||||
{
|
||||
|
||||
};
|
||||
#else
|
||||
// Struct whose ::Value member is equal to true if you can cast from T to U, and false otherwise.
|
||||
template <class T, class U>
|
||||
struct IsConvertible : BoolType<std::is_convertible<T, U>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if you can construct an object of type T using the arguments
|
||||
// provided.
|
||||
template<typename T, typename... Args>
|
||||
struct IsConstructible : BoolType<std::is_constructible<T, Args...>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an abstract class, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsAbstract : BoolType<std::is_abstract<T>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an abstract class, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsPod : BoolType<std::is_trivial<T>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is has a standard layout, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsStandardLayout : BoolType<std::is_standard_layout<T>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is trivially destructable, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsTriviallyDestructible : BoolType<std::is_trivially_destructible<T>::value>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// Struct whose ::Value member is equal to true if T is an enumeration type, and false otherwise.
|
||||
template<typename T>
|
||||
struct IsEnum : BoolType<std::is_enum<T>::value>
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
}
|
||||
} // DevDriver
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#if defined(_KERNEL_MODE)
|
||||
static_assert(false, "This header is for user mode windows, and it does not work in kernel mode.");
|
||||
#endif
|
||||
|
||||
// Our code expects these defined before including Windows.h.
|
||||
// However, we need to guard against clients defining them too.
|
||||
#ifndef _CRT_RAND_S
|
||||
#define _CRT_RAND_S
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
// WIN32_NO_STATUS makes Windows.h not include macro definitions from winnt.h
|
||||
// which collide with those from ntstatus.h. This avoids compilation errors
|
||||
// when other files that include ntstatus.h also include this file.
|
||||
#define WIN32_NO_STATUS
|
||||
#include <Windows.h>
|
||||
#undef WIN32_NO_STATUS
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#define DD_RESTRICT __restrict
|
||||
|
||||
#define DD_DEBUG_BREAK() __debugbreak()
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace Platform
|
||||
{
|
||||
/* platform functions for performing atomic operations */
|
||||
typedef volatile LONG Atomic;
|
||||
DD_CHECK_SIZE(Atomic, sizeof(int32));
|
||||
|
||||
typedef volatile LONG64 Atomic64;
|
||||
DD_CHECK_SIZE(Atomic64, sizeof(int64));
|
||||
|
||||
struct EmptyStruct {};
|
||||
|
||||
struct MutexStorage
|
||||
{
|
||||
CRITICAL_SECTION criticalSection;
|
||||
#if !defined(NDEBUG)
|
||||
Atomic lockCount;
|
||||
#endif
|
||||
};
|
||||
typedef Handle SemaphoreStorage;
|
||||
typedef HANDLE EventStorage;
|
||||
typedef HANDLE ThreadHandle;
|
||||
typedef DWORD ThreadReturnType;
|
||||
typedef HMODULE LibraryHandle;
|
||||
|
||||
constexpr ThreadHandle kInvalidThreadHandle = NULL;
|
||||
|
||||
// Maximum supported size for thread names, including NULL byte
|
||||
// This exists because some platforms have hard limits on thread name size.
|
||||
// Windows doesn't seem to have a thread name size limit, but we use this variable to control
|
||||
// a formatting buffer as well and we want to keep it reasonably small since it's stack allocated.
|
||||
static constexpr size_t kThreadNameMaxLength = 64;
|
||||
|
||||
#define DD_APIENTRY APIENTRY
|
||||
|
||||
namespace Windows
|
||||
{
|
||||
// Windows specific functions required for in-memory communication
|
||||
Handle CreateSharedSemaphore(uint32 initialCount, uint32 maxCount);
|
||||
Handle CopySemaphoreFromProcess(ProcessId processId, Handle hObject);
|
||||
Result SignalSharedSemaphore(Handle pSemaphore);
|
||||
Result WaitSharedSemaphore(Handle pSemaphore, uint32 millisecTimeout);
|
||||
void CloseSharedSemaphore(Handle pSemaphore);
|
||||
|
||||
Handle CreateSharedBuffer(Size bufferSizeInBytes);
|
||||
void CloseSharedBuffer(Handle hSharedBuffer);
|
||||
|
||||
Handle MapSystemBufferView(Handle hBuffer, Size bufferSizeInBytes);
|
||||
Handle MapProcessBufferView(Handle hBuffer, ProcessId processId);
|
||||
void UnmapBufferView(Handle hSharedBuffer, Handle hSharedBufferView);
|
||||
|
||||
// Whether or not the user has enabled Windows Developer Mode on their system
|
||||
// See: https://github.com/MicrosoftDocs/windows-uwp/blob/docs/hub/apps/get-started/enable-your-device-for-development.md
|
||||
bool IsWin10DeveloperModeEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "protocolServer.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IMsgChannel;
|
||||
|
||||
class BaseProtocolServer : public IProtocolServer
|
||||
{
|
||||
public:
|
||||
virtual ~BaseProtocolServer();
|
||||
|
||||
Protocol GetProtocol() const override final { return m_protocol; };
|
||||
SessionType GetType() const override final { return SessionType::Server; };
|
||||
Version GetMinVersion() const override final { return m_minVersion; };
|
||||
Version GetMaxVersion() const override final { return m_maxVersion; };
|
||||
|
||||
bool GetSupportedVersion(Version minVersion, Version maxVersion, Version * version) const override final;
|
||||
|
||||
virtual void Finalize() override;
|
||||
protected:
|
||||
BaseProtocolServer(IMsgChannel* pMsgChannel, Protocol protocol, Version minVersion, Version maxVersion);
|
||||
|
||||
// Helper functions for working with SizedPayloadContainers
|
||||
Result SendPayload(ISession* pSession, const SizedPayloadContainer* pPayload, uint32 timeoutInMs);
|
||||
Result ReceivePayload(ISession* pSession, SizedPayloadContainer* pPayload, uint32 timeoutInMs);
|
||||
|
||||
IMsgChannel* const m_pMsgChannel;
|
||||
const Protocol m_protocol;
|
||||
const Version m_minVersion;
|
||||
const Version m_maxVersion;
|
||||
|
||||
bool m_isFinalized;
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../core/inc/ddcDefs.h"
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DD_PLATFORM_WINDOWS_UM
|
||||
#if _WIN32 && !_KERNEL_MODE
|
||||
#define DD_PLATFORM_WINDOWS_UM 1
|
||||
#define DD_PLATFORM_IS_UM 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DD_PLATFORM_WINDOWS_KM
|
||||
#if _WIN32 && _KERNEL_MODE
|
||||
#define DD_PLATFORM_WINDOWS_KM 1
|
||||
#define DD_PLATFORM_IS_KM 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DD_PLATFORM_LINUX_UM
|
||||
#ifdef __linux__
|
||||
#define DD_PLATFORM_LINUX_UM 1
|
||||
#define DD_PLATFORM_IS_UM 1
|
||||
#define DD_PLATFORM_IS_GNU 1
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../core/inc/ddcPlatform.h"
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../core/inc/ddcTemplate.h"
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
#include "ddPlatform.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace TransferProtocol
|
||||
{
|
||||
class ServerBlock;
|
||||
}
|
||||
|
||||
// The maximum allowed name for a service name
|
||||
DD_STATIC_CONST size_t kMaxUriServiceNameLength = 128;
|
||||
|
||||
enum struct URIDataFormat : uint32
|
||||
{
|
||||
Unknown = 0,
|
||||
Text,
|
||||
Binary,
|
||||
Count
|
||||
};
|
||||
|
||||
// An interface to write bytes.
|
||||
class IByteWriter
|
||||
{
|
||||
protected:
|
||||
virtual ~IByteWriter() {}
|
||||
|
||||
public:
|
||||
// Finish all writing and return the last error.
|
||||
virtual Result End() = 0;
|
||||
|
||||
// Write exactly `length` bytes.
|
||||
virtual void WriteBytes(const void* pBytes, size_t length) = 0;
|
||||
|
||||
// Write a value as a byte array.
|
||||
// N.B.: Be mindful of your struct's implicit padding!
|
||||
template <typename T>
|
||||
void Write(const T& value)
|
||||
{
|
||||
static_assert(!Platform::IsPointer<T>::Value, "Writing a pointer is likely an error. Cast to an integer type if you mean it.");
|
||||
WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
};
|
||||
|
||||
// An interface to write and validate text.
|
||||
class ITextWriter
|
||||
{
|
||||
protected:
|
||||
virtual ~ITextWriter() {}
|
||||
|
||||
public:
|
||||
// Finish all writing and return the last error.
|
||||
virtual Result End() = 0;
|
||||
|
||||
// Write formatted text.
|
||||
// Try and only pass string literals as `pFmt`. Prefer: Write("%s", myGeneratedBuffer);
|
||||
virtual void Write(const char* pFmt, ...) = 0;
|
||||
|
||||
// Write specific types
|
||||
virtual void Write(uint64 value) = 0;
|
||||
virtual void Write(uint32 value) = 0;
|
||||
virtual void Write(uint16 value) = 0;
|
||||
virtual void Write(uint8 value) = 0;
|
||||
virtual void Write(int64 value) = 0;
|
||||
virtual void Write(int32 value) = 0;
|
||||
virtual void Write(int16 value) = 0;
|
||||
virtual void Write(double value) = 0;
|
||||
virtual void Write(float value) = 0;
|
||||
virtual void Write(bool value) = 0;
|
||||
virtual void Write(char value) = 0;
|
||||
};
|
||||
|
||||
// An interface to write and validate structured data - e.g. json or message pack
|
||||
class IStructuredWriter
|
||||
{
|
||||
protected:
|
||||
virtual ~IStructuredWriter() {}
|
||||
|
||||
public:
|
||||
// Finish all writing and return the last error.
|
||||
virtual Result End() = 0;
|
||||
|
||||
// Structured data is often nullable.
|
||||
// Write a "null" value.
|
||||
virtual void ValueNull() = 0;
|
||||
|
||||
// ===== Collection Writers ====================================================================================
|
||||
|
||||
// Begin writing a new list collection.
|
||||
virtual void BeginList() = 0;
|
||||
|
||||
// End the current list collection.
|
||||
virtual void EndList() = 0;
|
||||
|
||||
// Begin writing a new map collection.
|
||||
virtual void BeginMap() = 0;
|
||||
|
||||
// End the current map collection.
|
||||
virtual void EndMap() = 0;
|
||||
|
||||
// Write a key into a map.
|
||||
virtual void Key(const char* pKey) = 0;
|
||||
|
||||
// ===== Value Writers =========================================================================================
|
||||
|
||||
virtual void Value(const char* pValue) = 0;
|
||||
virtual void Value(const char* pValue, size_t length) = 0;
|
||||
|
||||
virtual void Value(uint64 value) = 0;
|
||||
virtual void Value(uint32 value) = 0;
|
||||
virtual void Value(uint16 value) = 0;
|
||||
virtual void Value(uint8 value) = 0;
|
||||
virtual void Value(int64 value) = 0;
|
||||
virtual void Value(int32 value) = 0;
|
||||
virtual void Value(int16 value) = 0;
|
||||
virtual void Value(int8 value) = 0;
|
||||
virtual void Value(double value) = 0;
|
||||
virtual void Value(float value) = 0;
|
||||
virtual void Value(bool value) = 0;
|
||||
virtual void Value(char value) = 0;
|
||||
|
||||
/// Writes an enum value as a String or hex value
|
||||
/// If DevDriver::ToString(Enum) returns NULL or an empty string, it will hex-encode the integer value.
|
||||
/// Otherwise, it will write that string
|
||||
template <typename Enum>
|
||||
void ValueEnumOrHex(Enum value)
|
||||
{
|
||||
const char* pString = ToString(value);
|
||||
if ((pString == nullptr) || (strcmp(pString, "") != 0))
|
||||
{
|
||||
Value(pString);
|
||||
}
|
||||
else
|
||||
{
|
||||
Valuef("0x%x", value);
|
||||
}
|
||||
}
|
||||
|
||||
// Write a formatted string
|
||||
template <typename... Args>
|
||||
void Valuef(const char* pFmt, Args&&... args)
|
||||
{
|
||||
char buffer[1024];
|
||||
Platform::Snprintf(buffer, pFmt, args...);
|
||||
Value(buffer);
|
||||
}
|
||||
|
||||
// ===== Key + Value Writers ===================================================================================
|
||||
|
||||
// Write a key-value pair where the value will be a list.
|
||||
void KeyAndBeginList(const char* pKey) { Key(pKey); BeginList(); }
|
||||
|
||||
// Write a key-value pair where the value will be a map.
|
||||
void KeyAndBeginMap(const char* pKey) { Key(pKey); BeginMap(); }
|
||||
|
||||
// Write a key-value pair.
|
||||
void KeyAndValue(const char* pKey, const char* pValue) { Key(pKey); Value(pValue); }
|
||||
void KeyAndValue(const char* pKey, const char* pValue, size_t length) { Key(pKey); Value(pValue, length); }
|
||||
void KeyAndValue(const char* pKey, uint64 value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, uint32 value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, int64 value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, int32 value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, double value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, float value) { Key(pKey); Value(value); }
|
||||
void KeyAndValue(const char* pKey, bool value) { Key(pKey); Value(value); }
|
||||
|
||||
template <typename Enum>
|
||||
void KeyAndValueEnumOrHex(const char* pKey, Enum value) { Key(pKey); ValueEnumOrHex(value); }
|
||||
|
||||
// Write a key-value pair where the value will be a "null" value.
|
||||
void KeyAndValueNull(const char* pKey) { Key(pKey); ValueNull(); }
|
||||
|
||||
// Write a key-value pair with a formatted value
|
||||
template <typename... Args>
|
||||
void KeyAndValuef(const char* pKey, const char* pFmt, Args&&... args) { Key(pKey); Valuef(pFmt, args...); }
|
||||
};
|
||||
|
||||
// An aggregate of the POST metadata for a request.
|
||||
struct PostDataInfo
|
||||
{
|
||||
const void* pData; // Immutable view of the post data
|
||||
uint32 size; // Size of the post data in bytes
|
||||
URIDataFormat format; // Format of the post data - i.e. how to read it
|
||||
|
||||
// Zero initialize the struct.
|
||||
PostDataInfo()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
// An interface that represents a unique URI request
|
||||
class IURIRequestContext
|
||||
{
|
||||
protected:
|
||||
virtual ~IURIRequestContext() {}
|
||||
|
||||
public:
|
||||
// Retrieve the request argument string
|
||||
// N.B: This is non-const and designed to be mutated
|
||||
virtual char* GetRequestArguments() = 0;
|
||||
|
||||
// Retrieve information about the post data of this request
|
||||
virtual const PostDataInfo& GetPostData() const = 0;
|
||||
|
||||
// Creates and returns a Writer to copy bytes into the response block.
|
||||
// Only a single writer is allowed per request context.
|
||||
// Returns:
|
||||
// - Result::Rejected if any writer of any type has already been returned
|
||||
// - Result::Error if `ppWriter` is `nullptr`
|
||||
virtual Result BeginByteResponse(IByteWriter** ppWriter) = 0;
|
||||
|
||||
// Creates and returns a Writer to copy text into the response block.
|
||||
// Only a single writer is allowed per request context.
|
||||
// Returns:
|
||||
// - Result::Rejected if any writer of any type has already been returned
|
||||
// - Result::Error if `ppWriter` is `nullptr`
|
||||
virtual Result BeginTextResponse(ITextWriter** ppWriter) = 0;
|
||||
|
||||
// Creates and returns a Writer to copy json into the response block.
|
||||
// Only a single writer is allowed per request context.
|
||||
// Returns:
|
||||
// - Result::Rejected if any writer of any type has already been returned
|
||||
// - Result::Error if `ppWriter` is `nullptr`
|
||||
virtual Result BeginJsonResponse(IStructuredWriter** ppWriter) = 0;
|
||||
};
|
||||
|
||||
struct URIResponseHeader
|
||||
{
|
||||
// The size of the response data in bytes
|
||||
size_t responseDataSizeInBytes;
|
||||
|
||||
// The format of the response data
|
||||
URIDataFormat responseDataFormat;
|
||||
};
|
||||
|
||||
// Base class for URI services
|
||||
class IService
|
||||
{
|
||||
public:
|
||||
virtual ~IService() {}
|
||||
|
||||
// Returns the name of the service
|
||||
virtual const char* GetName() const = 0;
|
||||
|
||||
// Returns the service version
|
||||
virtual Version GetVersion() const = 0;
|
||||
|
||||
// Attempts to handle a request from a client
|
||||
virtual Result HandleRequest(IURIRequestContext* pContext) = 0;
|
||||
|
||||
// Determines the size limit for post data requests for the client request. By default services
|
||||
// will not accept any post data. The pArguments paramter must remain non-const because the
|
||||
// service may need to manipulate it for further processing.
|
||||
virtual size_t QueryPostSizeLimit(char* pArguments) const
|
||||
{
|
||||
DD_UNUSED(pArguments);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
IService() {};
|
||||
};
|
||||
} // DevDriver
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
#include "msgChannel.h"
|
||||
#include "msgTransport.h"
|
||||
#include "protocols/systemProtocols.h"
|
||||
#include "protocols/typemap.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IProtocolServer;
|
||||
|
||||
// Server Creation Info
|
||||
// This struct extends the MessageChannelCreateInfo struct and adds information about the destination host
|
||||
// the client will connect to. It additionally allows specifying protocol servers to enable during initialization.
|
||||
// See msgChannel.h for a full list of members.
|
||||
struct ServerCreateInfo : public MessageChannelCreateInfo
|
||||
{
|
||||
HostInfo connectionInfo; // Connection information describing how the Server should connect
|
||||
// to the message bus.
|
||||
ProtocolFlags servers; // Set of boolean values indicating which servers should be created
|
||||
// during initialization.
|
||||
};
|
||||
|
||||
DD_STATIC_CONST uint32 kQueryStatusTimeoutInMs = 50;
|
||||
|
||||
class DevDriverServer
|
||||
{
|
||||
public:
|
||||
static bool IsConnectionAvailable(const HostInfo& hostInfo, uint32 timeout = kQueryStatusTimeoutInMs);
|
||||
|
||||
explicit DevDriverServer(const AllocCb& allocCb, const ServerCreateInfo& createInfo);
|
||||
~DevDriverServer();
|
||||
|
||||
Result Initialize();
|
||||
void Finalize();
|
||||
void Destroy();
|
||||
|
||||
const AllocCb& GetAllocCb() const { return m_allocCb; }
|
||||
|
||||
#if GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION < GPUOPEN_DRIVER_CONTROL_CLEANUP_VERSION
|
||||
// Called by the driver to mark the end of Platform and the start of device initialization.
|
||||
// Starting with GPUOPEN_DRIVER_CONTROL_CLEANUP_VERSION the driver should call the driver control
|
||||
// functions directly.
|
||||
void StartDeviceInit();
|
||||
#endif
|
||||
|
||||
bool IsConnected() const;
|
||||
IMsgChannel* GetMessageChannel() const;
|
||||
|
||||
DriverControlProtocol::DriverControlServer* GetDriverControlServer();
|
||||
RGPProtocol::RGPServer* GetRGPServer();
|
||||
EventProtocol::EventServer* GetEventServer();
|
||||
SettingsURIService::SettingsService* GetSettingsService();
|
||||
InfoURIService::InfoService* GetInfoService();
|
||||
|
||||
bool ShouldShowOverlay();
|
||||
|
||||
private:
|
||||
Result InitializeProtocols();
|
||||
void DestroyProtocols();
|
||||
|
||||
Result RegisterProtocol(Protocol protocol);
|
||||
void UnregisterProtocol(Protocol protocol);
|
||||
void FinalizeProtocol(Protocol protocol);
|
||||
|
||||
IMsgChannel* m_pMsgChannel;
|
||||
AllocCb m_allocCb;
|
||||
ServerCreateInfo m_createInfo;
|
||||
|
||||
template <Protocol protocol, class ...Args>
|
||||
inline Result RegisterProtocol(Args... args);
|
||||
|
||||
template <Protocol protocol>
|
||||
inline ProtocolServerType<protocol>* GetServer();
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddDefs.h>
|
||||
|
||||
#define GPUOPEN_INTERFACE_MAJOR_VERSION 42
|
||||
|
||||
#define GPUOPEN_INTERFACE_MINOR_VERSION 1
|
||||
|
||||
#define GPUOPEN_INTERFACE_VERSION ((GPUOPEN_INTERFACE_MAJOR_VERSION << 16) | GPUOPEN_INTERFACE_MINOR_VERSION)
|
||||
|
||||
#define GPUOPEN_MINIMUM_INTERFACE_MAJOR_VERSION 38
|
||||
|
||||
#ifndef GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION
|
||||
static_assert(false, "Client must define GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION.");
|
||||
#else
|
||||
static_assert((GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION >= GPUOPEN_MINIMUM_INTERFACE_MAJOR_VERSION) &&
|
||||
(GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION <= GPUOPEN_INTERFACE_MAJOR_VERSION),
|
||||
"The specified GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION is not supported.");
|
||||
#endif
|
||||
|
||||
// Next version number for interface breaking changes
|
||||
#define DD_UNRELEASED_MAJOR_VERSION 40
|
||||
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*| Version | Change Description |
|
||||
*| ------- | ---------------------------------------------------------------------------------------------------------|
|
||||
*| 42.1 | Move Escape Commands to the shared header for access outside of message.h |
|
||||
*| 42.0 | Updates RGP Protocol to support SPM counters and SE masking. |
|
||||
*| 41.0 | Updates DriverControlProtocol to allow user to query device clock frequencies for a given |
|
||||
*| | clock mode without changing the clock mode. |
|
||||
*| 40.0 | Moves DriverStatus enum out of DriverControlProtocol and into gpuopen.h, and renames several |
|
||||
*| | DriverControlProtocol functions. |
|
||||
*| 39.0 | Simplified the LoggingClient interface to remove the internal pending message requirement. |
|
||||
*| | Removed kInfiniteTimeout and replaced its uses with kLogicFailureTimeout. |
|
||||
*| | Decoupled RGP trace parameters from trace execution. |
|
||||
*| 38.0 | Added support for specifying hostname in ListenerCreateInfo and renamed enableUWP flag to |
|
||||
*| | enableKernelTransport. |
|
||||
*| 37.0 | Added support for Querying ClientInfo from DriverControlProtocol |
|
||||
*| 36.1 | Removed internal log message queue inside LoggingClient. This improves performance significantly. |
|
||||
*| 36.0 | Added support for capturing the RGP trace on specific frame or dispatch. |
|
||||
*| | Added bitfield to control whether driver internal code objects are included in the code object database. |
|
||||
*| 35.0 | Updated Settings URI enum SettingType to avoid X11 macro name collision. |
|
||||
*| 34.0 | Updated URI services to define a version number for each service. |
|
||||
*| 33.0 | Abstracts URIRequestContext into an abstract interface. |
|
||||
*| 32.0 | Updated RGPClient::EndTrace to support user specified timeout values. This allows tools to support |
|
||||
*| | long running traces via user controlled cancellation dialogs. |
|
||||
*| 31.0 | Clean up DevDriverClient and DevDriverServer create info structs. Replace TransportCreateInfo |
|
||||
*| | struct with MessageChannelCreateInfo and HostInfo structs. |
|
||||
*| 30.2 | Added support for RGP v6 protocol which supports trace trigger markers. |
|
||||
*| 30.1 | Add Push transfer support to the transfer protocol. Added PushBlock class, added v2 of the |
|
||||
*| | TransferProtocol, and did a lot of internal cleanup. Legacy interfaces will be deprecated in a future |
|
||||
*| | interface version change alongside URI changes. |
|
||||
*| 30.0 | Remove CloseSession and OrphanSession from the public ISession object interface, and move the |
|
||||
*| | functionality into the Session class. |
|
||||
*| 29.0 | Added a ResponseDataFormat enum to the URI protocol to distinguish between binary and text responses. |
|
||||
*| 28.0 | Formally deprecate legacy KMD client manager support in the Listener. |
|
||||
*| 27.2 | Updated FindFirstClient to support returning the matching ClientMetadata struct. |
|
||||
*| 27.1 | Added PipelineDumpsEnabled status flag. |
|
||||
*| 27.0 | Deprecate global client status flags + replace it with client metadata. |
|
||||
*| 26.0 | Add new trace parameters in the RGP protocol. |
|
||||
*| 25.0 | Initial refactor of LoggingProtocol. Removes Subcategories, being able to set/clear filter outside of a |
|
||||
*| | trace, and significantly reduces the complexity that is involved in using it. |
|
||||
*| 24.0 | Expanded driver initialization concept in driver control protocol. |
|
||||
*| 23.0 | Modified RGP client API usage pattern to be uniform across protocol versions. |
|
||||
*| 22.0 | Refactor RGP client interface to support calculating transfer progress. |
|
||||
*| 21.1 | Added backwards compatible workaround for the session termination bug until we get the fix in mainline. |
|
||||
*| 21.0 | Enable link disconnection detection for socket based transports. |
|
||||
*| 20.0 | Added support for specifying the clock mode used during RGP profiling. |
|
||||
*| 19.0 | Refactor platform thread functions so that they are contained in a class. This is the last part of the |
|
||||
*| | platform library that needed to be refactored, so future work will be focused on migrating the message |
|
||||
*| | bus components to use the main platform library again. |
|
||||
*| 18.0 | Consolidate DevDriver::DebugLevel and DevDriver::Message::DebugLevel into DevDriver::LogLevel. |
|
||||
*| 17.0 | Rename DD_VERSION_IS_SUPPORTED macro to DD_VERSION_SUPPORTS for conciseness. |
|
||||
*| 16.1 | Rework session version negotiation to allow clients to support multiple server versions. |
|
||||
*| 16.0 | Change semantics of CreateProtocolClient to AcquireProtocolClient. This aligns better with |
|
||||
*| | ReleaseProtoclClient in terms of semantics. |
|
||||
*| 15.0 | Added support for memory allocator callbacks via AllocCb. |
|
||||
*| 14.1 | Added DisableTrace call in RGP server to allow drivers to disable future traces if necessary. |
|
||||
*| 14.0 | Add TraceParameters to the RGP protocol to allow for configuration of trace behavior. |
|
||||
*| 13.0 | Deprecate DevDriverClient::CreateProtocolClient() in favor of typesafe templated version. |
|
||||
*| 12.0 | Deprecate API features tied to legacy network protocol versions: |
|
||||
*| | * Replace ConnectToRemoteClient with Connect, which now returns more detailed errors on failure |
|
||||
*| | * Eliminate Send and ReceiveSessionMessage functions in IMsgChannel and SessionManager |
|
||||
*| | * Rename AuthenticationFailed to VersionMismatch since it is more semantically accurate |
|
||||
*| | * Update IMsgChannel::Update so that it takes a default timeout value, get rid of m_receiveTimeoutInMs |
|
||||
*| 11.5 | Updated server to remove GetVersion() call and pass version into AcceptSession() instead. This allows |
|
||||
*| | servers to potentially implement backwards compatibility for older client versions. Additionally, |
|
||||
*| | completely eliminate SessionTermination type in favor of expanding Result type. This allows propagating |
|
||||
*| | more information on connection failures back to clients, as well as streamlines some code. |
|
||||
*| 11.4 | Implement per-protocol versioning. Client protocol is sent as part of session request, server decides |
|
||||
*| | whether or not to accept session both from client and from version. Also rearrange how certain network |
|
||||
*| | operations work: Syn now stores the initial session ID in the sessionId field of the message, Rst now |
|
||||
*| | includes a result code, and closing a session now implicitly flushes both the client/server. Rst |
|
||||
*| | Is also sent on just about every unknown session packet received, allowing faster error detection and |
|
||||
*| | recovery. Bump network version number |
|
||||
*| 11.3 | Change ProcessId type from 64bit to 32bit integer and bump network protocol version. |
|
||||
*| 11.2 | Update the network protocol to give external protocols values from 0-223 and system protocols 224-255. |
|
||||
*| | Also clean up + deprecate some of the constants associated with protocols. |
|
||||
*| 11.1 | Force alignment of all network transmitted structs, as well as pad. This is a breaking change for the |
|
||||
*| | network protocol, but is otherwise API compatible. |
|
||||
*| 11.0 | Deprecate the Protocol::ClientManangement enum, as well as ReadMessageBuffer and SendMessageBuffer in |
|
||||
*| | message.lib. |
|
||||
*| 10.0 | Remove callback from MessageChannel to prevent usage that can cause deadlocking. |
|
||||
*| 9.0 | Formalized support for selective discard of non-session messages based on right in the message. |
|
||||
*| | Implementation is that the sequence field of a message can be populated with the contents of a |
|
||||
*| | ClientMetadata struct, which is then used by the receiving message channel to determine if it should |
|
||||
*| | respond. Decision is based on whether or not the metadata matches the metadata of the receiving client. |
|
||||
*| 8.0 | Added support for default settings values in the settings protocol. Removed support for min and max |
|
||||
*| | settings values since the scripts don't actually support those anyways. |
|
||||
*| 7.0 | Added a Finalize function to DevDriverServer and all protocol server objects. This function now handles |
|
||||
*| | the wait on start functionality for drivers internally. Finalize should now be called instead of the old |
|
||||
*| | wait on start logic in client drivers. |
|
||||
*| 6.0 | Update client protocol management so that DevDriverClient no longer caches a single instance of each |
|
||||
*| | client protocol, and add ability for clients to directly create more than one client protocol instance. |
|
||||
*| | Additionally, make changes to underlying message channel/transport API that is not backwards compatible, |
|
||||
*| | as well as rename QueryClientInfoResponse to ClientInfoResponse and QueryClientInfoResponsePayload to |
|
||||
*| | ClientInfoStruct. |
|
||||
*| 5.0 | Update network protocol to allow specifying status flags at registration time, and add system message. |
|
||||
*| | to indicate when a driver has been halted. Additionally, this changes the format of the client |
|
||||
*| | registration packets so as to better detect version mismatch. It also fixes the ClientManangement typo. |
|
||||
*| 4.0 | Refactor interface so as to better delineate between system protcols/client protocols, as well as add |
|
||||
*| | ability to query protocol availability. Requires version bump, so also formally deprecated |
|
||||
*| | Result::Timeout and ClientStatusFlags::ProfilingEnabled, as well as moved entire SessionProtocol |
|
||||
*| | namespace out of the public headers. |
|
||||
*| 3.1 | Introduce kNumberClientProtocols to replace usage of Protocol::Count |
|
||||
*| 3.0 | Rename SettingsProtocol::SettingType::Bool to Boolean to avoid conflict with Xlib macro. Additionally |
|
||||
*| | formally deprecate Result::Timeout. |
|
||||
*| 2.2 | Added None (0) to ClientStatusFlags enum. |
|
||||
*| 2.1 | Added kNamedPipeName to global namespace. |
|
||||
*| 2.0 | Added functionality for enabling and disabling traces in RGPServer. Traces must now be explicitly |
|
||||
*| | enabled before remote trace requests will succeed. |
|
||||
*| 1.2 | Added AbortTrace() function to RGPServer. |
|
||||
*| 1.1 | Added support for RGP protocol. |
|
||||
*| 1.0 | Initial versioned release. |
|
||||
***********************************************************************************************************************
|
||||
*/
|
||||
|
||||
#define GPUOPEN_RGP_SPM_COUNTERS_VERSION 42
|
||||
#define GPUOPEN_DRIVER_CONTROL_QUERY_CLOCKS_BY_MODE_VERSION 41
|
||||
#define GPUOPEN_DRIVER_CONTROL_CLEANUP_VERSION 40
|
||||
#define GPUOPEN_DECOUPLED_RGP_PARAMETERS_VERSION 39
|
||||
#define GPUOPEN_SIMPLER_LOGGING_VERSION 39
|
||||
#define GPUOPEN_LISTENER_HOSTNAME_VERSION 38
|
||||
#define GPUOPEN_SETTINGS_URI_LINUX_BUILD 35
|
||||
#define GPUOPEN_VERSIONED_URI_SERVICES_VERSION 34
|
||||
#define GPUOPEN_URIINTERFACE_CLEANUP_VERSION 33
|
||||
#define GPUOPEN_LONG_RGP_TRACES_VERSION 32
|
||||
#define GPUOPEN_CREATE_INFO_CLEANUP_VERSION 31
|
||||
#define GPUOPEN_SESSION_INTERFACE_CLEANUP_VERSION 30
|
||||
#define GPUOPEN_URI_RESPONSE_FORMATS_VERSION 29
|
||||
#define GPUOPEN_DEPRECATE_LEGACY_KMD_VERSION 28
|
||||
#define GPUOPEN_DISTRIBUTED_STATUS_FLAGS_VERSION 27
|
||||
#define GPUOPEN_RGP_TRACE_PARAMETERS_V3_VERSION 26
|
||||
#define GPUOPEN_LOGGING_SIMPLIFICATION_VERSION 25
|
||||
#define GPUOPEN_DRIVERCONTROL_INITIALIZATION_VERSION 24
|
||||
#define GPUOPEN_RGP_UNIFORM_API_VERSION 23
|
||||
#define GPUOPEN_RGP_PROGRESS_VERSION 22
|
||||
#define GPUOPEN_KEEPALIVE_VERSION 21
|
||||
#define GPUOPEN_PROFILING_CLOCK_MODES_VERSION 20
|
||||
#define GPUOPEN_THREAD_REFACTOR_VERSION 19
|
||||
#define GPUOPEN_LOGLEVEL_CLEANUP_VERSION 18
|
||||
#define GPUOPEN_RENAME_MACRO_VERSION 17
|
||||
#define GPUOPEN_PROTOCOL_CLIENT_REUSE_VERSION 16
|
||||
#define GPUOPEN_MEMORY_ALLOCATORS_VERSION 15
|
||||
#define GPUOPEN_RGP_TRACE_PARAMETERS_VERSION 14
|
||||
#define GPUOPEN_DEPRECATE_CREATEPROTOCOLCLIENT_VERSION 13
|
||||
#define GPUOPEN_DEPRECATE_LEGACY_NETAPI_VERSION 12
|
||||
#define GPUOPEN_POST_GDC_CLEANUP_VERSION 11
|
||||
#define GPUOPEN_DEPRECATE_EXTERNAL_CALLBACK_VERSION 10
|
||||
#define GPUOPEN_SELECTIVE_RESPOND_VERSION 9
|
||||
#define GPUOPEN_DEFAULT_SETTINGS_VERSION 8
|
||||
#define GPUOPEN_SERVER_FINALIZE_VERSION 7
|
||||
#define GPUOPEN_DEPRECATE_LEGACY_VERSION 6
|
||||
#define GPUOPEN_CLIENT_REGISTRATION_VERSION 5
|
||||
#define GPUOPEN_PROTOCOL_CLEANUP_VERSION 4
|
||||
#define GPUOPEN_LINUX_BUILD_VERSION 3
|
||||
#define GPUOPEN_EXPLICIT_ENABLE_RGP_VERSION 2
|
||||
#define GPUOPEN_INITIAL_VERSION 1
|
||||
|
||||
// This will be properly defined when RMV 1.1 features are complete, defining it now allows
|
||||
// clients to code to the interface ahead of all of the work being complete.
|
||||
#define GPUOPEN_RMV_1_1_VERSION 0xFFFF
|
||||
|
||||
#define DD_VERSION_SUPPORTS(x) (GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION >= x)
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
typedef uint16_t ClientId;
|
||||
typedef uint32_t SessionId;
|
||||
typedef uint8_t MessageCode;
|
||||
typedef uint16_t WindowSize;
|
||||
typedef uint64_t Sequence;
|
||||
typedef uint16_t Version;
|
||||
typedef uint16_t StatusFlags;
|
||||
|
||||
#if DD_VERSION_SUPPORTS(GPUOPEN_SIMPLER_LOGGING_VERSION)
|
||||
// A common timeout in milliseconds for components to use when they do not expect timeout to fail.
|
||||
// If an operation that uses this timeout returns Result::NotReady, consider it a fatal error.
|
||||
DD_STATIC_CONST uint32 kLogicFailureTimeout = 1000;
|
||||
#else
|
||||
DD_STATIC_CONST uint32 kInfiniteTimeout = ~(0u);
|
||||
DD_STATIC_CONST uint32 kLogicFailureTimeout = kInfiniteTimeout;
|
||||
#endif
|
||||
DD_STATIC_CONST uint32 kNoWait = (0u);
|
||||
|
||||
////////////////////////////
|
||||
// Driver states
|
||||
enum struct DriverStatus : uint32
|
||||
{
|
||||
Running = 0,
|
||||
Paused,
|
||||
HaltedOnDeviceInit,
|
||||
EarlyDeviceInit,
|
||||
LateDeviceInit,
|
||||
PlatformInit,
|
||||
HaltedOnPlatformInit,
|
||||
HaltedPostDeviceInit,
|
||||
Count
|
||||
};
|
||||
|
||||
////////////////////////////
|
||||
// Client status codes
|
||||
enum struct ClientStatusFlags : StatusFlags
|
||||
{
|
||||
None = 0,
|
||||
DeveloperModeEnabled = (1 << 0),
|
||||
DeviceHaltOnConnect = (1 << 1),
|
||||
GpuCrashDumpsEnabled = (1 << 2),
|
||||
PipelineDumpsEnabled = (1 << 3),
|
||||
PlatformHaltOnConnect = (1 << 4),
|
||||
DriverInitializer = (1 << 5)
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ClientId, 2);
|
||||
DD_STATIC_CONST int16 kRouterPrefixWidth = 3;
|
||||
DD_STATIC_CONST int16 kRouterPrefixShift = (int16)(16 - kRouterPrefixWidth);
|
||||
DD_STATIC_CONST ClientId kClientIdMask = (1 << kRouterPrefixShift) - 1;
|
||||
DD_STATIC_CONST ClientId kRouterPrefixMask = static_cast<ClientId>(~(kClientIdMask));
|
||||
|
||||
union ProtocolFlags
|
||||
{
|
||||
struct DD_ALIGNAS(4)
|
||||
{
|
||||
// TODO: Replace logging, settings, and gpuCrashDump with "reserved" once all driver usage is removed.
|
||||
uint32 logging : 1;
|
||||
uint32 settings : 1;
|
||||
uint32 driverControl : 1;
|
||||
uint32 rgp : 1;
|
||||
uint32 etw : 1;
|
||||
uint32 gpuCrashDump : 1;
|
||||
uint32 event : 1;
|
||||
uint32 reserved : 25;
|
||||
};
|
||||
uint32 value;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ProtocolFlags, 4);
|
||||
|
||||
////////////////////////////
|
||||
// Component definitions
|
||||
enum struct Component : uint8
|
||||
{
|
||||
Unknown = 0,
|
||||
Server,
|
||||
Tool,
|
||||
Driver,
|
||||
Count
|
||||
};
|
||||
|
||||
struct DD_ALIGNAS(4) ClientMetadata
|
||||
{
|
||||
ProtocolFlags protocols;
|
||||
Component clientType;
|
||||
uint8 reserved;
|
||||
StatusFlags status;
|
||||
|
||||
// For System messages, which are not session-based, we alias the sequence field as ClientMetadata. This constructor
|
||||
// is provided to help unpack the raw 64-bit sequence field into a ClientMetadata struct without needing to type-cast
|
||||
explicit ClientMetadata(uint64 value)
|
||||
{
|
||||
// If we're going to alias as a 64-bit value, make sure the struct is still just 64-bits)
|
||||
static_assert(sizeof(uint64) == sizeof(ClientMetadata),
|
||||
"Size of ClientMetadata is no longer 64-bits, alias constructor needs updating");
|
||||
|
||||
// Bits 0-31 are the ProtocolFlags
|
||||
protocols.value = static_cast<uint32>(value & 0xFFFF);
|
||||
|
||||
// Bits 32-39 are the Component
|
||||
clientType = static_cast<Component>((value & 0xFF00000000) >> 32);
|
||||
|
||||
// Bits 40-47 are reserved, ignore them and zero initialize
|
||||
reserved = 0;
|
||||
|
||||
// Bits 48-63 are the StatusFlags
|
||||
status = static_cast<StatusFlags>((value & 0xFFFF000000000000) >> 48);
|
||||
}
|
||||
|
||||
// Default constructor, default initialize everything
|
||||
ClientMetadata() = default;
|
||||
|
||||
// Returns true if all values are default values
|
||||
bool IsDefault() const
|
||||
{
|
||||
return ((protocols.value == 0) && (clientType == Component::Unknown) && (status == 0));
|
||||
}
|
||||
|
||||
// Test if all non-zero fields in the ClientMetadata value are contained in the function parameter
|
||||
bool Matches(const ClientMetadata &right) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
// The Matches function treats this struct as a filter, so a ClientMetadata with all default (zero) values
|
||||
// by definition always matches.
|
||||
if (IsDefault() == false)
|
||||
{
|
||||
// Component is an enum, so the comparison needs to be equality
|
||||
const bool clientTypeMatches =
|
||||
(clientType != Component::Unknown)
|
||||
? (clientType == right.clientType)
|
||||
: true;
|
||||
|
||||
// ProtocolFlags is a bit field, so we can do a bitwise comparison
|
||||
const bool protocolMatches =
|
||||
(protocols.value != 0)
|
||||
? (protocols.value & right.protocols.value) == protocols.value
|
||||
: true;
|
||||
// StatusFlags is a bit field, so we can do a bitwise comparison
|
||||
const bool statusMatches =
|
||||
(status != 0)
|
||||
? (status & right.status) == status
|
||||
: true;
|
||||
result = clientTypeMatches & protocolMatches & statusMatches;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Test if any non-zero fields in the ClientMetadata value are contained in the function parameter
|
||||
bool MatchesAny(const ClientMetadata &right) const
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
// The MatchesAny function treats this struct as a filter, so a ClientMetadata with all default (zero) values
|
||||
// by definition always matches.
|
||||
if (IsDefault() == false)
|
||||
{
|
||||
// Component is an enum, so the comparison needs to be equality
|
||||
const bool clientTypeMatches = (clientType == right.clientType);
|
||||
// ProtocolFlags is a bit field, so we can do a bitwise comparison
|
||||
const bool protocolMatches = (protocols.value & right.protocols.value) != 0;
|
||||
// StatusFlags is a bit field, so we can do a bitwise comparison
|
||||
const bool statusMatches = (status & right.status) != 0;
|
||||
result = clientTypeMatches | protocolMatches | statusMatches;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ClientMetadata, 8);
|
||||
|
||||
////////////////////////////
|
||||
// Protocol definitions
|
||||
enum struct Protocol : uint8
|
||||
{
|
||||
DriverControl = 0,
|
||||
Reserved0,
|
||||
Reserved1,
|
||||
RGP,
|
||||
ETW,
|
||||
Reserved2,
|
||||
Event,
|
||||
DefinedProtocolCount,
|
||||
|
||||
// System enumerations
|
||||
MaxUserProtocol = 223,
|
||||
/* RESERVED FOR SYSTEM USE */
|
||||
Transfer = 251,
|
||||
URI = 252,
|
||||
Session = 253,
|
||||
ClientManagement = 254,
|
||||
System = 255,
|
||||
};
|
||||
|
||||
// this gives you the number of pre-defined user protocols that exist
|
||||
DD_STATIC_CONST uint32 kNumberClientProtocols = static_cast<uint32>(Protocol::DefinedProtocolCount);
|
||||
|
||||
// this gives you the maximum number of client protocols you can reserve.
|
||||
DD_STATIC_CONST uint32 kMaxClientProtocolId = static_cast<uint32>(Protocol::MaxUserProtocol);
|
||||
|
||||
static_assert(kNumberClientProtocols <= (kMaxClientProtocolId + 1), "Invalid protocol definitions specified");
|
||||
|
||||
///////////////////////
|
||||
// General definitions
|
||||
DD_STATIC_CONST uint32 kMessageVersion = 1011;
|
||||
|
||||
// Max string size for names and messages
|
||||
DD_STATIC_CONST Size kMaxStringLength = 128;
|
||||
|
||||
// Broadcast client ID
|
||||
DD_STATIC_CONST ClientId kBroadcastClientId = 0;
|
||||
|
||||
// Invalid Session ID
|
||||
DD_STATIC_CONST SessionId kInvalidSessionId = 0;
|
||||
|
||||
// Default network port number
|
||||
DD_STATIC_CONST uint16_t kDefaultNetworkPort = 27300;
|
||||
|
||||
// Transport type enumeration
|
||||
enum class TransportType : uint32
|
||||
{
|
||||
Local = 0,
|
||||
Remote,
|
||||
#if defined(DD_PLATFORM_WINDOWS_UM)
|
||||
MessageBus,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Struct used to designate a transport type, port number, and hostname
|
||||
struct HostInfo
|
||||
{
|
||||
TransportType type; // Transport type, as defined above
|
||||
uint16_t port; // Port number if applicable
|
||||
const char* pHostname; // Host address, address, or path
|
||||
};
|
||||
|
||||
// Default local host information
|
||||
DD_STATIC_CONST HostInfo kDefaultLocalHost =
|
||||
{
|
||||
TransportType::Remote,
|
||||
kDefaultNetworkPort,
|
||||
"localhost"
|
||||
};
|
||||
|
||||
// Default named pipe information
|
||||
DD_STATIC_CONST HostInfo kDefaultNamedPipe =
|
||||
{
|
||||
TransportType::Local,
|
||||
0,
|
||||
nullptr
|
||||
};
|
||||
|
||||
#if defined(DD_PLATFORM_WINDOWS_UM)
|
||||
// Default message bus information
|
||||
DD_STATIC_CONST HostInfo kMessageBus =
|
||||
{
|
||||
TransportType::MessageBus,
|
||||
0,
|
||||
nullptr
|
||||
};
|
||||
#endif
|
||||
|
||||
////////////////////////////
|
||||
// Common definition of a message header
|
||||
//
|
||||
// todo: better packing of these values
|
||||
// - payloadSize needs to be moved to where windowSize is currently
|
||||
// - windowSize, sessionId, and sequence need to be moved into protocol specific payloads
|
||||
// - minimum alignment could then be reduced to 2 bytes, and min packet size would be 8 bytes
|
||||
// - downside is that pretty much every protocol would need to define some extra data
|
||||
|
||||
DD_NETWORK_STRUCT(MessageHeader, 8)
|
||||
{
|
||||
// source and destination client ids
|
||||
ClientId srcClientId; // 0 - 15
|
||||
ClientId dstClientId; // 16 - 31
|
||||
|
||||
// protocol and command
|
||||
Protocol protocolId; // 31 - 38
|
||||
MessageCode messageId; // 39 - 47
|
||||
WindowSize windowSize; // 48 - 63
|
||||
|
||||
// payload size + current session ID
|
||||
Size payloadSize; // 64 - 91
|
||||
SessionId sessionId; // 92 - 127
|
||||
|
||||
// sequence number when using a session
|
||||
Sequence sequence; // 128 - 191
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(MessageHeader, 24);
|
||||
|
||||
DD_STATIC_CONST Size kMaxMessageSizeInBytes = 1408;
|
||||
DD_STATIC_CONST Size kMaxPayloadSizeInBytes = (kMaxMessageSizeInBytes - sizeof(MessageHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(MessageBuffer, 8)
|
||||
{
|
||||
MessageHeader header;
|
||||
char payload[kMaxPayloadSizeInBytes];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(MessageBuffer, sizeof(MessageHeader) + kMaxPayloadSizeInBytes);
|
||||
|
||||
// Helper function used to validate message buffers that arrive from an external source
|
||||
// Returns Success if the message buffer is valid and Error otherwise.
|
||||
inline Result ValidateMessageBuffer(const void* pMsgBuffer, size_t msgBufferSize)
|
||||
{
|
||||
Result result = Result::Error;
|
||||
|
||||
// Ensure that we've been passed valid parameters
|
||||
if ((pMsgBuffer != nullptr) && (msgBufferSize > 0))
|
||||
{
|
||||
// A valid message buffer must be no larger than the full size message buffer structure
|
||||
// and it must also be large enough to contain a valid header.
|
||||
if ((msgBufferSize <= sizeof(MessageBuffer)) && (msgBufferSize >= sizeof(MessageHeader)))
|
||||
{
|
||||
// Calculate the total size of the message from the data encoded in the buffer.
|
||||
const MessageHeader* pHeader = reinterpret_cast<const MessageHeader*>(pMsgBuffer);
|
||||
const size_t encodedMessageSize = (sizeof(MessageHeader) + pHeader->payloadSize);
|
||||
|
||||
// The encoded message size should match our expected size exactly
|
||||
if (encodedMessageSize == msgBufferSize)
|
||||
{
|
||||
result = Result::Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Result::InvalidParameter;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// tripwire - this intentionally will break if the message version changes. Since these are breaking changes already, we need to address
|
||||
// this problem when it happens.
|
||||
static_assert(kMessageVersion == 1011, "ClientInfoStruct needs to be updated so that clientName is long enough to support a full path");
|
||||
// todo: shorten clientDescription to 64bytes and make clientName 320bytes to support full path
|
||||
DD_NETWORK_STRUCT(ClientInfoStruct, 4)
|
||||
{
|
||||
char clientName[kMaxStringLength];
|
||||
char clientDescription[kMaxStringLength];
|
||||
// reserve 128bytes in case we need another string in the future
|
||||
char reserved[kMaxStringLength];
|
||||
ClientMetadata metadata;
|
||||
ProcessId processId;
|
||||
// pad this out to 512 bytes for future expansion
|
||||
char padding[116];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ClientInfoStruct, 512);
|
||||
|
||||
///////////////////////
|
||||
// GPU Open Message codes
|
||||
enum struct EscapeCommand : uint32
|
||||
{
|
||||
Unknown = 0,
|
||||
QueryStatus, // Will be deprecated in a future change
|
||||
RegisterClient,
|
||||
UnregisterClient,
|
||||
RegisterExternalClient, // Will be deprecated in a future change
|
||||
UnregisterExternalClient, // Will be deprecated in a future change
|
||||
UpdateClientStatus, // Will be deprecated in a future change
|
||||
QueryCapabilities,
|
||||
EnableDeveloperMode,
|
||||
DisableDeveloperMode,
|
||||
QueryDeveloperModeStatus,
|
||||
RegisterRouter,
|
||||
UnregisterRouter,
|
||||
AmdLogEvent,
|
||||
Count
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
#include "protocolClient.h"
|
||||
#include "protocolServer.h"
|
||||
#include "msgTransport.h"
|
||||
#include "ddUriInterface.h"
|
||||
#include "util/string.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IMsgChannel;
|
||||
class IService;
|
||||
class ISession;
|
||||
|
||||
namespace TransferProtocol
|
||||
{
|
||||
class TransferManager;
|
||||
}
|
||||
|
||||
namespace InfoURIService
|
||||
{
|
||||
class InfoService;
|
||||
}
|
||||
|
||||
// Temporarily changing from 10ms to 15ms to workaround a timing issue with Windows named pipes, should change back once that
|
||||
// transport is refactored/replaced.
|
||||
DD_STATIC_CONST uint32 kDefaultUpdateTimeoutInMs = 15;
|
||||
DD_STATIC_CONST uint32 kFindClientTimeout = 500;
|
||||
|
||||
// Enumeration of events that can occur on the message bus.
|
||||
enum class BusEventType : uint32
|
||||
{
|
||||
Unknown = 0,
|
||||
ClientHalted,
|
||||
PongRequest,
|
||||
};
|
||||
|
||||
/// Event data structure for the ClientHalted bus event
|
||||
struct BusEventClientHalted
|
||||
{
|
||||
ClientId clientId; /// Id of the client that is currently halted
|
||||
ClientInfoStruct clientInfo; /// Additional information about the client
|
||||
};
|
||||
|
||||
/// Event data structure for the PongRequest bus event
|
||||
struct BusEventPongRequest
|
||||
{
|
||||
ClientId clientId; /// Id of the client that is requesting a pong message
|
||||
const ClientInfoStruct* pClientInfo; /// Additional information about the client
|
||||
/// Note: May be nullptr for older clients
|
||||
bool* pShouldRespond; /// Set this to false if a pong should not be sent
|
||||
/// The default value is true.
|
||||
/// Note: This will never be nullptr
|
||||
};
|
||||
|
||||
// Callback function used to handle bus events
|
||||
typedef void (*PFN_BusEventCallback)(void* pUserdata, BusEventType type, const void* pEventData, size_t eventDataSize);
|
||||
|
||||
// Helper structure used to contain a bus event callback
|
||||
struct BusEventCallback
|
||||
{
|
||||
PFN_BusEventCallback pfnEventCallback; // Message bus event callback function
|
||||
void* pUserdata; // Message bus event callback userdata
|
||||
|
||||
/// Returns true if this callback contains a valid function
|
||||
bool IsValid() const { return (pfnEventCallback != nullptr); }
|
||||
|
||||
/// Executes the function stored within the callback
|
||||
void operator()(BusEventType type, const void* pEventData, size_t eventDataSize)
|
||||
{
|
||||
DD_ASSERT(IsValid());
|
||||
|
||||
pfnEventCallback(pUserdata, type, pEventData, eventDataSize);
|
||||
}
|
||||
};
|
||||
|
||||
// Struct of information required to initialize an IMsgChannel instance
|
||||
struct MessageChannelCreateInfo
|
||||
{
|
||||
StatusFlags initialFlags; // Initial client status flags.
|
||||
Component componentType; // Type of component the message channel represents.
|
||||
bool createUpdateThread; // Create a background processing thread for the message
|
||||
// channel. This should only be set to false if the
|
||||
// owning object is able to call IMsgChannel::Update()
|
||||
// at least once per frame.
|
||||
char clientDescription[kMaxStringLength]; // Description of the client provided to other clients on
|
||||
// the message bus.
|
||||
};
|
||||
|
||||
// Information required to establish a new session
|
||||
struct EstablishSessionInfo
|
||||
{
|
||||
Protocol protocol;
|
||||
Version minProtocolVersion;
|
||||
Version maxProtocolVersion;
|
||||
ClientId remoteClientId;
|
||||
const char* pSessionName;
|
||||
};
|
||||
|
||||
// "Temporary" structure to pack all create info without breaking back-compat
|
||||
struct MessageChannelCreateInfo2
|
||||
{
|
||||
MessageChannelCreateInfo channelInfo;
|
||||
HostInfo hostInfo;
|
||||
AllocCb allocCb;
|
||||
};
|
||||
|
||||
// Data structure that contains information about a client that has been discovered
|
||||
struct DiscoveredClientInfo
|
||||
{
|
||||
ClientId id; /// Id of the client
|
||||
ClientMetadata metadata; /// Metadata for the client
|
||||
|
||||
// Structure that contains additional information about the discovered client
|
||||
// This information may or may not be valid depending on the value of the "valid" field.
|
||||
struct
|
||||
{
|
||||
bool valid;
|
||||
ClientInfoStruct data;
|
||||
} clientInfo;
|
||||
};
|
||||
|
||||
// Callback function used to handle client discovery
|
||||
// Return true from this callback to indicate that the discovery process should be continued.
|
||||
typedef bool (*PFN_ClientDiscoveredCallback)(void* pUserdata, const DiscoveredClientInfo& clientInfo);
|
||||
|
||||
// Data structure that describes how a client discovery operation should be performed
|
||||
struct DiscoverClientsInfo
|
||||
{
|
||||
PFN_ClientDiscoveredCallback pfnCallback; /// Callback function pointer
|
||||
void* pUserdata; /// Userdata for callback
|
||||
ClientMetadata filter; /// Filters out incoming clients from the callback
|
||||
uint32 timeoutInMs; /// Timeout in milliseconds
|
||||
};
|
||||
|
||||
// Create a new message channel object
|
||||
Result CreateMessageChannel(const MessageChannelCreateInfo2& createInfo, IMsgChannel** ppMessageChannel);
|
||||
|
||||
class IMsgChannel
|
||||
{
|
||||
public:
|
||||
virtual ~IMsgChannel() {}
|
||||
|
||||
// Register, unregister, or check connected status.
|
||||
virtual Result Register(uint32 timeoutInMs = ~(0u)) = 0;
|
||||
virtual void Unregister() = 0;
|
||||
virtual bool IsConnected() = 0;
|
||||
|
||||
virtual void SetBusEventCallback(const BusEventCallback& callback) = 0;
|
||||
|
||||
// Send, receive, and forward messages
|
||||
virtual Result Send(ClientId dstClientId,
|
||||
Protocol protocol,
|
||||
MessageCode message,
|
||||
const ClientMetadata& metadata,
|
||||
uint32 payloadSizeInBytes,
|
||||
const void* pPayload) = 0;
|
||||
virtual Result Receive(MessageBuffer& message, uint32 timeoutInMs) = 0;
|
||||
virtual Result Forward(const MessageBuffer& messageBuffer) = 0;
|
||||
|
||||
// Register, unregister, and retrieve IProtocolServer objects
|
||||
virtual Result RegisterProtocolServer(IProtocolServer* pServer) = 0;
|
||||
virtual Result UnregisterProtocolServer(IProtocolServer* pServer) = 0;
|
||||
virtual IProtocolServer* GetProtocolServer(Protocol protocol) = 0;
|
||||
|
||||
// Initiates a connection to the specified destination client id
|
||||
// Returns the intermediate session via ppSession
|
||||
virtual Result EstablishSessionForClient(SharedPointer<ISession>* ppSession,
|
||||
const EstablishSessionInfo& sessionInfo) = 0;
|
||||
|
||||
// Register or Unregister an IService object
|
||||
virtual Result RegisterService(IService* pService) = 0;
|
||||
virtual Result UnregisterService(IService* pService) = 0;
|
||||
|
||||
// Get the allocator used to create this message channel
|
||||
virtual const AllocCb& GetAllocCb() const = 0;
|
||||
|
||||
// Attempts to discover clients on the message bus
|
||||
virtual Result DiscoverClients(const DiscoverClientsInfo& info) = 0;
|
||||
|
||||
// Returns client information for the first client to respond that matches the specified filter
|
||||
virtual Result FindFirstClient(const ClientMetadata& filter,
|
||||
ClientId* pClientId,
|
||||
uint32 timeoutInMs = kFindClientTimeout,
|
||||
ClientMetadata* pClientMetadata = nullptr) = 0;
|
||||
|
||||
// Get the client ID, or returns kBroadcastClientId if disconnected.
|
||||
virtual ClientId GetClientId() const = 0;
|
||||
|
||||
// Get the client information struct for the message channel.
|
||||
virtual const ClientInfoStruct& GetClientInfo() const = 0;
|
||||
|
||||
// Get a human-readable string describing the connection type.
|
||||
virtual const char* GetTransportName() const = 0;
|
||||
|
||||
// Set and get all client status flags.
|
||||
virtual Result SetStatusFlags(StatusFlags flags) = 0;
|
||||
virtual StatusFlags GetStatusFlags() const = 0;
|
||||
|
||||
// Set the specified client status flag.
|
||||
template <ClientStatusFlags flag>
|
||||
Result SetStatusFlag(bool enable)
|
||||
{
|
||||
Result toggleResult = Result::Success;
|
||||
StatusFlags oldFlags = GetStatusFlags();
|
||||
StatusFlags newFlags;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
// Toggle developer mode
|
||||
newFlags = oldFlags | static_cast<DevDriver::StatusFlags>(flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Toggle developer mode
|
||||
newFlags = oldFlags & ~static_cast<DevDriver::StatusFlags>(flag);
|
||||
}
|
||||
|
||||
if (newFlags != oldFlags)
|
||||
{
|
||||
toggleResult = SetStatusFlags(newFlags);
|
||||
}
|
||||
return toggleResult;
|
||||
}
|
||||
|
||||
// Get the specified client status flag.
|
||||
template <ClientStatusFlags flag>
|
||||
bool GetStatusFlag() const
|
||||
{
|
||||
return ((GetStatusFlags() & static_cast<StatusFlags>(flag)) != 0);
|
||||
}
|
||||
|
||||
virtual InfoURIService::InfoService& GetInfoService() = 0;
|
||||
|
||||
// Utility functions that should probably not be publicly exposed.
|
||||
// TODO: Refactor surrounding code to eliminate these.
|
||||
virtual TransferProtocol::TransferManager& GetTransferManager() = 0;
|
||||
virtual void Update(uint32 timeoutInMs = kDefaultUpdateTimeoutInMs) = 0;
|
||||
|
||||
protected:
|
||||
IMsgChannel() {};
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IMsgTransport
|
||||
{
|
||||
public:
|
||||
virtual ~IMsgTransport() {}
|
||||
|
||||
// Connect and disconnect from the transport.
|
||||
virtual Result Connect(ClientId* pClientId, uint32 timeoutInMs) = 0;
|
||||
virtual Result Disconnect() = 0;
|
||||
|
||||
// Read and Write messages from a connected transport
|
||||
virtual Result WriteMessage(const MessageBuffer &messageBuffer) = 0;
|
||||
virtual Result ReadMessage(MessageBuffer &messageBuffer, uint32 timeoutInMs) = 0;
|
||||
|
||||
// Get a human-readable string describing the connection type.
|
||||
virtual const char* GetTransportName() const = 0;
|
||||
|
||||
// Static method to be implemented by individual transports
|
||||
// true indicates that the transport is incapable of detecting
|
||||
// dropped connections and some form of keep-alive is required
|
||||
// false indicates that the transport can properly detect dropped
|
||||
// connections
|
||||
DD_STATIC_CONST bool RequiresKeepAlive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Static method to be implemented by individual transports
|
||||
// true indicates that Connect is expected to also negotiate a client ID
|
||||
// false indicates that the MessageChannel needs to do it's own client ID
|
||||
// negotiation, e.g. in the case of network connections
|
||||
DD_STATIC_CONST bool RequiresClientRegistration()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
IMsgTransport() {}
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../core/inc/platforms/ddcWinPlatform.h"
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
#include "protocolSession.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class Session;
|
||||
|
||||
class IProtocolClient : public IProtocolSession
|
||||
{
|
||||
public:
|
||||
virtual ~IProtocolClient() {}
|
||||
|
||||
virtual Version GetSessionVersion() const = 0;
|
||||
|
||||
virtual Result Connect(ClientId clientId, uint32 timeoutInMs) = 0;
|
||||
virtual Result Connect(ClientId clientId) = 0;
|
||||
virtual void Disconnect() = 0;
|
||||
|
||||
virtual bool IsConnected() const = 0;
|
||||
virtual ClientId GetRemoteClientId() const = 0;
|
||||
|
||||
virtual bool QueryConnectionStatus() = 0;
|
||||
protected:
|
||||
IProtocolClient() {}
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
#include "protocolSession.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IMsgChannel;
|
||||
class Session;
|
||||
|
||||
class IProtocolServer : public IProtocolSession
|
||||
{
|
||||
public:
|
||||
virtual ~IProtocolServer() {}
|
||||
|
||||
virtual void Finalize() = 0;
|
||||
|
||||
virtual bool GetSupportedVersion(Version minVersion, Version maxVersion, Version *version) const = 0;
|
||||
virtual bool AcceptSession(const SharedPointer<ISession>& pSession) = 0;
|
||||
|
||||
virtual void SessionEstablished(const SharedPointer<ISession> &pSession) = 0;
|
||||
virtual void UpdateSession(const SharedPointer<ISession> &pSession) = 0;
|
||||
virtual void SessionTerminated(const SharedPointer<ISession> &pSession, Result terminationReason) = 0;
|
||||
protected:
|
||||
IProtocolServer() {}
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gpuopen.h>
|
||||
#include <ddPlatform.h>
|
||||
#include <util/sharedptr.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
// A container struct that can hold any protocol's payload and keep track of its size.
|
||||
// Not intended for network transport. This struct is intended to help simplify code that works with variably sized payloads.
|
||||
// The struct is 8 byte aligned because the internal payload field requires 8 byte alignment.
|
||||
DD_ALIGNED_STRUCT(SizedPayloadContainer, 8)
|
||||
{
|
||||
uint32 payloadSize;
|
||||
uint32 padding;
|
||||
char payload[kMaxPayloadSizeInBytes];
|
||||
|
||||
// For safety purposes we limit the CreatePayload and GetPayload methods to types that:
|
||||
//
|
||||
// 1. Have a standard layout, to ensure that the contents are safe to transmit across the network
|
||||
// 2. Are trivially destructible, to ensure that a user doesn't construct an object and then overwrite it
|
||||
// without destroying it
|
||||
// 3. Small enough to fit inside the payload field of this struct
|
||||
template<typename T>
|
||||
struct CanUseAsPayload
|
||||
{
|
||||
static_assert(Platform::IsStandardLayout<T>::Value, "Type provided does not meet standard layout requirements");
|
||||
static_assert(Platform::IsTriviallyDestructible<T>::Value, "Type provided is not trivially destructible");
|
||||
static_assert((sizeof(T) <= kMaxPayloadSizeInBytes), "Type provided is too large to fit in the container");
|
||||
|
||||
DD_STATIC_CONST bool Value = Platform::IsStandardLayout<T>::Value &&
|
||||
Platform::IsTriviallyDestructible<T>::Value &&
|
||||
(sizeof(T) <= kMaxPayloadSizeInBytes);
|
||||
};
|
||||
|
||||
// We additionally only allow creation of a payload if the type is constructible using the arguments specified
|
||||
template<typename T, typename... Args>
|
||||
struct CanCreatePayload
|
||||
{
|
||||
static_assert(CanUseAsPayload<T>::Value, "Type specified cannot be used as a payload");
|
||||
static_assert(Platform::IsConstructible<T, Args...>::Value, "Type provided cannot be constructed with the provided arguments");
|
||||
|
||||
DD_STATIC_CONST bool Value = CanUseAsPayload<T>::Value &&
|
||||
Platform::IsConstructible<T, Args...>::Value;
|
||||
};
|
||||
|
||||
// Convenience function to allow in-place construction of a payload object using placement new.
|
||||
template<typename T,
|
||||
typename... Args,
|
||||
typename = typename Platform::EnableIf<CanCreatePayload<T, Args...>::Value>::Type>
|
||||
void CreatePayload(Args&&... args)
|
||||
{
|
||||
// This is tremendously unsafe, but we use placement new to construct an object inside the buffer.
|
||||
// Why do we do this? The big benefit is that it lets us skip having to create a temporary object
|
||||
// and then copy it into this buffer.
|
||||
//
|
||||
// There are a couple of other ancillary benefits that are useful. The biggest is that if an object has
|
||||
// a constexpr constructor it can initialize the memory using a memcpy/move instead of having to actually
|
||||
// call the constructor. The other benefit is that if the constructor omits initializing memory (e.g.,
|
||||
// a giant data buffer) it will also skip re-initializing the memory here. This is not the case with
|
||||
// when you create another instance of the object and copy it - the temporary object is almost certainly
|
||||
// zero initialized, and the copy/move will result in the entire struct being copied.
|
||||
|
||||
static_assert(alignof(T) <= alignof(SizedPayloadContainer), "Type provided cannot be aligned in the container");
|
||||
|
||||
new(reinterpret_cast<T*>(&payload[0])) T(Platform::Forward<Args>(args)...);
|
||||
payloadSize = sizeof(T);
|
||||
padding = 0;
|
||||
}
|
||||
|
||||
// Convenience function to allow accessing the payload as if it was the specified type.
|
||||
template<typename T,
|
||||
typename = typename Platform::EnableIf<CanUseAsPayload<T>::Value>::Type>
|
||||
T& GetPayload()
|
||||
{
|
||||
return *GetPayloadPointer<T>(&payload[0]);
|
||||
}
|
||||
|
||||
private:
|
||||
// Convenience function to allow accessing the payload as if it was the specified type.
|
||||
template<typename T,
|
||||
typename = typename Platform::EnableIf<CanUseAsPayload<T>::Value>::Type>
|
||||
static constexpr T* GetPayloadPointer(char* DD_RESTRICT pPointer)
|
||||
{
|
||||
static_assert(alignof(T) <= alignof(SizedPayloadContainer), "Type provided cannot be aligned in the container");
|
||||
return (T*)(pPointer);
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SizedPayloadContainer, 8 + kMaxPayloadSizeInBytes);
|
||||
|
||||
class IMsgChannel;
|
||||
class Session;
|
||||
|
||||
enum struct SessionType
|
||||
{
|
||||
Unknown = 0,
|
||||
Client,
|
||||
Server
|
||||
};
|
||||
|
||||
class ISession
|
||||
{
|
||||
public:
|
||||
virtual ~ISession() {};
|
||||
|
||||
virtual Result Send(uint32 payloadSizeInBytes, const void* pPayload, uint32 timeoutInMs) = 0;
|
||||
virtual Result Receive(uint32 payloadSizeInBytes, void *pPayload, uint32 *pBytesReceived, uint32 timeoutInMs) = 0;
|
||||
virtual Result WaitForConnection(uint32 timeoutInMs) = 0;
|
||||
virtual Result WaitForDisconnection(uint32 timeoutInMs) = 0;
|
||||
|
||||
virtual bool IsClosed() const = 0;
|
||||
|
||||
virtual void* SetUserData(void* pUserdata) = 0;
|
||||
virtual void* GetUserData() const = 0;
|
||||
virtual SessionId GetSessionId() const = 0;
|
||||
virtual ClientId GetDestinationClientId() const = 0;
|
||||
virtual Version GetVersion() const = 0;
|
||||
virtual Protocol GetProtocol() const = 0;
|
||||
|
||||
// Helper functions for working with SizedPayloadContainers and managing back-compat.
|
||||
Result SendPayload(const SizedPayloadContainer& payload, uint32 timeoutInMs)
|
||||
{
|
||||
return Send(payload.payloadSize, payload.payload, timeoutInMs);
|
||||
}
|
||||
|
||||
Result ReceivePayload(SizedPayloadContainer* pPayload, uint32 timeoutInMs)
|
||||
{
|
||||
DD_ASSERT(pPayload != nullptr);
|
||||
return Receive(sizeof(pPayload->payload), pPayload->payload, &pPayload->payloadSize, timeoutInMs);
|
||||
}
|
||||
|
||||
protected:
|
||||
ISession() {}
|
||||
};
|
||||
|
||||
class IProtocolSession
|
||||
{
|
||||
public:
|
||||
virtual ~IProtocolSession() {}
|
||||
|
||||
virtual Protocol GetProtocol() const = 0;
|
||||
virtual SessionType GetType() const = 0;
|
||||
virtual Version GetMinVersion() const = 0;
|
||||
virtual Version GetMaxVersion() const = 0;
|
||||
|
||||
protected:
|
||||
IProtocolSession() {}
|
||||
};
|
||||
} // DevDriver
|
||||
+531
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
|
||||
#define DRIVERCONTROL_PROTOCOL_VERSION 10
|
||||
|
||||
#define DRIVERCONTROL_PROTOCOL_MINIMUM_VERSION 1
|
||||
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*| Version | Change Description |
|
||||
*| ------- | ---------------------------------------------------------------------------------------------------------|
|
||||
*| 10.0 | Add ability to set clock mode on all adapters. |
|
||||
*| 9.0 | Added a feature that allows tools to indicate when they will be ignoring a specific driver. |
|
||||
*| 8.0 | Added a new version of the step driver response that contains the current driver status. |
|
||||
*| 7.0 | Corrected a back-compat issue related to the new device clock query code. |
|
||||
*| 6.0 | Added ability to query device clock frequencies for a given clock mode. |
|
||||
*| 5.0 | Cleaned up the driver facing interface. |
|
||||
*| 4.0 | Added HaltedOnPostDeviceInit state. |
|
||||
*| 3.0 | Added QueryClientInfoRequest support. |
|
||||
*| 2.1 | Added initialization time step functionality. |
|
||||
*| 2.0 | Added initialization time driver status values and a terminate driver command. |
|
||||
*| 1.0 | Initial version |
|
||||
***********************************************************************************************************************
|
||||
*/
|
||||
|
||||
#define DRIVERCONTROL_SET_CLOCKS_ALL_ADAPTERS_VERSION 10
|
||||
#define DRIVERCONTROL_IGNORE_DRIVER_VERSION 9
|
||||
#define DRIVERCONTROL_STEP_RETURN_STATUS_VERSION 8
|
||||
#define DRIVERCONTROL_QUERY_BY_MODE_BACK_COMPAT_VERSION 7
|
||||
#define DRIVERCONTROL_QUERY_DEVICE_CLOCKS_BY_MODE_VERSION 6
|
||||
#define DRIVERCONTROL_DRIVER_INTERFACE_CLEANUP_VERSION 5
|
||||
#define DRIVERCONTROL_HALTEDPOSTDEVICEINIT_VERSION 4
|
||||
#define DRIVERCONTROL_QUERYCLIENTINFO_VERSION 3
|
||||
#define DRIVERCONTROL_INITIALIZATION_STATUS_VERSION 2
|
||||
#define DRIVERCONTROL_INITIAL_VERSION 1
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace DriverControlProtocol
|
||||
{
|
||||
///////////////////////
|
||||
// DriverControl Constants
|
||||
DD_STATIC_CONST uint32 kLegacyDriverControlPayloadSize = 16;
|
||||
|
||||
///////////////////////
|
||||
// DriverControl Protocol
|
||||
enum struct DriverControlMessage : MessageCode
|
||||
{
|
||||
Unknown = 0,
|
||||
PauseDriverRequest,
|
||||
PauseDriverResponse,
|
||||
ResumeDriverRequest,
|
||||
ResumeDriverResponse,
|
||||
QueryNumGpusRequest,
|
||||
QueryNumGpusResponse,
|
||||
QueryDeviceClockModeRequest,
|
||||
QueryDeviceClockModeResponse,
|
||||
SetDeviceClockModeRequest,
|
||||
SetDeviceClockModeResponse,
|
||||
QueryDeviceClockRequest,
|
||||
QueryDeviceClockResponse,
|
||||
QueryMaxDeviceClockRequest,
|
||||
QueryMaxDeviceClockResponse,
|
||||
QueryDriverStatusRequest,
|
||||
QueryDriverStatusResponse,
|
||||
StepDriverRequest,
|
||||
StepDriverResponse,
|
||||
QueryClientInfoRequest,
|
||||
QueryClientInfoResponse,
|
||||
QueryDeviceClockByModeRequest,
|
||||
QueryDeviceClockByModeResponse,
|
||||
StepDriverResponseV2,
|
||||
IgnoreDriverRequest,
|
||||
IgnoreDriverResponse,
|
||||
Count
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// DriverControl Types
|
||||
enum struct DeviceClockMode : uint32
|
||||
{
|
||||
Unknown = 0,
|
||||
Default,
|
||||
Profiling,
|
||||
MinimumMemory,
|
||||
MinimumEngine,
|
||||
Peak,
|
||||
Count
|
||||
};
|
||||
|
||||
#if GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION < GPUOPEN_DRIVER_CONTROL_CLEANUP_VERSION
|
||||
typedef DevDriver::DriverStatus DriverStatus;
|
||||
#endif
|
||||
|
||||
///////////////////////
|
||||
// DriverControl Payloads
|
||||
DD_NETWORK_STRUCT(DriverControlHeader, 4)
|
||||
{
|
||||
DriverControlMessage command;
|
||||
char _padding[3];
|
||||
|
||||
constexpr DriverControlHeader(DriverControlMessage message)
|
||||
: command(message)
|
||||
, _padding()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(DriverControlHeader, 4);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Pause Driver Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(PauseDriverRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr PauseDriverRequestPayload()
|
||||
: header(DriverControlMessage::PauseDriverRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(PauseDriverRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(PauseDriverResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
|
||||
constexpr PauseDriverResponsePayload(Result result)
|
||||
: header(DriverControlMessage::PauseDriverResponse)
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(PauseDriverResponsePayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Resume Driver Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(ResumeDriverRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr ResumeDriverRequestPayload()
|
||||
: header(DriverControlMessage::ResumeDriverRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ResumeDriverRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(ResumeDriverResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
|
||||
constexpr ResumeDriverResponsePayload(Result result)
|
||||
: header(DriverControlMessage::ResumeDriverResponse)
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ResumeDriverResponsePayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Num Gpus Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryNumGpusRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr QueryNumGpusRequestPayload()
|
||||
: header(DriverControlMessage::QueryNumGpusRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryNumGpusRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(QueryNumGpusResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
uint32 numGpus;
|
||||
|
||||
constexpr QueryNumGpusResponsePayload(Result result, uint32 numGpus)
|
||||
: header(DriverControlMessage::QueryNumGpusResponse)
|
||||
, result(result)
|
||||
, numGpus(numGpus)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryNumGpusResponsePayload, sizeof(DriverControlHeader) + 8);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Device Clock Mode Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockModeRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 gpuIndex;
|
||||
|
||||
constexpr QueryDeviceClockModeRequestPayload(uint32 gpuIndex)
|
||||
: header(DriverControlMessage::QueryDeviceClockModeRequest)
|
||||
, gpuIndex(gpuIndex)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockModeRequestPayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockModeResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
DeviceClockMode mode;
|
||||
|
||||
constexpr QueryDeviceClockModeResponsePayload(Result result, DeviceClockMode mode)
|
||||
: header(DriverControlMessage::QueryDeviceClockModeResponse)
|
||||
, result(result)
|
||||
, mode(mode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockModeResponsePayload, sizeof(DriverControlHeader) + 8);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Set Device Clock Mode Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(SetDeviceClockModeRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 gpuIndex;
|
||||
DeviceClockMode mode;
|
||||
|
||||
constexpr SetDeviceClockModeRequestPayload(uint32 gpuIndex, DeviceClockMode mode)
|
||||
: header(DriverControlMessage::SetDeviceClockModeRequest)
|
||||
, gpuIndex(gpuIndex)
|
||||
, mode(mode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SetDeviceClockModeRequestPayload, sizeof(DriverControlHeader) + 8);
|
||||
|
||||
DD_NETWORK_STRUCT(SetDeviceClockModeResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
|
||||
constexpr SetDeviceClockModeResponsePayload(Result result)
|
||||
: header(DriverControlMessage::SetDeviceClockModeResponse)
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SetDeviceClockModeResponsePayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Device Clock Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 gpuIndex;
|
||||
|
||||
constexpr QueryDeviceClockRequestPayload(uint32 gpuIndex)
|
||||
: header(DriverControlMessage::QueryDeviceClockRequest)
|
||||
, gpuIndex(gpuIndex)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockRequestPayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
float gpuClock;
|
||||
float memClock;
|
||||
|
||||
constexpr QueryDeviceClockResponsePayload(Result result, float gpuClock, float memClock)
|
||||
: header(DriverControlMessage::QueryDeviceClockResponse)
|
||||
, result(result)
|
||||
, gpuClock(gpuClock)
|
||||
, memClock(memClock)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockResponsePayload, sizeof(DriverControlHeader) + 12);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Device Clock By Mode Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockByModeRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 gpuIndex;
|
||||
DeviceClockMode deviceClockMode;
|
||||
|
||||
constexpr QueryDeviceClockByModeRequestPayload(uint32 gpuIndex, DeviceClockMode clockMode)
|
||||
: header(DriverControlMessage::QueryDeviceClockByModeRequest)
|
||||
, gpuIndex(gpuIndex)
|
||||
, deviceClockMode(clockMode)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockByModeRequestPayload, sizeof(DriverControlHeader) + 8);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryDeviceClockByModeResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
float gpuClock;
|
||||
float memClock;
|
||||
|
||||
constexpr QueryDeviceClockByModeResponsePayload(Result result, float gpuClock, float memClock)
|
||||
: header(DriverControlMessage::QueryDeviceClockByModeResponse)
|
||||
, result(result)
|
||||
, gpuClock(gpuClock)
|
||||
, memClock(memClock)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDeviceClockByModeResponsePayload, sizeof(DriverControlHeader) + 12);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Max Device Clock Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryMaxDeviceClockRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 gpuIndex;
|
||||
|
||||
constexpr QueryMaxDeviceClockRequestPayload(uint32 gpuIndex)
|
||||
: header(DriverControlMessage::QueryMaxDeviceClockRequest)
|
||||
, gpuIndex(gpuIndex)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryMaxDeviceClockRequestPayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryMaxDeviceClockResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
float maxGpuClock;
|
||||
float maxMemClock;
|
||||
|
||||
constexpr QueryMaxDeviceClockResponsePayload(Result result, float maxGpuClock, float maxMemClock)
|
||||
: header(DriverControlMessage::QueryMaxDeviceClockResponse)
|
||||
, result(result)
|
||||
, maxGpuClock(maxGpuClock)
|
||||
, maxMemClock(maxMemClock)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryMaxDeviceClockResponsePayload, sizeof(DriverControlHeader) + 12);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Driver Status Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryDriverStatusRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr QueryDriverStatusRequestPayload()
|
||||
: header(DriverControlMessage::QueryDriverStatusRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDriverStatusRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(QueryDriverStatusResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
DriverStatus status;
|
||||
|
||||
constexpr QueryDriverStatusResponsePayload(DriverStatus status)
|
||||
: header(DriverControlMessage::QueryDriverStatusResponse)
|
||||
, status(status)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryDriverStatusResponsePayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Step Driver Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(StepDriverRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
uint32 count;
|
||||
|
||||
constexpr StepDriverRequestPayload(uint32 count)
|
||||
: header(DriverControlMessage::StepDriverRequest)
|
||||
, count(count)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(StepDriverRequestPayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
DD_NETWORK_STRUCT(StepDriverResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
|
||||
constexpr StepDriverResponsePayload(Result result)
|
||||
: header(DriverControlMessage::StepDriverResponse)
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(StepDriverResponsePayload, sizeof(DriverControlHeader) + 4);
|
||||
|
||||
DD_NETWORK_STRUCT(StepDriverResponsePayloadV2, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
Result result;
|
||||
DriverStatus status;
|
||||
|
||||
constexpr StepDriverResponsePayloadV2(Result result, DriverStatus status)
|
||||
: header(DriverControlMessage::StepDriverResponseV2)
|
||||
, result(result)
|
||||
, status(status)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(StepDriverResponsePayloadV2, sizeof(DriverControlHeader) + 8);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Query Client Info Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(QueryClientInfoRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr QueryClientInfoRequestPayload()
|
||||
: header(DriverControlMessage::QueryClientInfoRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryClientInfoRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(QueryClientInfoResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
ClientInfoStruct clientInfo;
|
||||
|
||||
constexpr QueryClientInfoResponsePayload(const ClientInfoStruct& clientInfo)
|
||||
: header(DriverControlMessage::QueryClientInfoResponse)
|
||||
, clientInfo(clientInfo)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryClientInfoResponsePayload, sizeof(DriverControlHeader) + sizeof(ClientInfoStruct));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Ignore Driver Request/Response
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
DD_NETWORK_STRUCT(IgnoreDriverRequestPayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr IgnoreDriverRequestPayload()
|
||||
: header(DriverControlMessage::IgnoreDriverRequest)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(IgnoreDriverRequestPayload, sizeof(DriverControlHeader));
|
||||
|
||||
DD_NETWORK_STRUCT(IgnoreDriverResponsePayload, 4)
|
||||
{
|
||||
DriverControlHeader header;
|
||||
|
||||
constexpr IgnoreDriverResponsePayload()
|
||||
: header(DriverControlMessage::IgnoreDriverResponse)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(IgnoreDriverResponsePayload, sizeof(DriverControlHeader));
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "baseProtocolServer.h"
|
||||
#include "driverControlProtocol.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace DriverControlProtocol
|
||||
{
|
||||
DD_STATIC_CONST uint32 kMaxNumGpus = 16;
|
||||
|
||||
typedef Result(*SetDeviceClockModeCallback)(uint32 gpuIndex, DeviceClockMode clockMode, void* pUserdata);
|
||||
|
||||
#if GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION < GPUOPEN_DRIVER_CONTROL_QUERY_CLOCKS_BY_MODE_VERSION
|
||||
typedef Result(*QueryDeviceClockCallback)(uint32 gpuIndex, float* pGpuClock, float* pMemClock, void* pUserdata);
|
||||
typedef Result(*QueryMaxDeviceClockCallback)(uint32 gpuIndex, float* pMaxGpuClock, float* pMaxMemClock, void* pUserdata);
|
||||
|
||||
struct DeviceClockCallbackInfo
|
||||
{
|
||||
QueryDeviceClockCallback queryClockCallback;
|
||||
QueryMaxDeviceClockCallback queryMaxClockCallback;
|
||||
SetDeviceClockModeCallback setCallback;
|
||||
void* pUserdata;
|
||||
};
|
||||
#else
|
||||
typedef Result(*QueryDeviceClockCallback)(uint32 gpuIndex, DevDriver::DriverControlProtocol::DeviceClockMode clockMode, float* pGpuClock, float* pMemClock, void* pUserdata);
|
||||
|
||||
struct DeviceClockCallbackInfo
|
||||
{
|
||||
QueryDeviceClockCallback queryClockCallback;
|
||||
SetDeviceClockModeCallback setCallback;
|
||||
void* pUserdata;
|
||||
};
|
||||
#endif
|
||||
|
||||
enum class SessionState;
|
||||
|
||||
class DriverControlServer : public BaseProtocolServer
|
||||
{
|
||||
public:
|
||||
explicit DriverControlServer(IMsgChannel* pMsgChannel);
|
||||
~DriverControlServer();
|
||||
|
||||
void Finalize() override;
|
||||
|
||||
// Session handling functions
|
||||
bool AcceptSession(const SharedPointer<ISession>& pSession) override;
|
||||
void SessionEstablished(const SharedPointer<ISession>& pSession) override;
|
||||
void UpdateSession(const SharedPointer<ISession>& pSession) override;
|
||||
void SessionTerminated(const SharedPointer<ISession>& pSession, Result terminationReason) override;
|
||||
|
||||
// Driver state functions
|
||||
#if GPUOPEN_CLIENT_INTERFACE_MAJOR_VERSION < GPUOPEN_DRIVER_CONTROL_CLEANUP_VERSION
|
||||
// These functions just pass through to the new renamed variants to preserve backward compatibility
|
||||
void WaitForDriverResume() { DriverTick(); }
|
||||
void StartDeviceInit() { StartEarlyDeviceInit(); }
|
||||
void FinishDriverInitialization() { FinishDeviceInit(); }
|
||||
#endif
|
||||
void StartEarlyDeviceInit();
|
||||
void StartLateDeviceInit();
|
||||
void FinishDeviceInit();
|
||||
void PauseDriver();
|
||||
void ResumeDriver();
|
||||
void DriverTick();
|
||||
|
||||
// Other public functions
|
||||
bool IsDriverInitialized() const;
|
||||
DriverStatus QueryDriverStatus();
|
||||
void SetNumGpus(uint32 numGpus);
|
||||
void SetDeviceClockCallback(const DeviceClockCallbackInfo& deviceClockCallbackInfo);
|
||||
uint32 GetNumGpus();
|
||||
DeviceClockMode GetDeviceClockMode(uint32 gpuIndex);
|
||||
|
||||
// Sets the client id that's expected to walk us through the driver initialization process.
|
||||
// If this isn't set, the server will attempt to find a suitable client itself via broadcast + discovery.
|
||||
void SetDriverInitClientId(ClientId clientId) { m_driverInitClientId = clientId; }
|
||||
|
||||
/// Returns true if this driver will be ignored by tools
|
||||
bool IsDriverIgnored() const { return m_isIgnored; }
|
||||
|
||||
private:
|
||||
void LockData();
|
||||
void UnlockData();
|
||||
|
||||
// Private driver state functions
|
||||
void AdvanceDriverInitState();
|
||||
void WaitForResume();
|
||||
bool DiscoverHaltRequests();
|
||||
void HandleDriverHalt();
|
||||
bool IsHalted() const
|
||||
{
|
||||
return ((m_driverStatus == DriverStatus::HaltedOnPlatformInit) ||
|
||||
(m_driverStatus == DriverStatus::HaltedOnDeviceInit) ||
|
||||
(m_driverStatus == DriverStatus::HaltedPostDeviceInit));
|
||||
}
|
||||
|
||||
// Protocol message handlers
|
||||
SessionState HandlePauseDriverRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleResumeDriverRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryDeviceClockModeRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleSetDeviceClockModeRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryDeviceClockRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryDeviceClockByModeRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryMaxDeviceClockRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryNumGpusRequest(SizedPayloadContainer& container);
|
||||
SessionState HandleQueryDriverStatusRequest(SizedPayloadContainer& container, const Version sessionVersion);
|
||||
SessionState HandleStepDriverRequest(SizedPayloadContainer& container, const Version sessionVersion);
|
||||
SessionState HandleIgnoreDriverRequest(SizedPayloadContainer& container);
|
||||
|
||||
Platform::Mutex m_mutex;
|
||||
DriverStatus m_driverStatus;
|
||||
Platform::Event m_driverResumedEvent;
|
||||
|
||||
uint32 m_numGpus;
|
||||
DeviceClockMode m_deviceClockModes[kMaxNumGpus];
|
||||
DeviceClockCallbackInfo m_deviceClockCallbackInfo;
|
||||
Platform::Atomic m_numSessions;
|
||||
Platform::Atomic m_stepCounter;
|
||||
bool m_initStepRequested;
|
||||
|
||||
// The client id of the remote client who's responsible for walking us through the driver initialization
|
||||
// process.
|
||||
ClientId m_driverInitClientId;
|
||||
|
||||
// This value is set to true if a remote tool has indicated that this driver will be ignored
|
||||
bool m_isIgnored;
|
||||
|
||||
DD_STATIC_CONST uint32 kBroadcastIntervalInMs = 100;
|
||||
DD_STATIC_CONST uint32 kDefaultDriverStartTimeoutMs = 1000;
|
||||
};
|
||||
}
|
||||
} // DevDriver
|
||||
+537
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push)
|
||||
|
||||
#include "gpuopen.h"
|
||||
|
||||
#define RGP_PROTOCOL_VERSION 11
|
||||
|
||||
#define RGP_PROTOCOL_MINIMUM_VERSION 2
|
||||
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*| Version | Change Description |
|
||||
*| ------- | ---------------------------------------------------------------------------------------------------------|
|
||||
*| 11.0 | Version bumped to indicate driver support for SE mask only applying to detailed instruction tracing |
|
||||
*| 10.0 | Added support for SPM counters and SE masking. |
|
||||
*| 9.0 | Decoupled trace parameters from execute trace request. |
|
||||
*| 8.0 | Added support for capturing the RGP trace on specific frame or dispatch |
|
||||
*| | Added bitfield to control whether driver internal code objects are included in the code object database |
|
||||
*| 7.0 | Added support for aborting traces that are still in the pending state on the server. |
|
||||
*| 6.0 | Added support for trace trigger markers. |
|
||||
*| 5.0 | Added support for allow compute presents trace parameter and removed unused clock mode parameter. |
|
||||
*| 4.0 | Added support for reporting trace transfer progress. |
|
||||
*| 3.0 | Updated TraceParameters struct to allow for specifying profiling clock mode. |
|
||||
*| 2.0 | Add TraceParameters struct and ExecuteTraceRequestPayload so a client can specify trace options. |
|
||||
*| 1.0 | Initial version |
|
||||
***********************************************************************************************************************
|
||||
*/
|
||||
|
||||
#define RGP_DETAILED_SEMASK_VERSION 11
|
||||
#define RGP_SPM_COUNTERS_VERSION 10
|
||||
#define RGP_DECOUPLED_TRACE_PARAMETERS 9
|
||||
#define RGP_FRAME_CAPTURE_VERSION 8
|
||||
#define RGP_PENDING_ABORT_VERSION 7
|
||||
#define RGP_TRIGGER_MARKERS_VERSION 6
|
||||
#define RGP_COMPUTE_PRESENTS_VERSION 5
|
||||
#define RGP_TRACE_PROGRESS_VERSION 4
|
||||
#define RGP_PROFILING_CLOCK_MODES_VERSION 3
|
||||
#define RGP_TRACE_PARAMETERS_VERSION 2
|
||||
#define RGP_INITIAL_VERSION 1
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace RGPProtocol
|
||||
{
|
||||
///////////////////////
|
||||
// RGP Protocol
|
||||
enum struct RGPMessage : MessageCode
|
||||
{
|
||||
Unknown = 0,
|
||||
ExecuteTraceRequest,
|
||||
TraceDataChunk,
|
||||
TraceDataSentinel,
|
||||
QueryProfilingStatusRequest,
|
||||
QueryProfilingStatusResponse,
|
||||
EnableProfilingRequest,
|
||||
EnableProfilingResponse,
|
||||
TraceDataHeader,
|
||||
AbortTrace,
|
||||
QueryTraceParametersRequest,
|
||||
QueryTraceParametersResponse,
|
||||
UpdateTraceParametersRequest,
|
||||
UpdateTraceParametersResponse,
|
||||
UpdateSpmConfigRequest,
|
||||
UpdateSpmConfigData,
|
||||
UpdateSpmConfigResponse,
|
||||
Count
|
||||
};
|
||||
|
||||
// @note: We currently subtract sizeof(uint32) instead of sizeof(RGPMessage) to work around struct packing issues.
|
||||
// The compiler pads out RGPMessage to 4 bytes when it's included in the payload struct. It also pads out
|
||||
// the TraceDataChunk data field to 1000 bytes. This causes the total payload size to be 1004 bytes which is
|
||||
// 4 bytes larger than the maximum size allowed.
|
||||
DD_STATIC_CONST Size kMaxTraceDataChunkSize = (kMaxPayloadSizeInBytes - sizeof(uint32) - sizeof(uint32));
|
||||
|
||||
///////////////////////
|
||||
// RGP Constants
|
||||
const uint32 kMarkerStringLength = 256;
|
||||
const uint32 kMaxSpmCountersPerUpdate = 320;
|
||||
|
||||
// Define the number of bits per SPM id value
|
||||
constexpr uint32 kSpmBlockIdBits = 8;
|
||||
constexpr uint32 kSpmInstanceIdBits = 12;
|
||||
constexpr uint32 kSpmEventIdBits = 12;
|
||||
|
||||
// Define the max SPM id values based on the number of bits we allocate for them in the network packet
|
||||
constexpr uint32 kMaxSpmBlockId = (1 << kSpmBlockIdBits);
|
||||
constexpr uint32 kMaxSpmInstanceId = (1 << kSpmInstanceIdBits);
|
||||
constexpr uint32 kMaxSpmEventId = (1 << kSpmEventIdBits);
|
||||
|
||||
// The application can specify this value for the instance id and it will be expanded into
|
||||
// all available instances on the driver side.
|
||||
// The counter fields are bit packed when transferred over the network so we need to account for that here
|
||||
// rather than simply setting all bits.
|
||||
constexpr uint32 kSpmAllInstancesId = (kMaxSpmInstanceId - 1);
|
||||
|
||||
///////////////////////
|
||||
// RGP Types
|
||||
DD_NETWORK_STRUCT(TraceDataChunk, 4)
|
||||
{
|
||||
uint32 dataSize;
|
||||
uint8 data[kMaxTraceDataChunkSize];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceDataChunk, kMaxTraceDataChunkSize + sizeof(int32));
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParameters, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 reserved : 31;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParameters, 12);
|
||||
|
||||
enum struct ProfilingClockMode : uint32
|
||||
{
|
||||
Stable = 0,
|
||||
Max,
|
||||
Normal,
|
||||
Count
|
||||
};
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV2, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
ProfilingClockMode clockMode;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 reserved : 31;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV2, 16);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV3, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 reserved : 30;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV3, 12);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV4, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 reserved : 30;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
|
||||
// Begin Tag
|
||||
uint32 beginTagHigh;
|
||||
uint32 beginTagLow;
|
||||
|
||||
// End Tag
|
||||
uint32 endTagHigh;
|
||||
uint32 endTagLow;
|
||||
|
||||
// Begin/End Marker Strings
|
||||
char beginMarker[kMarkerStringLength];
|
||||
char endMarker[kMarkerStringLength];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV4, 540);
|
||||
|
||||
enum struct CaptureTriggerMode : uint32
|
||||
{
|
||||
Present = 0,
|
||||
Markers,
|
||||
Index,
|
||||
Count
|
||||
};
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV5, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
uint32 captureStartIndex;
|
||||
uint32 captureStopIndex;
|
||||
CaptureTriggerMode captureMode;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 captureDriverCodeObjects : 1;
|
||||
uint32 reserved : 29;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
|
||||
// Begin Tag
|
||||
uint32 beginTagHigh;
|
||||
uint32 beginTagLow;
|
||||
|
||||
// End Tag
|
||||
uint32 endTagHigh;
|
||||
uint32 endTagLow;
|
||||
|
||||
// Begin/End Marker Strings
|
||||
char beginMarker[kMarkerStringLength];
|
||||
char endMarker[kMarkerStringLength];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV5, 552);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV6, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
uint32 captureStartIndex;
|
||||
uint32 captureStopIndex;
|
||||
CaptureTriggerMode captureMode;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 captureDriverCodeObjects : 1;
|
||||
uint32 reserved : 29;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
|
||||
// Begin Tag
|
||||
uint32 beginTagHigh;
|
||||
uint32 beginTagLow;
|
||||
|
||||
// End Tag
|
||||
uint32 endTagHigh;
|
||||
uint32 endTagLow;
|
||||
|
||||
// Begin/End Marker Strings
|
||||
char beginMarker[kMarkerStringLength];
|
||||
char endMarker[kMarkerStringLength];
|
||||
|
||||
// Target pipeline hash
|
||||
uint32 pipelineHashHi;
|
||||
uint32 pipelineHashLo;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV6, 560);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceParametersV7, 4)
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
uint32 captureStartIndex;
|
||||
uint32 captureStopIndex;
|
||||
CaptureTriggerMode captureMode;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 captureDriverCodeObjects : 1;
|
||||
uint32 enableSpm : 1;
|
||||
uint32 reserved : 28;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
|
||||
// Begin Tag
|
||||
uint32 beginTagHigh;
|
||||
uint32 beginTagLow;
|
||||
|
||||
// End Tag
|
||||
uint32 endTagHigh;
|
||||
uint32 endTagLow;
|
||||
|
||||
// Begin/End Marker Strings
|
||||
char beginMarker[kMarkerStringLength];
|
||||
char endMarker[kMarkerStringLength];
|
||||
|
||||
// Target pipeline hash
|
||||
uint32 pipelineHashHi;
|
||||
uint32 pipelineHashLo;
|
||||
|
||||
// Shader Engine Mask
|
||||
uint32 seMask;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceParametersV7, 564);
|
||||
|
||||
DD_NETWORK_STRUCT(SpmCounterId, 4)
|
||||
{
|
||||
uint32 blockId : kSpmBlockIdBits;
|
||||
uint32 instanceId : kSpmInstanceIdBits;
|
||||
uint32 eventId : kSpmEventIdBits;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SpmCounterId, 4);
|
||||
|
||||
static_assert(
|
||||
kSpmBlockIdBits + kSpmInstanceIdBits + kSpmEventIdBits == 8 * sizeof(SpmCounterId),
|
||||
"SpmCounterId is wasting bits");
|
||||
|
||||
enum struct ProfilingStatus : uint32
|
||||
{
|
||||
NotAvailable = 0,
|
||||
Available,
|
||||
Enabled,
|
||||
Count
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// RGP Payloads
|
||||
|
||||
DD_NETWORK_STRUCT(ExecuteTraceRequestPayload, 4)
|
||||
{
|
||||
TraceParameters parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ExecuteTraceRequestPayload, 12);
|
||||
|
||||
DD_NETWORK_STRUCT(ExecuteTraceRequestPayloadV2, 4)
|
||||
{
|
||||
TraceParametersV2 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ExecuteTraceRequestPayloadV2, 16);
|
||||
|
||||
DD_NETWORK_STRUCT(ExecuteTraceRequestPayloadV3, 4)
|
||||
{
|
||||
TraceParametersV3 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ExecuteTraceRequestPayloadV3, 12);
|
||||
|
||||
DD_NETWORK_STRUCT(ExecuteTraceRequestPayloadV4, 4)
|
||||
{
|
||||
TraceParametersV4 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ExecuteTraceRequestPayloadV4, 540);
|
||||
|
||||
DD_NETWORK_STRUCT(ExecuteTraceRequestPayloadV5, 4)
|
||||
{
|
||||
TraceParametersV5 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ExecuteTraceRequestPayloadV5, 552);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceDataChunkPayload, 4)
|
||||
{
|
||||
TraceDataChunk chunk;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceDataChunkPayload, kMaxTraceDataChunkSize + sizeof(int32));
|
||||
|
||||
DD_NETWORK_STRUCT(TraceDataSentinelPayload, 4)
|
||||
{
|
||||
Result result;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceDataSentinelPayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(TraceDataHeaderPayload, 4)
|
||||
{
|
||||
Result result;
|
||||
uint32 numChunks;
|
||||
uint32 sizeInBytes;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(TraceDataHeaderPayload, 12);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryProfilingStatusResponsePayload, 4)
|
||||
{
|
||||
ProfilingStatus status;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryProfilingStatusResponsePayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(EnableProfilingResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(EnableProfilingResponsePayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryTraceParametersResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
TraceParametersV6 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryTraceParametersResponsePayload, 564);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryTraceParametersResponsePayloadV2, 4)
|
||||
{
|
||||
Result result;
|
||||
TraceParametersV7 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryTraceParametersResponsePayloadV2, 568);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateTraceParametersRequestPayload, 4)
|
||||
{
|
||||
TraceParametersV6 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateTraceParametersRequestPayload, 560);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateTraceParametersRequestPayloadV2, 4)
|
||||
{
|
||||
TraceParametersV7 parameters;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateTraceParametersRequestPayloadV2, 564);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateTraceParametersResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateTraceParametersResponsePayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateSpmConfigRequestPayload, 4)
|
||||
{
|
||||
uint32 sampleFrequency;
|
||||
uint32 memoryLimitInMb;
|
||||
uint32 numDataPayloads;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateSpmConfigRequestPayload, 12);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateSpmConfigDataPayload, 4)
|
||||
{
|
||||
uint32 numCounters;
|
||||
SpmCounterId counters[kMaxSpmCountersPerUpdate];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateSpmConfigDataPayload, 1284);
|
||||
|
||||
DD_NETWORK_STRUCT(UpdateSpmConfigResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(UpdateSpmConfigResponsePayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(RGPPayload, 4)
|
||||
{
|
||||
RGPMessage command;
|
||||
// pad out to 4 bytes for alignment requirements
|
||||
char padding[3];
|
||||
union
|
||||
{
|
||||
ExecuteTraceRequestPayload executeTraceRequest;
|
||||
ExecuteTraceRequestPayloadV2 executeTraceRequestV2;
|
||||
ExecuteTraceRequestPayloadV3 executeTraceRequestV3;
|
||||
ExecuteTraceRequestPayloadV4 executeTraceRequestV4;
|
||||
ExecuteTraceRequestPayloadV5 executeTraceRequestV5;
|
||||
TraceDataChunkPayload traceDataChunk;
|
||||
TraceDataSentinelPayload traceDataSentinel;
|
||||
TraceDataHeaderPayload traceDataHeader;
|
||||
QueryProfilingStatusResponsePayload queryProfilingStatusResponse;
|
||||
EnableProfilingResponsePayload enableProfilingStatusResponse;
|
||||
QueryTraceParametersResponsePayload queryTraceParametersResponse;
|
||||
QueryTraceParametersResponsePayloadV2 queryTraceParametersResponseV2;
|
||||
UpdateTraceParametersRequestPayload updateTraceParametersRequest;
|
||||
UpdateTraceParametersRequestPayloadV2 updateTraceParametersRequestV2;
|
||||
UpdateTraceParametersResponsePayload updateTraceParametersResponse;
|
||||
UpdateSpmConfigRequestPayload updateSpmConfigRequest;
|
||||
UpdateSpmConfigDataPayload updateSpmConfigData;
|
||||
UpdateSpmConfigResponsePayload updateSpmConfigResponse;
|
||||
};
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(RGPPayload, kMaxPayloadSizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "baseProtocolServer.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
#include "rgpProtocol.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace RGPProtocol
|
||||
{
|
||||
enum class TraceStatus : uint32
|
||||
{
|
||||
Idle = 0,
|
||||
Pending,
|
||||
Running,
|
||||
Finishing,
|
||||
Aborting
|
||||
};
|
||||
|
||||
struct ServerTraceParametersInfo
|
||||
{
|
||||
uint32 gpuMemoryLimitInMb;
|
||||
uint32 numPreparationFrames;
|
||||
uint32 captureStartIndex;
|
||||
uint32 captureStopIndex;
|
||||
CaptureTriggerMode captureMode;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 enableInstructionTokens : 1;
|
||||
uint32 allowComputePresents : 1;
|
||||
uint32 captureDriverCodeObjects : 1;
|
||||
uint32 enableSpm : 1;
|
||||
uint32 reserved : 28;
|
||||
};
|
||||
uint32 u32All;
|
||||
} flags;
|
||||
|
||||
uint64 beginTag;
|
||||
uint64 endTag;
|
||||
|
||||
char beginMarker[kMarkerStringLength];
|
||||
char endMarker[kMarkerStringLength];
|
||||
|
||||
uint64 pipelineHash;
|
||||
|
||||
#if DD_VERSION_SUPPORTS(GPUOPEN_RGP_SPM_COUNTERS_VERSION)
|
||||
uint32 seMask;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ServerSpmCounterId
|
||||
{
|
||||
uint32 blockId;
|
||||
uint32 instanceId;
|
||||
uint32 eventId;
|
||||
};
|
||||
|
||||
struct ServerSpmConfig
|
||||
{
|
||||
uint32 sampleFrequency;
|
||||
uint32 memoryLimitInMb;
|
||||
};
|
||||
|
||||
typedef bool (*PFN_ValidateSpmConfig)(void* pUserdata, const ServerSpmConfig* pConfig, const Vector<ServerSpmCounterId>* pCounterData);
|
||||
struct ValidateSpmCallbackInfo
|
||||
{
|
||||
void* pUserdata;
|
||||
PFN_ValidateSpmConfig pfnValidateSpmConfig;
|
||||
};
|
||||
|
||||
struct RGPSession;
|
||||
|
||||
class RGPServer : public BaseProtocolServer
|
||||
{
|
||||
public:
|
||||
explicit RGPServer(IMsgChannel* pMsgChannel);
|
||||
~RGPServer();
|
||||
|
||||
void Finalize() override;
|
||||
|
||||
bool AcceptSession(const SharedPointer<ISession>& pSession) override;
|
||||
void SessionEstablished(const SharedPointer<ISession>& pSession) override;
|
||||
void UpdateSession(const SharedPointer<ISession>& pSession) override;
|
||||
void SessionTerminated(const SharedPointer<ISession>& pSession, Result terminationReason) override;
|
||||
|
||||
// Returns true if traces are currently enabled.
|
||||
bool TracesEnabled();
|
||||
|
||||
// Allows remote clients to request traces.
|
||||
Result EnableTraces();
|
||||
|
||||
// Disable support for traces.
|
||||
Result DisableTraces();
|
||||
|
||||
// Returns true if a client has requested a trace and it has not been started yet.
|
||||
bool IsTracePending();
|
||||
|
||||
// Returns true if a client has requested a trace and it is currently running.
|
||||
bool IsTraceRunning();
|
||||
|
||||
// Returns true if the server is currently outputting trace results to a client.
|
||||
bool IsTraceOutputInProgress();
|
||||
|
||||
// Starts a new trace. This will only succeed if a trace was previously pending.
|
||||
Result BeginTrace();
|
||||
|
||||
// Ends a trace. This will only succeed if a trace was previously in progress.
|
||||
Result EndTrace();
|
||||
|
||||
// Aborts a trace. This will only succeed if a trace was previously in progress.
|
||||
Result AbortTrace();
|
||||
|
||||
// Writes data into the current trace. This can only be performed when there is a trace in progress.
|
||||
Result WriteTraceData(const uint8* pTraceData, size_t traceDataSize);
|
||||
|
||||
// Returns the current profiling status on the rgp server.
|
||||
ProfilingStatus QueryProfilingStatus();
|
||||
|
||||
// Returns the current trace parameters on the rgp server.
|
||||
ServerTraceParametersInfo QueryTraceParameters();
|
||||
|
||||
// Populates the provided structure with the current perf counter config and returns data for each counter
|
||||
// in the provided vector
|
||||
Result QuerySpmConfig(ServerSpmConfig* pConfig, Vector<ServerSpmCounterId>* pCounterData);
|
||||
|
||||
// Sets a validation callback that will be used to validate SPM configuration data
|
||||
void SetSpmValidationCallback(const ValidateSpmCallbackInfo& callback);
|
||||
|
||||
private:
|
||||
void LockData();
|
||||
void UnlockData();
|
||||
void ClearCurrentSession();
|
||||
Result UpdateSpmConfig(const ServerSpmConfig& config, const Vector<ServerSpmCounterId>& counters);
|
||||
|
||||
Platform::Mutex m_mutex;
|
||||
TraceStatus m_traceStatus;
|
||||
RGPSession* m_pCurrentSessionData;
|
||||
ProfilingStatus m_profilingStatus;
|
||||
ServerTraceParametersInfo m_traceParameters;
|
||||
ServerSpmConfig m_spmConfig;
|
||||
Vector<ServerSpmCounterId> m_spmCounterData;
|
||||
ValidateSpmCallbackInfo m_spmValidationCb;
|
||||
};
|
||||
}
|
||||
} // DevDriver
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpuopen.h"
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
namespace SystemProtocol
|
||||
{
|
||||
///////////////////////
|
||||
// GPU Open System Protocol
|
||||
enum struct SystemMessage : MessageCode
|
||||
{
|
||||
Unknown = 0,
|
||||
ClientConnected,
|
||||
ClientDisconnected,
|
||||
Ping,
|
||||
Pong,
|
||||
QueryClientInfo,
|
||||
ClientInfo,
|
||||
Halted,
|
||||
Count,
|
||||
};
|
||||
}
|
||||
|
||||
namespace SessionProtocol
|
||||
{
|
||||
///////////////////////
|
||||
// GPU Open Session Protocol
|
||||
enum struct SessionMessage : MessageCode
|
||||
{
|
||||
Unknown = 0,
|
||||
Syn,
|
||||
SynAck,
|
||||
Fin,
|
||||
Data,
|
||||
Ack,
|
||||
Rst,
|
||||
Count
|
||||
};
|
||||
|
||||
typedef uint8 SessionVersion;
|
||||
// Session protocol 2 lets session servers return session version as part of the synack
|
||||
DD_STATIC_CONST SessionVersion kSessionProtocolVersionSynAckVersion = 2;
|
||||
// Session protocol 1 lets session clients specify a max range supported as part of the syn
|
||||
DD_STATIC_CONST SessionVersion kSessionProtocolRangeVersion = 1;
|
||||
// current version is 2
|
||||
DD_STATIC_CONST SessionVersion kSessionProtocolVersion = kSessionProtocolVersionSynAckVersion;
|
||||
// not mentioned is session version 0. It only supported min version in SynAck, servers reporting it cannot
|
||||
// cleanly terminate in response to a Fin packet.
|
||||
|
||||
// tripwire - this intentionally will break if the message version changes. Since that implies a breaking change, we need to address
|
||||
// to re-baseline this as version 0 and update the SynPayload struct at the same time
|
||||
static_assert(kMessageVersion == 1011, "Session packets need to be cleaned up as part of the next protocol version");
|
||||
|
||||
DD_NETWORK_STRUCT(SynPayload, 4)
|
||||
{
|
||||
Version minVersion;
|
||||
Protocol protocol;
|
||||
// pad out to 4 bytes
|
||||
SessionVersion sessionVersion;
|
||||
|
||||
// New fields read if sessionVersion != 0
|
||||
Version maxVersion;
|
||||
// pad out to 8 bytes
|
||||
uint8 reserved[2];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SynPayload, 8);
|
||||
|
||||
//
|
||||
// SynPayloadV2 is here so that we can use it with the next breaking message bus change.
|
||||
//
|
||||
//DD_NETWORK_STRUCT(SynPayloadV2, 4)
|
||||
//{
|
||||
// Protocol protocol;
|
||||
// SessionVersion sessionVersion;
|
||||
// Version minVersion;
|
||||
// Version maxVersion;
|
||||
// // pad out to 8 bytes
|
||||
// uint8 reserved[2];
|
||||
//};
|
||||
|
||||
//DD_CHECK_SIZE(SynPayloadV2, 8);
|
||||
|
||||
DD_NETWORK_STRUCT(SynAckPayload, 8)
|
||||
{
|
||||
Sequence sequence;
|
||||
SessionId initialSessionId;
|
||||
Version version;
|
||||
SessionVersion sessionVersion;
|
||||
uint8 reserved[1];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SynAckPayload, 16);
|
||||
}
|
||||
|
||||
namespace ClientManagementProtocol
|
||||
{
|
||||
|
||||
///////////////////////
|
||||
// GPU Open ClientManagement Protocol
|
||||
enum struct ManagementMessage : MessageCode
|
||||
{
|
||||
Unknown = 0,
|
||||
ConnectRequest,
|
||||
ConnectResponse,
|
||||
DisconnectNotification,
|
||||
DisconnectResponse,
|
||||
SetClientFlags,
|
||||
SetClientFlagsResponse,
|
||||
QueryStatus,
|
||||
QueryStatusResponse,
|
||||
KeepAlive,
|
||||
Count
|
||||
};
|
||||
|
||||
DD_STATIC_CONST MessageBuffer kOutOfBandMessage =
|
||||
{
|
||||
{ // header
|
||||
kBroadcastClientId, //srcClientId
|
||||
kBroadcastClientId, //dstClientId
|
||||
Protocol::ClientManagement, //protocolId
|
||||
0, //messageId
|
||||
0, //windowSize
|
||||
0, //payloadSize
|
||||
0, //sessionId
|
||||
kMessageVersion //sequence
|
||||
},
|
||||
{} // payload
|
||||
};
|
||||
|
||||
inline bool IsOutOfBandMessage(const MessageBuffer &message)
|
||||
{
|
||||
// an out of band message is denoted by both the dstClientId and srcClientId
|
||||
// being initialized to kBroadcastClientId.
|
||||
static_assert(kBroadcastClientId == 0, "Error, kBroadcastClientId is non-zero. IsOutOfBandMessage needs to be fixed");
|
||||
return ((message.header.dstClientId | message.header.srcClientId) == kBroadcastClientId);
|
||||
}
|
||||
|
||||
inline bool IsValidOutOfBandMessage(const MessageBuffer &message)
|
||||
{
|
||||
// an out of band message is only valid if the sequence field is initialized with the correct version
|
||||
// and the protocolId is equal to the receiving client's Protocol::ClientManagement value
|
||||
return ((message.header.sequence == kMessageVersion) &
|
||||
(message.header.protocolId == Protocol::ClientManagement));
|
||||
}
|
||||
|
||||
DD_NETWORK_STRUCT(ConnectRequestPayload, 4)
|
||||
{
|
||||
StatusFlags initialClientFlags;
|
||||
uint8 padding[2];
|
||||
Component componentType;
|
||||
uint8 reserved[3];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ConnectRequestPayload, 8);
|
||||
|
||||
DD_NETWORK_STRUCT(ConnectResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
ClientId clientId;
|
||||
// pad this out to 8 bytes for future expansion
|
||||
uint8 padding[2];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(ConnectResponsePayload, 8);
|
||||
|
||||
DD_NETWORK_STRUCT(SetClientFlagsPayload, 4)
|
||||
{
|
||||
StatusFlags flags;
|
||||
uint8 padding[2];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SetClientFlagsPayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(SetClientFlagsResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(SetClientFlagsResponsePayload, 4);
|
||||
|
||||
DD_NETWORK_STRUCT(QueryStatusResponsePayload, 4)
|
||||
{
|
||||
Result result;
|
||||
StatusFlags flags;
|
||||
uint8 reserved[2];
|
||||
};
|
||||
|
||||
DD_CHECK_SIZE(QueryStatusResponsePayload, 8);
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
class IProtocolServer;
|
||||
class IProtocolClient;
|
||||
|
||||
template <Protocol protocol>
|
||||
struct ProtocolServerMap
|
||||
{
|
||||
typedef IProtocolServer type;
|
||||
};
|
||||
|
||||
template <Protocol protocol>
|
||||
struct ProtocolClientMap
|
||||
{
|
||||
typedef IProtocolClient type;
|
||||
};
|
||||
|
||||
template <Protocol protocol>
|
||||
using ProtocolServerType = typename ProtocolServerMap<protocol>::type;
|
||||
|
||||
template <Protocol protocol>
|
||||
using ProtocolClientType = typename ProtocolClientMap<protocol>::type;
|
||||
|
||||
namespace DriverControlProtocol
|
||||
{
|
||||
class DriverControlServer;
|
||||
class DriverControlClient;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::DriverControl>
|
||||
{
|
||||
typedef DriverControlProtocol::DriverControlServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::DriverControl>
|
||||
{
|
||||
typedef DriverControlProtocol::DriverControlClient type;
|
||||
};
|
||||
|
||||
namespace RGPProtocol
|
||||
{
|
||||
class RGPServer;
|
||||
class RGPClient;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::RGP>
|
||||
{
|
||||
typedef RGPProtocol::RGPServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::RGP>
|
||||
{
|
||||
typedef RGPProtocol::RGPClient type;
|
||||
};
|
||||
|
||||
namespace EventProtocol
|
||||
{
|
||||
class EventServer;
|
||||
class EventClient;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::Event>
|
||||
{
|
||||
typedef EventProtocol::EventServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::Event>
|
||||
{
|
||||
typedef EventProtocol::EventClient type;
|
||||
};
|
||||
|
||||
namespace ETWProtocol
|
||||
{
|
||||
class ETWServer;
|
||||
class ETWClient;
|
||||
}
|
||||
|
||||
namespace SettingsURIService
|
||||
{
|
||||
class SettingsService;
|
||||
}
|
||||
|
||||
namespace InfoURIService
|
||||
{
|
||||
class InfoService;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::ETW>
|
||||
{
|
||||
typedef ETWProtocol::ETWServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::ETW>
|
||||
{
|
||||
typedef ETWProtocol::ETWClient type;
|
||||
};
|
||||
|
||||
namespace TransferProtocol
|
||||
{
|
||||
class TransferServer;
|
||||
class TransferClient;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::Transfer>
|
||||
{
|
||||
typedef TransferProtocol::TransferServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::Transfer>
|
||||
{
|
||||
typedef TransferProtocol::TransferClient type;
|
||||
};
|
||||
|
||||
namespace URIProtocol
|
||||
{
|
||||
class URIServer;
|
||||
class URIClient;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ProtocolServerMap<Protocol::URI>
|
||||
{
|
||||
typedef URIProtocol::URIServer type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ProtocolClientMap<Protocol::URI>
|
||||
{
|
||||
typedef URIProtocol::URIClient type;
|
||||
};
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddPlatform.h>
|
||||
#include <metrohash.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
|
||||
namespace MetroHash
|
||||
{
|
||||
/// 128-bit hash structure
|
||||
struct Hash
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32 dwords[4]; ///< Output hash in dwords.
|
||||
uint8 bytes[16]; ///< Output hash in bytes.
|
||||
};
|
||||
};
|
||||
|
||||
// Compacts a 128-bit hash into a 64-bit one by XOR'ing the low and high 64-bits together.
|
||||
inline uint64 Compact64(
|
||||
const Hash* pHash)
|
||||
{
|
||||
return (static_cast<uint64>(pHash->dwords[3] ^ pHash->dwords[1]) |
|
||||
(static_cast<uint64>(pHash->dwords[2] ^ pHash->dwords[0]) << 32));
|
||||
}
|
||||
|
||||
// Compacts a 64-bit hash checksum into a 32-bit one by XOR'ing each 32-bit chunk together.
|
||||
inline uint32 Compact32(
|
||||
const Hash* pHash)
|
||||
{
|
||||
return pHash->dwords[3] ^ pHash->dwords[2] ^ pHash->dwords[1] ^ pHash->dwords[0];
|
||||
}
|
||||
|
||||
// Compacts a 64-bit hash checksum into a 32-bit one by XOR'ing each 32-bit chunk together.
|
||||
inline uint32 Compact32(
|
||||
const uint64 hash)
|
||||
{
|
||||
return static_cast<uint32>(hash) ^ static_cast<uint32>(hash >> 32);
|
||||
}
|
||||
|
||||
inline uint64 MetroHash64(const uint8* pData, const uint64 dataSize)
|
||||
{
|
||||
uint64 hash = 0;
|
||||
Util::MetroHash64::Hash(pData, dataSize, reinterpret_cast<uint8*>(&hash));
|
||||
return hash;
|
||||
}
|
||||
|
||||
inline uint32 MetroHash32(const uint8* pData, const uint64 dataSize)
|
||||
{
|
||||
return Compact32(MetroHash64(pData, dataSize));
|
||||
}
|
||||
|
||||
inline uint64 HashCStr64(const char* pString)
|
||||
{
|
||||
return MetroHash64(reinterpret_cast<const uint8*>(pString), strlen(pString));
|
||||
}
|
||||
|
||||
} // MetroHash
|
||||
} // DevDriver
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <ddPlatform.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
// The value half of a key-value pair from a StructuredReader.
|
||||
// This always wraps a valid IValue pointer, but the value semantically stored may be empty. (e.g. a Json null)
|
||||
class StructuredValue
|
||||
{
|
||||
public:
|
||||
// In order to avoid leaking internal headers, we treat this member as an opaque data type.
|
||||
// Its size and alignment is checked in the cpp file.
|
||||
/// This is an internal type, only exposed due to limitations in C++ semantics.
|
||||
struct OpaqueNode
|
||||
{
|
||||
void* blob[2] = {};
|
||||
};
|
||||
|
||||
~StructuredValue() = default;
|
||||
|
||||
StructuredValue()
|
||||
: m_opaque()
|
||||
{}
|
||||
|
||||
explicit StructuredValue(OpaqueNode opaque)
|
||||
: m_opaque(opaque)
|
||||
{}
|
||||
|
||||
StructuredValue(StructuredValue&& other) = default;
|
||||
StructuredValue(const StructuredValue& other) = default;
|
||||
|
||||
StructuredValue& operator=(StructuredValue&& other) = default;
|
||||
StructuredValue& operator=(const StructuredValue& other) = default;
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Null = 0,
|
||||
Array,
|
||||
Map,
|
||||
Str,
|
||||
Bool,
|
||||
Int,
|
||||
Uint,
|
||||
Double,
|
||||
Float,
|
||||
};
|
||||
|
||||
// Type of data contained in this node.
|
||||
Type GetType() const;
|
||||
|
||||
const char* GetTypeString() const
|
||||
{
|
||||
switch (GetType())
|
||||
{
|
||||
case StructuredValue::Type::Null: return "Null";
|
||||
|
||||
case StructuredValue::Type::Array: return "Array";
|
||||
case StructuredValue::Type::Map: return "Map";
|
||||
case StructuredValue::Type::Str: return "Str";
|
||||
|
||||
case StructuredValue::Type::Bool: return "Bool";
|
||||
|
||||
case StructuredValue::Type::Int: return "Int";
|
||||
case StructuredValue::Type::Uint: return "Uint";
|
||||
|
||||
case StructuredValue::Type::Double: return "Double";
|
||||
case StructuredValue::Type::Float: return "Float";
|
||||
default:
|
||||
DD_WARN_ALWAYS();
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new empty value
|
||||
StructuredValue MakeNull() const;
|
||||
|
||||
// Return whether this is an empty, or "null" node.
|
||||
bool IsNull() const;
|
||||
|
||||
/// ===== Unsigned Integer Types
|
||||
|
||||
/// Returns true when this node contains a Uint8. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetUint8(uint8* pValue) const;
|
||||
// Returns true when this node contains a Uint16. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetUint16(uint16* pValue) const;
|
||||
// Returns true when this node contains a Uint32. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetUint32(uint32* pValue) const;
|
||||
// Returns true when this node contains a Uint64. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetUint64(uint64* pValue) const;
|
||||
|
||||
/// ===== Signed Integer Types
|
||||
|
||||
/// Returns true when this node contains a Int8. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetInt8(int8* pValue) const;
|
||||
// Returns true when this node contains a Int16. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetInt16(int16* pValue) const;
|
||||
// Returns true when this node contains a Int32. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetInt32(int32* pValue) const;
|
||||
// Returns true when this node contains a Int64. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetInt64(int64* pValue) const;
|
||||
|
||||
/// ===== Floating Point Types
|
||||
|
||||
/// Returns true when this node contains a Float. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetFloat(float* pValue) const;
|
||||
// Returns true when this node contains a Double. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetDouble(double* pValue) const;
|
||||
|
||||
/// ===== Other Types
|
||||
|
||||
// Returns true when this node contains a Bool. If pValue is not NULL, copy out the node's value
|
||||
DD_NODISCARD bool GetBool(bool* pValue) const;
|
||||
|
||||
// Copy a string value from a node into a buffer
|
||||
// If the StructuredValue is not a string,
|
||||
// false is returned and no writes occur
|
||||
//
|
||||
// If pStringSize is not NULL,
|
||||
// the string length is written and processing continues
|
||||
//
|
||||
// If pBuffer is not NULL,
|
||||
// not more than bufferSize bytes (including a NULL terminator) are written.
|
||||
// If the buffer is large enough to hold the entire string,
|
||||
// true is returned
|
||||
//
|
||||
// If both pBuffer and pStringSize are NULL and the value *is* a string,
|
||||
// true is returned
|
||||
//
|
||||
// TODO: ... this is complicated. Should we use a Result?
|
||||
// The other types are simple enough that they benefit from using bool instead of a Result, but Strings may not.
|
||||
DD_NODISCARD bool GetStringCopy(char* pBuffer, size_t bufferSize, size_t* pStringSize) const;
|
||||
|
||||
template <size_t BufferSize>
|
||||
DD_NODISCARD bool GetStringCopy(char(&buffer)[BufferSize]) const
|
||||
{
|
||||
return GetStringCopy(buffer, BufferSize, nullptr);
|
||||
}
|
||||
|
||||
// Return a NULL-terminated string from the backing messagepack data.
|
||||
// This will fail and return NULL if the embedded string does not end with a NULL byte. Use GetStringCopy() if this is the case.
|
||||
DD_NODISCARD const char* GetStringPtr() const;
|
||||
|
||||
// Lookup a value in a map by a string key
|
||||
// If the key does not exist, returns false and writes a Null value to `*pValue`
|
||||
DD_NODISCARD bool GetValueByKey(const char* pKey, StructuredValue* pValue) const;
|
||||
|
||||
// Lookup a value in an array.
|
||||
// If `index` is out of bounds, returns false and writes a Null value to `*pValue`
|
||||
DD_NODISCARD bool GetValueByIndex(size_t index, StructuredValue* pValue) const;
|
||||
|
||||
// Query information about Maps and Arrays
|
||||
|
||||
// Returns whether this node has key-value pairs
|
||||
bool IsMap() const;
|
||||
|
||||
// Returns whether this node has numeric indices
|
||||
bool IsArray() const;
|
||||
|
||||
// Returns the length of the array if this node is an array, otherwise 0.
|
||||
size_t GetArrayLength() const;
|
||||
|
||||
// Get-methods with defaults
|
||||
// If you don't want to check the `bool` value anyway, prefer these.
|
||||
|
||||
uint8 GetUint8Or(uint8 defaultValue) const
|
||||
{
|
||||
const bool ok = GetUint8(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint16 GetUint16Or(uint16 defaultValue) const
|
||||
{
|
||||
const bool ok = GetUint16(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint32 GetUint32Or(uint32 defaultValue) const
|
||||
{
|
||||
const bool ok = GetUint32(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
uint64 GetUint64Or(uint64 defaultValue) const
|
||||
{
|
||||
const bool ok = GetUint64(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int8 GetInt8Or(int8 defaultValue) const
|
||||
{
|
||||
const bool ok = GetInt8(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int16 GetInt16Or(int16 defaultValue) const
|
||||
{
|
||||
const bool ok = GetInt16(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int32 GetInt32Or(int32 defaultValue) const
|
||||
{
|
||||
const bool ok = GetInt32(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int64 GetInt64Or(int64 defaultValue) const
|
||||
{
|
||||
const bool ok = GetInt64(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
float GetFloatOr(float defaultValue) const
|
||||
{
|
||||
const bool ok = GetFloat(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
double GetDoubleOr(double defaultValue) const
|
||||
{
|
||||
const bool ok = GetDouble(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
bool GetBoolOr(bool defaultValue) const
|
||||
{
|
||||
const bool ok = GetBool(&defaultValue);
|
||||
DD_UNUSED(ok);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// Index methods
|
||||
|
||||
StructuredValue operator[](const char* pKey) const
|
||||
{
|
||||
StructuredValue next = MakeNull();
|
||||
|
||||
// Ignore the result of this fetch, `next` is already an empty value
|
||||
const bool ok = GetValueByKey(pKey, &next);
|
||||
DD_UNUSED(ok);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
StructuredValue operator[](size_t index) const
|
||||
{
|
||||
StructuredValue next = MakeNull();
|
||||
|
||||
// Ignore the result of this fetch, `next` is already an empty value
|
||||
const bool ok = GetValueByIndex(index, &next);
|
||||
DD_UNUSED(ok);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
StructuredValue operator[](T index) const
|
||||
{
|
||||
// This overload exists so that we don't get ambiguous calls when calling operator[] with integer types.
|
||||
// If the type of the index can't be statically cast to a size_t, this will fail to compile.
|
||||
// Note: pointer types cannot be static_cast()'d, which is great!
|
||||
return this->operator[](static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
private:
|
||||
bool ResetInternalErrorStateImpl(const char* pFile, int line, const char* pCallingFunction) const;
|
||||
|
||||
OpaqueNode m_opaque;
|
||||
};
|
||||
|
||||
// Top level container of structured data
|
||||
class IStructuredReader
|
||||
{
|
||||
public:
|
||||
virtual ~IStructuredReader() {};
|
||||
|
||||
DD_NODISCARD static Result CreateFromJson(
|
||||
const void* pBytes,
|
||||
size_t numBytes,
|
||||
const AllocCb& allocCb,
|
||||
IStructuredReader** ppReader
|
||||
);
|
||||
|
||||
DD_NODISCARD static Result CreateFromMessagePack(
|
||||
const uint8* pBytes,
|
||||
size_t numBytes,
|
||||
const AllocCb& allocCb,
|
||||
IStructuredReader** ppReader
|
||||
);
|
||||
|
||||
static void Destroy(IStructuredReader **ppReader);
|
||||
|
||||
/// Get the root object being read
|
||||
virtual StructuredValue GetRoot() const = 0;
|
||||
|
||||
/// Get the allocation callbacks
|
||||
virtual const AllocCb& GetAllocCb() const = 0;
|
||||
};
|
||||
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddPlatform.h>
|
||||
#include <util/ddMetroHash.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
|
||||
/// ====================================================================================================================
|
||||
/// Hashes the bytes of a Key using MetroHash
|
||||
template<typename Key>
|
||||
struct DefaultHashFunc
|
||||
{
|
||||
uint32 operator()(const Key& key) const
|
||||
{
|
||||
return MetroHash::MetroHash32(reinterpret_cast<const uint8*>(&key), sizeof(Key));
|
||||
}
|
||||
};
|
||||
|
||||
/// ====================================================================================================================
|
||||
/// Hashes a const char* CString Key using Metrohash
|
||||
template<>
|
||||
struct DefaultHashFunc<const char*>
|
||||
{
|
||||
uint32 operator()(const char* pKey) const
|
||||
{
|
||||
// We cannot pass NULL strings to strlen() and friends, so guard against it anyway.
|
||||
uint32 hash = 0;
|
||||
DD_ASSERT(pKey != nullptr);
|
||||
if (pKey != nullptr)
|
||||
{
|
||||
hash = MetroHash::MetroHash32(reinterpret_cast<const uint8*>(pKey), strlen(pKey));
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
/// Pointer keys are usually a mistake, so this version is explicitly 'delete'd
|
||||
/// Overload this template if you're sure you need this. (See: const char* above)
|
||||
template<typename T>
|
||||
struct DefaultHashFunc<T*>
|
||||
{
|
||||
uint32 operator()(const T* pKey) const = delete;
|
||||
};
|
||||
|
||||
/// Generic compare functor for types that have defined the comparison operator
|
||||
///
|
||||
/// Used by @ref HashBase to prevent defining compare functions for each type.
|
||||
template<typename Key>
|
||||
struct DefaultEqualFunc
|
||||
{
|
||||
bool operator()(const Key& key1, const Key& key2) const { return (key1 == key2); }
|
||||
};
|
||||
|
||||
/// String compare functor for use with C-style strings
|
||||
template<>
|
||||
struct DefaultEqualFunc<const char*>
|
||||
{
|
||||
bool operator()(const char* pKey1, const char* pKey2) const
|
||||
{
|
||||
DD_ASSERT(pKey1 != nullptr);
|
||||
DD_ASSERT(pKey2 != nullptr);
|
||||
return (strcmp(pKey1, pKey2) == 0);
|
||||
}
|
||||
};
|
||||
|
||||
/// Generic compare functor for types with arbitrary size
|
||||
///
|
||||
/// Used by @ref HashBase to prevent defining compare functions for each type.
|
||||
template<typename Key>
|
||||
struct BitwiseEqualFunc
|
||||
{
|
||||
bool operator()(const Key& key1, const Key& key2) const { return (memcmp(&key1, &key2, sizeof(Key)) == 0); }
|
||||
};
|
||||
|
||||
} // namespace DevDriver
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddPlatform.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
// Helper structure that sets value to true if T is not abstract and is constructable using the provided
|
||||
// arguments, otherwise it returns false. We use this to prevent the Create() function from being defined
|
||||
// for classes that are not creatable. This in turn prevents code from being generated that causes
|
||||
// Container to be defined, which leads to compile errors even if the client application never attempts
|
||||
// to directly create an object of that type.
|
||||
template<typename T, typename... Args>
|
||||
struct CanConstruct
|
||||
{
|
||||
DD_STATIC_CONST bool Value = !Platform::IsAbstract<T>::Value && Platform::IsConstructible<T, Args...>::Value;
|
||||
};
|
||||
|
||||
// SharedPointerBase is the common parent class used by SharedPointer<>
|
||||
// It implements common functions (e.g., pointer management) but cannot ever be
|
||||
// used directly. The purpose of this separation is to enable SharedPointer to perform
|
||||
// typecasts between derived and base types by casting through SharedPointerBase.
|
||||
class SharedPointerBase
|
||||
{
|
||||
// SharedPointer is a subclass, but all need to have access to the protected + private members
|
||||
template<typename T>
|
||||
friend class SharedPointer;
|
||||
// public functions available to all subclasses
|
||||
public:
|
||||
// check to see if the class has been set
|
||||
bool IsNull() const { return m_pObject == nullptr; }
|
||||
|
||||
// clear the pointer and, if required, delete the underlying allocation
|
||||
void Clear()
|
||||
{
|
||||
if (m_pContainer != nullptr)
|
||||
{
|
||||
if (m_pContainer->Release() == 0)
|
||||
{
|
||||
// ContainerBase has been declared with a virtual destructor, which guarantees
|
||||
// that the specific ContainerBase subclass destructor is called
|
||||
DD_DELETE(m_pContainer, m_pContainer->GetAllocCb());
|
||||
}
|
||||
m_pContainer = nullptr;
|
||||
m_pObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Inner class that provides a standardized reference counted container interface
|
||||
// Subclassed by SharedPointer to include an actual object
|
||||
class ContainerBase
|
||||
{
|
||||
public:
|
||||
// Construct container and initialize ref count to zero. This class should never be
|
||||
// constructed directly by anything other than a subclass.
|
||||
constexpr ContainerBase(const AllocCb &allocCb)
|
||||
: m_allocCb(allocCb)
|
||||
, m_refCount(0)
|
||||
{
|
||||
//DD_PRINT(LogLevel::Never, "Created reference counted container %i", m_refCount);
|
||||
}
|
||||
|
||||
// Destroy the container. Since this class is never directly created, this ensures
|
||||
// subclasses (and the contained object) are always destroyed correctly.
|
||||
virtual ~ContainerBase()
|
||||
{
|
||||
DD_ASSERT(m_refCount == 0);
|
||||
DD_PRINT(LogLevel::Never, "Deleted reference counted container %i", m_refCount);
|
||||
}
|
||||
|
||||
// Increments the reference count of the container
|
||||
int32 Retain(void)
|
||||
{
|
||||
DD_ASSERT(m_refCount >= 0);
|
||||
int32 result = Platform::AtomicIncrement(&m_refCount);
|
||||
DD_ASSERT(result >= 1);
|
||||
DD_PRINT(LogLevel::Never, "Incremented reference count: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Decrements the reference count of the container
|
||||
int32 Release(void)
|
||||
{
|
||||
int32 result = Platform::AtomicDecrement(&m_refCount);
|
||||
DD_ASSERT(result >= 0);
|
||||
DD_PRINT(LogLevel::Never, "Decremented reference count: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the reference count of the container
|
||||
int32 QueryReferenceCount(void) const
|
||||
{
|
||||
return m_refCount;
|
||||
}
|
||||
|
||||
// Retrieve the allocator callbacks so it can be destroyed
|
||||
const AllocCb& GetAllocCb() const { return m_allocCb; }
|
||||
private:
|
||||
// Allocator callbacks
|
||||
const AllocCb m_allocCb;
|
||||
// Reference count
|
||||
Platform::Atomic m_refCount;
|
||||
|
||||
};
|
||||
|
||||
// Default constructor that is constexpr. Allows the compiler to inline this if it wants to.
|
||||
constexpr SharedPointerBase()
|
||||
: m_pContainer(nullptr)
|
||||
, m_pObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// Initialize the object using the provided pointer
|
||||
SharedPointerBase(ContainerBase* pContainer, void* pObject)
|
||||
: m_pContainer(pContainer)
|
||||
, m_pObject(pObject)
|
||||
{
|
||||
// We should always have a valid object if the container is valid.
|
||||
DD_ASSERT((m_pContainer == nullptr) || (m_pObject != nullptr));
|
||||
|
||||
// If we have a valid container, increment the reference count.
|
||||
if (m_pContainer != nullptr)
|
||||
{
|
||||
m_pContainer->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy constructor copies the container pointer and increments the reference count
|
||||
SharedPointerBase(const SharedPointerBase &right)
|
||||
: SharedPointerBase(right.m_pContainer, right.m_pObject)
|
||||
{
|
||||
}
|
||||
|
||||
// Move constructor takes the container pointer and clears the other container's pointer
|
||||
SharedPointerBase(SharedPointerBase &&right)
|
||||
: m_pContainer(Platform::Exchange(right.m_pContainer, nullptr))
|
||||
, m_pObject(Platform::Exchange(right.m_pObject, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
// On deletion of the object clear the pointer
|
||||
~SharedPointerBase()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
private:
|
||||
// Pointer to the shared container
|
||||
ContainerBase* m_pContainer;
|
||||
// Pointer to the object inside the shared container. We keep a copy of this to allow
|
||||
// direct access to the object since we might not know the actual parent type of it.
|
||||
void* m_pObject;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class SharedPointer : public SharedPointerBase
|
||||
{
|
||||
public:
|
||||
// Create SharedPointer object with the default constructor
|
||||
constexpr SharedPointer() : SharedPointerBase() {};
|
||||
|
||||
SharedPointer(const SharedPointer<T>&) = default;
|
||||
|
||||
// Copy conversion constructor. Creates a new object if you can cast from type U to type T.
|
||||
template <typename U, typename = typename Platform::EnableIf<Platform::IsConvertible<U*, T*>::Value>::Type>
|
||||
SharedPointer(const SharedPointer<U> &right)
|
||||
: SharedPointerBase(Platform::Forward<const SharedPointerBase>(right))
|
||||
{
|
||||
}
|
||||
|
||||
// Move conversion constructor. Takes ownership of the shared container if you can cast from type U to type T.
|
||||
template <typename U, typename = typename Platform::EnableIf<Platform::IsConvertible<U*, T*>::Value>::Type>
|
||||
SharedPointer(SharedPointer<U> &&right)
|
||||
: SharedPointerBase(Platform::Forward<SharedPointerBase>(right))
|
||||
{
|
||||
}
|
||||
|
||||
// Assignment operator to allow copy + swap idiom
|
||||
SharedPointer<T> &operator= (SharedPointer<T> right)
|
||||
{
|
||||
m_pContainer = Platform::Exchange(right.m_pContainer, m_pContainer);
|
||||
m_pObject = Platform::Exchange(right.m_pObject, m_pObject);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Indirection operator. Returns a const reference to the object in the shared container.
|
||||
// This operator is unsafe to use if the container hasn't been allocated.
|
||||
T& operator*() const
|
||||
{
|
||||
DD_ASSERT(m_pObject != nullptr);
|
||||
return *Get();
|
||||
}
|
||||
|
||||
// Member of pointer operator. Returns a pointer to the object in the shared container.
|
||||
// This operator is unsafe to use if the container hasn't been allocated.
|
||||
T* operator->() const
|
||||
{
|
||||
DD_ASSERT(m_pObject != nullptr);
|
||||
return Get();
|
||||
}
|
||||
|
||||
// Templated comparison operator. Allows comparing shared pointer objects so long as U is convertable to T.
|
||||
template <typename U, typename = typename Platform::EnableIf<Platform::IsConvertible<U*, T*>::Value>::Type>
|
||||
bool operator== (const SharedPointer< U >&right) const
|
||||
{
|
||||
return m_pObject == right.m_pObject;
|
||||
}
|
||||
|
||||
// Templated comparison operator. Allows comparing shared pointer objects so long as U is convertable to T.
|
||||
template <typename U, typename = typename Platform::EnableIf<Platform::IsConvertible<U*, T*>::Value>::Type>
|
||||
bool operator!= (const SharedPointer< U >&right) const
|
||||
{
|
||||
return m_pObject != right.m_pObject;
|
||||
}
|
||||
|
||||
// Get a pointer to the contained object
|
||||
T* Get() const
|
||||
{
|
||||
return static_cast<T* const>(m_pObject);
|
||||
}
|
||||
|
||||
// Returns the reference count for the container
|
||||
int32 QueryReferenceCount() const
|
||||
{
|
||||
return m_pContainer->QueryReferenceCount();
|
||||
}
|
||||
|
||||
// Create a SharedPointer using the provided allocator callbacks and arguments
|
||||
// This function is only valid if the class is not a valid class
|
||||
template<typename... Args,
|
||||
typename = typename Platform::EnableIf<CanConstruct<T, Args...>::Value>::Type>
|
||||
static SharedPointer<T> Create(const AllocCb& allocCb, Args&&... args)
|
||||
{
|
||||
SharedPointer result;
|
||||
Container *pContainer =
|
||||
DD_NEW(Container, allocCb)(allocCb, Platform::Forward<Args>(args)...);
|
||||
|
||||
if (pContainer != nullptr)
|
||||
{
|
||||
result = SharedPointer(pContainer, &pContainer->m_object);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private:
|
||||
// Templated Container class that inherents the type from the outer (SharedPointer) class
|
||||
class Container : public ContainerBase
|
||||
{
|
||||
public:
|
||||
// Constructor that initializes ContainerBase class and the object using the provided parameters
|
||||
template<typename... Args>
|
||||
explicit constexpr Container(const AllocCb& allocCb, Args&&... args)
|
||||
: ContainerBase(allocCb)
|
||||
, m_object(Platform::Forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
// Actual object that the SharedPointer instance encapsulates
|
||||
T m_object;
|
||||
};
|
||||
|
||||
// Private constructor to allow direct initialization using an externally created Container
|
||||
explicit SharedPointer(Container* pContainer, T* pObject)
|
||||
: SharedPointerBase(static_cast<ContainerBase*>(pContainer), pObject)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // DevDriver
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <util/hashFunc.h>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
// A String class that stores the string inline with a compile-time maximum size.
|
||||
// This class facilitiates passing bounded sized C Strings around without dynamic allocation. It has POD semantics
|
||||
// when copied or passed by value into functions, and can be stored in a vector.
|
||||
template<size_t FixedSize>
|
||||
class FixedString
|
||||
{
|
||||
private:
|
||||
char m_data[FixedSize];
|
||||
|
||||
public:
|
||||
FixedString()
|
||||
{
|
||||
// Only the first byte needs to be initialized - we actively do not want to zero the entire array!
|
||||
m_data[0] = 0;
|
||||
}
|
||||
|
||||
FixedString(const FixedString<FixedSize>&) = default;
|
||||
FixedString(FixedString<FixedSize>&&) = default;
|
||||
|
||||
~FixedString() {}
|
||||
|
||||
FixedString<FixedSize>& operator=(FixedString<FixedSize>& pOther)
|
||||
{
|
||||
Platform::Strncpy(m_data, pOther.m_data, sizeof(m_data));
|
||||
return *this;
|
||||
}
|
||||
|
||||
FixedString<FixedSize>& operator=(FixedString<FixedSize>&& pOther)
|
||||
{
|
||||
Platform::Strncpy(m_data, pOther.m_data, sizeof(m_data));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const FixedString<FixedSize>& other) const
|
||||
{
|
||||
return strncmp(this->AsCStr(), other.AsCStr(), FixedSize) == 0;
|
||||
}
|
||||
|
||||
bool operator!=(const FixedString<FixedSize>& other) const
|
||||
{
|
||||
return strncmp(this->AsCStr(), other.AsCStr(), FixedSize) != 0;
|
||||
}
|
||||
|
||||
// Create a FixedString from a C String, truncating the copy if pString is too long
|
||||
FixedString(const char* pString) { Platform::Strncpy(m_data, pString, sizeof(m_data)); }
|
||||
|
||||
// Return a pointer to the inline C String.
|
||||
const char* AsCStr() const { return m_data; }
|
||||
|
||||
char* AsCStr() { return m_data; }
|
||||
|
||||
// Computes the length of the string.
|
||||
// Note! This is an O(N) operation!
|
||||
size_t Size() const { return strlen(m_data); }
|
||||
};
|
||||
|
||||
// Sanity check for class size.
|
||||
static_assert(sizeof(FixedString<16>) == 16, "FixedString<16> should be exactly 16 bytes");
|
||||
|
||||
/// ====================================================================================================================
|
||||
// Hashes a FixedString<> Key using Metrohash
|
||||
template<size_t Size>
|
||||
struct DefaultHashFunc<FixedString<Size>>
|
||||
{
|
||||
uint32 operator()(const FixedString<Size>& key) const { return DefaultHashFunc<const char*>()(key.AsCStr()); }
|
||||
};
|
||||
|
||||
/// ====================================================================================================================
|
||||
/// Utility functions for strings
|
||||
/// ====================================================================================================================
|
||||
|
||||
enum struct HexStringFmt
|
||||
{
|
||||
Lowercase,
|
||||
Uppercase,
|
||||
};
|
||||
|
||||
/// ====================================================================================================================
|
||||
// Encode not more than `numBytes` from `pBytes` into hexadecimal, storing not more than stringBufferSize characters
|
||||
// into pStringBuffer.
|
||||
//
|
||||
// This is the compliment of DecodeFromHexString() and is suitable for saving large binary blocks in text formats such
|
||||
// as Json.
|
||||
//
|
||||
// This function NULL terminates its output if it writes anything.
|
||||
// Hex pairs are written to `pStrBuff` in pairs - either both digits are written or neither is. A lone nibble
|
||||
// is never written to the buffer.
|
||||
// Thus, Hex strings are always an even length (+ a NULL byte)
|
||||
//
|
||||
// Returns the number of characters written out through `pStrBuff` (including the NULL terminator).
|
||||
template <HexStringFmt fmt = HexStringFmt::Lowercase>
|
||||
inline size_t EncodeToHexString(const void* pBytesIn, size_t numBytes, char* pStrBuff, size_t strBuffSize)
|
||||
{
|
||||
const uint8* pBytes = static_cast<const uint8*>(pBytesIn);
|
||||
|
||||
// Character offset that we've written into pStrBuff
|
||||
size_t charsProcessed = 0;
|
||||
|
||||
if ((pBytes != nullptr) && (numBytes != 0) && (pStrBuff != nullptr) && (strBuffSize != 0))
|
||||
{
|
||||
|
||||
// Both lookups are indexed by nibble
|
||||
constexpr const char kHexStringLookupLower[] = "0123456789abcdef";
|
||||
constexpr const char kHexStringLookupUpper[] = "0123456789ABCDEF";
|
||||
|
||||
// This is the index where our next character pair goes.
|
||||
// We save this outside of the loop to NULL terminate correctly.
|
||||
size_t strIdx = 0;
|
||||
for (size_t byteIdx = 0; byteIdx < numBytes; byteIdx += 1)
|
||||
{
|
||||
// We're going to write two bytes this loop, but need to exit early if we're out of bounds.
|
||||
// We need room for:
|
||||
// - the high nibble
|
||||
// - the low nibble
|
||||
// - the NULL terminator
|
||||
// Offsets (from stdIdx) of 0, 1, and 2 must be within the buffer bounds.
|
||||
if ((strIdx + 2) < strBuffSize)
|
||||
{
|
||||
const uint8 byte = pBytes[byteIdx];
|
||||
|
||||
if (fmt == HexStringFmt::Lowercase)
|
||||
{
|
||||
pStrBuff[strIdx + 0] = kHexStringLookupLower[byte >> 4]; // High nibble first
|
||||
pStrBuff[strIdx + 1] = kHexStringLookupLower[byte & 0xf]; // Low nibble
|
||||
}
|
||||
else
|
||||
{
|
||||
pStrBuff[strIdx + 0] = kHexStringLookupUpper[byte >> 4]; // High nibble first
|
||||
pStrBuff[strIdx + 1] = kHexStringLookupUpper[byte & 0xf]; // Low nibble
|
||||
}
|
||||
|
||||
strIdx += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pStrBuff[strIdx] = '\0';
|
||||
charsProcessed += strIdx + 1; // Hex characters (if any) + NULL
|
||||
}
|
||||
|
||||
return charsProcessed;
|
||||
}
|
||||
|
||||
/// ====================================================================================================================
|
||||
// Helper function that translates hex digits into numeric values.
|
||||
// Returns 0xff if the value is not a hex digit
|
||||
#if DD_CPLUSPLUS_SUPPORTS(CPP17)
|
||||
constexpr uint8 HexDigitToValue(char c)
|
||||
#else
|
||||
inline uint8 HexDigitToValue(char c)
|
||||
#endif
|
||||
{
|
||||
// We use a switch case here to get the point across
|
||||
// gcc9, clang8, and MSVC all turn this into a lookup table indexing with c (sometimes subtracting from it first)
|
||||
|
||||
switch (c)
|
||||
{
|
||||
// clang-format off
|
||||
case '0':
|
||||
case '1': case '2': case '3':
|
||||
case '4': case '5': case '6':
|
||||
case '7': case '8': case '9':
|
||||
return c - '0';
|
||||
|
||||
case 'a': case 'A': return 0xa;
|
||||
case 'b': case 'B': return 0xb;
|
||||
case 'c': case 'C': return 0xc;
|
||||
case 'd': case 'D': return 0xd;
|
||||
case 'e': case 'E': return 0xe;
|
||||
case 'f': case 'F': return 0xf;
|
||||
|
||||
default:
|
||||
return 0xff;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
#if DD_CPLUSPLUS_SUPPORTS(CPP17)
|
||||
static_assert(HexDigitToValue('Z') == 0xff);
|
||||
|
||||
static_assert(HexDigitToValue('0') == 0);
|
||||
static_assert(HexDigitToValue('1') == 1);
|
||||
static_assert(HexDigitToValue('2') == 2);
|
||||
static_assert(HexDigitToValue('3') == 3);
|
||||
static_assert(HexDigitToValue('4') == 4);
|
||||
static_assert(HexDigitToValue('5') == 5);
|
||||
static_assert(HexDigitToValue('6') == 6);
|
||||
static_assert(HexDigitToValue('7') == 7);
|
||||
static_assert(HexDigitToValue('8') == 8);
|
||||
static_assert(HexDigitToValue('9') == 9);
|
||||
|
||||
static_assert(HexDigitToValue('a') == 10);
|
||||
static_assert(HexDigitToValue('b') == 11);
|
||||
static_assert(HexDigitToValue('c') == 12);
|
||||
static_assert(HexDigitToValue('d') == 13);
|
||||
static_assert(HexDigitToValue('e') == 14);
|
||||
static_assert(HexDigitToValue('f') == 15);
|
||||
|
||||
static_assert(HexDigitToValue('A') == 10);
|
||||
static_assert(HexDigitToValue('B') == 11);
|
||||
static_assert(HexDigitToValue('C') == 12);
|
||||
static_assert(HexDigitToValue('D') == 13);
|
||||
static_assert(HexDigitToValue('E') == 14);
|
||||
static_assert(HexDigitToValue('F') == 15);
|
||||
#endif
|
||||
|
||||
/// ====================================================================================================================
|
||||
// Decode not more than `strLength` hex characters from `pStrBuff` into their binary representation, storing
|
||||
// not more than `numBytes` into `pBytesOut`.
|
||||
//
|
||||
// This is the compliment of EncodeToHexString() and is suitable for decoding large binary blocks out of text formats
|
||||
// such as Json.
|
||||
//
|
||||
// Returns the number of bytes written out through `pBytesOut`.
|
||||
inline size_t DecodeFromHexString(const char* pStrBuff, size_t strLength, void* pBytesOut, size_t numBytes)
|
||||
{
|
||||
uint8* pBytes = static_cast<uint8*>(pBytesOut);
|
||||
|
||||
// Byte offset that we've written into pBytes
|
||||
size_t bytesProcessed = 0;
|
||||
|
||||
// Note: Only even-length hex strings are supported
|
||||
if ((strLength % 2 == 0) && (pBytes != nullptr) && (numBytes != 0) && (pStrBuff != nullptr) && (strLength != 0))
|
||||
{
|
||||
size_t byteIdx = 0;
|
||||
|
||||
// Process two characters (one byte) per iteration.
|
||||
// This loop is bounded on two sizes: the string buffer and the byte buffer
|
||||
for (size_t strIdx = 0;
|
||||
((strIdx + 1) < strLength) && (byteIdx < numBytes);
|
||||
strIdx += 2, byteIdx += 1)
|
||||
{
|
||||
const uint8 hi = HexDigitToValue(pStrBuff[strIdx + 0]); // High nibble first
|
||||
const uint8 lo = HexDigitToValue(pStrBuff[strIdx + 1]); // Low nibble
|
||||
|
||||
if ((lo != 0xff) && (hi != 0xff))
|
||||
{
|
||||
pBytes[byteIdx] = (hi << 4) | lo;
|
||||
bytesProcessed += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-hex digit encountered, this is a parsing error.
|
||||
// This log statement is compiled out, but may be useful for debugging something funny.
|
||||
DD_PRINT(LogLevel::Never,
|
||||
"[DecodeFromHexString] Expected hex digits ([0-9a-fA-F]), but found \"%c%c\"",
|
||||
pStrBuff[strIdx + 0],
|
||||
pStrBuff[strIdx + 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bytesProcessed;
|
||||
}
|
||||
|
||||
} // namespace DevDriver
|
||||
@@ -0,0 +1,605 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2021-2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ddPlatform.h>
|
||||
|
||||
#if !DD_PLATFORM_WINDOWS_KM
|
||||
#include <type_traits>
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
namespace DevDriver
|
||||
{
|
||||
template <typename T, size_t defaultCapacity = 8>
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
class Iterator;
|
||||
|
||||
// The capacity this Vector can hold without allocating extra space.
|
||||
static constexpr size_t DefaultCapacity = defaultCapacity;
|
||||
|
||||
// Standard constructor
|
||||
explicit Vector(const AllocCb& allocCb)
|
||||
: m_pData(m_data)
|
||||
, m_size(0)
|
||||
, m_capacity(defaultCapacity)
|
||||
, m_allocCb(allocCb)
|
||||
{
|
||||
}
|
||||
|
||||
// Move constructor
|
||||
Vector(Vector &&rhs)
|
||||
: m_pData(m_data) // default initialize it to the default allocation
|
||||
, m_size(Platform::Exchange(rhs.m_size, (size_t)0)) // move the rhs size value into ours
|
||||
, m_capacity(defaultCapacity) // initialize the capacity to default
|
||||
, m_allocCb(rhs.m_allocCb) // copy the allocator callback
|
||||
{
|
||||
// if the vector will fit inside the default allocation, move it into it
|
||||
if (m_size <= defaultCapacity)
|
||||
{
|
||||
for (size_t index = 0; index < m_size; index++)
|
||||
{
|
||||
m_data[index] = Platform::Move(rhs.m_pData[index]);
|
||||
}
|
||||
}
|
||||
else // otherwise, we want to move the allocation + replace the capacity
|
||||
{
|
||||
m_pData = Platform::Exchange(rhs.m_pData, rhs.m_data);
|
||||
m_capacity = Platform::Exchange(rhs.m_capacity, defaultCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor
|
||||
~Vector()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void operator=(Vector&& rhs)
|
||||
{
|
||||
Swap(rhs);
|
||||
}
|
||||
|
||||
// Convenience methods
|
||||
size_t Size() const { return m_size; }
|
||||
size_t Capacity() const { return m_capacity; }
|
||||
bool IsEmpty() const { return (m_size == 0); }
|
||||
|
||||
// Subscript operator
|
||||
T& operator[](size_t index) { DD_ASSERT(index < m_size); return m_pData[index]; }
|
||||
const T& operator[](size_t index) const { DD_ASSERT(index < m_size); return m_pData[index]; }
|
||||
|
||||
// Insert elements into the back of the Vector
|
||||
template <class... Args>
|
||||
bool PushBack(Args&&... args)
|
||||
{
|
||||
bool result = false;
|
||||
Reserve(m_size + 1);
|
||||
if (m_size < m_capacity)
|
||||
{
|
||||
m_pData[m_size] = T(Platform::Forward<Args>(args)...);
|
||||
++m_size;
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Insert elements from another Vector to the back of the Vector
|
||||
bool Append(const Vector<T>& other)
|
||||
{
|
||||
return Append(other.Data(), other.Size());
|
||||
}
|
||||
|
||||
template <size_t Len>
|
||||
bool Append(const T (&buffer)[Len])
|
||||
{
|
||||
return Append(buffer, Len);
|
||||
}
|
||||
|
||||
// This is un-used by default, but may be overloaded for some Ts
|
||||
bool Append(const T* pTs);
|
||||
|
||||
// Insert elements from a buffer to the back of the Vector
|
||||
// An empty slice (countOfTs == 0) is effectively a no-op
|
||||
bool Append(const T* pTs, size_t countOfTs)
|
||||
{
|
||||
// Check that we get a valid pointer. If this fires, we'll crash but this is more visible than just crashing
|
||||
// in a memcpy below.
|
||||
if (countOfTs != 0)
|
||||
{
|
||||
DD_ASSERT(pTs != nullptr);
|
||||
}
|
||||
|
||||
// Pre-allocate all the new elements, since we know how many there are.
|
||||
const size_t oldSize = Grow(countOfTs);
|
||||
|
||||
// Some types can be bulk-transferred with a memcpy.
|
||||
// Instead of letting the compiler guess, we dictate when dealing with Pods.
|
||||
if (Platform::IsPod<T>::Value)
|
||||
{
|
||||
memcpy(&m_pData[oldSize], pTs, (sizeof(T) * countOfTs));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < countOfTs; ++i)
|
||||
{
|
||||
m_pData[oldSize + i] = pTs[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Pretend Grow() cannot fail, since we cannot check allocation failure with it right now.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pop elements out of the Vector
|
||||
bool PopBack(T* pData)
|
||||
{
|
||||
bool result = !IsEmpty();
|
||||
if (result)
|
||||
{
|
||||
--m_size;
|
||||
if (pData != nullptr)
|
||||
{
|
||||
*pData = Platform::Move(m_pData[m_size]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pop elements out of the Vector
|
||||
bool PopFront(T* pData)
|
||||
{
|
||||
bool result = !IsEmpty();
|
||||
if (result)
|
||||
{
|
||||
if (pData != nullptr)
|
||||
{
|
||||
*pData = Platform::Move(m_pData[0]);
|
||||
}
|
||||
|
||||
--m_size;
|
||||
|
||||
if (m_size > 0)
|
||||
{
|
||||
for (size_t i = 0; i < m_size; i++)
|
||||
{
|
||||
m_pData[i] = Platform::Move(m_pData[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Remove the object at the specified index. Does not maintain order.
|
||||
void Remove(size_t index)
|
||||
{
|
||||
DD_ASSERT(index < m_size);
|
||||
|
||||
const size_t lastIndex = m_size - 1;
|
||||
|
||||
// If the index is the last index, we move the last element into it's place
|
||||
if (index != lastIndex)
|
||||
{
|
||||
m_pData[index] = Platform::Move(m_pData[lastIndex]);
|
||||
}
|
||||
// Otherwise, if it is the last element and not a POD we replace it with a default constructed object
|
||||
else if (!Platform::IsPod<T>::Value)
|
||||
{
|
||||
m_pData[index] = T();
|
||||
}
|
||||
|
||||
--m_size;
|
||||
}
|
||||
|
||||
// Remove all instances of the specified object from the vector. Does not maintain order.
|
||||
size_t Remove(const T& object)
|
||||
{
|
||||
size_t numRemoved = 0;
|
||||
|
||||
for (size_t index = m_size; index > 0; index--)
|
||||
{
|
||||
if (m_pData[index - 1] == object)
|
||||
{
|
||||
Remove(index - 1);
|
||||
numRemoved++;
|
||||
}
|
||||
}
|
||||
return numRemoved;
|
||||
}
|
||||
|
||||
// Free all memory
|
||||
void Clear()
|
||||
{
|
||||
if (m_pData != m_data)
|
||||
{
|
||||
// If the object is not a POD we explicitly destroy all objects prior to freeing the allocation.
|
||||
if (!Platform::IsPod<T>::Value)
|
||||
{
|
||||
for (size_t i = 0; i < m_capacity; i++)
|
||||
{
|
||||
m_pData[i].~T();
|
||||
}
|
||||
}
|
||||
DD_FREE(m_pData, m_allocCb);
|
||||
m_pData = m_data;
|
||||
m_capacity = defaultCapacity;
|
||||
m_size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Clears all objects stored, but doesn't free memory.
|
||||
void Reset()
|
||||
{
|
||||
// If the object is not a POD we need to destroy all instances and replace them with default constructed
|
||||
// instances.
|
||||
if (!Platform::IsPod<T>::Value)
|
||||
{
|
||||
for (size_t index = 0; index < m_size; index++)
|
||||
{
|
||||
m_pData[index] = T();
|
||||
}
|
||||
}
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
// Swaps the contents of the current vector with the provided vector
|
||||
void Swap(Vector& rhs)
|
||||
{
|
||||
// If we can, we swap allocations directly
|
||||
if ((m_pData != m_data) && (rhs.m_pData != rhs.m_data))
|
||||
{
|
||||
m_pData = Platform::Exchange(rhs.m_pData, m_pData);
|
||||
}
|
||||
// Else if the other object is using the default allocation we move it's contents here
|
||||
// and give ownership of our allocation to it
|
||||
else if (m_pData != m_data)
|
||||
{
|
||||
for (size_t index = 0; index < rhs.m_size; index++)
|
||||
{
|
||||
m_data[index] = Platform::Move(rhs.m_data[index]);
|
||||
}
|
||||
rhs.m_pData = Platform::Exchange(m_pData, m_data);
|
||||
}
|
||||
// Else if this object is using the default allocation we move our data into it's allocation
|
||||
// and take ownership of our allocation to it
|
||||
else if (rhs.m_pData != rhs.m_data)
|
||||
{
|
||||
for (size_t index = 0; index < m_size; index++)
|
||||
{
|
||||
rhs.m_data[index] = Platform::Move(m_data[index]);
|
||||
}
|
||||
m_pData = Platform::Exchange(rhs.m_pData, rhs.m_data);
|
||||
}
|
||||
// Otherwise we just exchange all the objects that we need to
|
||||
else
|
||||
{
|
||||
for (size_t index = 0; index < Platform::Max(m_size, rhs.m_size); index++)
|
||||
{
|
||||
m_data[index] = Platform::Exchange(rhs.m_data[index], m_data[index]);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we exchange the rest of the data
|
||||
m_allocCb = Platform::Exchange(rhs.m_allocCb, m_allocCb);
|
||||
m_capacity = Platform::Exchange(rhs.m_capacity, m_capacity);
|
||||
m_size = Platform::Exchange(rhs.m_size, m_size);
|
||||
}
|
||||
|
||||
// Get a pointer to the beginning of the data
|
||||
//
|
||||
// Returns nullptr if there is no data available
|
||||
const T* Data() const
|
||||
{
|
||||
return (Size() != 0) ? m_pData : nullptr;
|
||||
}
|
||||
|
||||
// Get a pointer to the beginning of the data
|
||||
//
|
||||
// Returns nullptr if there is no data available
|
||||
T* Data()
|
||||
{
|
||||
return (Size() != 0) ? m_pData : nullptr;
|
||||
}
|
||||
|
||||
// Allocates enough memory to hold the specified number of elements
|
||||
void Reserve(size_t newSize)
|
||||
{
|
||||
if (m_capacity < newSize)
|
||||
{
|
||||
const size_t newCapacity = Platform::Pow2Pad(Platform::Max(newSize, (size_t)1));
|
||||
const size_t allocSize = sizeof(T) * newCapacity;
|
||||
T* pData = static_cast<T*>(DD_MALLOC(allocSize, alignof(T), m_allocCb));
|
||||
|
||||
DD_ASSERT(pData != nullptr);
|
||||
|
||||
// If the struct is not a POD, then we need to construct objects
|
||||
if (is_type_trivial() == false)
|
||||
{
|
||||
size_t i = 0;
|
||||
// First, we move all existing objects into the vector.
|
||||
for (; i < m_size; i++)
|
||||
{
|
||||
new(&pData[i]) T(Platform::Move(m_pData[i]));
|
||||
}
|
||||
// Then we construct new objects with the remaining memory.
|
||||
for (; i < newCapacity; i++)
|
||||
{
|
||||
new(&pData[i]) T();
|
||||
}
|
||||
}
|
||||
// Otherwise, we just copy the existing data into the new vector and call it good.
|
||||
else
|
||||
{
|
||||
// Need to use reinterpret_cast here because gcc can't seem to evaluate
|
||||
// `is_trivial_v` at compile-time, thus generating a no-class-memaccess warning.
|
||||
// `if constexpr` fixes the issue, but AMDLOG's toolchain doesn't support c++17.
|
||||
std::memcpy(reinterpret_cast<void*>(pData), m_pData, m_size * sizeof(T));
|
||||
}
|
||||
|
||||
if (m_pData != m_data)
|
||||
{
|
||||
// If the object wasn't a POD we need to destroy all instances before freeing the memory.
|
||||
if (!Platform::IsPod<T>::Value)
|
||||
{
|
||||
for (size_t i = 0; i < m_capacity; i++)
|
||||
{
|
||||
m_pData[i].~T();
|
||||
}
|
||||
}
|
||||
DD_FREE(m_pData, m_allocCb);
|
||||
}
|
||||
m_pData = pData;
|
||||
m_capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
// Resizes the vector. Implicitly destroys objects if newSize is smaller than the existing size.
|
||||
void Resize(size_t newSize)
|
||||
{
|
||||
// TODO: Reserve should return whether allocation failed
|
||||
Reserve(newSize);
|
||||
|
||||
// If the object isn't a POD and we are shrinking the size, we need to replace destroyed objects with
|
||||
// default constructed instances.
|
||||
if (!Platform::IsPod<T>::Value)
|
||||
{
|
||||
for (size_t i = newSize; i < m_size; i++)
|
||||
{
|
||||
m_pData[i] = T();
|
||||
}
|
||||
}
|
||||
m_size = newSize;
|
||||
}
|
||||
|
||||
// Resizes the vector, zeroing additional elements
|
||||
//
|
||||
// Warning: This will break badly if your type cannot be safely memset() to 0!
|
||||
void ResizeAndZero(size_t newSize)
|
||||
{
|
||||
// TODO: Reserve should return whether allocation failed
|
||||
Reserve(newSize);
|
||||
|
||||
if (newSize > m_size)
|
||||
{
|
||||
memset(&m_pData[m_size], 0, (newSize - m_size) * sizeof(T));
|
||||
}
|
||||
|
||||
m_size = newSize;
|
||||
}
|
||||
|
||||
// Grows the vector by the specified number of elements and returns the previous size
|
||||
size_t Grow(size_t numElements)
|
||||
{
|
||||
const size_t oldSize = m_size;
|
||||
|
||||
Resize(m_size + numElements);
|
||||
|
||||
return oldSize;
|
||||
}
|
||||
|
||||
// Iterator creation function
|
||||
Iterator Begin() const
|
||||
{
|
||||
return CreateIterator(0);
|
||||
}
|
||||
|
||||
// Iterator creation function
|
||||
constexpr Iterator End() const
|
||||
{
|
||||
return Iterator(nullptr, 0);
|
||||
}
|
||||
|
||||
// Iterator creation function
|
||||
Iterator CreateIterator(size_t index) const
|
||||
{
|
||||
if (index < m_size)
|
||||
return Iterator(this, index);
|
||||
return End();
|
||||
}
|
||||
|
||||
// Finds the first index for the provided object
|
||||
Iterator Find(const T& object) const
|
||||
{
|
||||
auto it = Begin();
|
||||
for (; it != End(); ++it)
|
||||
{
|
||||
if (*it == object)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
// Removes the element represented by the provided iterator. Does not maintain order.
|
||||
Iterator Remove(const Iterator& it)
|
||||
{
|
||||
DD_ASSERT(it.m_pContainer == this);
|
||||
|
||||
Remove(it.m_index);
|
||||
if (it.m_index < m_size)
|
||||
return it;
|
||||
|
||||
return End();
|
||||
}
|
||||
|
||||
/// Returns the internal allocator
|
||||
const AllocCb& GetAllocCb() const { return m_allocCb; }
|
||||
|
||||
private:
|
||||
// Disallow copy construct.
|
||||
Vector(Vector& rhs) = delete;
|
||||
|
||||
// This indirection fixes the warning comparision of a constant with another constant. This should be
|
||||
// replace with `if constexpr` once AMDLog upgrades to support C++17.
|
||||
constexpr bool is_type_trivial()
|
||||
{
|
||||
#if !DD_PLATFORM_WINDOWS_KM
|
||||
return std::is_trivial_v<T>;
|
||||
#else
|
||||
// <type_traits> not available in kernel so treat every type as nontrivial
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
T m_data[defaultCapacity];
|
||||
T* m_pData;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
AllocCb m_allocCb;
|
||||
};
|
||||
|
||||
// Iterator class for the Vector type
|
||||
template <typename T, size_t defaultCapacity>
|
||||
class Vector<T, defaultCapacity>::Iterator
|
||||
{
|
||||
friend Vector;
|
||||
public:
|
||||
// Comparison operators
|
||||
bool operator==(const Iterator& rhs) const
|
||||
{
|
||||
return ((m_pContainer == rhs.m_pContainer) && (m_index == rhs.m_index));
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator& rhs) const
|
||||
{
|
||||
return ((m_pContainer != rhs.m_pContainer) || (m_index != rhs.m_index));
|
||||
}
|
||||
|
||||
// Prefix operator to increment the iterator
|
||||
Iterator& operator++()
|
||||
{
|
||||
if (m_pContainer != nullptr)
|
||||
{
|
||||
m_index += 1;
|
||||
if (m_index >= m_pContainer->m_size)
|
||||
{
|
||||
m_index = 0;
|
||||
m_pContainer = nullptr;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Addition operator to add to the iterator
|
||||
Iterator& operator+(size_t value)
|
||||
{
|
||||
if (m_pContainer != nullptr)
|
||||
{
|
||||
m_index += value;
|
||||
if (m_index >= m_pContainer->m_size)
|
||||
{
|
||||
m_index = 0;
|
||||
m_pContainer = nullptr;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Indirection operator
|
||||
T& operator*() const
|
||||
{
|
||||
DD_ASSERT(m_pContainer != nullptr);
|
||||
return m_pContainer->m_pData[m_index];
|
||||
}
|
||||
|
||||
// Member of pointer operator. Returns a pointer to the object in the shared container.
|
||||
T* operator->() const
|
||||
{
|
||||
DD_ASSERT(m_pContainer != nullptr);
|
||||
return &m_pContainer->m_pData[m_index];
|
||||
}
|
||||
private:
|
||||
// Constructor is private to ensure it cannot be created by anything other than the Vector itself
|
||||
Iterator(const Vector* pContainer, size_t index) :
|
||||
m_pContainer(pContainer),
|
||||
m_index(index)
|
||||
{
|
||||
};
|
||||
|
||||
const Vector* m_pContainer;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
//
|
||||
// functions necessary for C++ ranged based for loop support
|
||||
//
|
||||
|
||||
// Implement begin() function for range-based for loops
|
||||
template <typename T, size_t defaultCapacity>
|
||||
inline typename Vector<T, defaultCapacity>::Iterator begin(Vector<T, defaultCapacity>& rhs)
|
||||
{
|
||||
return rhs.Begin();
|
||||
}
|
||||
|
||||
// Implement end() function for range-based for loops
|
||||
template <typename T, size_t defaultCapacity>
|
||||
inline constexpr typename Vector<T, defaultCapacity>::Iterator end(const Vector<T, defaultCapacity>& rhs)
|
||||
{
|
||||
return rhs.End();
|
||||
}
|
||||
|
||||
// Specialized functions for using Vector<> like a String
|
||||
template <>
|
||||
inline bool Vector<char>::Append(const char* pStr)
|
||||
{
|
||||
return Append(pStr, strlen(pStr));
|
||||
}
|
||||
|
||||
template <>
|
||||
template <size_t Len>
|
||||
inline bool Vector<char>::Append(const char (&str)[Len])
|
||||
{
|
||||
return Append(str, strlen(str));
|
||||
}
|
||||
|
||||
} // DevDriver
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
//---------------------------------------------------------------------
|
||||
// CRC32
|
||||
//
|
||||
// Calculate a 32bit crc using a the Sarwate look up table method. The original algorithm was created by
|
||||
// Dilip V. Sarwate, and is based off of Stephan Brumme's implementation. See also:
|
||||
// https://dl.acm.org/citation.cfm?doid=63030.63037
|
||||
// http://create.stephan-brumme.com/crc32/#sarwate
|
||||
//
|
||||
//// Copyright (c) 2011-2016 Stephan Brumme. All rights reserved.
|
||||
//*****************************************************************************************************************
|
||||
// * This software is provided 'as-is', without any express or implied warranty. In no event will the author be held
|
||||
// * liable for any damages arising from the use of this software. Permission is granted to anyone to use this
|
||||
// * software for any purpose, including commercial applications, and to alter it and redistribute it freely,
|
||||
// * subject to the following restrictions:
|
||||
// * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original
|
||||
// * software
|
||||
// * 2. If you use this software in a product, an acknowledgment in the product documentation would be
|
||||
// * appreciated but is not required.
|
||||
// * 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the
|
||||
// * original software.
|
||||
// *****************************************************************************************************************
|
||||
//
|
||||
// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
|
||||
//
|
||||
// This software program is licensed subject to the BSD License,
|
||||
// available at http://www.opensource.org/licenses/bsd-license.html.
|
||||
//
|
||||
//
|
||||
// Tables for software CRC generation
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
static inline uint32_t CRC32(const void *pData, size_t length, uint32_t lastCRC = 0)
|
||||
{
|
||||
DD_STATIC_CONST uint32_t lookupTable[256] =
|
||||
{
|
||||
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,
|
||||
0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
|
||||
0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
|
||||
0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
|
||||
0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,
|
||||
0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
|
||||
0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
|
||||
0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
|
||||
0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
|
||||
0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
|
||||
0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,
|
||||
0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
|
||||
0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,
|
||||
0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
|
||||
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
|
||||
0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
|
||||
0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,
|
||||
0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
|
||||
0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,
|
||||
0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
|
||||
0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
|
||||
0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
|
||||
0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,
|
||||
0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
|
||||
0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,
|
||||
0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
|
||||
0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
|
||||
0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
|
||||
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,
|
||||
0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
|
||||
0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,
|
||||
0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
|
||||
};
|
||||
|
||||
uint32_t crc = ~lastCRC; // same as lastCRC ^ 0xFFFFFFFF
|
||||
const unsigned char* DD_RESTRICT pCurrent = (const unsigned char*)pData;
|
||||
while (length--)
|
||||
crc = (crc >> 8) ^ lookupTable[(crc & 0xFF) ^ *pCurrent++];
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
***********************************************************************************************************************
|
||||
*
|
||||
* Copyright (c) 2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
/**
|
||||
***********************************************************************************************************************
|
||||
* @file trackedCmdLocation.h
|
||||
* @brief Defines the format used for correlation buffers reported through
|
||||
* ICmdBufferReporting::CorrelationReportOnSubmit,
|
||||
* - enum class TrackedCmdLocationMode
|
||||
* - struct TrackedCmdLocation
|
||||
*
|
||||
* Plus the helper functions
|
||||
* - TrackedCmdLocationGetDeltaInDwords
|
||||
* - TrackedCmdLocationGetDeltaInBytes
|
||||
***********************************************************************************************************************
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Pal
|
||||
{
|
||||
|
||||
namespace CmdDisassembly
|
||||
{
|
||||
|
||||
/// @brief enum class TrackedCmdLocationMode
|
||||
/// Defines how to interpret the unions within struct TrackedCmdLocation
|
||||
///
|
||||
enum class TrackedCmdLocationMode : uint8_t
|
||||
{
|
||||
Invalid = 0,
|
||||
Before,
|
||||
After,
|
||||
Delta, // before and after
|
||||
ClientId,
|
||||
ClientEventId
|
||||
};
|
||||
|
||||
/// @brief struct TrackedCmdLocation defines the format used for correlation data submitted through
|
||||
/// ICmdBufferReporting::CorrelationReportOnSubmit, and is two DWORDs in size (uint64_t)
|
||||
///
|
||||
/// @detail struct TrackedCmdLocation has a number of flavors interpreted by its member m_mode
|
||||
///
|
||||
/// For m_mode == TrackedCmdLocationMode::Before, TrackedCmdLocationMode::After or
|
||||
/// TrackedCmdLocationMode::Delta, m_correlateInternal will be used
|
||||
///
|
||||
/// For m_mode == TrackedCmdLocationMode::ClientId, m_clientId will be used
|
||||
///
|
||||
/// For m_mode == TrackedCmdLocationMode::ClientEventId, m_clientEvent will be used
|
||||
///
|
||||
///
|
||||
/// For use as m_correlateInternal
|
||||
/// m_correlateInternal.m_event refers to an internal function that can be converted to a name via
|
||||
/// Pal::CmdDisassembly::TrackedCmdSupportBase
|
||||
/// m_correlateInternal.m_ptr is address within the cmdList being correlated by this
|
||||
/// TrackedCmdLocation
|
||||
/// For a cmdList with baseAddress and sizeInBytes, m_ptr is in the range
|
||||
/// [baseAddress, baseAddress+sizeInBytes)
|
||||
/// m_correlateInternal.m_deltaInDWords is only used when m_mode == TrackedCmdLocationMode::Delta
|
||||
/// And describes a TrackedCmdLocationMode::Before, TrackedCmdLocationMode::After pair
|
||||
/// when the m_ptr corresponding to TrackedCmdLocationMode::Before is m_ptr
|
||||
/// and for TrackedCmdLocationMode::After is m_ptr + m_deltaInDWords * sizeof(DWORD)
|
||||
/// m_deltaInDWords = 0 if no DWORDS/PM4Packets were written between to the corresponding cmdList
|
||||
/// between TrackedCmdLocationMode::Before and TrackedCmdLocationMode::After for the
|
||||
/// event described by m_event
|
||||
///
|
||||
/// For use as m_clientEvent
|
||||
/// m_clientEvent.m_clientEventId is a number provided by the client, provided by a call to
|
||||
/// IAmdExtCmdDisassembly::IssueClientEvent(clientId, clientEventId)
|
||||
/// The m_ptr for this event will be the next TrackedCmdLocation, which will have
|
||||
/// m_correlateInternal.m_mode == TrackedCmdLocationMode::Delta
|
||||
/// m_correlateInternal.m_event == PostClientEvent
|
||||
/// m_correlateInternal.m_deltaInDWords == 0
|
||||
///
|
||||
/// For use as m_clientId
|
||||
/// m_clientId.m_clientId is an identifier use by the client for the cmdList that corresponds to
|
||||
/// this array of correlation data. This will have been set through a call to
|
||||
/// IAmdExtCmdDisassembly::IssueClientEvent(clientId, clientEventId)
|
||||
/// When internal correlation is not active, this will be the first tracked location. Otherwise
|
||||
/// it will not appear until what tracking occurs during Reset is complete.
|
||||
struct TrackedCmdLocation
|
||||
{
|
||||
static constexpr uint32_t DeltaBitCount = 5;
|
||||
static constexpr uint32_t MaxDelta = (1LL << DeltaBitCount) - 1;
|
||||
static constexpr uint32_t DwordDeltaShift = 3;
|
||||
static constexpr uint8_t PostClientEvent = 0xff;
|
||||
|
||||
static constexpr uint64_t PtrBitCount = 48;
|
||||
/// NoCorrespondingBaseAddress is set to an impossible pointer value, that still fits in to the 48 fits
|
||||
/// used for m_correlateInternal.m_ptr;
|
||||
static constexpr uint64_t NoCorrespondingBaseAddress = (1LL << PtrBitCount) - 1;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t m_mode : 3;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t m_mode : 3; // TrackedCmdLocationMode::Before/After/Delta
|
||||
uint64_t m_event : 8; // TrackedEvents
|
||||
uint64_t m_ptr : PtrBitCount; // Note, can probably use two bits fewer,
|
||||
// since these addresses appear to be at a minimum 4-byte aligned.
|
||||
uint64_t m_deltaInDWords : DeltaBitCount;
|
||||
} m_correlateInternal;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t m_mode : 3;
|
||||
uint64_t m_clientId : 61;
|
||||
} m_clientId;
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t m_mode : 3;
|
||||
uint64_t m_clientEventId : 61;
|
||||
|
||||
} m_clientEvent;
|
||||
|
||||
uint64_t m_all;
|
||||
};
|
||||
};
|
||||
|
||||
// =====================================================================================================================
|
||||
/// @brief Helper funcion to obtain DeltaInDwords from TrackedCmdLocation
|
||||
///
|
||||
/// @detail m_correlateInternal.m_deltaInDWords is only used when m_mode == TrackedCmdLocationMode::Delta
|
||||
/// And describes a TrackedCmdLocationMode::Before, TrackedCmdLocationMode::After pair
|
||||
/// when the m_ptr corresponding to TrackedCmdLocationMode::Before is m_ptr
|
||||
/// and for TrackedCmdLocationMode::After is m_ptr + m_deltaInDWords * sizeof(DWORD)
|
||||
/// m_deltaInDWords = 0 if no DWORDS/PM4Packets were written between to the corresponding cmdList
|
||||
/// between TrackedCmdLocationMode::Before and TrackedCmdLocationMode::After for the
|
||||
/// event described by m_event
|
||||
///
|
||||
///
|
||||
/// @returns 0 in m_mode != TrackedCmdLocationMode::Delta
|
||||
/// m_correlateInternal.m_deltaInDWords otherwise
|
||||
constexpr uint64_t TrackedCmdLocationGetDeltaInDwords(
|
||||
const TrackedCmdLocation location)
|
||||
{
|
||||
const TrackedCmdLocationMode mode = static_cast<TrackedCmdLocationMode>(location.m_mode);
|
||||
if (mode == TrackedCmdLocationMode::Delta)
|
||||
{
|
||||
return location.m_correlateInternal.m_deltaInDWords;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================================================================
|
||||
/// @brief Helper funcion to convert DeltaInDwords from TrackedCmdLocation to "InBytes"
|
||||
///
|
||||
/// @returns 0 in m_mode != TrackedCmdLocationMode::Delta
|
||||
/// m_correlateInternal.m_deltaInDWords * sizeof(DWORD) otherwise - where DWORD is uint32_t
|
||||
constexpr uint64_t TrackedCmdLocationGetDeltaInBytes(
|
||||
const TrackedCmdLocation location)
|
||||
{
|
||||
return TrackedCmdLocationGetDeltaInDwords(location) << TrackedCmdLocation::DwordDeltaShift;
|
||||
}
|
||||
|
||||
} // namespace CmdDisassembly
|
||||
} // namespace Pal
|
||||
@@ -0,0 +1,70 @@
|
||||
##
|
||||
#######################################################################################################################
|
||||
#
|
||||
# Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
#######################################################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.1...3.21)
|
||||
|
||||
project(MetroHash VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
option(METROHASH_ENABLE_WERROR "Build with -Werror enabled" OFF)
|
||||
|
||||
add_library(metrohash STATIC "")
|
||||
|
||||
target_include_directories(metrohash PUBLIC src)
|
||||
|
||||
target_sources(metrohash PRIVATE src/metrohash64.cpp
|
||||
src/metrohash128.cpp)
|
||||
|
||||
|
||||
set_target_properties(metrohash PROPERTIES CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS OFF
|
||||
POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
|
||||
if(METROHASH_ENABLE_WERROR)
|
||||
target_compile_options(metrohash PRIVATE -Werror)
|
||||
endif()
|
||||
|
||||
# [GCC] Exceptions
|
||||
# https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html
|
||||
#
|
||||
# [GCC] Options Controlling C++ Dialect
|
||||
# https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/C_002b_002b-Dialect-Options.html
|
||||
target_compile_options(metrohash PRIVATE
|
||||
-fno-exceptions # Disable exception handling support.
|
||||
-fno-rtti) # Disable run-time type information support.
|
||||
|
||||
# [GCC] Options to Request or Suppress Warnings
|
||||
# https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Warning-Options.html
|
||||
target_compile_options(metrohash PRIVATE
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic)
|
||||
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
|
||||
# [MSVC] Exception Handling Model
|
||||
#
|
||||
# [MSVC] Enable Run-Time Type Information
|
||||
#
|
||||
# [MSVC] Buffer Security Check
|
||||
target_compile_options(metrohash PRIVATE
|
||||
/EHsc # Catches only C++ exceptions and assumes
|
||||
# functions declared as extern "C" never throw a C++ exception.
|
||||
/GR- # Disables run-time type information.
|
||||
/GS-) # Disables detection of buffer overruns.
|
||||
|
||||
# [MSVC] Warning Level
|
||||
target_compile_options(metrohash PRIVATE
|
||||
/W4 # Enable warning level 4.
|
||||
/WX) # Treat warnings as errors.
|
||||
|
||||
else()
|
||||
message(FATAL_ERROR "Compiler ${CMAKE_CXX_COMPILER_ID} is not supported!")
|
||||
endif()
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,56 @@
|
||||
## MetroHash: Faster, Better Hash Functions
|
||||
|
||||
MetroHash is a set of state-of-the-art hash functions for *non-cryptographic* use cases. They are notable for being algorithmically generated in addition to their exceptional performance. The set of published hash functions may be expanded in the future, having been selected from a very large set of hash functions that have been constructed this way.
|
||||
|
||||
* Fastest general-purpose functions for bulk hashing.
|
||||
* Fastest general-purpose functions for small, variable length keys.
|
||||
* Robust statistical bias profile, similar to the MD5 cryptographic hash.
|
||||
* Hashes can be constructed incrementally (**new**)
|
||||
* 64-bit, 128-bit, and 128-bit CRC variants currently available.
|
||||
* Optimized for modern x86-64 microarchitectures.
|
||||
* Elegant, compact, readable functions.
|
||||
|
||||
You can read more about the design and history [here](http://www.jandrewrogers.com/2015/05/27/metrohash/).
|
||||
|
||||
## News
|
||||
|
||||
### 23 October 2018
|
||||
|
||||
The project has been re-licensed under Apache License v2.0. The purpose of this license change is consistency with the imminent release of MetroHash v2.0, which is also licensed under the Apache license.
|
||||
|
||||
### 27 July 2015
|
||||
|
||||
Two new 64-bit and 128-bit algorithms add the ability to construct hashes incrementally. In addition to supporting incremental construction, the algorithms are slightly superior to the prior versions.
|
||||
|
||||
A big change is that these new algorithms are implemented as C++ classes that support both incremental and stateless hashing. These classes also have a static method for verifying the implementation against the test vectors built into the classes. Implementations are now fully contained by their respective headers e.g. "metrohash128.h".
|
||||
|
||||
*Note: an incremental version of the 128-bit CRC version is on its way but is not included in this push.*
|
||||
|
||||
**Usage Example For Stateless Hashing**
|
||||
|
||||
`MetroHash128::Hash(key, key_length, hash_ptr, seed)`
|
||||
|
||||
**Usage Example For Incremental Hashing**
|
||||
|
||||
`MetroHash128 hasher;`
|
||||
`hasher.Update(partial_key, partial_key_length);`
|
||||
`...`
|
||||
`hasher.Update(partial_key, partial_key_length);`
|
||||
`hasher.Finalize(hash_ptr);`
|
||||
|
||||
An `Initialize(seed)` method allows the hasher objects to be reused.
|
||||
|
||||
|
||||
### 27 May 2015
|
||||
|
||||
Six hash functions have been included in the initial release:
|
||||
|
||||
* 64-bit hash functions, "metrohash64_1" and "metrohash64_2"
|
||||
* 128-bit hash functions, "metrohash128_1" and "metrohash128_2"
|
||||
* 128-bit hash functions using CRC instructions, "metrohash128crc_1" and "metrohash128crc_2"
|
||||
|
||||
Hash functions in the same family are effectively statistically unique. In other words, if you need two hash functions for a bloom filter, you can use "metrohash64_1" and "metrohash64_2" in the same implementation without issue. An unbounded set of statistically unique functions can be generated in each family. The functions in this repo were generated specifically for public release.
|
||||
|
||||
The hash function generation software made no effort toward portability. While these hash functions should be easily portable to big-endian microarchitectures, they have not been tested on them and the performance optimization algorithms were not targeted at them. ARM64 microarchitectures might be a worthwhile hash function generation targets if I had the hardware.
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
####
|
||||
#
|
||||
# Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
####
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Common MetroHash Implementation Files
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
vpath %.cpp $(METROHASH_DEPTH)/src
|
||||
|
||||
CPPFILES += metrohash64.cpp \
|
||||
metrohash128.cpp
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Common MetroHash Includes
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
LCXXINCS += -I$(METROHASH_DEPTH)/src
|
||||
@@ -0,0 +1,24 @@
|
||||
// metrohash.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef METROHASH_METROHASH_H
|
||||
#define METROHASH_METROHASH_H
|
||||
|
||||
#include "metrohash64.h"
|
||||
#include "metrohash128.h"
|
||||
#include "metrohash128crc.h"
|
||||
|
||||
#endif // #ifndef METROHASH_METROHASH_H
|
||||
@@ -0,0 +1,419 @@
|
||||
// metrohash128.cpp
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#include <string.h>
|
||||
#include "platform.h"
|
||||
#include "metrohash128.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
const char * MetroHash128::test_string = "012345678901234567890123456789012345678901234567890123456789012";
|
||||
|
||||
const uint8_t MetroHash128::test_seed_0[16] = {
|
||||
0xC7, 0x7C, 0xE2, 0xBF, 0xA4, 0xED, 0x9F, 0x9B,
|
||||
0x05, 0x48, 0xB2, 0xAC, 0x50, 0x74, 0xA2, 0x97
|
||||
};
|
||||
|
||||
const uint8_t MetroHash128::test_seed_1[16] = {
|
||||
0x45, 0xA3, 0xCD, 0xB8, 0x38, 0x19, 0x9D, 0x7F,
|
||||
0xBD, 0xD6, 0x8D, 0x86, 0x7A, 0x14, 0xEC, 0xEF
|
||||
};
|
||||
|
||||
|
||||
|
||||
MetroHash128::MetroHash128(const uint64_t seed)
|
||||
{
|
||||
Initialize(seed);
|
||||
}
|
||||
|
||||
|
||||
void MetroHash128::Initialize(const uint64_t seed)
|
||||
{
|
||||
// initialize internal hash registers
|
||||
state.v[0] = (static_cast<uint64_t>(seed) - k0) * k3;
|
||||
state.v[1] = (static_cast<uint64_t>(seed) + k1) * k2;
|
||||
state.v[2] = (static_cast<uint64_t>(seed) + k0) * k2;
|
||||
state.v[3] = (static_cast<uint64_t>(seed) - k1) * k3;
|
||||
|
||||
// initialize total length of input
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void MetroHash128::Update(const uint8_t * const buffer, const uint64_t length)
|
||||
{
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(buffer);
|
||||
const uint8_t * const end = ptr + length;
|
||||
|
||||
// input buffer may be partially filled
|
||||
if (bytes % 32)
|
||||
{
|
||||
uint64_t fill = 32 - (bytes % 32);
|
||||
if (fill > length)
|
||||
fill = length;
|
||||
|
||||
memcpy(input.b + (bytes % 32), ptr, static_cast<size_t>(fill));
|
||||
ptr += fill;
|
||||
bytes += fill;
|
||||
|
||||
// input buffer is still partially filled
|
||||
if ((bytes % 32) != 0) return;
|
||||
|
||||
// process full input buffer
|
||||
state.v[0] += read_u64(&input.b[ 0]) * k0; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
|
||||
state.v[1] += read_u64(&input.b[ 8]) * k1; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
|
||||
state.v[2] += read_u64(&input.b[16]) * k2; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
|
||||
state.v[3] += read_u64(&input.b[24]) * k3; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
|
||||
}
|
||||
|
||||
// bulk update
|
||||
bytes += (end - ptr);
|
||||
while (ptr <= (end - 32))
|
||||
{
|
||||
// process directly from the source, bypassing the input buffer
|
||||
state.v[0] += read_u64(ptr) * k0; ptr += 8; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
|
||||
state.v[1] += read_u64(ptr) * k1; ptr += 8; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
|
||||
state.v[2] += read_u64(ptr) * k2; ptr += 8; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
|
||||
state.v[3] += read_u64(ptr) * k3; ptr += 8; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
|
||||
}
|
||||
|
||||
// store remaining bytes in input buffer
|
||||
if (ptr < end)
|
||||
memcpy(input.b, ptr, end - ptr);
|
||||
}
|
||||
|
||||
|
||||
void MetroHash128::Finalize(uint8_t * const hash)
|
||||
{
|
||||
// finalize bulk loop, if used
|
||||
if (bytes >= 32)
|
||||
{
|
||||
state.v[2] ^= rotate_right(((state.v[0] + state.v[3]) * k0) + state.v[1], 21) * k1;
|
||||
state.v[3] ^= rotate_right(((state.v[1] + state.v[2]) * k1) + state.v[0], 21) * k0;
|
||||
state.v[0] ^= rotate_right(((state.v[0] + state.v[2]) * k0) + state.v[3], 21) * k1;
|
||||
state.v[1] ^= rotate_right(((state.v[1] + state.v[3]) * k1) + state.v[2], 21) * k0;
|
||||
}
|
||||
|
||||
// process any bytes remaining in the input buffer
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(input.b);
|
||||
const uint8_t * const end = ptr + (bytes % 32);
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
state.v[0] += read_u64(ptr) * k2; ptr += 8; state.v[0] = rotate_right(state.v[0],33) * k3;
|
||||
state.v[1] += read_u64(ptr) * k2; ptr += 8; state.v[1] = rotate_right(state.v[1],33) * k3;
|
||||
state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 45) * k1;
|
||||
state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 45) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
state.v[0] += read_u64(ptr) * k2; ptr += 8; state.v[0] = rotate_right(state.v[0],33) * k3;
|
||||
state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 27) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
state.v[1] += read_u32(ptr) * k2; ptr += 4; state.v[1] = rotate_right(state.v[1],33) * k3;
|
||||
state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 46) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
state.v[0] += read_u16(ptr) * k2; ptr += 2; state.v[0] = rotate_right(state.v[0],33) * k3;
|
||||
state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 22) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
state.v[1] += read_u8 (ptr) * k2; state.v[1] = rotate_right(state.v[1],33) * k3;
|
||||
state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 58) * k0;
|
||||
}
|
||||
|
||||
state.v[0] += rotate_right((state.v[0] * k0) + state.v[1], 13);
|
||||
state.v[1] += rotate_right((state.v[1] * k1) + state.v[0], 37);
|
||||
state.v[0] += rotate_right((state.v[0] * k2) + state.v[1], 13);
|
||||
state.v[1] += rotate_right((state.v[1] * k3) + state.v[0], 37);
|
||||
|
||||
bytes = 0;
|
||||
|
||||
// do any endian conversion here
|
||||
|
||||
memcpy(hash, state.v, 16);
|
||||
}
|
||||
|
||||
|
||||
void MetroHash128::Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed)
|
||||
{
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(buffer);
|
||||
const uint8_t * const end = ptr + length;
|
||||
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = (static_cast<uint64_t>(seed) - k0) * k3;
|
||||
v[1] = (static_cast<uint64_t>(seed) + k1) * k2;
|
||||
|
||||
if (length >= 32)
|
||||
{
|
||||
v[2] = (static_cast<uint64_t>(seed) + k0) * k2;
|
||||
v[3] = (static_cast<uint64_t>(seed) - k1) * k3;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 21) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 21) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 21) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 21) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 45) * k1;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 45) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 27) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 46) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 22) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 58) * k0;
|
||||
}
|
||||
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 13);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 37);
|
||||
v[0] += rotate_right((v[0] * k2) + v[1], 13);
|
||||
v[1] += rotate_right((v[1] * k3) + v[0], 37);
|
||||
|
||||
// do any endian conversion here
|
||||
|
||||
memcpy(hash, v, 16);
|
||||
}
|
||||
|
||||
|
||||
bool MetroHash128::ImplementationVerified()
|
||||
{
|
||||
uint8_t hash[16];
|
||||
const uint8_t * key = reinterpret_cast<const uint8_t *>(MetroHash128::test_string);
|
||||
|
||||
// verify one-shot implementation
|
||||
MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 0);
|
||||
if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false;
|
||||
|
||||
MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 1);
|
||||
if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false;
|
||||
|
||||
// verify incremental implementation
|
||||
MetroHash128 metro;
|
||||
|
||||
metro.Initialize(0);
|
||||
metro.Update(reinterpret_cast<const uint8_t *>(MetroHash128::test_string), strlen(MetroHash128::test_string));
|
||||
metro.Finalize(hash);
|
||||
if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false;
|
||||
|
||||
metro.Initialize(1);
|
||||
metro.Update(reinterpret_cast<const uint8_t *>(MetroHash128::test_string), strlen(MetroHash128::test_string));
|
||||
metro.Finalize(hash);
|
||||
if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void metrohash128_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xC83A91E1;
|
||||
static const uint64_t k1 = 0x8648DBDB;
|
||||
static const uint64_t k2 = 0x7BDEC03B;
|
||||
static const uint64_t k3 = 0x2F5870A5;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = ((static_cast<uint64_t>(seed) - k0) * k3) + len;
|
||||
v[1] = ((static_cast<uint64_t>(seed) + k1) * k2) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
v[2] = ((static_cast<uint64_t>(seed) + k0) * k2) + len;
|
||||
v[3] = ((static_cast<uint64_t>(seed) - k1) * k3) + len;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 26) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 26) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 26) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 30) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 17) * k1;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 17) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 20) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 18) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],33) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 24) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],33) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 24) * k0;
|
||||
}
|
||||
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 13);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 37);
|
||||
v[0] += rotate_right((v[0] * k2) + v[1], 13);
|
||||
v[1] += rotate_right((v[1] * k3) + v[0], 37);
|
||||
|
||||
// do any endian conversion here
|
||||
|
||||
memcpy(out, v, 16);
|
||||
}
|
||||
|
||||
|
||||
void metrohash128_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xD6D018F5;
|
||||
static const uint64_t k1 = 0xA2AA033B;
|
||||
static const uint64_t k2 = 0x62992FC1;
|
||||
static const uint64_t k3 = 0x30BC5B29;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = ((static_cast<uint64_t>(seed) - k0) * k3) + len;
|
||||
v[1] = ((static_cast<uint64_t>(seed) + k1) * k2) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
v[2] = ((static_cast<uint64_t>(seed) + k0) * k2) + len;
|
||||
v[3] = ((static_cast<uint64_t>(seed) - k1) * k3) + len;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 33) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 33) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 33) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 33) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],29) * k3;
|
||||
v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],29) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 29) * k1;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 29) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],29) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 29) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
v[1] += read_u32(ptr) * k2; ptr += 4; v[1] = rotate_right(v[1],29) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 25) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
v[0] += read_u16(ptr) * k2; ptr += 2; v[0] = rotate_right(v[0],29) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 30) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
v[1] += read_u8 (ptr) * k2; v[1] = rotate_right(v[1],29) * k3;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 18) * k0;
|
||||
}
|
||||
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 33);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 33);
|
||||
v[0] += rotate_right((v[0] * k2) + v[1], 33);
|
||||
v[1] += rotate_right((v[1] * k3) + v[0], 33);
|
||||
|
||||
// do any endian conversion here
|
||||
|
||||
memcpy(out, v, 16);
|
||||
}
|
||||
|
||||
} // Util
|
||||
@@ -0,0 +1,85 @@
|
||||
// metrohash128.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#ifndef METROHASH_METROHASH_128_H
|
||||
#define METROHASH_METROHASH_128_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
class MetroHash128
|
||||
{
|
||||
public:
|
||||
static const uint32_t bits = 128;
|
||||
|
||||
// Constructor initializes the same as Initialize()
|
||||
MetroHash128(const uint64_t seed=0);
|
||||
|
||||
// Initializes internal state for new hash with optional seed
|
||||
void Initialize(const uint64_t seed=0);
|
||||
|
||||
// Update the hash state with a string of bytes. If the length
|
||||
// is sufficiently long, the implementation switches to a bulk
|
||||
// hashing algorithm directly on the argument buffer for speed.
|
||||
void Update(const uint8_t * buffer, const uint64_t length);
|
||||
|
||||
// Updates the hash state with the specified object. Modified by Advanced Micro Devices, Inc.
|
||||
template <typename T>
|
||||
void Update(const T& object)
|
||||
{
|
||||
Update(reinterpret_cast<const uint8_t*>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
// Constructs the final hash and writes it to the argument buffer.
|
||||
// After a hash is finalized, this instance must be Initialized()-ed
|
||||
// again or the behavior of Update() and Finalize() is undefined.
|
||||
void Finalize(uint8_t * const hash);
|
||||
|
||||
// A non-incremental function implementation. This can be significantly
|
||||
// faster than the incremental implementation for some usage patterns.
|
||||
static void Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed=0);
|
||||
|
||||
// Does implementation correctly execute test vectors?
|
||||
static bool ImplementationVerified();
|
||||
|
||||
// test vectors -- Hash(test_string, seed=0) => test_seed_0
|
||||
static const char * test_string;
|
||||
static const uint8_t test_seed_0[16];
|
||||
static const uint8_t test_seed_1[16];
|
||||
|
||||
private:
|
||||
static const uint64_t k0 = 0xC83A91E1;
|
||||
static const uint64_t k1 = 0x8648DBDB;
|
||||
static const uint64_t k2 = 0x7BDEC03B;
|
||||
static const uint64_t k3 = 0x2F5870A5;
|
||||
|
||||
struct { uint64_t v[4]; } state;
|
||||
struct { uint8_t b[32]; } input;
|
||||
uint64_t bytes;
|
||||
};
|
||||
|
||||
|
||||
// Legacy 128-bit hash functions -- do not use
|
||||
void metrohash128_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
void metrohash128_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
|
||||
} // Util
|
||||
|
||||
#endif // #ifndef METROHASH_METROHASH_128_H
|
||||
@@ -0,0 +1,178 @@
|
||||
// metrohash128crc.cpp
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#include <nmmintrin.h>
|
||||
#include <string.h>
|
||||
#include "metrohash.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
void metrohash128crc_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xC83A91E1;
|
||||
static const uint64_t k1 = 0x8648DBDB;
|
||||
static const uint64_t k2 = 0x7BDEC03B;
|
||||
static const uint64_t k3 = 0x2F5870A5;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = ((static_cast<uint64_t>(seed) - k0) * k3) + len;
|
||||
v[1] = ((static_cast<uint64_t>(seed) + k1) * k2) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
v[2] = ((static_cast<uint64_t>(seed) + k0) * k2) + len;
|
||||
v[3] = ((static_cast<uint64_t>(seed) - k1) * k3) + len;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] ^= _mm_crc32_u64(v[0], read_u64(ptr)); ptr += 8;
|
||||
v[1] ^= _mm_crc32_u64(v[1], read_u64(ptr)); ptr += 8;
|
||||
v[2] ^= _mm_crc32_u64(v[2], read_u64(ptr)); ptr += 8;
|
||||
v[3] ^= _mm_crc32_u64(v[3], read_u64(ptr)); ptr += 8;
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 34) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 37) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 34) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 37) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],34) * k3;
|
||||
v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],34) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 30) * k1;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 30) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],36) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 23) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
v[1] ^= _mm_crc32_u64(v[0], read_u32(ptr)); ptr += 4;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 19) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
v[0] ^= _mm_crc32_u64(v[1], read_u16(ptr)); ptr += 2;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 13) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
v[1] ^= _mm_crc32_u64(v[0], read_u8 (ptr));
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 17) * k0;
|
||||
}
|
||||
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 11);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 26);
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 11);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 26);
|
||||
|
||||
memcpy(out, v, 16);
|
||||
}
|
||||
|
||||
|
||||
void metrohash128crc_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xEE783E2F;
|
||||
static const uint64_t k1 = 0xAD07C493;
|
||||
static const uint64_t k2 = 0x797A90BB;
|
||||
static const uint64_t k3 = 0x2E4B2E1B;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = ((static_cast<uint64_t>(seed) - k0) * k3) + len;
|
||||
v[1] = ((static_cast<uint64_t>(seed) + k1) * k2) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
v[2] = ((static_cast<uint64_t>(seed) + k0) * k2) + len;
|
||||
v[3] = ((static_cast<uint64_t>(seed) - k1) * k3) + len;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] ^= _mm_crc32_u64(v[0], read_u64(ptr)); ptr += 8;
|
||||
v[1] ^= _mm_crc32_u64(v[1], read_u64(ptr)); ptr += 8;
|
||||
v[2] ^= _mm_crc32_u64(v[2], read_u64(ptr)); ptr += 8;
|
||||
v[3] ^= _mm_crc32_u64(v[3], read_u64(ptr)); ptr += 8;
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 12) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 19) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 12) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 19) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],41) * k3;
|
||||
v[1] += read_u64(ptr) * k2; ptr += 8; v[1] = rotate_right(v[1],41) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 10) * k1;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 10) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
v[0] += read_u64(ptr) * k2; ptr += 8; v[0] = rotate_right(v[0],34) * k3;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 22) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
v[1] ^= _mm_crc32_u64(v[0], read_u32(ptr)); ptr += 4;
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 14) * k0;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
v[0] ^= _mm_crc32_u64(v[1], read_u16(ptr)); ptr += 2;
|
||||
v[0] ^= rotate_right((v[0] * k2) + v[1], 15) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
v[1] ^= _mm_crc32_u64(v[0], read_u8 (ptr));
|
||||
v[1] ^= rotate_right((v[1] * k3) + v[0], 18) * k0;
|
||||
}
|
||||
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 15);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 27);
|
||||
v[0] += rotate_right((v[0] * k0) + v[1], 15);
|
||||
v[1] += rotate_right((v[1] * k1) + v[0], 27);
|
||||
|
||||
memcpy(out, v, 16);
|
||||
}
|
||||
|
||||
} // Util
|
||||
@@ -0,0 +1,33 @@
|
||||
// metrohash128crc.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#ifndef METROHASH_METROHASH_128_CRC_H
|
||||
#define METROHASH_METROHASH_128_CRC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
// Legacy 128-bit hash functions
|
||||
void metrohash128crc_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
void metrohash128crc_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
|
||||
} // Util
|
||||
|
||||
#endif // #ifndef METROHASH_METROHASH_128_CRC_H
|
||||
@@ -0,0 +1,415 @@
|
||||
// metrohash64.cpp
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#include "platform.h"
|
||||
#include "metrohash64.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
const char * MetroHash64::test_string = "012345678901234567890123456789012345678901234567890123456789012";
|
||||
|
||||
const uint8_t MetroHash64::test_seed_0[8] = { 0x6B, 0x75, 0x3D, 0xAE, 0x06, 0x70, 0x4B, 0xAD };
|
||||
const uint8_t MetroHash64::test_seed_1[8] = { 0x3B, 0x0D, 0x48, 0x1C, 0xF4, 0xB9, 0xB8, 0xDF };
|
||||
|
||||
|
||||
|
||||
MetroHash64::MetroHash64(const uint64_t seed)
|
||||
{
|
||||
Initialize(seed);
|
||||
}
|
||||
|
||||
|
||||
void MetroHash64::Initialize(const uint64_t seed)
|
||||
{
|
||||
vseed = (static_cast<uint64_t>(seed) + k2) * k0;
|
||||
|
||||
// initialize internal hash registers
|
||||
state.v[0] = vseed;
|
||||
state.v[1] = vseed;
|
||||
state.v[2] = vseed;
|
||||
state.v[3] = vseed;
|
||||
|
||||
// initialize total length of input
|
||||
bytes = 0;
|
||||
}
|
||||
|
||||
|
||||
void MetroHash64::Update(const uint8_t * const buffer, const uint64_t length)
|
||||
{
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(buffer);
|
||||
const uint8_t * const end = ptr + length;
|
||||
|
||||
// input buffer may be partially filled
|
||||
if (bytes % 32)
|
||||
{
|
||||
uint64_t fill = 32 - (bytes % 32);
|
||||
if (fill > length)
|
||||
fill = length;
|
||||
|
||||
memcpy(input.b + (bytes % 32), ptr, static_cast<size_t>(fill));
|
||||
ptr += fill;
|
||||
bytes += fill;
|
||||
|
||||
// input buffer is still partially filled
|
||||
if ((bytes % 32) != 0) return;
|
||||
|
||||
// process full input buffer
|
||||
state.v[0] += read_u64(&input.b[ 0]) * k0; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
|
||||
state.v[1] += read_u64(&input.b[ 8]) * k1; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
|
||||
state.v[2] += read_u64(&input.b[16]) * k2; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
|
||||
state.v[3] += read_u64(&input.b[24]) * k3; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
|
||||
}
|
||||
|
||||
// bulk update
|
||||
bytes += static_cast<uint64_t>(end - ptr);
|
||||
while (ptr <= (end - 32))
|
||||
{
|
||||
// process directly from the source, bypassing the input buffer
|
||||
state.v[0] += read_u64(ptr) * k0; ptr += 8; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
|
||||
state.v[1] += read_u64(ptr) * k1; ptr += 8; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
|
||||
state.v[2] += read_u64(ptr) * k2; ptr += 8; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
|
||||
state.v[3] += read_u64(ptr) * k3; ptr += 8; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
|
||||
}
|
||||
|
||||
// store remaining bytes in input buffer
|
||||
if (ptr < end)
|
||||
memcpy(input.b, ptr, static_cast<size_t>(end - ptr));
|
||||
}
|
||||
|
||||
|
||||
void MetroHash64::Finalize(uint8_t * const hash)
|
||||
{
|
||||
// finalize bulk loop, if used
|
||||
if (bytes >= 32)
|
||||
{
|
||||
state.v[2] ^= rotate_right(((state.v[0] + state.v[3]) * k0) + state.v[1], 37) * k1;
|
||||
state.v[3] ^= rotate_right(((state.v[1] + state.v[2]) * k1) + state.v[0], 37) * k0;
|
||||
state.v[0] ^= rotate_right(((state.v[0] + state.v[2]) * k0) + state.v[3], 37) * k1;
|
||||
state.v[1] ^= rotate_right(((state.v[1] + state.v[3]) * k1) + state.v[2], 37) * k0;
|
||||
|
||||
state.v[0] = vseed + (state.v[0] ^ state.v[1]);
|
||||
}
|
||||
|
||||
// process any bytes remaining in the input buffer
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(input.b);
|
||||
const uint8_t * const end = ptr + (bytes % 32);
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
state.v[1] = state.v[0] + (read_u64(ptr) * k2); ptr += 8; state.v[1] = rotate_right(state.v[1],29) * k3;
|
||||
state.v[2] = state.v[0] + (read_u64(ptr) * k2); ptr += 8; state.v[2] = rotate_right(state.v[2],29) * k3;
|
||||
state.v[1] ^= rotate_right(state.v[1] * k0, 21) + state.v[2];
|
||||
state.v[2] ^= rotate_right(state.v[2] * k3, 21) + state.v[1];
|
||||
state.v[0] += state.v[2];
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
state.v[0] += read_u64(ptr) * k3; ptr += 8;
|
||||
state.v[0] ^= rotate_right(state.v[0], 55) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
state.v[0] += read_u32(ptr) * k3; ptr += 4;
|
||||
state.v[0] ^= rotate_right(state.v[0], 26) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
state.v[0] += read_u16(ptr) * k3; ptr += 2;
|
||||
state.v[0] ^= rotate_right(state.v[0], 48) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
state.v[0] += read_u8 (ptr) * k3;
|
||||
state.v[0] ^= rotate_right(state.v[0], 37) * k1;
|
||||
}
|
||||
|
||||
state.v[0] ^= rotate_right(state.v[0], 28);
|
||||
state.v[0] *= k0;
|
||||
state.v[0] ^= rotate_right(state.v[0], 29);
|
||||
|
||||
bytes = 0;
|
||||
|
||||
// do any endian conversion here
|
||||
|
||||
memcpy(hash, state.v, 8);
|
||||
}
|
||||
|
||||
|
||||
void MetroHash64::Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed)
|
||||
{
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(buffer);
|
||||
const uint8_t * const end = ptr + length;
|
||||
|
||||
uint64_t h = (static_cast<uint64_t>(seed) + k2) * k0;
|
||||
|
||||
if (length >= 32)
|
||||
{
|
||||
uint64_t v[4];
|
||||
v[0] = h;
|
||||
v[1] = h;
|
||||
v[2] = h;
|
||||
v[3] = h;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 37) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 37) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 37) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 37) * k0;
|
||||
h += v[0] ^ v[1];
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
uint64_t v0 = h + (read_u64(ptr) * k2); ptr += 8; v0 = rotate_right(v0,29) * k3;
|
||||
uint64_t v1 = h + (read_u64(ptr) * k2); ptr += 8; v1 = rotate_right(v1,29) * k3;
|
||||
v0 ^= rotate_right(v0 * k0, 21) + v1;
|
||||
v1 ^= rotate_right(v1 * k3, 21) + v0;
|
||||
h += v1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
h += read_u64(ptr) * k3; ptr += 8;
|
||||
h ^= rotate_right(h, 55) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
h += read_u32(ptr) * k3; ptr += 4;
|
||||
h ^= rotate_right(h, 26) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
h += read_u16(ptr) * k3; ptr += 2;
|
||||
h ^= rotate_right(h, 48) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
h += read_u8 (ptr) * k3;
|
||||
h ^= rotate_right(h, 37) * k1;
|
||||
}
|
||||
|
||||
h ^= rotate_right(h, 28);
|
||||
h *= k0;
|
||||
h ^= rotate_right(h, 29);
|
||||
|
||||
memcpy(hash, &h, 8);
|
||||
}
|
||||
|
||||
|
||||
bool MetroHash64::ImplementationVerified()
|
||||
{
|
||||
uint8_t hash[8];
|
||||
const uint8_t * key = reinterpret_cast<const uint8_t *>(MetroHash64::test_string);
|
||||
|
||||
// verify one-shot implementation
|
||||
MetroHash64::Hash(key, strlen(MetroHash64::test_string), hash, 0);
|
||||
if (memcmp(hash, MetroHash64::test_seed_0, 8) != 0) return false;
|
||||
|
||||
MetroHash64::Hash(key, strlen(MetroHash64::test_string), hash, 1);
|
||||
if (memcmp(hash, MetroHash64::test_seed_1, 8) != 0) return false;
|
||||
|
||||
// verify incremental implementation
|
||||
MetroHash64 metro;
|
||||
|
||||
metro.Initialize(0);
|
||||
metro.Update(reinterpret_cast<const uint8_t *>(MetroHash64::test_string), strlen(MetroHash64::test_string));
|
||||
metro.Finalize(hash);
|
||||
if (memcmp(hash, MetroHash64::test_seed_0, 8) != 0) return false;
|
||||
|
||||
metro.Initialize(1);
|
||||
metro.Update(reinterpret_cast<const uint8_t *>(MetroHash64::test_string), strlen(MetroHash64::test_string));
|
||||
metro.Finalize(hash);
|
||||
if (memcmp(hash, MetroHash64::test_seed_1, 8) != 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void metrohash64_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xC83A91E1;
|
||||
static const uint64_t k1 = 0x8648DBDB;
|
||||
static const uint64_t k2 = 0x7BDEC03B;
|
||||
static const uint64_t k3 = 0x2F5870A5;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t hash = ((static_cast<uint64_t>(seed) + k2) * k0) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
uint64_t v[4];
|
||||
v[0] = hash;
|
||||
v[1] = hash;
|
||||
v[2] = hash;
|
||||
v[3] = hash;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 33) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 33) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 33) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 33) * k0;
|
||||
hash += v[0] ^ v[1];
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
uint64_t v0 = hash + (read_u64(ptr) * k0); ptr += 8; v0 = rotate_right(v0,33) * k1;
|
||||
uint64_t v1 = hash + (read_u64(ptr) * k1); ptr += 8; v1 = rotate_right(v1,33) * k2;
|
||||
v0 ^= rotate_right(v0 * k0, 35) + v1;
|
||||
v1 ^= rotate_right(v1 * k3, 35) + v0;
|
||||
hash += v1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
hash += read_u64(ptr) * k3; ptr += 8;
|
||||
hash ^= rotate_right(hash, 33) * k1;
|
||||
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
hash += read_u32(ptr) * k3; ptr += 4;
|
||||
hash ^= rotate_right(hash, 15) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
hash += read_u16(ptr) * k3; ptr += 2;
|
||||
hash ^= rotate_right(hash, 13) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
hash += read_u8 (ptr) * k3;
|
||||
hash ^= rotate_right(hash, 25) * k1;
|
||||
}
|
||||
|
||||
hash ^= rotate_right(hash, 33);
|
||||
hash *= k0;
|
||||
hash ^= rotate_right(hash, 33);
|
||||
|
||||
memcpy(out, &hash, 8);
|
||||
}
|
||||
|
||||
|
||||
void metrohash64_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out)
|
||||
{
|
||||
static const uint64_t k0 = 0xD6D018F5;
|
||||
static const uint64_t k1 = 0xA2AA033B;
|
||||
static const uint64_t k2 = 0x62992FC1;
|
||||
static const uint64_t k3 = 0x30BC5B29;
|
||||
|
||||
const uint8_t * ptr = reinterpret_cast<const uint8_t*>(key);
|
||||
const uint8_t * const end = ptr + len;
|
||||
|
||||
uint64_t hash = ((static_cast<uint64_t>(seed) + k2) * k0) + len;
|
||||
|
||||
if (len >= 32)
|
||||
{
|
||||
uint64_t v[4];
|
||||
v[0] = hash;
|
||||
v[1] = hash;
|
||||
v[2] = hash;
|
||||
v[3] = hash;
|
||||
|
||||
do
|
||||
{
|
||||
v[0] += read_u64(ptr) * k0; ptr += 8; v[0] = rotate_right(v[0],29) + v[2];
|
||||
v[1] += read_u64(ptr) * k1; ptr += 8; v[1] = rotate_right(v[1],29) + v[3];
|
||||
v[2] += read_u64(ptr) * k2; ptr += 8; v[2] = rotate_right(v[2],29) + v[0];
|
||||
v[3] += read_u64(ptr) * k3; ptr += 8; v[3] = rotate_right(v[3],29) + v[1];
|
||||
}
|
||||
while (ptr <= (end - 32));
|
||||
|
||||
v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 30) * k1;
|
||||
v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 30) * k0;
|
||||
v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 30) * k1;
|
||||
v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 30) * k0;
|
||||
hash += v[0] ^ v[1];
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 16)
|
||||
{
|
||||
uint64_t v0 = hash + (read_u64(ptr) * k2); ptr += 8; v0 = rotate_right(v0,29) * k3;
|
||||
uint64_t v1 = hash + (read_u64(ptr) * k2); ptr += 8; v1 = rotate_right(v1,29) * k3;
|
||||
v0 ^= rotate_right(v0 * k0, 34) + v1;
|
||||
v1 ^= rotate_right(v1 * k3, 34) + v0;
|
||||
hash += v1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 8)
|
||||
{
|
||||
hash += read_u64(ptr) * k3; ptr += 8;
|
||||
hash ^= rotate_right(hash, 36) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 4)
|
||||
{
|
||||
hash += read_u32(ptr) * k3; ptr += 4;
|
||||
hash ^= rotate_right(hash, 15) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 2)
|
||||
{
|
||||
hash += read_u16(ptr) * k3; ptr += 2;
|
||||
hash ^= rotate_right(hash, 15) * k1;
|
||||
}
|
||||
|
||||
if ((end - ptr) >= 1)
|
||||
{
|
||||
hash += read_u8 (ptr) * k3;
|
||||
hash ^= rotate_right(hash, 23) * k1;
|
||||
}
|
||||
|
||||
hash ^= rotate_right(hash, 28);
|
||||
hash *= k0;
|
||||
hash ^= rotate_right(hash, 29);
|
||||
|
||||
memcpy(out, &hash, 8);
|
||||
}
|
||||
|
||||
} // Util
|
||||
@@ -0,0 +1,86 @@
|
||||
// metrohash64.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#ifndef METROHASH_METROHASH_64_H
|
||||
#define METROHASH_METROHASH_64_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
class MetroHash64
|
||||
{
|
||||
public:
|
||||
static const uint32_t bits = 64;
|
||||
|
||||
// Constructor initializes the same as Initialize()
|
||||
MetroHash64(const uint64_t seed=0);
|
||||
|
||||
// Initializes internal state for new hash with optional seed
|
||||
void Initialize(const uint64_t seed=0);
|
||||
|
||||
// Update the hash state with a string of bytes. If the length
|
||||
// is sufficiently long, the implementation switches to a bulk
|
||||
// hashing algorithm directly on the argument buffer for speed.
|
||||
void Update(const uint8_t * buffer, const uint64_t length);
|
||||
|
||||
// Updates the hash state with the specified object. Modified by Advanced Micro Devices, Inc.
|
||||
template <typename T>
|
||||
void Update(const T& object)
|
||||
{
|
||||
Update(reinterpret_cast<const uint8_t*>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
// Constructs the final hash and writes it to the argument buffer.
|
||||
// After a hash is finalized, this instance must be Initialized()-ed
|
||||
// again or the behavior of Update() and Finalize() is undefined.
|
||||
void Finalize(uint8_t * const hash);
|
||||
|
||||
// A non-incremental function implementation. This can be significantly
|
||||
// faster than the incremental implementation for some usage patterns.
|
||||
static void Hash(const uint8_t * buffer, const uint64_t length, uint8_t * const hash, const uint64_t seed=0);
|
||||
|
||||
// Does implementation correctly execute test vectors?
|
||||
static bool ImplementationVerified();
|
||||
|
||||
// test vectors -- Hash(test_string, seed=0) => test_seed_0
|
||||
static const char * test_string;
|
||||
static const uint8_t test_seed_0[8];
|
||||
static const uint8_t test_seed_1[8];
|
||||
|
||||
private:
|
||||
static const uint64_t k0 = 0xD6D018F5;
|
||||
static const uint64_t k1 = 0xA2AA033B;
|
||||
static const uint64_t k2 = 0x62992FC1;
|
||||
static const uint64_t k3 = 0x30BC5B29;
|
||||
|
||||
struct { uint64_t v[4]; } state;
|
||||
struct { uint8_t b[32]; } input;
|
||||
uint64_t bytes;
|
||||
uint64_t vseed;
|
||||
};
|
||||
|
||||
|
||||
// Legacy 64-bit hash functions -- do not use
|
||||
void metrohash64_1(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
void metrohash64_2(const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * out);
|
||||
|
||||
} // Util
|
||||
|
||||
#endif // #ifndef METROHASH_METROHASH_64_H
|
||||
@@ -0,0 +1,62 @@
|
||||
// platform.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Modifications Copyright© 2019 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
#ifndef METROHASH_PLATFORM_H
|
||||
#define METROHASH_PLATFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
// rotate right idiom recognized by most compilers
|
||||
inline static uint64_t rotate_right(uint64_t v, unsigned k)
|
||||
{
|
||||
return (v >> k) | (v << (64 - k));
|
||||
}
|
||||
|
||||
inline static uint64_t read_u64(const void * const ptr)
|
||||
{
|
||||
uint64_t val;
|
||||
memcpy(&val, ptr, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
inline static uint64_t read_u32(const void * const ptr)
|
||||
{
|
||||
uint32_t val;
|
||||
memcpy(&val, ptr, sizeof(val));
|
||||
return static_cast<uint64_t>(val);
|
||||
}
|
||||
|
||||
inline static uint64_t read_u16(const void * const ptr)
|
||||
{
|
||||
uint16_t val;
|
||||
memcpy(&val, ptr, sizeof(val));
|
||||
return static_cast<uint64_t>(val);
|
||||
}
|
||||
|
||||
inline static uint64_t read_u8 (const void * const ptr)
|
||||
{
|
||||
return static_cast<uint64_t>(*reinterpret_cast<const uint8_t *>(ptr));
|
||||
}
|
||||
|
||||
} // Util
|
||||
|
||||
#endif // #ifndef METROHASH_PLATFORM_H
|
||||
@@ -0,0 +1,63 @@
|
||||
// testvector.h
|
||||
//
|
||||
// Copyright 2015-2018 J. Andrew Rogers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef METROHASH_TESTVECTOR_H
|
||||
#define METROHASH_TESTVECTOR_H
|
||||
|
||||
#include "metrohash.h"
|
||||
|
||||
|
||||
typedef void (*HashFunction) (const uint8_t * key, uint64_t len, uint32_t seed, uint8_t * hash);
|
||||
|
||||
struct TestVectorData
|
||||
{
|
||||
HashFunction function;
|
||||
uint32_t bits;
|
||||
const char * key;
|
||||
uint32_t seed;
|
||||
uint8_t hash[64];
|
||||
};
|
||||
|
||||
// The test vector string is selected such that it will properly exercise every
|
||||
// internal branch of the hash function. Currently that requires a string with
|
||||
// a length of (at least) 63 bytes.
|
||||
|
||||
static const char * test_key_63 = "012345678901234567890123456789012345678901234567890123456789012";
|
||||
|
||||
// The hash assumes a little-endian architecture. Treating the hash results
|
||||
// as an array of uint64_t should enable conversion for big-endian implementations.
|
||||
const TestVectorData TestVector [] =
|
||||
{
|
||||
// seed = 0
|
||||
{ metrohash64_1, 64, test_key_63, 0, "658F044F5C730E40" },
|
||||
{ metrohash64_2, 64, test_key_63, 0, "073CAAB960623211" },
|
||||
{ metrohash128_1, 128, test_key_63, 0, "ED9997ED9D0A8B0FF3F266399477788F" },
|
||||
{ metrohash128_2, 128, test_key_63, 0, "7BBA6FE119CF35D45507EDF3505359AB" },
|
||||
{ metrohash128crc_1, 128, test_key_63, 0, "B329ED67831604D3DFAC4E4876D8262F" },
|
||||
{ metrohash128crc_2, 128, test_key_63, 0, "0502A67E257BBD77206BBCA6BBEF2653" },
|
||||
|
||||
// seed = 1
|
||||
{ metrohash64_1, 64, test_key_63, 1, "AE49EBB0A856537B" },
|
||||
{ metrohash64_2, 64, test_key_63, 1, "CF518E9CF58402C0" },
|
||||
{ metrohash128_1, 128, test_key_63, 1, "DDA6BA67F7DE755EFDF6BEABECCFD1F4" },
|
||||
{ metrohash128_2, 128, test_key_63, 1, "2DA6AF149A5CDBC12B09DB0846D69EF0" },
|
||||
{ metrohash128crc_1, 128, test_key_63, 1, "E8FAB51AF19F18A7B10D0A57D4276DF2" },
|
||||
{ metrohash128crc_2, 128, test_key_63, 1, "2D54F87181A0CF64B02C50D95692BC19" },
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // #ifndef METROHASH_TESTVECTOR_H
|
||||
Reference in New Issue
Block a user