diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/common/bit_util.h | 16 | ||||
-rw-r--r-- | src/common/detached_tasks.cpp | 8 | ||||
-rw-r--r-- | src/common/logging/backend.cpp | 6 | ||||
-rw-r--r-- | src/common/lz4_compression.cpp | 76 | ||||
-rw-r--r-- | src/common/lz4_compression.h | 55 | ||||
-rw-r--r-- | src/common/multi_level_queue.h | 2 | ||||
-rw-r--r-- | src/common/thread.cpp | 37 | ||||
-rw-r--r-- | src/common/thread.h | 14 | ||||
-rw-r--r-- | src/common/threadsafe_queue.h | 4 |
10 files changed, 157 insertions, 64 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 850ce8006..5639021d3 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -91,6 +91,8 @@ add_library(common STATIC logging/log.h logging/text_formatter.cpp logging/text_formatter.h + lz4_compression.cpp + lz4_compression.h math_util.h memory_hook.cpp memory_hook.h @@ -136,3 +138,4 @@ endif() create_target_directory_groups(common) target_link_libraries(common PUBLIC Boost::boost fmt microprofile) +target_link_libraries(common PRIVATE lz4_static) diff --git a/src/common/bit_util.h b/src/common/bit_util.h index a4f9ed4aa..d032df413 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) { return 32; } -inline u64 CountLeadingZeroes64(u64 value) { +inline u32 CountLeadingZeroes64(u64 value) { unsigned long leading_zero = 0; if (_BitScanReverse64(&leading_zero, value) != 0) { @@ -47,15 +47,15 @@ inline u32 CountLeadingZeroes32(u32 value) { return 32; } - return __builtin_clz(value); + return static_cast<u32>(__builtin_clz(value)); } -inline u64 CountLeadingZeroes64(u64 value) { +inline u32 CountLeadingZeroes64(u64 value) { if (value == 0) { return 64; } - return __builtin_clzll(value); + return static_cast<u32>(__builtin_clzll(value)); } #endif @@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) { return 32; } -inline u64 CountTrailingZeroes64(u64 value) { +inline u32 CountTrailingZeroes64(u64 value) { unsigned long trailing_zero = 0; if (_BitScanForward64(&trailing_zero, value) != 0) { @@ -85,15 +85,15 @@ inline u32 CountTrailingZeroes32(u32 value) { return 32; } - return __builtin_ctz(value); + return static_cast<u32>(__builtin_ctz(value)); } -inline u64 CountTrailingZeroes64(u64 value) { +inline u32 CountTrailingZeroes64(u64 value) { if (value == 0) { return 64; } - return __builtin_ctzll(value); + return static_cast<u32>(__builtin_ctzll(value)); } #endif diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp index a347d9e02..f268d6021 100644 --- a/src/common/detached_tasks.cpp +++ b/src/common/detached_tasks.cpp @@ -16,22 +16,22 @@ DetachedTasks::DetachedTasks() { } void DetachedTasks::WaitForAllTasks() { - std::unique_lock<std::mutex> lock(mutex); + std::unique_lock lock{mutex}; cv.wait(lock, [this]() { return count == 0; }); } DetachedTasks::~DetachedTasks() { - std::unique_lock<std::mutex> lock(mutex); + std::unique_lock lock{mutex}; ASSERT(count == 0); instance = nullptr; } void DetachedTasks::AddTask(std::function<void()> task) { - std::unique_lock<std::mutex> lock(instance->mutex); + std::unique_lock lock{instance->mutex}; ++instance->count; std::thread([task{std::move(task)}]() { task(); - std::unique_lock<std::mutex> lock(instance->mutex); + std::unique_lock lock{instance->mutex}; --instance->count; std::notify_all_at_thread_exit(instance->cv, std::move(lock)); }) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 4462ff3fb..a03179520 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -46,12 +46,12 @@ public: } void AddBackend(std::unique_ptr<Backend> backend) { - std::lock_guard<std::mutex> lock(writing_mutex); + std::lock_guard lock{writing_mutex}; backends.push_back(std::move(backend)); } void RemoveBackend(std::string_view backend_name) { - std::lock_guard<std::mutex> lock(writing_mutex); + std::lock_guard lock{writing_mutex}; const auto it = std::remove_if(backends.begin(), backends.end(), [&backend_name](const auto& i) { return backend_name == i->GetName(); }); @@ -80,7 +80,7 @@ private: backend_thread = std::thread([&] { Entry entry; auto write_logs = [&](Entry& e) { - std::lock_guard<std::mutex> lock(writing_mutex); + std::lock_guard lock{writing_mutex}; for (const auto& backend : backends) { backend->Write(e); } diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp new file mode 100644 index 000000000..ade6759bb --- /dev/null +++ b/src/common/lz4_compression.cpp @@ -0,0 +1,76 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <lz4hc.h> + +#include "common/assert.h" +#include "common/lz4_compression.h" + +namespace Common::Compression { + +std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) { + ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); + + const auto source_size_int = static_cast<int>(source_size); + const int max_compressed_size = LZ4_compressBound(source_size_int); + std::vector<u8> compressed(max_compressed_size); + + const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), + reinterpret_cast<char*>(compressed.data()), + source_size_int, max_compressed_size); + + if (compressed_size <= 0) { + // Compression failed + return {}; + } + + compressed.resize(compressed_size); + + return compressed; +} + +std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, + s32 compression_level) { + ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); + + compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); + + const auto source_size_int = static_cast<int>(source_size); + const int max_compressed_size = LZ4_compressBound(source_size_int); + std::vector<u8> compressed(max_compressed_size); + + const int compressed_size = LZ4_compress_HC( + reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), + source_size_int, max_compressed_size, compression_level); + + if (compressed_size <= 0) { + // Compression failed + return {}; + } + + compressed.resize(compressed_size); + + return compressed; +} + +std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) { + return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); +} + +std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, + std::size_t uncompressed_size) { + std::vector<u8> uncompressed(uncompressed_size); + const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), + reinterpret_cast<char*>(uncompressed.data()), + static_cast<int>(compressed.size()), + static_cast<int>(uncompressed.size())); + if (static_cast<int>(uncompressed_size) != size_check) { + // Decompression failed + return {}; + } + return uncompressed; +} + +} // namespace Common::Compression diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h new file mode 100644 index 000000000..fe2231a6c --- /dev/null +++ b/src/common/lz4_compression.h @@ -0,0 +1,55 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <vector> + +#include "common/common_types.h" + +namespace Common::Compression { + +/** + * Compresses a source memory region with LZ4 and returns the compressed data in a vector. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size); + +/** + * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression + * levels result in a smaller compressed size, but require more CPU time for compression. The + * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can + * also be decompressed with the default LZ4 decompression. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * @param compression_level the used compression level. Should be between 3 and 12. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level); + +/** + * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level. + * + * @param source the uncompressed source memory region. + * @param source_size the size in bytes of the uncompressed source memory region. + * + * @return the compressed data. + */ +std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size); + +/** + * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector. + * + * @param compressed the compressed source memory region. + * @param uncompressed_size the size in bytes of the uncompressed data. + * + * @return the decompressed data. + */ +std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size); + +} // namespace Common::Compression
\ No newline at end of file diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h index 2b61b91e0..9cb448f56 100644 --- a/src/common/multi_level_queue.h +++ b/src/common/multi_level_queue.h @@ -72,7 +72,7 @@ public: u64 prios = mlq.used_priorities; prios &= ~((1ULL << (current_priority + 1)) - 1); if (prios == 0) { - current_priority = mlq.depth(); + current_priority = static_cast<u32>(mlq.depth()); } else { current_priority = CountTrailingZeroes64(prios); it = GetBeginItForPrio(); diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 5144c0d9f..fe7a420cc 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -27,18 +27,6 @@ namespace Common { #ifdef _MSC_VER -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { - SetThreadAffinityMask(thread, mask); -} - -void SetCurrentThreadAffinity(u32 mask) { - SetThreadAffinityMask(GetCurrentThread(), mask); -} - -void SwitchCurrentThread() { - SwitchToThread(); -} - // Sets the debugger-visible name of the current thread. // Uses undocumented (actually, it is now documented) trick. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp @@ -70,31 +58,6 @@ void SetCurrentThreadName(const char* name) { #else // !MSVC_VER, so must be POSIX threads -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { -#ifdef __APPLE__ - thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1); -#elif (defined __linux__ || defined __FreeBSD__) && !(defined ANDROID) - cpu_set_t cpu_set; - CPU_ZERO(&cpu_set); - - for (int i = 0; i != sizeof(mask) * 8; ++i) - if ((mask >> i) & 1) - CPU_SET(i, &cpu_set); - - pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set); -#endif -} - -void SetCurrentThreadAffinity(u32 mask) { - SetThreadAffinity(pthread_self(), mask); -} - -#ifndef _WIN32 -void SwitchCurrentThread() { - usleep(1000 * 1); -} -#endif - // MinGW with the POSIX threading model does not support pthread_setname_np #if !defined(_WIN32) || defined(_MSC_VER) void SetCurrentThreadName(const char* name) { diff --git a/src/common/thread.h b/src/common/thread.h index 2cf74452d..0cfd98be6 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -9,14 +9,13 @@ #include <cstddef> #include <mutex> #include <thread> -#include "common/common_types.h" namespace Common { class Event { public: void Set() { - std::lock_guard<std::mutex> lk(mutex); + std::lock_guard lk{mutex}; if (!is_set) { is_set = true; condvar.notify_one(); @@ -24,14 +23,14 @@ public: } void Wait() { - std::unique_lock<std::mutex> lk(mutex); + std::unique_lock lk{mutex}; condvar.wait(lk, [&] { return is_set; }); is_set = false; } template <class Clock, class Duration> bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) { - std::unique_lock<std::mutex> lk(mutex); + std::unique_lock lk{mutex}; if (!condvar.wait_until(lk, time, [this] { return is_set; })) return false; is_set = false; @@ -39,7 +38,7 @@ public: } void Reset() { - std::unique_lock<std::mutex> lk(mutex); + std::unique_lock lk{mutex}; // no other action required, since wait loops on the predicate and any lingering signal will // get cleared on the first iteration is_set = false; @@ -57,7 +56,7 @@ public: /// Blocks until all "count" threads have called Sync() void Sync() { - std::unique_lock<std::mutex> lk(mutex); + std::unique_lock lk{mutex}; const std::size_t current_generation = generation; if (++waiting == count) { @@ -78,9 +77,6 @@ private: std::size_t generation = 0; // Incremented once each time the barrier is used }; -void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); -void SetCurrentThreadAffinity(u32 mask); -void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms void SetCurrentThreadName(const char* name); } // namespace Common diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index 821e8536a..e714ba5b3 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h @@ -78,7 +78,7 @@ public: T PopWait() { if (Empty()) { - std::unique_lock<std::mutex> lock(cv_mutex); + std::unique_lock lock{cv_mutex}; cv.wait(lock, [this]() { return !Empty(); }); } T t; @@ -137,7 +137,7 @@ public: template <typename Arg> void Push(Arg&& t) { - std::lock_guard<std::mutex> lock(write_lock); + std::lock_guard lock{write_lock}; spsc_queue.Push(t); } |