Reapply amdgpu-windows-interop revert. (#1893)

## Overview and rationale

This reverts https://github.com/ROCm/rocm-systems/pull/1886, which...
* Re-applies https://github.com/ROCm/rocm-systems/pull/1866
* Reverts https://github.com/ROCm/rocm-systems/pull/1728

(So it restores the [`amdgpu-windows-interop/`](https://github.com/ROCm/rocm-systems/tree/develop/shared/amdgpu-windows-interop) folder back to the state from a few weeks ago)

The rationale for this change is at https://github.com/ROCm/rocm-systems/pull/1866:
> Last PAL update broke applications on gfx12 Windows.

## Cross-repository change details

That PR failed to build but was merged with this explanation:

> TheRock CI Windows build fails as expected with this revert.
> 
> References to these PAL members need to be stripped out in a patch on TheRock.
> 
> ```
> 11.3	C:\home\runner\_work\rocm-systems\rocm-systems\projects\clr\rocclr\device\pal\palubercapturemgr.cpp(152): error C2039: 'RegisterTraceStateChangeCallback': is not a member of 'GpuUtil::TraceSession'
> 11.4	C:\home\runner\_work\rocm-systems\rocm-systems\shared\amdgpu-windows-interop\pal\inc\gpuUtil\palTraceSession.h(372): note: see declaration of 'GpuUtil::TraceSession'
> 11.4	C:\home\runner\_work\rocm-systems\rocm-systems\projects\clr\rocclr\device\pal\palubercapturemgr.cpp(195): error C2039: 'UnregisterTraceStateChangeCallback': is not a member of 'GpuUtil::TraceSession'
> 11.4	C:\home\runner\_work\rocm-systems\rocm-systems\shared\amdgpu-windows-interop\pal\inc\gpuUtil\palTraceSession.h(372): note: see declaration of 'GpuUtil::TraceSession'
> ```

The patch in TheRock was updated in https://github.com/ROCm/TheRock/pull/2154. This rolls forward by updating the ref for TheRock.

That original PR could have been sequenced differently to avoid a build break - perhaps by
* Pointing to a branch in TheRock with the patch rebased
* Deleting the patch in the workflows here but holding a local copy of the path to be applied in workflows
* Landing the patch as a normal commit instead of carrying it at all

## Test plan

1. Watch TheRock CI here (https://github.com/ROCm/rocm-systems/actions/runs/19447202693/job/55644411119?pr=1893)
2. Build locally:
    
    ```bash
    # In rocm-systems
    git am --whitespace=nowarn D:\projects\TheRock\patches\amd-mainline\rocm-systems\0001-Revert-SWDEV-543498-Some-compute-Ubertrace-profiles-.patch
    git am --whitespace=nowarn D:\projects\TheRock\patches\amd-mainline\rocm-systems\0003-Use-is_versioned-true-consistently-in-both-Comgr-Loa.patch
    git am --whitespace=nowarn D:\projects\TheRock\patches\amd-mainline\rocm-systems\0006-Explicitly-load-libamdhip64.so.7.patch
    # Note: the build fails with the observed errors if patch 0001 is not applied!
    
    # In TheRock
    cmake -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe \
      -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
      -DPython3_EXECUTABLE=d:/projects/TheRock/.venv/Scripts/python \
      -DTHEROCK_ROCM_SYSTEMS_SOURCE_DIR=d:/projects/TheRock/../rocm-systems \  # IMPORTANT
      -DTHEROCK_AMDGPU_FAMILIES=gfx110X-all \
      -DBUILD_TESTING=ON \
      -DTHEROCK_ENABLE_ALL=ON \
      -Damd-llvm_BUILD_TYPE=RelWithDebInfo \
      -S D:/projects/TheRock \
      -B D:/projects/TheRock/build \
      -G Ninja
    
    cmake --build D:/projects/TheRock/build --target hip-clr
    # [build] Build finished with exit code 0
    cmake --build D:/projects/TheRock/build --target ocl-clr+dist
    # [build] Build finished with exit code 0
    ```
This commit is contained in:
Scott Todd
2025-11-18 07:17:06 -08:00
committed by GitHub
parent 44a32e23ac
commit fa772be675
139 changed files with 44141 additions and 44363 deletions
@@ -1,269 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,378 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,115 +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();
}
}
}
/*
***********************************************************************************************************************
*
* 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();
}
}
}
@@ -1,62 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,28 +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"
/*
***********************************************************************************************************************
*
* 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"
@@ -1,48 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,28 +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"
/*
***********************************************************************************************************************
*
* 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"
@@ -1,28 +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"
/*
***********************************************************************************************************************
*
* 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"
@@ -1,291 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,103 +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
/*
***********************************************************************************************************************
*
* 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
File diff suppressed because it is too large Load Diff
@@ -1,271 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,70 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,28 +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"
/*
***********************************************************************************************************************
*
* 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"
@@ -1,54 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,53 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,175 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,157 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,174 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,217 +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);
}
}
/*
***********************************************************************************************************************
*
* 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);
}
}
@@ -1,168 +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;
};
}
/*
***********************************************************************************************************************
*
* 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;
};
}
@@ -1,86 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,335 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,102 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,291 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,292 +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
/*
***********************************************************************************************************************
*
* 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
File diff suppressed because it is too large Load Diff
@@ -1,77 +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;
}
//---------------------------------------------------------------------
// 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;
}
@@ -1,187 +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
/*
***********************************************************************************************************************
*
* 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
@@ -1,70 +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()
##
#######################################################################################################################
#
# 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()
@@ -1,201 +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.
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.
@@ -1,56 +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.
## 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.
@@ -1,20 +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
####
#
# 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
@@ -1,24 +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
// 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
@@ -1,419 +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
// 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
@@ -1,85 +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
// 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
@@ -1,178 +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
// 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
@@ -1,33 +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
// 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
@@ -1,415 +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
// 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
@@ -1,86 +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
// 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
@@ -1,62 +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
// 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
@@ -1,63 +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
// 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