From a956f7b77091a6f04ec7e0e386c34fcf356288cc Mon Sep 17 00:00:00 2001 From: dev0 Date: Sun, 21 Dec 2025 07:49:28 +0530 Subject: [PATCH] [FEAT]: VCPKG --- CMake/FindDeps.cmake | 7 +- CMake/Triplets/arm64-linux-neon.cmake | 7 ++ CMake/Triplets/arm64-windows-cross.cmake | 9 ++ CMake/Triplets/wasm32-emscripten-simd.cmake | 9 ++ CMake/Triplets/x64-linux-avx2.cmake | 7 ++ CMakePresets.json | 131 ++++++++------------ Src/IACore/imp/cpp/DataOps.cpp | 23 ++-- Src/IACore/imp/cpp/HttpClient.cpp | 1 + Src/IACore/imp/cpp/IPC.cpp | 22 ++-- Src/IACore/inc/IACore/DataOps.hpp | 4 +- Src/IACore/inc/IACore/IPC.hpp | 2 +- Tests/Unit/CMakeLists.txt | 1 + Tests/Unit/DataOps.cpp | 113 +++++++++++++++++ 13 files changed, 226 insertions(+), 110 deletions(-) create mode 100644 CMake/Triplets/arm64-linux-neon.cmake create mode 100644 CMake/Triplets/arm64-windows-cross.cmake create mode 100644 CMake/Triplets/wasm32-emscripten-simd.cmake create mode 100644 CMake/Triplets/x64-linux-avx2.cmake create mode 100644 Tests/Unit/DataOps.cpp diff --git a/CMake/FindDeps.cmake b/CMake/FindDeps.cmake index 15142f8..ec91aff 100644 --- a/CMake/FindDeps.cmake +++ b/CMake/FindDeps.cmake @@ -98,19 +98,16 @@ set(EXPECTED_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(HTTPLIB_REQUIRE_OPENSSL OFF CACHE BOOL "" FORCE) set(HTTPLIB_REQUIRE_ZLIB OFF CACHE BOOL "" FORCE) +set(HTTPLIB_NO_EXCEPTIONS ON CACHE BOOL "" FORCE) set(ZSTD_BUILD_SHARED OFF CACHE BOOL "" FORCE) set(ZSTD_BUILD_STATIC ON CACHE BOOL "" FORCE) set(ZLIB_COMPAT ON CACHE BOOL "" FORCE) -set(ZLIB_ENABLE_TESTS OFF CACHE BOOL "" FORCE) +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) FetchContent_MakeAvailable(ZLIB zstd) -if(TARGET libzstd_static AND NOT TARGET zstd::libzstd) - add_library(zstd::libzstd ALIAS libzstd_static) -endif() - FetchContent_MakeAvailable(httplib pugixml nlohmann_json glaze simdjson tl-expected unordered_dense mimalloc) find_package(OpenSSL REQUIRED) diff --git a/CMake/Triplets/arm64-linux-neon.cmake b/CMake/Triplets/arm64-linux-neon.cmake new file mode 100644 index 0000000..ce29ac3 --- /dev/null +++ b/CMake/Triplets/arm64-linux-neon.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Linux) + +set(VCPKG_C_FLAGS "-march=armv8-a+simd") +set(VCPKG_CXX_FLAGS "-march=armv8-a+simd") diff --git a/CMake/Triplets/arm64-windows-cross.cmake b/CMake/Triplets/arm64-windows-cross.cmake new file mode 100644 index 0000000..1871ea0 --- /dev/null +++ b/CMake/Triplets/arm64-windows-cross.cmake @@ -0,0 +1,9 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Windows) + +set(VCPKG_POLICY_EMPTY_PACKAGE enabled) + +set(VCPKG_C_FLAGS "--target=arm64-pc-windows-msvc") +set(VCPKG_CXX_FLAGS "--target=arm64-pc-windows-msvc") diff --git a/CMake/Triplets/wasm32-emscripten-simd.cmake b/CMake/Triplets/wasm32-emscripten-simd.cmake new file mode 100644 index 0000000..ef2926b --- /dev/null +++ b/CMake/Triplets/wasm32-emscripten-simd.cmake @@ -0,0 +1,9 @@ +set(VCPKG_TARGET_ARCHITECTURE wasm32) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Emscripten) + +set(VCPKG_C_FLAGS "-msimd128 -pthread") +set(VCPKG_CXX_FLAGS "-msimd128 -pthread") + +set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "$ENV{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake") \ No newline at end of file diff --git a/CMake/Triplets/x64-linux-avx2.cmake b/CMake/Triplets/x64-linux-avx2.cmake new file mode 100644 index 0000000..cf0539a --- /dev/null +++ b/CMake/Triplets/x64-linux-avx2.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_CMAKE_SYSTEM_NAME Linux) + +set(VCPKG_C_FLAGS "-mavx2 -mfma") +set(VCPKG_CXX_FLAGS "-mavx2 -mfma") diff --git a/CMakePresets.json b/CMakePresets.json index 57d8177..7ea877d 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -12,103 +12,74 @@ "binaryDir": "${sourceDir}/out/build/${presetName}", "cacheVariables": { "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", - "CMAKE_C_COMPILER": "clang", - "CMAKE_CXX_COMPILER": "clang++" + "WITH_AVX2": "ON", + "WITH_NEON": "ON", + "VCPKG_OVERLAY_TRIPLETS": "${sourceDir}/CMake/Triplets", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" } }, { - "name": "windows-base", - "hidden": true, + "name": "linux-x64", + "displayName": "Linux x64 (AVX2)", "inherits": "base-common", - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - }, "cacheVariables": { + "CMAKE_SYSTEM_NAME": "Linux", + "CMAKE_SYSTEM_PROCESSOR": "x86_64", + "CMAKE_C_FLAGS": "-mavx2 -mfma", + "CMAKE_CXX_FLAGS": "-mavx2 -mfma", + "VCPKG_TARGET_TRIPLET": "x64-linux" + } + }, + { + "name": "linux-arm64", + "displayName": "Linux ARM64 (NEON)", + "inherits": "base-common", + "cacheVariables": { + "CMAKE_SYSTEM_NAME": "Linux", + "CMAKE_SYSTEM_PROCESSOR": "aarch64", + "CMAKE_C_COMPILER_TARGET": "aarch64-linux-gnu", + "CMAKE_CXX_COMPILER_TARGET": "aarch64-linux-gnu", + "CMAKE_CXX_FLAGS": "-march=armv8-a+simd", + "CMAKE_SYSROOT": "/usr/aarch64-linux-gnu", + "VCPKG_TARGET_TRIPLET": "arm64-linux" + } + }, + { + "name": "windows-x64", + "displayName": "Windows x64 (AVX2)", + "inherits": "base-common", + "cacheVariables": { + "CMAKE_SYSTEM_NAME": "Windows", + "CMAKE_SYSTEM_PROCESSOR": "x86_64", "CMAKE_C_COMPILER": "clang-cl", "CMAKE_CXX_COMPILER": "clang-cl", - "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_CXX_FLAGS": "/arch:AVX2", "VCPKG_TARGET_TRIPLET": "x64-windows" } }, { - "name": "linux-base", - "hidden": true, + "name": "windows-arm64", + "displayName": "Windows ARM64 (NEON)", "inherits": "base-common", - "condition": { - "type": "notEquals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "windows-default", - "displayName": "Windows (Clang-CL + VCPKG)", - "description": "Windows build using Clang-CL and VCPKG dependencies", - "inherits": "windows-base" - }, - { - "name": "linux-default", - "displayName": "Linux (Clang)", - "description": "Linux build using Clang", - "inherits": "linux-base" - }, - { - "name": "linux-ci", - "displayName": "Linux CI Build", - "description": "Linux CI Build", - "inherits": "linux-base", "cacheVariables": { - "IS_CI_BUILD": "ON" + "CMAKE_SYSTEM_NAME": "Windows", + "CMAKE_SYSTEM_PROCESSOR": "aarch64", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_CXX_FLAGS": "--target=arm64-pc-windows-msvc -fuse-ld=lld-link", + "VCPKG_TARGET_TRIPLET": "arm64-windows" } }, { - "name": "wasm-default", - "displayName": "WebAssembly (Emscripten)", - "description": "Build using Emscripten toolchain", - "generator": "Ninja", - "binaryDir": "${sourceDir}/out/build/wasm-release", - "toolchainFile": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", + "name": "wasm", + "displayName": "WebAssembly (SIMD)", + "inherits": "base-common", "cacheVariables": { - "CMAKE_CXX_FLAGS": "-msimd128 -pthread" - } - } - ], - "buildPresets": [ - { - "name": "windows-debug", - "configurePreset": "windows-default", - "configuration": "Debug", - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "linux-debug", - "configurePreset": "linux-default", - "configuration": "Debug", - "condition": { - "type": "notEquals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "linux-wasm-debug", - "configurePreset": "wasm-default", - "configuration": "Debug" - }, - { - "name": "linux-ci-release", - "configurePreset": "linux-ci", - "configuration": "Release", - "condition": { - "type": "notEquals", - "lhs": "${hostSystemName}", - "rhs": "Windows" + "CMAKE_SYSTEM_NAME": "Emscripten", + "CMAKE_SYSTEM_PROCESSOR": "wasm32", + "VCPKG_TARGET_TRIPLET": "wasm32-emscripten-simd", + "VCPKG_HOST_TRIPLET": "x64-linux", + "VCPKG_CHAINLOAD_TOOLCHAIN_FILE": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" } } ] diff --git a/Src/IACore/imp/cpp/DataOps.cpp b/Src/IACore/imp/cpp/DataOps.cpp index 4b3c453..04dfd1d 100644 --- a/Src/IACore/imp/cpp/DataOps.cpp +++ b/Src/IACore/imp/cpp/DataOps.cpp @@ -146,8 +146,8 @@ namespace IACore namespace IACore { CONSTEXPR UINT32 XXH_PRIME32_1 = 0x9E3779B1U; - CONSTEXPR UINT32 XXH_PRIME32_2 = 0x85EBCA6BU; - CONSTEXPR UINT32 XXH_PRIME32_3 = 0xC2B2AE35U; + CONSTEXPR UINT32 XXH_PRIME32_2 = 0x85EBCA77U; + CONSTEXPR UINT32 XXH_PRIME32_3 = 0xC2B2AE3DU; CONSTEXPR UINT32 XXH_PRIME32_4 = 0x27D4EB2FU; CONSTEXPR UINT32 XXH_PRIME32_5 = 0x165667B1U; @@ -159,12 +159,12 @@ namespace IACore return seed; } - UINT32 DataOps::Hash_xxHash(IN CONST String &string) + UINT32 DataOps::Hash_xxHash(IN CONST String &string, IN UINT32 seed) { - return Hash_xxHash(Span(reinterpret_cast(string.data()), string.size())); + return Hash_xxHash(Span(reinterpret_cast(string.data()), string.length()), seed); } - UINT32 DataOps::Hash_xxHash(IN Span data) + UINT32 DataOps::Hash_xxHash(IN Span data, IN UINT32 seed) { CONST UINT8 *p = data.data(); CONST UINT8 *CONST bEnd = p + data.size(); @@ -174,10 +174,10 @@ namespace IACore { const UINT8 *const limit = bEnd - 16; - UINT32 v1 = XXH_PRIME32_1 + XXH_PRIME32_2; - UINT32 v2 = XXH_PRIME32_2; - UINT32 v3 = 0; - UINT32 v4 = -XXH_PRIME32_1; + UINT32 v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2; + UINT32 v2 = seed + XXH_PRIME32_2; + UINT32 v3 = seed + 0; + UINT32 v4 = seed - XXH_PRIME32_1; do { @@ -194,13 +194,14 @@ namespace IACore h32 = std::rotl(v1, 1) + std::rotl(v2, 7) + std::rotl(v3, 12) + std::rotl(v4, 18); } else - h32 = XXH_PRIME32_5; + h32 = seed + XXH_PRIME32_5; h32 += (UINT32) data.size(); while (p + 4 <= bEnd) { - h32 += ReadUnaligned(p) * XXH_PRIME32_3; + const auto t = ReadUnaligned(p) * XXH_PRIME32_3; + h32 += t; h32 = std::rotl(h32, 17) * XXH_PRIME32_4; p += 4; } diff --git a/Src/IACore/imp/cpp/HttpClient.cpp b/Src/IACore/imp/cpp/HttpClient.cpp index d304d85..1305d25 100644 --- a/Src/IACore/imp/cpp/HttpClient.cpp +++ b/Src/IACore/imp/cpp/HttpClient.cpp @@ -228,6 +228,7 @@ namespace IACore case EHeaderType::WARNING: return "Warning"; } + return ""; } BOOL HttpClient::IsSuccessResponseCode(IN EResponseCode code) diff --git a/Src/IACore/imp/cpp/IPC.cpp b/Src/IACore/imp/cpp/IPC.cpp index 345efd3..edccf32 100644 --- a/Src/IACore/imp/cpp/IPC.cpp +++ b/Src/IACore/imp/cpp/IPC.cpp @@ -191,7 +191,7 @@ namespace IACore { for (auto &session : m_activeSessions) { - ProcessOps::TerminateProcess(session->ProcessHandle); + ProcessOps::TerminateProcess(session->NodeProcess); FileOps::UnmapFile(session->MappedPtr); FileOps::UnlinkSharedMemory(session->SharedMemName); SocketOps::Close(session->DataSocket); @@ -200,7 +200,7 @@ namespace IACore for (auto &session : m_pendingSessions) { - ProcessOps::TerminateProcess(session->ProcessHandle); + ProcessOps::TerminateProcess(session->NodeProcess); FileOps::UnmapFile(session->MappedPtr); FileOps::UnlinkSharedMemory(session->SharedMemName); SocketOps::Close(session->ListenerSocket); @@ -221,7 +221,7 @@ namespace IACore if (now - session->CreationTime > std::chrono::seconds(5)) { - ProcessOps::TerminateProcess(session->ProcessHandle); + ProcessOps::TerminateProcess(session->NodeProcess); FileOps::UnmapFile(session->MappedPtr); FileOps::UnlinkSharedMemory(session->SharedMemName); @@ -249,7 +249,7 @@ namespace IACore SocketOps::Close(session->ListenerSocket); session->ListenerSocket = INVALID_SOCKET; - const auto sessionID = session->ProcessHandle->ID.load(); + const auto sessionID = session->NodeProcess->ID.load(); const auto sessionPtr = session.get(); m_activeSessions.push_back(std::move(session)); m_pendingSessions.erase(m_pendingSessions.begin() + i); @@ -261,7 +261,7 @@ namespace IACore { auto &node = m_activeSessions[i]; - auto nodeID = node->ProcessHandle->ID.load(); + auto nodeID = node->NodeProcess->ID.load(); RingBufferView::PacketHeader header; @@ -275,7 +275,7 @@ namespace IACore OnSignal(nodeID, signal); else if (res == 0 || (res < 0 && !SocketOps::IsWouldBlock())) { - ProcessOps::TerminateProcess(node->ProcessHandle); + ProcessOps::TerminateProcess(node->NodeProcess); FileOps::UnmapFile(node->MappedPtr); FileOps::UnlinkSharedMemory(node->SharedMemName); @@ -355,7 +355,7 @@ namespace IACore String args = std::format("\"{}\"", desc.Serialize()); - session->ProcessHandle = ProcessOps::SpawnProcessAsync( + session->NodeProcess = ProcessOps::SpawnProcessAsync( FileOps::NormalizeExecutablePath(executablePath).string(), args, [sid](IN StringView line) { UNUSED(sid); @@ -379,10 +379,10 @@ namespace IACore // Give some time for child node to stablize std::this_thread::sleep_for(std::chrono::seconds(1)); - if (!session->ProcessHandle->IsActive()) + if (!session->NodeProcess->IsActive()) return MakeUnexpected(std::format("Failed to spawn the child process \"{}\"", executablePath.string())); - auto processID = session->ProcessHandle->ID.load(); + auto processID = session->NodeProcess->ID.load(); session->CreationTime = SteadyClock::now(); m_pendingSessions.push_back(std::move(session)); @@ -398,7 +398,7 @@ namespace IACore isPending = false; for (auto it = m_pendingSessions.begin(); it != m_pendingSessions.end(); it++) { - if (it->get()->ProcessHandle->ID.load() == nodeID) + if (it->get()->NodeProcess->ID.load() == nodeID) { isPending = true; break; @@ -417,7 +417,7 @@ namespace IACore auto &node = itNode->second; - ProcessOps::TerminateProcess(node->ProcessHandle); + ProcessOps::TerminateProcess(node->NodeProcess); FileOps::UnmapFile(node->MappedPtr); FileOps::UnlinkSharedMemory(node->SharedMemName); SocketOps::Close(node->DataSocket); diff --git a/Src/IACore/inc/IACore/DataOps.hpp b/Src/IACore/inc/IACore/DataOps.hpp index 1e6b092..0bf68ef 100644 --- a/Src/IACore/inc/IACore/DataOps.hpp +++ b/Src/IACore/inc/IACore/DataOps.hpp @@ -33,8 +33,8 @@ namespace IACore STATIC UINT32 Hash_FNV1A(IN CONST String &string); STATIC UINT32 Hash_FNV1A(IN Span data); - STATIC UINT32 Hash_xxHash(IN CONST String &string); - STATIC UINT32 Hash_xxHash(IN Span data); + STATIC UINT32 Hash_xxHash(IN CONST String &string, IN UINT32 seed = 0); + STATIC UINT32 Hash_xxHash(IN Span data, IN UINT32 seed = 0); STATIC UINT32 CRC32(IN Span data); diff --git a/Src/IACore/inc/IACore/IPC.hpp b/Src/IACore/inc/IACore/IPC.hpp index f9dacb7..0f87297 100644 --- a/Src/IACore/inc/IACore/IPC.hpp +++ b/Src/IACore/inc/IACore/IPC.hpp @@ -101,7 +101,7 @@ namespace IACore struct NodeSession { SteadyTimePoint CreationTime{}; - SharedPtr ProcessHandle; + SharedPtr NodeProcess; Mutex SendMutex; diff --git a/Tests/Unit/CMakeLists.txt b/Tests/Unit/CMakeLists.txt index cdb66bd..4bf7ea0 100644 --- a/Tests/Unit/CMakeLists.txt +++ b/Tests/Unit/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SOURCES Main.cpp Utils.cpp Environment.cpp + DataOps.cpp ProcessOps.cpp StreamReader.cpp RingBuffer.cpp diff --git a/Tests/Unit/DataOps.cpp b/Tests/Unit/DataOps.cpp new file mode 100644 index 0000000..53663a4 --- /dev/null +++ b/Tests/Unit/DataOps.cpp @@ -0,0 +1,113 @@ +// IACore-OSS; The Core Library for All IA Open Source Projects +// Copyright (C) 2025 IAS (ias@iasoft.dev) +// +// 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. + +#include + +#include + +using namespace IACore; + +// ----------------------------------------------------------------------------- +// Test Block Definition +// ----------------------------------------------------------------------------- + +IAT_BEGIN_BLOCK(Core, DataOps) + +BOOL TestCRC32() +{ + { + String s = "123456789"; + Span span(reinterpret_cast(s.data()), s.size()); + UINT32 result = DataOps::CRC32(span); + + IAT_CHECK_EQ(result, 0xE3069283); + } + + { + UINT32 result = DataOps::CRC32({}); + IAT_CHECK_EQ(result, 0); + } + + { + std::vector buffer(33); + for (size_t i = 1; i < 33; ++i) + buffer[i] = (UINT8) i; + + std::vector refData(32); + for (size_t i = 0; i < 32; ++i) + refData[i] = (UINT8) (i + 1); + + UINT32 hashRef = DataOps::CRC32(Span(refData.data(), refData.size())); + + UINT32 hashUnaligned = DataOps::CRC32(Span(buffer.data() + 1, 32)); + + IAT_CHECK_EQ(hashRef, hashUnaligned); + } + + return TRUE; +} + +BOOL TestHash_xxHash() +{ + { + String s = "123456789"; + UINT32 result = DataOps::Hash_xxHash(s); + IAT_CHECK_EQ(result, 0x937bad67); + } + + { + String s = "The quick brown fox jumps over the lazy dog"; + UINT32 result = DataOps::Hash_xxHash(s); + IAT_CHECK_EQ(result, 0xE85EA4DE); + } + + { + String s = "Test"; + UINT32 r1 = DataOps::Hash_xxHash(s); + UINT32 r2 = DataOps::Hash_xxHash(Span((PCUINT8) s.data(), s.size())); + IAT_CHECK_EQ(r1, r2); + } + + return TRUE; +} + +BOOL TestHash_FNV1A() +{ + { + String s = "123456789"; + UINT32 result = DataOps::Hash_FNV1A(Span((PCUINT8) s.data(), s.size())); + IAT_CHECK_EQ(result, 0xbb86b11c); + } + + { + UINT32 result = DataOps::Hash_FNV1A(Span{}); + IAT_CHECK_EQ(result, 0x811C9DC5); + } + + return TRUE; +} + +// ------------------------------------------------------------------------- +// Registration +// ------------------------------------------------------------------------- +IAT_BEGIN_TEST_LIST() +IAT_ADD_TEST(TestCRC32); +IAT_ADD_TEST(TestHash_FNV1A); +IAT_ADD_TEST(TestHash_xxHash); +IAT_END_TEST_LIST() + +IAT_END_BLOCK() + +IAT_REGISTER_ENTRY(Core, DataOps)