diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-04 15:32:14 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-12-05 01:22:50 +0300 |
commit | c21ed9eedf73010bc81342518177dfdfb0d56bd7 (patch) | |
tree | 72f8fde4463080cfe5a38eb0babc051cfe32c51e /library/cpp/actors/util | |
parent | ec1311bf2e8cc231723b8b5e484ca576663a1309 (diff) | |
download | ydb-c21ed9eedf73010bc81342518177dfdfb0d56bd7.tar.gz |
Intermediate changes
Diffstat (limited to 'library/cpp/actors/util')
62 files changed, 0 insertions, 9742 deletions
diff --git a/library/cpp/actors/util/CMakeLists.darwin-arm64.txt b/library/cpp/actors/util/CMakeLists.darwin-arm64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.linux-aarch64.txt b/library/cpp/actors/util/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 9c5183c2bd..0000000000 --- a/library/cpp/actors/util/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,29 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.linux-x86_64.txt b/library/cpp/actors/util/CMakeLists.linux-x86_64.txt deleted file mode 100644 index 9c5183c2bd..0000000000 --- a/library/cpp/actors/util/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,29 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/CMakeLists.txt b/library/cpp/actors/util/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/util/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/util/CMakeLists.windows-x86_64.txt b/library/cpp/actors/util/CMakeLists.windows-x86_64.txt deleted file mode 100644 index be68d418f7..0000000000 --- a/library/cpp/actors/util/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,28 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -add_subdirectory(ut) - -add_library(cpp-actors-util) -target_link_libraries(cpp-actors-util PUBLIC - contrib-libs-cxxsupp - yutil - cpp-containers-absl_flat_hash - cpp-deprecated-atomic - library-cpp-pop_count -) -target_sources(cpp-actors-util PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/affinity.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_track.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/should_continue.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/threadparkpad.cpp -) diff --git a/library/cpp/actors/util/README.md b/library/cpp/actors/util/README.md deleted file mode 100644 index ff2d573fe8..0000000000 --- a/library/cpp/actors/util/README.md +++ /dev/null @@ -1,99 +0,0 @@ -## Memory tracker - -https://a.yandex-team.ru/arc/trunk/arcadia/library/cpp/actors/util/memory_track.h - -Использование: - -* отслеживание аллокаций экземпляров конкретного класса через new/delete и new[]/delete[] -* отслеживание аллокаций в контейнерах -* ручное отслеживание моментов аллокации/деаллокации - ----- - -### Отслеживание аллокаций класса через new/delete - -Использование с автоматически генерируемой меткой: - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; -``` - -Использование с пользовательским именем метки: - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; -``` - ----- - -### Отслеживание аллокаций в контейнерах - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - -std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - -using TKey = int; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - -std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - -std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; -``` - ----- - -### Ручное отслеживание аллокаций/деаллокаций - -```cpp -#include <library/cpp/actors/util/memory_track.h> - -static const char ManualLabel[] = "ManualLabel"; - -... -NActors::NMemory::TLabel<ManualLabel>::Add(size); - -... -NActors::NMemory::TLabel<ManualLabel>::Sub(size); -``` - ----- - -### Собираемые метрики - -Сервис **utils**, пользовательская метка **label**, сенсоры: - -- MT/Count: количество аллокаций в моменте -- MT/Memory: аллоцированная память в моменте -- MT/PeakCount: пиковое значение количества аллокаций (сэмплится с фиксированной частотой) -- MT/PeakMemory: пиковое значение аллоцированной памяти - diff --git a/library/cpp/actors/util/affinity.cpp b/library/cpp/actors/util/affinity.cpp deleted file mode 100644 index 5851105ae7..0000000000 --- a/library/cpp/actors/util/affinity.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "affinity.h" - -#ifdef _linux_ -#include <sched.h> -#endif - -class TAffinity::TImpl { -#ifdef _linux_ - cpu_set_t Mask; -#endif -public: - TImpl() { -#ifdef _linux_ - int ar = sched_getaffinity(0, sizeof(cpu_set_t), &Mask); - Y_DEBUG_ABORT_UNLESS(ar == 0); -#endif - } - - explicit TImpl(const ui8* cpus, ui32 size) { -#ifdef _linux_ - CPU_ZERO(&Mask); - for (ui32 i = 0; i != size; ++i) { - if (cpus[i]) { - CPU_SET(i, &Mask); - } - } -#else - Y_UNUSED(cpus); - Y_UNUSED(size); -#endif - } - - void Set() const { -#ifdef _linux_ - int ar = sched_setaffinity(0, sizeof(cpu_set_t), &Mask); - Y_DEBUG_ABORT_UNLESS(ar == 0); -#endif - } - - operator TCpuMask() const { - TCpuMask result; -#ifdef _linux_ - for (ui32 i = 0; i != CPU_SETSIZE; ++i) { - result.Cpus.emplace_back(CPU_ISSET(i, &Mask)); - } - result.RemoveTrailingZeros(); -#endif - return result; - } - -}; - -TAffinity::TAffinity() { -} - -TAffinity::~TAffinity() { -} - -TAffinity::TAffinity(const ui8* x, ui32 sz) { - if (x && sz) { - Impl.Reset(new TImpl(x, sz)); - } -} - -TAffinity::TAffinity(const TCpuMask& mask) { - if (!mask.IsEmpty()) { - static_assert(sizeof(ui8) == sizeof(mask.Cpus[0])); - const ui8* x = reinterpret_cast<const ui8*>(&mask.Cpus[0]); - const ui32 sz = mask.Size(); - Impl.Reset(new TImpl(x, sz)); - } -} - -void TAffinity::Current() { - Impl.Reset(new TImpl()); -} - -void TAffinity::Set() const { - if (!!Impl) { - Impl->Set(); - } -} - -bool TAffinity::Empty() const { - return !Impl; -} - -TAffinity::operator TCpuMask() const { - if (!!Impl) { - return *Impl; - } - return TCpuMask(); -} diff --git a/library/cpp/actors/util/affinity.h b/library/cpp/actors/util/affinity.h deleted file mode 100644 index ae106ed180..0000000000 --- a/library/cpp/actors/util/affinity.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "defs.h" -#include "cpumask.h" - -// Platform-specific class to set or get thread affinity -class TAffinity: public TThrRefBase, TNonCopyable { - class TImpl; - THolder<TImpl> Impl; - -public: - TAffinity(); - TAffinity(const ui8* cpus, ui32 size); - explicit TAffinity(const TCpuMask& mask); - ~TAffinity(); - - void Current(); - void Set() const; - bool Empty() const; - - operator TCpuMask() const; -}; - -// Scoped affinity setter -class TAffinityGuard : TNonCopyable { - bool Stacked; - TAffinity OldAffinity; - -public: - TAffinityGuard(const TAffinity* affinity) { - Stacked = false; - if (affinity && !affinity->Empty()) { - OldAffinity.Current(); - affinity->Set(); - Stacked = true; - } - } - - ~TAffinityGuard() { - Release(); - } - - void Release() { - if (Stacked) { - OldAffinity.Set(); - Stacked = false; - } - } -}; diff --git a/library/cpp/actors/util/cpu_load_log.h b/library/cpp/actors/util/cpu_load_log.h deleted file mode 100644 index 225f7148da..0000000000 --- a/library/cpp/actors/util/cpu_load_log.h +++ /dev/null @@ -1,227 +0,0 @@ -#pragma once - -#include "defs.h" -#include <library/cpp/deprecated/atomic/atomic.h> -#include <library/cpp/pop_count/popcount.h> - -static constexpr ui64 BitDurationNs = 131'072; // A power of 2 - -template <ui64 DataSize> -struct TCpuLoadLog { - static constexpr ui64 BitsSize = DataSize * 64; - TAtomic LastTimeNs = 0; - ui64 Data[DataSize]; - - TCpuLoadLog() { - LastTimeNs = 0; - for (size_t i = 0; i < DataSize; ++i) { - Data[i] = 0; - } - } - - TCpuLoadLog(ui64 timeNs) { - LastTimeNs = timeNs; - for (size_t i = 0; i < DataSize; ++i) { - Data[i] = 0; - } - } - - void RegisterBusyPeriod(ui64 timeNs) { - RegisterBusyPeriod<true>(timeNs, AtomicGet(LastTimeNs)); - } - - template <bool ModifyLastTime> - void RegisterBusyPeriod(ui64 timeNs, ui64 lastTimeNs) { - timeNs |= 1ull; - if (timeNs < lastTimeNs) { - for (ui64 i = 0; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - return; - } - const ui64 lastIdx = timeNs / BitDurationNs; - const ui64 curIdx = lastTimeNs / BitDurationNs; - ui64 firstElementIdx = curIdx / 64; - const ui64 firstBitIdx = curIdx % 64; - const ui64 lastElementIdx = lastIdx / 64; - const ui64 lastBitIdx = lastIdx % 64; - if (firstElementIdx == lastElementIdx) { - ui64 prevValue = 0; - if (firstBitIdx != 0) { - prevValue = AtomicGet(Data[firstElementIdx % DataSize]); - } - const ui64 bits = (((~0ull) << (firstBitIdx + (63-lastBitIdx))) >> (63-lastBitIdx)); - const ui64 newValue = prevValue | bits; - AtomicSet(Data[firstElementIdx % DataSize], newValue); - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - return; - } - // process the first element - ui64 prevValue = 0; - if (firstBitIdx != 0) { - prevValue = AtomicGet(Data[firstElementIdx % DataSize]); - } - const ui64 bits = ((~0ull) << firstBitIdx); - const ui64 newValue = (prevValue | bits); - AtomicSet(Data[firstElementIdx % DataSize], newValue); - ++firstElementIdx; - // process the fully filled elements - const ui64 firstLoop = firstElementIdx / DataSize; - const ui64 lastLoop = lastElementIdx / DataSize; - const ui64 lastOffset = lastElementIdx % DataSize; - if (firstLoop < lastLoop) { - for (ui64 i = firstElementIdx % DataSize; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - for (ui64 i = 0; i < lastOffset; ++i) { - AtomicSet(Data[i], ~0ull); - } - } else { - for (ui64 i = firstElementIdx % DataSize; i < lastOffset; ++i) { - AtomicSet(Data[i], ~0ull); - } - } - // process the last element - const ui64 newValue2 = ((~0ull) >> (63-lastBitIdx)); - AtomicSet(Data[lastOffset], newValue2); - if (ModifyLastTime) { - AtomicSet(LastTimeNs, timeNs); - } - } - - void RegisterIdlePeriod(ui64 timeNs) { - timeNs &= ~1ull; - ui64 lastTimeNs = AtomicGet(LastTimeNs); - if (timeNs < lastTimeNs) { - // Fast check first, slower chec later - if ((timeNs | 1ull) < lastTimeNs) { - // Time goes back, dont panic, just mark the whole array 'busy' - for (ui64 i = 0; i < DataSize; ++i) { - AtomicSet(Data[i], ~0ull); - } - AtomicSet(LastTimeNs, timeNs); - return; - } - } - const ui64 curIdx = lastTimeNs / BitDurationNs; - const ui64 lastIdx = timeNs / BitDurationNs; - ui64 firstElementIdx = curIdx / 64; - const ui64 lastElementIdx = lastIdx / 64; - if (firstElementIdx >= lastElementIdx) { - AtomicSet(LastTimeNs, timeNs); - return; - } - // process the first partially filled element - ++firstElementIdx; - // process all other elements - const ui64 firstLoop = firstElementIdx / DataSize; - const ui64 lastLoop = lastElementIdx / DataSize; - const ui64 lastOffset = lastElementIdx % DataSize; - if (firstLoop < lastLoop) { - for (ui64 i = firstElementIdx % DataSize; i < DataSize; ++i) { - AtomicSet(Data[i], 0); - } - for (ui64 i = 0; i <= lastOffset; ++i) { - AtomicSet(Data[i], 0); - } - } else { - for (ui64 i = firstElementIdx % DataSize; i <= lastOffset; ++i) { - AtomicSet(Data[i], 0); - } - } - AtomicSet(LastTimeNs, timeNs); - } -}; - -template <ui64 DataSize> -struct TMinusOneCpuEstimator { - static constexpr ui64 BitsSize = DataSize * 64; - ui64 BeginDelayIdx; - ui64 EndDelayIdx; - ui64 Idle; - ui64 Delay[BitsSize]; - - ui64 MaxLatencyIncreaseWithOneLessCpu(TCpuLoadLog<DataSize>** logs, i64 logCount, ui64 timeNs, ui64 periodNs) { - Y_ABORT_UNLESS(logCount > 0); - ui64 endTimeNs = timeNs; - - ui64 lastTimeNs = timeNs; - for (i64 log_idx = 0; log_idx < logCount; ++log_idx) { - ui64 x = AtomicGet(logs[log_idx]->LastTimeNs); - if ((x & 1) == 1) { - lastTimeNs = Min(lastTimeNs, x); - } else { - logs[log_idx]->template RegisterBusyPeriod<false>(endTimeNs, x); - } - } - const ui64 beginTimeNs = periodNs < timeNs ? timeNs - periodNs : 0; - - ui64 beginIdx = beginTimeNs / BitDurationNs; - ui64 lastIdx = lastTimeNs / BitDurationNs; - ui64 beginElementIdx = beginIdx / 64; - ui64 lastElementIdx = lastIdx / 64; - - BeginDelayIdx = 0; - EndDelayIdx = 0; - Idle = 0; - ui64 maxDelay = 0; - ui64 bucket = 0; - for (ui64 idx = beginElementIdx; idx <= lastElementIdx; ++idx) { - ui64 i = idx % DataSize; - ui64 input = AtomicGet(logs[0]->Data[i]); - ui64 all_busy = ~0ull; - for (i64 log_idx = 1; log_idx < logCount; ++log_idx) { - ui64 x = AtomicGet(logs[log_idx]->Data[i]); - all_busy &= x; - } - if (!input) { - if (!bucket) { - Idle += 64 - PopCount(all_busy); - continue; - } - } - for (i64 bit_idx = 0; bit_idx < 64; ++bit_idx) { - ui64 x = (1ull << bit_idx); - if (all_busy & x) { - if (input & x) { - // Push into the queue - bucket++; - Delay[EndDelayIdx] = EndDelayIdx; - ++EndDelayIdx; - } else { - // All busy - } - } else { - if (input & x) { - // Move success - } else { - if (bucket) { - // Remove from the queue - bucket--; - ui64 stored = Delay[BeginDelayIdx]; - ++BeginDelayIdx; - ui64 delay = EndDelayIdx - stored; - maxDelay = Max(maxDelay, delay); - //Cerr << "bit_idx: " << bit_idx << " stored: " << stored << " delay: " << delay << Endl; - } else { - Idle++; - } - } - } - } - } - if (bucket) { - ui64 stored = Delay[BeginDelayIdx]; - ui64 delay = EndDelayIdx - stored; - maxDelay = Max(maxDelay, delay); - //Cerr << "last stored: " << stored << " delay: " << delay << Endl; - } - return maxDelay * BitDurationNs; - } -}; - diff --git a/library/cpp/actors/util/cpu_load_log_ut.cpp b/library/cpp/actors/util/cpu_load_log_ut.cpp deleted file mode 100644 index 7109123c6e..0000000000 --- a/library/cpp/actors/util/cpu_load_log_ut.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "cpu_load_log.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/sanitizers.h> -#include <util/system/thread.h> - -Y_UNIT_TEST_SUITE(CpuLoadLog) { - - TString PrintBits(ui64 x) { - TStringStream str; - for (ui64 i = 0; i < 64; ++i) { - if (x & (1ull << i)) { - str << "1"; - } else { - str << "0"; - } - } - return str.Str(); - } - - Y_UNIT_TEST(FillAll) { - TCpuLoadLog<5> log(100*BitDurationNs); - log.RegisterBusyPeriod(101*BitDurationNs); - log.RegisterBusyPeriod(163*BitDurationNs); - log.RegisterBusyPeriod(164*BitDurationNs); - log.RegisterBusyPeriod(165*BitDurationNs); - log.RegisterBusyPeriod(331*BitDurationNs); - log.RegisterBusyPeriod(340*BitDurationNs); - log.RegisterBusyPeriod(420*BitDurationNs); - log.RegisterBusyPeriod(511*BitDurationNs); - //for (ui64 i = 0; i < 5; ++i) { - // Cerr << "i: " << i << " bits: " << PrintBits(log.Data[i]) << Endl; - //} - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_C((ui64(log.Data[i]) == ~ui64(0)), "Unequal at " << i << "\n got: " << PrintBits(log.Data[i]) - << "\n expected: " << PrintBits(~ui64(0))); - } - } - - Y_UNIT_TEST(PartialFill) { - TCpuLoadLog<5> log(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b0ull)); - log.RegisterBusyPeriod(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(0*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs/2); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b11ull)); - log.RegisterIdlePeriod(3*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b11ull)); - log.RegisterBusyPeriod(3*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0b1011ull)); - log.RegisterBusyPeriod(63*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits((~0ull)^0b0100ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b0ull)); - log.RegisterBusyPeriod(128*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits((~0ull)^0b0100ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0b1ull)); - log.RegisterBusyPeriod(1*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(2*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod(128*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod(192*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterBusyPeriod(192*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(~0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(~0ull)); - log.RegisterIdlePeriod((192+5*64-1)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0b1ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(0ull)); - log.RegisterIdlePeriod((192+15*64)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[0]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[1]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[2]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[3]), PrintBits(0ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log.Data[4]), PrintBits(0ull)); - } - - Y_UNIT_TEST(Estimator) { - TCpuLoadLog<5> *log[10]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - - for (ui64 i = 0; i < 5*64; i+=2) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod(i*BitDurationNs); - } - log[0]->RegisterIdlePeriod((5*64-2)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[0]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[4]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - for (ui64 i = 0; i < 5*64-1; i+=2) { - log[1]->RegisterIdlePeriod((i+1)*BitDurationNs); - log[1]->RegisterBusyPeriod((i+1)*BitDurationNs); - } - log[1]->RegisterIdlePeriod((5*64-2+1)*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[0]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[4]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64)*BitDurationNs-1, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 1); - - value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64+10)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 12); - - delete log[0]; - delete log[1]; - } - - Y_UNIT_TEST(Estimator2) { - TCpuLoadLog<5> *log[2]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - for (ui64 i = 0; i < 5*64; i+=2) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod(i*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[0]->Data[i]), - PrintBits(0b0101010101010101010101010101010101010101010101010101010101010101ull)); - } - for (ui64 i = 0; i < 5*64-1; i+=2) { - log[1]->RegisterIdlePeriod((i+1)*BitDurationNs); - log[1]->RegisterBusyPeriod((i+1)*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - UNIT_ASSERT_VALUES_EQUAL(PrintBits(log[1]->Data[i]), - PrintBits(0b1010101010101010101010101010101010101010101010101010101010101010ull)); - } - - log[0]->Data[2] = ~0ull; - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 2, (5*64-1)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 32); - - delete log[0]; - delete log[1]; - } - - Y_UNIT_TEST(Estimator3) { - TCpuLoadLog<5> *log[3]; - log[0] = new TCpuLoadLog<5>(0*BitDurationNs); - log[1] = new TCpuLoadLog<5>(0*BitDurationNs); - log[2] = new TCpuLoadLog<5>(0*BitDurationNs); - TMinusOneCpuEstimator<5> estimator; - - for (ui64 i = 0; i < 5*64; i+=8) { - log[0]->RegisterIdlePeriod(i*BitDurationNs); - log[0]->RegisterBusyPeriod((i+3)*BitDurationNs); - log[1]->RegisterIdlePeriod(i*BitDurationNs); - log[1]->RegisterBusyPeriod((i+3)*BitDurationNs); - log[2]->RegisterIdlePeriod(i*BitDurationNs); - log[2]->RegisterBusyPeriod((i+3)*BitDurationNs); - } - for (ui64 i = 0; i < 5; ++i) { - for (ui64 n = 0; n < 3; ++n) { - UNIT_ASSERT_VALUES_EQUAL_C(PrintBits(log[n]->Data[i]), - PrintBits(0b0000111100001111000011110000111100001111000011110000111100001111ull), - " i: " << i << " n: " << n); - } - } - - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(log, 3, (5*64-5)*BitDurationNs, 3*64*BitDurationNs); - UNIT_ASSERT_VALUES_EQUAL(value/BitDurationNs, 4); - - delete log[0]; - delete log[1]; - delete log[2]; - } - /* - class TWorkerThread : public ISimpleThread { - private: - std::function<void()> Func; - double Time = 0.0; - - public: - TWorkerThread(std::function<void()> func) - : Func(std::move(func)) - { } - - double GetTime() const { - return Time; - } - - static THolder<TWorkerThread> Spawn(std::function<void()> func) { - THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func)); - thread->Start(); - return thread; - } - - private: - void* ThreadProc() noexcept override { - THPTimer timer; - Func(); - Time = timer.Passed(); - return nullptr; - } - }; - - void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) { - // Concurrency factor 4 is up to 16 threads - - auto workerFunc = [&](size_t threadIndex) { - }; - - TVector<THolder<TWorkerThread>> workers(threads); - for (size_t i = 0; i < threads; ++i) { - workers[i] = TWorkerThread::Spawn([workerFunc, i]() { - workerFunc(i); - }); - } - - double maxTime = 0; - for (size_t i = 0; i < threads; ++i) { - workers[i]->Join(); - maxTime = Max(maxTime, workers[i]->GetTime()); - } - - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl; - } - - void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) { - for (size_t i = 0; i < 3; ++i) { - DoConcurrentPushPop(threads, perThreadCount); - } - } - - static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000); - - Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); } - */ -} diff --git a/library/cpp/actors/util/cpumask.h b/library/cpp/actors/util/cpumask.h deleted file mode 100644 index 29741aa1d6..0000000000 --- a/library/cpp/actors/util/cpumask.h +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <library/cpp/containers/stack_vector/stack_vec.h> - -#include <util/string/split.h> -#include <util/generic/yexception.h> - -using TCpuId = ui32; - -// Simple data structure to operate with set of cpus -struct TCpuMask { - TStackVec<bool, 1024> Cpus; - - // Creates empty mask - TCpuMask() {} - - // Creates mask with single cpu set - explicit TCpuMask(TCpuId cpuId) { - Set(cpuId); - } - - // Initialize mask from raw boolean array - template <class T> - TCpuMask(const T* cpus, TCpuId size) { - Cpus.reserve(size); - for (TCpuId i = 0; i != size; ++i) { - Cpus.emplace_back(bool(cpus[i])); - } - } - - // Parse a numerical list of processors. The numbers are separated by commas and may include ranges. For example: 0,5,7,9-11 - explicit TCpuMask(const TString& cpuList) { - try { - for (TStringBuf s : StringSplitter(cpuList).Split(',')) { - TCpuId l, r; - if (s.find('-') != TString::npos) { - StringSplitter(s).Split('-').CollectInto(&l, &r); - } else { - l = r = FromString<TCpuId>(s); - } - if (r >= Cpus.size()) { - Cpus.resize(r + 1, false); - } - for (TCpuId cpu = l; cpu <= r; cpu++) { - Cpus[cpu] = true; - } - } - } catch (...) { - ythrow TWithBackTrace<yexception>() << "Exception occured while parsing cpu list '" << cpuList << "': " << CurrentExceptionMessage(); - } - } - - // Returns size of underlying vector - TCpuId Size() const { - return Cpus.size(); - } - - // Returns number of set bits in mask - TCpuId CpuCount() const { - TCpuId result = 0; - for (bool value : Cpus) { - result += value; - } - return result; - } - - bool IsEmpty() const { - for (bool value : Cpus) { - if (value) { - return false; - } - } - return true; - } - - bool IsSet(TCpuId cpu) const { - return cpu < Cpus.size() && Cpus[cpu]; - } - - void Set(TCpuId cpu) { - if (cpu >= Cpus.size()) { - Cpus.resize(cpu + 1, false); - } - Cpus[cpu] = true; - } - - void Reset(TCpuId cpu) { - if (cpu < Cpus.size()) { - Cpus[cpu] = false; - } - } - - void RemoveTrailingZeros() { - while (!Cpus.empty() && !Cpus.back()) { - Cpus.pop_back(); - } - } - - explicit operator bool() const { - return !IsEmpty(); - } - - TCpuMask operator &(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator |(const TCpuMask& rhs) const { - TCpuMask result; - TCpuId size = Max(Size(), rhs.Size()); - result.Cpus.reserve(size); - for (TCpuId cpu = 0; cpu < size; cpu++) { - result.Cpus.emplace_back(IsSet(cpu) || rhs.IsSet(cpu)); - } - return result; - } - - TCpuMask operator -(const TCpuMask& rhs) const { - TCpuMask result; - result.Cpus.reserve(Size()); - for (TCpuId cpu = 0; cpu < Size(); cpu++) { - result.Cpus.emplace_back(IsSet(cpu) && !rhs.IsSet(cpu)); - } - return result; - } -}; diff --git a/library/cpp/actors/util/datetime.h b/library/cpp/actors/util/datetime.h deleted file mode 100644 index cbec5965d6..0000000000 --- a/library/cpp/actors/util/datetime.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <util/system/hp_timer.h> -#include <util/system/platform.h> - -#if defined(_win_) -#include <intrin.h> -#pragma intrinsic(__rdtsc) -#endif // _win_ - -#if defined(_darwin_) && !defined(_x86_) -#include <mach/mach_time.h> -#endif - -// GetCycleCount() from util/system/datetime.h uses rdtscp, which is more accurate than rdtsc, -// but rdtscp disables processor's out-of-order execution, so it can be slow -Y_FORCE_INLINE ui64 GetCycleCountFast() { -#if defined(_MSC_VER) - // Generates the rdtsc instruction, which returns the processor time stamp. - // The processor time stamp records the number of clock cycles since the last reset. - return __rdtsc(); -#elif defined(__clang__) && !defined(_arm64_) - return __builtin_readcyclecounter(); -#elif defined(_x86_64_) - unsigned hi, lo; - __asm__ __volatile__("rdtsc" - : "=a"(lo), "=d"(hi)); - return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); -#elif defined(_i386_) - ui64 x; - __asm__ volatile("rdtsc\n\t" - : "=A"(x)); - return x; -#elif defined(_darwin_) - return mach_absolute_time(); -#elif defined(_arm32_) - return MicroSeconds(); -#elif defined(_arm64_) - ui64 x; - - __asm__ __volatile__("isb; mrs %0, cntvct_el0" - : "=r"(x)); - - return x; -#else -#error "unsupported arch" -#endif -} - -// NHPTimer::GetTime fast analog -Y_FORCE_INLINE void GetTimeFast(NHPTimer::STime* pTime) noexcept { - *pTime = GetCycleCountFast(); -} - -namespace NActors { - inline double Ts2Ns(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e9; - } - - inline double Ts2Us(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e6; - } - - inline double Ts2Ms(ui64 ts) { - return NHPTimer::GetSeconds(ts) * 1e3; - } - - inline ui64 Us2Ts(double us) { - return ui64(NHPTimer::GetClockRate() * us / 1e6); - } - - struct TTimeTracker { - ui64 Ts; - TTimeTracker(): Ts(GetCycleCountFast()) {} - ui64 Elapsed() { - ui64 ts = GetCycleCountFast(); - std::swap(Ts, ts); - return Ts - ts; - } - }; -} diff --git a/library/cpp/actors/util/defs.h b/library/cpp/actors/util/defs.h deleted file mode 100644 index 70f969753e..0000000000 --- a/library/cpp/actors/util/defs.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -// unique tag to fix pragma once gcc glueing: ./library/actors/util/defs.h - -#include <util/system/defaults.h> -#include <util/generic/bt_exception.h> -#include <util/generic/noncopyable.h> -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/yexception.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/align.h> -#include <util/generic/vector.h> -#include <util/datetime/base.h> -#include <util/generic/ylimits.h> -#include "intrinsics.h" diff --git a/library/cpp/actors/util/funnel_queue.h b/library/cpp/actors/util/funnel_queue.h deleted file mode 100644 index 15af57b121..0000000000 --- a/library/cpp/actors/util/funnel_queue.h +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once - -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/generic/noncopyable.h> - -template <typename ElementType> -class TFunnelQueue: private TNonCopyable { -public: - TFunnelQueue() noexcept - : Front(nullptr) - , Back(nullptr) - { - } - - virtual ~TFunnelQueue() noexcept { - for (auto entry = Front; entry; entry = DeleteEntry(entry)) - continue; - } - - /// Push element. Can be used from many threads. Return true if is first element. - bool - Push(ElementType&& element) noexcept { - TEntry* const next = NewEntry(static_cast<ElementType&&>(element)); - TEntry* const prev = AtomicSwap(&Back, next); - AtomicSet(prev ? prev->Next : Front, next); - return !prev; - } - - /// Extract top element. Must be used only from one thread. Return true if have more. - bool - Pop() noexcept { - if (TEntry* const top = AtomicGet(Front)) { - const auto last = AtomicCas(&Back, nullptr, top); - if (last) // This is last element in queue. Queue is empty now. - AtomicCas(&Front, nullptr, top); - else // This element is not last. - for (;;) { - if (const auto next = AtomicGet(top->Next)) { - AtomicSet(Front, next); - break; - } - // But Next is null. Wait next assignment in spin lock. - } - - DeleteEntry(top); - return !last; - } - - return false; - } - - /// Peek top element. Must be used only from one thread. - ElementType& - Top() const noexcept { - return AtomicGet(Front)->Data; - } - - bool - IsEmpty() const noexcept { - return !AtomicGet(Front); - } - -protected: - class TEntry: private TNonCopyable { - friend class TFunnelQueue; - - private: - explicit TEntry(ElementType&& element) noexcept - : Data(static_cast<ElementType&&>(element)) - , Next(nullptr) - { - } - - ~TEntry() noexcept { - } - - public: - ElementType Data; - TEntry* volatile Next; - }; - - TEntry* volatile Front; - TEntry* volatile Back; - - virtual TEntry* NewEntry(ElementType&& element) noexcept { - return new TEntry(static_cast<ElementType&&>(element)); - } - - virtual TEntry* DeleteEntry(TEntry* entry) noexcept { - const auto next = entry->Next; - delete entry; - return next; - } - -protected: - struct TEntryIter { - TEntry* ptr; - - ElementType& operator*() { - return ptr->Data; - } - - ElementType* operator->() { - return &ptr->Data; - } - - TEntryIter& operator++() { - ptr = AtomicGet(ptr->Next); - return *this; - } - - bool operator!=(const TEntryIter& other) const { - return ptr != other.ptr; - } - - bool operator==(const TEntryIter& other) const { - return ptr == other.ptr; - } - }; - - struct TConstEntryIter { - const TEntry* ptr; - - const ElementType& operator*() { - return ptr->Data; - } - - const ElementType* operator->() { - return &ptr->Data; - } - - TEntryIter& operator++() { - ptr = AtomicGet(ptr->Next); - return *this; - } - - bool operator!=(const TConstEntryIter& other) const { - return ptr != other.ptr; - } - - bool operator==(const TConstEntryIter& other) const { - return ptr == other.ptr; - } - }; - -public: - using const_iterator = TConstEntryIter; - using iterator = TEntryIter; - - iterator begin() { - return {AtomicGet(Front)}; - } - const_iterator cbegin() { - return {AtomicGet(Front)}; - } - const_iterator begin() const { - return {AtomicGet(Front)}; - } - - iterator end() { - return {nullptr}; - } - const_iterator cend() { - return {nullptr}; - } - const_iterator end() const { - return {nullptr}; - } -}; - -template <typename ElementType> -class TPooledFunnelQueue: public TFunnelQueue<ElementType> { -public: - TPooledFunnelQueue() noexcept - : Stack(nullptr) - { - } - - virtual ~TPooledFunnelQueue() noexcept override { - for (auto entry = TBase::Front; entry; entry = TBase::DeleteEntry(entry)) - continue; - for (auto entry = Stack; entry; entry = TBase::DeleteEntry(entry)) - continue; - TBase::Back = TBase::Front = Stack = nullptr; - } - -private: - typedef TFunnelQueue<ElementType> TBase; - - typename TBase::TEntry* volatile Stack; - -protected: - virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override { - while (const auto top = AtomicGet(Stack)) - if (AtomicCas(&Stack, top->Next, top)) { - top->Data = static_cast<ElementType&&>(element); - AtomicSet(top->Next, nullptr); - return top; - } - - return TBase::NewEntry(static_cast<ElementType&&>(element)); - } - - virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override { - entry->Data = ElementType(); - const auto next = entry->Next; - do - AtomicSet(entry->Next, AtomicGet(Stack)); - while (!AtomicCas(&Stack, entry, entry->Next)); - return next; - } -}; - -template <typename ElementType, template <typename T> class TQueueType = TFunnelQueue> -class TCountedFunnelQueue: public TQueueType<ElementType> { -public: - TCountedFunnelQueue() noexcept - : Count(0) - { - } - - TAtomicBase GetSize() const noexcept { - return AtomicGet(Count); - } - -private: - typedef TQueueType<ElementType> TBase; - - virtual typename TBase::TEntry* NewEntry(ElementType&& element) noexcept override { - AtomicAdd(Count, 1); - return TBase::NewEntry(static_cast<ElementType&&>(element)); - } - - virtual typename TBase::TEntry* DeleteEntry(typename TBase::TEntry* entry) noexcept override { - AtomicSub(Count, 1); - return TBase::DeleteEntry(entry); - } - - TAtomic Count; -}; diff --git a/library/cpp/actors/util/futex.h b/library/cpp/actors/util/futex.h deleted file mode 100644 index c193f8d128..0000000000 --- a/library/cpp/actors/util/futex.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#ifdef _linux_ - -#include <linux/futex.h> -#include <unistd.h> -#include <sys/syscall.h> - -static long SysFutex(void* addr1, int op, int val1, struct timespec* timeout, void* addr2, int val3) { - return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); -} - -#endif diff --git a/library/cpp/actors/util/intrinsics.h b/library/cpp/actors/util/intrinsics.h deleted file mode 100644 index c02b633b70..0000000000 --- a/library/cpp/actors/util/intrinsics.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include <util/system/defaults.h> -#include <library/cpp/deprecated/atomic/atomic.h> -#include <util/system/spinlock.h> - -#include <library/cpp/sse/sse.h> // The header chooses appropriate SSE support - -static_assert(sizeof(TAtomic) == 8, "expect sizeof(TAtomic) == 8"); - -// we need explicit 32 bit operations to keep cache-line friendly packs -// so have to define some atomics additionaly to arcadia one -#ifdef _win_ -#pragma intrinsic(_InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchangeAdd) -#pragma intrinsic(_InterlockedIncrement) -#pragma intrinsic(_InterlockedDecrement) -#endif - -inline bool AtomicUi32Cas(volatile ui32* a, ui32 exchange, ui32 compare) { -#ifdef _win_ - return _InterlockedCompareExchange((volatile long*)a, exchange, compare) == (long)compare; -#else - ui32 expected = compare; - return __atomic_compare_exchange_n(a, &expected, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Add(volatile ui32* a, ui32 add) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, add) + add; -#else - return __atomic_add_fetch(a, add, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Sub(volatile ui32* a, ui32 sub) { -#ifdef _win_ - return _InterlockedExchangeAdd((volatile long*)a, -(long)sub) - sub; -#else - return __atomic_sub_fetch(a, sub, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Increment(volatile ui32* a) { -#ifdef _win_ - return _InterlockedIncrement((volatile long*)a); -#else - return __atomic_add_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -inline ui32 AtomicUi32Decrement(volatile ui32* a) { -#ifdef _win_ - return _InterlockedDecrement((volatile long*)a); -#else - return __atomic_sub_fetch(a, 1, __ATOMIC_SEQ_CST); -#endif -} - -template <typename T> -inline void AtomicStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELEASE); -#endif -} - -template <typename T> -inline void RelaxedStore(volatile T* a, T x) { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); -#ifdef _win_ - *a = x; -#else - __atomic_store_n(a, x, __ATOMIC_RELAXED); -#endif -} - -template <typename T> -inline T AtomicLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_ACQUIRE); -#endif -} - -template <typename T> -inline T RelaxedLoad(volatile T* a) { -#ifdef _win_ - return *a; -#else - return __atomic_load_n(a, __ATOMIC_RELAXED); -#endif -} diff --git a/library/cpp/actors/util/local_process_key.h b/library/cpp/actors/util/local_process_key.h deleted file mode 100644 index bff8bef81b..0000000000 --- a/library/cpp/actors/util/local_process_key.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include <util/string/builder.h> -#include <util/system/mutex.h> -#include <util/generic/strbuf.h> -#include <util/generic/vector.h> -#include <util/generic/hash.h> -#include <util/generic/singleton.h> -#include <util/generic/serialized_enum.h> - -class TLocalProcessKeyStateIndexLimiter { -public: - static constexpr ui32 GetMaxKeysCount() { - return 10000; - } -}; - -template <class T> -class TLocalProcessKeyStateIndexConstructor { -public: -}; - -template <typename T> -class TLocalProcessKeyState { - -template <typename U, const char* Name> -friend class TLocalProcessKey; -template <typename U, class TClass, ui32 KeyLengthLimit> -friend class TLocalProcessExtKey; -template <typename U, typename EnumT> -friend class TEnumProcessKey; - -public: - static TLocalProcessKeyState& GetInstance() { - return *Singleton<TLocalProcessKeyState<T>>(); - } - - ui32 GetCount() const { - return MaxKeysCount; - } - - TStringBuf GetNameByIndex(size_t index) const { - Y_ABORT_UNLESS(index < Names.size()); - return Names[index]; - } - - size_t GetIndexByName(TStringBuf name) const { - TGuard<TMutex> g(Mutex); - auto it = Map.find(name); - Y_ENSURE(it != Map.end()); - return it->second; - } - - TLocalProcessKeyState() { - Names.resize(MaxKeysCount); - } - - size_t Register(TStringBuf name) { - TGuard<TMutex> g(Mutex); - auto it = Map.find(name); - if (it != Map.end()) { - return it->second; - } - const ui32 index = TLocalProcessKeyStateIndexConstructor<T>::BuildCurrentIndex(name, Names.size()); - auto x = Map.emplace(name, index); - if (x.second) { - Y_ABORT_UNLESS(index < Names.size(), "a lot of actors or tags for memory monitoring"); - Names[index] = name; - } - - return x.first->second; - } - -private: - - static constexpr ui32 MaxKeysCount = TLocalProcessKeyStateIndexLimiter::GetMaxKeysCount(); - -private: - TVector<TString> Names; - THashMap<TString, size_t> Map; - TMutex Mutex; -}; - -template <typename T, const char* Name> -class TLocalProcessKey { -public: - static TStringBuf GetName() { - return Name; - } - - static size_t GetIndex() { - return Index; - } - -private: - inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(Name); -}; - -template <typename T, class TClass, ui32 KeyLengthLimit = 0> -class TLocalProcessExtKey { -public: - static TStringBuf GetName() { - return Name; - } - - static size_t GetIndex() { - return Index; - } - -private: - - static TString TypeNameRobust() { - const TString className = TypeName<TClass>(); - if (KeyLengthLimit && className.size() > KeyLengthLimit) { - return className.substr(0, KeyLengthLimit - 3) + "..."; - } else { - return className; - } - } - - static const inline TString Name = TypeName<TClass>(); - inline static size_t Index = TLocalProcessKeyState<T>::GetInstance().Register(TypeNameRobust()); -}; - -template <typename T, typename EnumT> -class TEnumProcessKey { -public: - static TStringBuf GetName(const EnumT key) { - return TLocalProcessKeyState<T>::GetInstance().GetNameByIndex(GetIndex(key)); - } - - static size_t GetIndex(const EnumT key) { - ui32 index = static_cast<ui32>(key); - Y_ABORT_UNLESS(index < Enum2Index.size()); - return Enum2Index[index]; - } - -private: - inline static TVector<size_t> RegisterAll() { - static_assert(std::is_enum<EnumT>::value, "Enum is required"); - - TVector<size_t> enum2Index; - auto names = GetEnumNames<EnumT>(); - ui32 maxId = 0; - for (const auto& [k, v] : names) { - maxId = Max(maxId, static_cast<ui32>(k)); - } - enum2Index.resize(maxId + 1); - for (const auto& [k, v] : names) { - ui32 enumId = static_cast<ui32>(k); - enum2Index[enumId] = TLocalProcessKeyState<T>::GetInstance().Register(v); - } - return enum2Index; - } - - inline static TVector<size_t> Enum2Index = RegisterAll(); -}; diff --git a/library/cpp/actors/util/memory_track.cpp b/library/cpp/actors/util/memory_track.cpp deleted file mode 100644 index 5f422116be..0000000000 --- a/library/cpp/actors/util/memory_track.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "memory_track.h" -#include "memory_tracker.h" - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TThreadLocalInfo::TThreadLocalInfo() - : Metrics(TMemoryTracker::Instance()->GetCount()) -{ - TMemoryTracker::Instance()->OnCreateThread(this); -} - -TThreadLocalInfo::~TThreadLocalInfo() { - TMemoryTracker::Instance()->OnDestroyThread(this); -} - -TMetric* TThreadLocalInfo::GetMetric(size_t index) { - if (Y_UNLIKELY(index >= Metrics.size())) { - return &Null; - } - return &Metrics[index]; -} - -const std::vector<TMetric>& TThreadLocalInfo::GetMetrics() const { - return Metrics; -} - -size_t TBaseLabel::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - return TMemoryTracker::Instance()->RegisterStaticMemoryLabel(name, hasSensor); -} - -} - -} -} - diff --git a/library/cpp/actors/util/memory_track.h b/library/cpp/actors/util/memory_track.h deleted file mode 100644 index 6035333eeb..0000000000 --- a/library/cpp/actors/util/memory_track.h +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -#include <vector> - -#include <util/system/type_name.h> -#include <util/thread/singleton.h> - -#define ENABLE_MEMORY_TRACKING - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMetric { - std::atomic<ssize_t> Memory; - std::atomic<ssize_t> Count; - - void Copy(const TMetric& other) { - Memory.store(other.GetMemory(), std::memory_order_relaxed); - Count.store(other.GetCount(), std::memory_order_relaxed); - } - -public: - TMetric() - : Memory(0) - , Count(0) - {} - - inline TMetric(const TMetric& other) { - Copy(other); - } - - inline TMetric(TMetric&& other) { - Copy(other); - } - - inline TMetric& operator=(const TMetric& other) { - Copy(other); - return *this; - } - - inline TMetric& operator=(TMetric&& other) { - Copy(other); - return *this; - } - - inline ssize_t GetMemory() const { - return Memory.load(std::memory_order_relaxed); - } - inline void SetMemory(ssize_t value) { - Memory.store(value, std::memory_order_relaxed); - } - - inline ssize_t GetCount() const { - return Count.load(std::memory_order_relaxed); - } - inline void SetCount(ssize_t value) { - Count.store(value, std::memory_order_relaxed); - } - - inline void operator+=(const TMetric& other) { - SetMemory(GetMemory() + other.GetMemory()); - SetCount(GetCount() + other.GetCount()); - } - - inline void CalculatePeak(const TMetric& other) { - SetMemory(Max(GetMemory(), other.GetMemory())); - SetCount(Max(GetCount(), other.GetCount())); - } - - inline void Add(size_t size) { - SetMemory(GetMemory() + size); - SetCount(GetCount() + 1); - } - - inline void Sub(size_t size) { - SetMemory(GetMemory() - size); - SetCount(GetCount() - 1); - } -}; - - -class TThreadLocalInfo { -public: - TThreadLocalInfo(); - ~TThreadLocalInfo(); - - TMetric* GetMetric(size_t index); - const std::vector<TMetric>& GetMetrics() const; - -private: - std::vector<TMetric> Metrics; - - inline static TMetric Null = {}; -}; - - -class TBaseLabel { -protected: - static size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - inline static TMetric* GetLocalMetric(size_t index) { - return FastTlsSingleton<TThreadLocalInfo>()->GetMetric(index); - } -}; - - -template <const char* Name> -class TNameLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(Name, true); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename TType> -class TTypeLabel - : TBaseLabel -{ -public: - static void Add(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Add(size); -#else - Y_UNUSED(size); -#endif - } - - static void Sub(size_t size) { -#if defined(ENABLE_MEMORY_TRACKING) - Y_UNUSED(MetricInit); - - if (Y_UNLIKELY(!Metric)) { - Metric = GetLocalMetric(Index); - } - - Metric->Sub(size); -#else - Y_UNUSED(size); -#endif - } - -private: -#if defined(ENABLE_MEMORY_TRACKING) - inline static size_t Index = Max<size_t>(); - inline static struct TMetricInit { - TMetricInit() { - Index = RegisterStaticMemoryLabel(TypeName<TType>().c_str(), false); - } - } MetricInit; - - inline static thread_local TMetric* Metric = nullptr; -#endif -}; - - -template <typename T> -struct TTrackHelper { -#if defined(ENABLE_MEMORY_TRACKING) - void* operator new(size_t size) { - T::Add(size); - return malloc(size); - } - - void* operator new[](size_t size) { - T::Add(size); - return malloc(size); - } - - void operator delete(void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } - - void operator delete[](void* ptr, size_t size) { - T::Sub(size); - free(ptr); - } -#endif -}; - -template <typename TType, typename T> -struct TAllocHelper { - typedef size_t size_type; - typedef TType value_type; - typedef TType* pointer; - typedef const TType* const_pointer; - - struct propagate_on_container_copy_assignment : public std::false_type {}; - struct propagate_on_container_move_assignment : public std::false_type {}; - struct propagate_on_container_swap : public std::false_type {}; - - pointer allocate(size_type n, const void* hint = nullptr) { - Y_UNUSED(hint); - auto size = n * sizeof(TType); - T::Add(size); - return (pointer)malloc(size); - } - - void deallocate(pointer ptr, size_t n) { - auto size = n * sizeof(TType); - T::Sub(size); - free((void*)ptr); - } -}; - -} // NPrivate - - -template <const char* Name> -using TLabel = NPrivate::TNameLabel<Name>; - -template <typename TType, const char* Name = nullptr> -struct TTrack - : public NPrivate::TTrackHelper<NPrivate::TNameLabel<Name>> -{ -}; - -template <typename TType> -struct TTrack<TType, nullptr> - : public NPrivate::TTrackHelper<NPrivate::TTypeLabel<TType>> -{ -}; - -template <typename TType, const char* Name = nullptr> -struct TAlloc - : public NPrivate::TAllocHelper<TType, NPrivate::TNameLabel<Name>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U, Name> other; - }; -}; - -template <typename TType> -struct TAlloc<TType, nullptr> - : public NPrivate::TAllocHelper<TType, NPrivate::TTypeLabel<TType>> -{ - template<typename U> - struct rebind { - typedef TAlloc<U> other; - }; -}; - -} -} - diff --git a/library/cpp/actors/util/memory_tracker.cpp b/library/cpp/actors/util/memory_tracker.cpp deleted file mode 100644 index 8a12452c71..0000000000 --- a/library/cpp/actors/util/memory_tracker.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "memory_tracker.h" - -#include <util/generic/xrange.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -TMemoryTracker* TMemoryTracker::Instance() { - return SingletonWithPriority<TMemoryTracker, 0>(); -} - -void TMemoryTracker::Initialize() { - GlobalMetrics.resize(Indices.size()); -} - -const std::map<TString, size_t>& TMemoryTracker::GetMetricIndices() const { - return Indices; -} - -const std::unordered_set<size_t>& TMemoryTracker::GetSensors() const { - return Sensors; -} - -TString TMemoryTracker::GetName(size_t index) const { - return Names[index]; -} - -size_t TMemoryTracker::GetCount() const { - return Indices.size(); -} - -void TMemoryTracker::GatherMetrics(std::vector<TMetric>& metrics) const { - metrics.resize(0); - auto count = GetCount(); - - if (!count || GlobalMetrics.size() != count) { - return; - } - - TReadGuard guard(LockThreadInfo); - - metrics.resize(count); - for (size_t i : xrange(count)) { - metrics[i] += GlobalMetrics[i]; - } - - for (auto info : ThreadInfo) { - auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - metrics[i] += localMetrics[i]; - } - } - } -} - -size_t TMemoryTracker::RegisterStaticMemoryLabel(const char* name, bool hasSensor) { - size_t index = 0; - auto found = Indices.find(name); - if (found == Indices.end()) { - TString str(name); - auto next = Names.size(); - Indices.emplace(str, next); - Names.push_back(str); - index = next; - } else { - index = found->second; - } - - if (hasSensor) { - Sensors.emplace(index); - } - return index; -} - -void TMemoryTracker::OnCreateThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - ThreadInfo.insert(info); -} - -void TMemoryTracker::OnDestroyThread(TThreadLocalInfo* info) { - TWriteGuard guard(LockThreadInfo); - - auto count = GetCount(); - if (count && GlobalMetrics.size() == count) { - const auto& localMetrics = info->GetMetrics(); - if (localMetrics.size() == count) { - for (size_t i : xrange(count)) { - GlobalMetrics[i] += localMetrics[i]; - } - } - } - - ThreadInfo.erase(info); -} - -} - -} -} - diff --git a/library/cpp/actors/util/memory_tracker.h b/library/cpp/actors/util/memory_tracker.h deleted file mode 100644 index e74508191b..0000000000 --- a/library/cpp/actors/util/memory_tracker.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "memory_track.h" - -#include <map> -#include <unordered_map> -#include <unordered_set> - -#include <util/system/rwlock.h> - -namespace NActors { -namespace NMemory { - -namespace NPrivate { - -class TMemoryTracker { -public: - static TMemoryTracker* Instance(); - - void Initialize(); - - const std::map<TString, size_t>& GetMetricIndices() const; - const std::unordered_set<size_t>& GetSensors() const; - TString GetName(size_t index) const; - size_t GetCount() const; - - void GatherMetrics(std::vector<TMetric>& metrics) const; - -private: - size_t RegisterStaticMemoryLabel(const char* name, bool hasSensor); - - void OnCreateThread(TThreadLocalInfo* info); - void OnDestroyThread(TThreadLocalInfo* info); - -private: - std::map<TString, size_t> Indices; - std::vector<TString> Names; - - std::vector<TMetric> GlobalMetrics; - - std::unordered_set<size_t> Sensors; - - std::unordered_set<TThreadLocalInfo*> ThreadInfo; - TRWMutex LockThreadInfo; - - friend class TThreadLocalInfo; - friend class TBaseLabel; -}; - -} - -} -} diff --git a/library/cpp/actors/util/memory_tracker_ut.cpp b/library/cpp/actors/util/memory_tracker_ut.cpp deleted file mode 100644 index 1b8eff7cc5..0000000000 --- a/library/cpp/actors/util/memory_tracker_ut.cpp +++ /dev/null @@ -1,263 +0,0 @@ -#include "memory_tracker.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/system/hp_timer.h> -#include <util/system/thread.h> - -namespace NActors { -namespace NMemory { - -Y_UNIT_TEST_SUITE(TMemoryTrackerTest) { - -#if defined(ENABLE_MEMORY_TRACKING) - -using namespace NPrivate; - -size_t FindLabelIndex(const char* label) { - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - auto it = indices.find(label); - UNIT_ASSERT(it != indices.end()); - return it->second; -} - - -struct TTypeLabeled - : public NActors::NMemory::TTrack<TTypeLabeled> -{ - char payload[16]; -}; - -static constexpr char NamedLabel[] = "NamedLabel"; - -struct TNameLabeled - : public NActors::NMemory::TTrack<TNameLabeled, NamedLabel> -{ - char payload[32]; -}; - -#ifndef _win_ -Y_UNIT_TEST(Gathering) -{ - TMemoryTracker::Instance()->Initialize(); - - auto* typed = new TTypeLabeled; - auto* typedArray = new TTypeLabeled[3]; - - auto* named = new TNameLabeled; - auto* namedArray = new TNameLabeled[5]; - NActors::NMemory::TLabel<NamedLabel>::Add(100); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto typeIndex = FindLabelIndex(TypeName<TTypeLabeled>().c_str()); - UNIT_ASSERT(typeIndex < metrics.size()); - UNIT_ASSERT(metrics[typeIndex].GetMemory() == sizeof(TTypeLabeled) * 4 + sizeof(size_t)); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 2); - - auto nameIndex = FindLabelIndex(NamedLabel); - UNIT_ASSERT(nameIndex < metrics.size()); - UNIT_ASSERT(metrics[nameIndex].GetMemory() == sizeof(TNameLabeled) * 6 + sizeof(size_t) + 100); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 3); - - NActors::NMemory::TLabel<NamedLabel>::Sub(100); - delete [] namedArray; - delete named; - - delete [] typedArray; - delete typed; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - - UNIT_ASSERT(metrics[typeIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[typeIndex].GetCount() == 0); - - UNIT_ASSERT(metrics[nameIndex].GetMemory() == 0); - UNIT_ASSERT(metrics[nameIndex].GetCount() == 0); -} -#endif - -static constexpr char InContainerLabel[] = "InContainerLabel"; - -struct TInContainer { - char payload[16]; -}; - -Y_UNIT_TEST(Containers) { - TMemoryTracker::Instance()->Initialize(); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer>> vecT; - vecT.resize(5); - - std::vector<TInContainer, NActors::NMemory::TAlloc<TInContainer, InContainerLabel>> vecN; - vecN.resize(7); - - using TKey = int; - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> mapT; - mapT.emplace(0, TInContainer()); - mapT.emplace(1, TInContainer()); - - std::map<TKey, TInContainer, std::less<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> mapN; - mapN.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>>> umapT; - umapT.emplace(0, TInContainer()); - - std::unordered_map<TKey, TInContainer, std::hash<TKey>, std::equal_to<TKey>, - NActors::NMemory::TAlloc<std::pair<const TKey, TInContainer>, InContainerLabel>> umapN; - umapN.emplace(0, TInContainer()); - umapN.emplace(1, TInContainer()); - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - - auto indices = TMemoryTracker::Instance()->GetMetricIndices(); - for (auto& [name, index] : indices) { - Cerr << "---- " << name - << ": memory = " << metrics[index].GetMemory() - << ", count = " << metrics[index].GetCount() << Endl; - } - - auto vecTIndex = FindLabelIndex(TypeName<TInContainer>().c_str()); - UNIT_ASSERT(metrics[vecTIndex].GetMemory() >= ssize_t(sizeof(TInContainer) * 5)); - UNIT_ASSERT(metrics[vecTIndex].GetCount() == 1); - - auto labelIndex = FindLabelIndex(InContainerLabel); - UNIT_ASSERT(metrics[labelIndex].GetCount() == 5); - UNIT_ASSERT(metrics[labelIndex].GetMemory() >= ssize_t( - sizeof(TInContainer) * 7 + - sizeof(decltype(mapN)::value_type) + - sizeof(decltype(umapN)::value_type) * 2)); -} - - -static constexpr char InThreadLabel[] = "InThreadLabel"; - -struct TInThread - : public NActors::NMemory::TTrack<TInThread, InThreadLabel> -{ - char payload[16]; -}; - -void* ThreadProc(void*) { - return new TInThread; -} - -Y_UNIT_TEST(Threads) { - TMemoryTracker::Instance()->Initialize(); - - auto index = FindLabelIndex(InThreadLabel); - - auto* object1 = new TInThread; - - std::vector<TMetric> metrics; - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - TThread thread(&ThreadProc, nullptr); - thread.Start(); - auto* object2 = static_cast<TInThread*>(thread.Join()); - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread) * 2); - UNIT_ASSERT(metrics[index].GetCount() == 2); - - delete object2; - - TMemoryTracker::Instance()->GatherMetrics(metrics); - UNIT_ASSERT(metrics[index].GetMemory() == sizeof(TInThread)); - UNIT_ASSERT(metrics[index].GetCount() == 1); - - delete object1; -} - - -struct TNotTracked { - char payload[16]; -}; - -struct TTracked - : public NActors::NMemory::TTrack<TTracked> -{ - char payload[16]; -}; - -template <typename T> -double MeasureAllocations() { - constexpr size_t objectsCount = 4 << 20; - - std::vector<T*> objects; - objects.resize(objectsCount); - - THPTimer timer; - - for (size_t i = 0; i < objectsCount; ++i) { - objects[i] = new T; - } - - for (size_t i = 0; i < objectsCount; ++i) { - delete objects[i]; - } - - auto seconds = timer.Passed(); - Cerr << "---- objects: " << objectsCount << ", time: " << seconds << Endl; - return seconds; -} - -Y_UNIT_TEST(Performance) { - TMemoryTracker::Instance()->Initialize(); - - constexpr size_t Runs = 16; - - Cerr << "---- warmup" << Endl; - MeasureAllocations<TNotTracked>(); - MeasureAllocations<TTracked>(); - - std::vector<double> noTrack; - std::vector<double> track; - - for (size_t run = 0; run < Runs; ++run) { - Cerr << "---- no track" << Endl; - auto time = MeasureAllocations<TNotTracked>(); - noTrack.push_back(time); - - Cerr << "---- track" << Endl; - time = MeasureAllocations<TTracked>(); - track.push_back(time); - } - - double meanNoTrack = 0, stddevNoTrack = 0; - double meanTrack = 0, stddevTrack = 0; - for (size_t i = 0; i < Runs; ++i) { - meanNoTrack += noTrack[i]; - meanTrack += track[i]; - } - meanNoTrack /= Runs; - meanTrack /= Runs; - - auto sqr = [](double val) { return val * val; }; - - for (size_t i = 0; i < Runs; ++i) { - stddevNoTrack += sqr(noTrack[i] - meanNoTrack); - stddevTrack += sqr(track[i] - meanTrack); - } - stddevNoTrack = sqrt(stddevNoTrack / (Runs - 1)); - stddevTrack = sqrt(stddevTrack / (Runs - 1)); - - Cerr << "---- no track - mean: " << meanNoTrack << ", stddev: " << stddevNoTrack << Endl; - Cerr << "---- track - mean: " << meanTrack << ", stddev: " << stddevTrack << Endl; - Cerr << "---- tracking is slower by " << int((meanTrack / meanNoTrack - 1.0) * 100) << "%" << Endl; -} - -#endif - -} - -} -} diff --git a/library/cpp/actors/util/named_tuple.h b/library/cpp/actors/util/named_tuple.h deleted file mode 100644 index 67f185bba8..0000000000 --- a/library/cpp/actors/util/named_tuple.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "defs.h" - -template <typename TDerived> -struct TNamedTupleBase { - friend bool operator==(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() == y.ConvertToTuple(); - } - - friend bool operator!=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() != y.ConvertToTuple(); - } - - friend bool operator<(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() < y.ConvertToTuple(); - } - - friend bool operator<=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() <= y.ConvertToTuple(); - } - - friend bool operator>(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() > y.ConvertToTuple(); - } - - friend bool operator>=(const TDerived& x, const TDerived& y) { - return x.ConvertToTuple() >= y.ConvertToTuple(); - } -}; diff --git a/library/cpp/actors/util/queue_chunk.h b/library/cpp/actors/util/queue_chunk.h deleted file mode 100644 index 8a4e02d8cb..0000000000 --- a/library/cpp/actors/util/queue_chunk.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "defs.h" - -template <typename T, ui32 TSize, typename TDerived> -struct TQueueChunkDerived { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunkDerived*)) / sizeof(T); - static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TDerived* volatile Next; - - TQueueChunkDerived() { - memset(this, 0, sizeof(TQueueChunkDerived)); - } -}; - -template <typename T, ui32 TSize> -struct TQueueChunk { - static const ui32 EntriesCount = (TSize - sizeof(TQueueChunk*)) / sizeof(T); - static_assert(EntriesCount > 0, "expect EntriesCount > 0"); - - volatile T Entries[EntriesCount]; - TQueueChunk* volatile Next; - - TQueueChunk() { - memset(this, 0, sizeof(TQueueChunk)); - } -}; diff --git a/library/cpp/actors/util/queue_oneone_inplace.h b/library/cpp/actors/util/queue_oneone_inplace.h deleted file mode 100644 index 288011955a..0000000000 --- a/library/cpp/actors/util/queue_oneone_inplace.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include "defs.h" -#include "queue_chunk.h" - -template <typename T, ui32 TSize, typename TChunk = TQueueChunk<T, TSize>> -class TOneOneQueueInplace : TNonCopyable { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::valuer"); - - TChunk* ReadFrom; - ui32 ReadPosition; - ui32 WritePosition; - TChunk* WriteTo; - - friend class TReadIterator; - -public: - class TReadIterator { - TChunk* ReadFrom; - ui32 ReadPosition; - - public: - TReadIterator(TChunk* readFrom, ui32 readPosition) - : ReadFrom(readFrom) - , ReadPosition(readPosition) - { - } - - inline T Next() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition++]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - ReadPosition = 0; - return Next(); - } - return T{}; - } - }; - - TOneOneQueueInplace() - : ReadFrom(new TChunk()) - , ReadPosition(0) - , WritePosition(0) - , WriteTo(ReadFrom) - { - } - - ~TOneOneQueueInplace() { - Y_DEBUG_ABORT_UNLESS(Head() == 0); - delete ReadFrom; - } - - struct TPtrCleanDestructor { - static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { - while (T head = x->Pop()) - delete head; - delete x; - } - }; - - struct TCleanDestructor { - static inline void Destroy(TOneOneQueueInplace<T, TSize>* x) noexcept { - while (x->Pop() != nullptr) - continue; - delete x; - } - }; - - struct TPtrCleanInplaceMallocDestructor { - template <typename TPtrVal> - static inline void Destroy(TOneOneQueueInplace<TPtrVal*, TSize>* x) noexcept { - while (TPtrVal* head = x->Pop()) { - head->~TPtrVal(); - free(head); - } - delete x; - } - }; - - void Push(T x) noexcept { - if (WritePosition != TChunk::EntriesCount) { - AtomicStore(&WriteTo->Entries[WritePosition], x); - ++WritePosition; - } else { - TChunk* next = new TChunk(); - next->Entries[0] = x; - AtomicStore(&WriteTo->Next, next); - WriteTo = next; - WritePosition = 1; - } - } - - T Head() { - TChunk* head = ReadFrom; - if (ReadPosition != TChunk::EntriesCount) { - return AtomicLoad(&head->Entries[ReadPosition]); - } else if (TChunk* next = AtomicLoad(&head->Next)) { - ReadFrom = next; - delete head; - ReadPosition = 0; - return Head(); - } - return T{}; - } - - T Pop() { - T ret = Head(); - if (ret) - ++ReadPosition; - return ret; - } - - TReadIterator Iterator() { - return TReadIterator(ReadFrom, ReadPosition); - } -}; diff --git a/library/cpp/actors/util/rc_buf.cpp b/library/cpp/actors/util/rc_buf.cpp deleted file mode 100644 index 946c9846ee..0000000000 --- a/library/cpp/actors/util/rc_buf.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "rc_buf.h" - -template<> -void Out<TRcBuf>(IOutputStream& s, const TRcBuf& x) { - s.Write(TStringBuf(x)); -} diff --git a/library/cpp/actors/util/rc_buf.h b/library/cpp/actors/util/rc_buf.h deleted file mode 100644 index db0f7deff5..0000000000 --- a/library/cpp/actors/util/rc_buf.h +++ /dev/null @@ -1,1120 +0,0 @@ -#pragma once - -#include <atomic> -#include <new> - -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/hash_set.h> -#include <util/generic/scope.h> -#include <util/stream/str.h> -#include <util/system/sanitizers.h> -#include <util/system/valgrind.h> -#include <util/generic/array_ref.h> -#include <util/system/sys_alloc.h> - -#include "shared_data.h" -#include "rc_buf_backend.h" - -#ifdef KIKIMR_TRACE_CONTIGUOUS_DATA_GROW -#include "shared_data_backtracing_owner.h" -#endif - -namespace NContiguousDataDetails { - template<typename TContainer> - struct TContainerTraits { - static char* UnsafeGetDataMut(const TContainer& backend) { - return const_cast<char*>(backend.data()); - } - }; -} // NContiguousDataDetails - -class TContiguousSpan -{ -private: - const char *Data_ = nullptr; - size_t Size_ = 0; - -public: - TContiguousSpan() = default; - - TContiguousSpan(const char *data, size_t size) - : Data_(data) - , Size_(size) - {} - - TContiguousSpan(const TString& str) - : Data_(str.data()) - , Size_(str.size()) - {} - - TContiguousSpan(const TStringBuf& str) - : Data_(str.data()) - , Size_(str.size()) - {} - - TContiguousSpan(const TArrayRef<char>& ref) - : Data_(ref.data()) - , Size_(ref.size()) - {} - - TContiguousSpan(const TArrayRef<const char>& ref) - : Data_(ref.data()) - , Size_(ref.size()) - {} - - TContiguousSpan(const NActors::TSharedData& data) - : Data_(data.data()) - , Size_(data.size()) - {} - - const char& operator[](size_t index) const { - Y_DEBUG_ABORT_UNLESS(index < Size_); - return Data_[index]; - } - - const char *data() const noexcept { - return Data_; - } - - size_t size() const noexcept { - return Size_; - } - - const char *GetData() const noexcept { - return Data_; - } - - size_t GetSize() const noexcept { - return Size_; - } - - const char *Data() const noexcept { - return Data_; - } - - size_t Size() const noexcept { - return Size_; - } - - TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TContiguousSpan(data() + pos, n); - } - - template<std::size_t Index> - auto get() const noexcept - { - static_assert(Index < 2, - "Index out of bounds for TContiguousSpan"); - if constexpr (Index == 0) return Data_; - if constexpr (Index == 1) return Size_; - } - - friend bool operator==(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) != 0; } - friend bool operator< (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TContiguousSpan& x, const TContiguousSpan& y) { return Compare(x, y) >= 0; } - -private: - static int Compare(const TContiguousSpan& x, const TContiguousSpan& y) { - int res = 0; - if (const size_t common = std::min(x.size(), y.size())) { - res = std::memcmp(x.data(), y.data(), common); - } - return res ? res : x.size() - y.size(); - } -}; - - - -namespace std -{ - template<> - struct tuple_size<::TContiguousSpan> - : integral_constant<size_t, 2> {}; - - template<> - struct tuple_element<0, ::TContiguousSpan> - { - using type = const char *; - }; - - template<> - struct tuple_element<1, ::TContiguousSpan> - { - using type = size_t; - }; -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator==(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) == TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator!=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) != TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator<(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) < TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator<=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) <= TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator>(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) > TContiguousSpan(rhs); -} - -template < - class TLeft, - class TRight, - typename std::enable_if<std::is_convertible<TLeft,TContiguousSpan>::value>::type* = nullptr, - typename std::enable_if<std::is_convertible<TRight,TContiguousSpan>::value>::type* = nullptr - > -bool operator>=(const TLeft& lhs, const TRight& rhs) { - return TContiguousSpan(lhs) >= TContiguousSpan(rhs); -} - - -class TMutableContiguousSpan -{ -private: - char *Data = nullptr; - size_t Size = 0; - -public: - TMutableContiguousSpan() = default; - - TMutableContiguousSpan(char *data, size_t size) - : Data(data) - , Size(size) - {} - - char *data() noexcept { - return Data; - } - - char *GetData() noexcept { - return Data; - } - - TMutableContiguousSpan SubSpan(size_t pos, size_t n) noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TMutableContiguousSpan(data() + pos, n); - } - - const char *data() const noexcept { - return Data; - } - - size_t size() const noexcept { - return Size; - } - - const char *GetData() const noexcept { - return Data; - } - - size_t GetSize() const noexcept { - return Size; - } - - TContiguousSpan SubSpan(size_t pos, size_t n) const noexcept { - pos = Min(pos, size()); - n = Min(n, size() - pos); - return TContiguousSpan(data() + pos, n); - } - - operator TContiguousSpan() const noexcept { - return TContiguousSpan(Data, Size); - } -}; - -struct IContiguousChunk : TThrRefBase { - using TPtr = TIntrusivePtr<IContiguousChunk>; - - virtual ~IContiguousChunk() = default; - - /** - * Should give immutable access to data - */ - virtual TContiguousSpan GetData() const = 0; - - /** - * Should give mutable access to underlying data - * If data is shared - data should be copied - * E.g. for TString str.Detach() should be used - * Possibly invalidates previous *GetData*() calls - */ - virtual TMutableContiguousSpan GetDataMut() = 0; - - /** - * Should give mutable access to undelying data as fast as possible - * Even if data is shared this property should be ignored - * E.g. in TString const_cast<char *>(str.data()) should be used - * Possibly invalidates previous *GetData*() calls - */ - virtual TMutableContiguousSpan UnsafeGetDataMut() { - return GetDataMut(); - } - - /** - * Should return true if GetDataMut() would not copy contents when called. - */ - virtual bool IsPrivate() const { - return true; - } - - virtual size_t GetOccupiedMemorySize() const = 0; -}; - -class TRope; -class TRopeArena; - -class TRcBuf { - friend class TRope; - friend class TRopeArena; - - using TInternalBackend = NDetail::TRcBufInternalBackend; - - class TBackend { - enum class EType : uintptr_t { - STRING, - SHARED_DATA, - INTERNAL_BACKEND, - EXTERNAL_BACKEND, - }; - - struct TBackendHolder { - uintptr_t Data[2]; - explicit operator bool() const noexcept { - return Data[0] || Data[1]; - } - friend bool operator ==(const TBackendHolder& x, const TBackendHolder& y) { - return x.Data[0] == y.Data[0] && x.Data[1] == y.Data[1]; - } - }; - - constexpr static TBackendHolder Empty = {0, 0}; - -#ifndef TSTRING_IS_STD_STRING - static_assert(sizeof(TBackendHolder) >= sizeof(TString)); -#endif - static_assert(sizeof(TBackendHolder) >= sizeof(NActors::TSharedData)); - static_assert(sizeof(TBackendHolder) >= sizeof(TInternalBackend)); - - TBackendHolder Owner = TBackend::Empty; // lower bits contain type of the owner - - public: - using TCookies = TInternalBackend::TCookies; - - static constexpr struct TControlToken {} ControlToken; - static constexpr size_t CookiesSize = sizeof(TCookies); - - TBackend() = default; - - TBackend(const TBackend& other) - : Owner(other.Owner ? Clone(other.Owner) : TBackend::Empty) - {} - - TBackend(TBackend&& other) - : Owner(std::exchange(other.Owner, TBackend::Empty)) - {} - - TBackend(TString s) - : Owner(Construct<TString>(EType::STRING, std::move(s))) - {} - - TBackend(NActors::TSharedData s) - : Owner(Construct<NActors::TSharedData>(EType::SHARED_DATA, std::move(s))) - {} - - TBackend(TInternalBackend backend) - : Owner(Construct<TInternalBackend>(EType::INTERNAL_BACKEND, std::move(backend))) - {} - - TBackend(IContiguousChunk::TPtr backend) - : Owner(Construct<IContiguousChunk::TPtr>(EType::EXTERNAL_BACKEND, std::move(backend))) - {} - - ~TBackend() { - if (Owner) { - Destroy(Owner); - } - } - - TBackend& operator =(const TBackend& other) { - if (Y_UNLIKELY(this == &other)) { - return *this; - } - - if (Owner) { - Destroy(Owner); - } - if (other.Owner) { - Owner = Clone(other.Owner); - } else { - Owner = TBackend::Empty; - } - return *this; - } - - TBackend& operator =(TBackend&& other) { - if (Y_UNLIKELY(this == &other)) { - return *this; - } - - if (Owner) { - Destroy(Owner); - } - Owner = std::exchange(other.Owner, TBackend::Empty); - return *this; - } - - bool operator ==(const TBackend& other) const { - return Owner == other.Owner; - } - - const void *UniqueId() const { - return reinterpret_cast<const void*>(Owner.Data[0]); - } - - TCookies* GetCookies() { - if(!Owner) { - return nullptr; - } - return Visit(Owner, [](EType, auto& value) -> TCookies* { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TInternalBackend>) { - return value.GetCookies(); - } else { - return nullptr; - } - }); - } - - const TCookies* GetCookies() const { - return const_cast<TBackend&>(*this).GetCookies(); - } - - bool IsPrivate() const { - if(!Owner) { - return true; - } - return Visit(Owner, [](EType, auto& value) -> bool { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return value.IsPrivate(); - } else if constexpr (std::is_same_v<T, TString>) { - return value.IsDetached(); - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value.RefCount() == 1 && value->IsPrivate(); - } else { - static_assert(TDependentFalse<T>); - } - }); - } - - TContiguousSpan GetData() const { - if (!Owner) { - return TContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString> || std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return {value.data(), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetData(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - TMutableContiguousSpan GetDataMut() { - if (!Owner) { - return TMutableContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return {value.Detach(), value.size()}; - } else if constexpr (std::is_same_v<T, NActors::TSharedData>) { - if (value.IsShared()) { - value = NActors::TSharedData::Copy(value.data(), value.size()); - } - return {value.mutable_data(), value.size()}; - } else if constexpr (std::is_same_v<T, TInternalBackend>) { - if (value.IsShared()) { - value = TInternalBackend::Copy(value.data(), value.size()); - } - return {value.mutable_data(), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetDataMut(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - TMutableContiguousSpan UnsafeGetDataMut() const { - if (!Owner) { - return TMutableContiguousSpan(); - } - return Visit(Owner, [](EType, auto& value) -> TMutableContiguousSpan { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return {const_cast<char*>(value.data()), value.size()}; - } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return {const_cast<char*>(value.data()), value.size()}; - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->UnsafeGetDataMut(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - size_t GetOccupiedMemorySize() const { - if (!Owner) { - return 0; - } - return Visit(Owner, [](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TString>) { - return value.capacity(); - } else if constexpr (std::is_same_v<T, NActors::TSharedData> || std::is_same_v<T, TInternalBackend>) { - return value.size(); // There is no capacity - } else if constexpr (std::is_same_v<T, IContiguousChunk::TPtr>) { - return value->GetOccupiedMemorySize(); - } else { - static_assert(TDependentFalse<T>, "unexpected type"); - } - }); - } - - template <class TType> - bool ContainsNativeType() const { - if (!Owner) { - return false; - } - return Visit(Owner, [](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - return std::is_same_v<T, TType>; - }); - } - - bool CanGrowFront(const char* begin) const { - if (!Owner) { - return false; - } - const TCookies* cookies = GetCookies(); - return cookies && (IsPrivate() || cookies->Begin.load() == begin); - } - - bool CanGrowBack(const char* end) const { - if (!Owner) { - return false; - } - const TCookies* cookies = GetCookies(); - return cookies && (IsPrivate() || cookies->End.load() == end); - } - - void UpdateCookiesUnsafe(const char* contBegin, const char* contEnd) { - if (!Owner) { - return; - } - TCookies* cookies = GetCookies(); - if (cookies) { - cookies->Begin.store(contBegin); - cookies->End.store(contEnd); - } - } - - bool UpdateCookiesBegin(const char* curBegin, const char* contBegin) { - if (!Owner) { - return false; - } - - TCookies* cookies = GetCookies(); - if (cookies) { - return cookies->Begin.compare_exchange_weak(curBegin, contBegin); - } - return false; - } - - bool UpdateCookiesEnd(const char* curEnd, const char* contEnd) { - if (!Owner) { - return false; - } - - TCookies* cookies = GetCookies(); - if (cookies) { - return cookies->End.compare_exchange_weak(curEnd, contEnd); - } - return false; - } - - template <typename TResult, typename TCallback> - std::invoke_result_t<TCallback, const TResult*> ApplySpecificValue(TCallback&& callback) const { - static_assert(std::is_same_v<TResult, TString> || - std::is_same_v<TResult, NActors::TSharedData> || - std::is_same_v<TResult, TInternalBackend> || - std::is_same_v<TResult, IContiguousChunk::TPtr>); - - if (!Owner) { - return callback(nullptr); - } - return Visit(Owner, [&](EType, auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, TResult>) { - return callback(&value); - } else { - return callback(nullptr); - } - }); - } - - explicit operator bool() const { - return static_cast<bool>(Owner); - } - - private: - static constexpr uintptr_t TypeMask = (1 << 3) - 1; - static constexpr uintptr_t ValueMask = ~TypeMask; - - template<typename T> - struct TObjectHolder { - struct TWrappedObject : TThrRefBase { - T Value; - TWrappedObject(T&& value) - : Value(std::move(value)) - {} - }; - TIntrusivePtr<TWrappedObject> Object; - - TObjectHolder(T&& object) - : Object(MakeIntrusive<TWrappedObject>(std::move(object))) - {} - }; - - template<typename TObject> - static TBackendHolder Construct(EType type, TObject&& object) { - if constexpr (sizeof(TObject) <= sizeof(TBackendHolder)) { - TBackendHolder res = TBackend::Empty; - new(&res) std::decay_t<TObject>(std::forward<TObject>(object)); - Y_DEBUG_ABORT_UNLESS((res.Data[0] & ValueMask) == res.Data[0]); - res.Data[0] = res.Data[0] | static_cast<uintptr_t>(type); - return res; - } else { - return Construct<TObjectHolder<TObject>>(type, TObjectHolder<TObject>(std::forward<TObject>(object))); - } - } - - template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>> - static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> VisitRaw(TOwner& origValue, TCallback&& callback) { - Y_DEBUG_ABORT_UNLESS(origValue); - const EType type = static_cast<EType>(origValue.Data[0] & TypeMask); - TBackendHolder value(origValue); - value.Data[0] = value.Data[0] & ValueMask; - // bring object type back - Y_SCOPE_EXIT(&value, &origValue, type){ - if constexpr(!IsConst) { - value.Data[0] = value.Data[0] | static_cast<uintptr_t>(type); - origValue = value; - } else { - Y_UNUSED(value); - Y_UNUSED(origValue); - Y_UNUSED(type); - } - }; - auto caller = [&](auto& value) { return std::invoke(std::forward<TCallback>(callback), type, value); }; - auto wrapper = [&](auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (sizeof(T) <= sizeof(TBackendHolder)) { - return caller(value); - } else { - return caller(reinterpret_cast<std::conditional_t<IsConst, const TObjectHolder<T>&, TObjectHolder<T>&>>(value)); - } - }; - switch (type) { - case EType::STRING: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TString&, TString&>>(value)); - case EType::SHARED_DATA: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const NActors::TSharedData&, NActors::TSharedData&>>(value)); - case EType::INTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const TInternalBackend&, TInternalBackend&>>(value)); - case EType::EXTERNAL_BACKEND: return wrapper(reinterpret_cast<std::conditional_t<IsConst, const IContiguousChunk::TPtr&, IContiguousChunk::TPtr&>>(value)); - } - Y_ABORT("Unexpected type# %" PRIu64, static_cast<ui64>(type)); - } - - template<typename TOwner, typename TCallback, bool IsConst = std::is_const_v<TOwner>> - static std::invoke_result_t<TCallback, EType, std::conditional_t<IsConst, const TString&, TString&>> Visit(TOwner& value, TCallback&& callback) { - return VisitRaw(value, [&](EType type, auto& value) { - return std::invoke(std::forward<TCallback>(callback), type, Unwrap(value)); - }); - } - - template<typename T> static T& Unwrap(T& object) { return object; } - template<typename T> static T& Unwrap(TObjectHolder<T>& holder) { return holder.Object->Value; } - template<typename T> static const T& Unwrap(const TObjectHolder<T>& holder) { return holder.Object->Value; } - - template<typename TOwner> - static TBackendHolder Clone(TOwner& value) { - return VisitRaw(value, [](EType type, auto& value) { return Construct(type, value); }); - } - - template<typename TOwner> - static void Destroy(TOwner& value) { - VisitRaw(value, [](EType, auto& value) { CallDtor(value); }); - } - - template<typename T> - static void CallDtor(T& value) { - value.~T(); - } - }; - - static constexpr struct TOwnedPiece {} OwnedPiece{}; - - TBackend Backend; // who actually holds the data - const char *Begin; // data start - const char *End; // data end - - explicit TRcBuf(TInternalBackend s, const char *data, size_t size) - : Backend(std::move(s)) - { - Y_ABORT_UNLESS(Backend.GetData().data() == nullptr || - (Backend.GetCookies() && Backend.GetCookies()->Begin == data && Backend.GetCookies()->End == data + size)); - Begin = data; - End = data + size; - } - - explicit TRcBuf(TInternalBackend s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - TRcBuf(TOwnedPiece, const char *data, size_t size, const TRcBuf& from) - : TRcBuf(from.Backend, {data, size}) - { - Y_ABORT_UNLESS(data >= from.GetData()); - Y_ABORT_UNLESS(data < from.GetData() + from.GetSize()); - Y_ABORT_UNLESS(data + size <= from.GetData() + from.GetSize()); - Backend.UpdateCookiesUnsafe(Begin, End); - } - - TRcBuf(TOwnedPiece, const char *begin, const char *end, const TRcBuf& from) - : TRcBuf(OwnedPiece, begin, end - begin, from) - {} - -public: - static constexpr struct TPiece {} Piece{}; - - enum class EResizeResult { - NoAlloc, - Alloc, - }; - - enum class EResizeStrategy { - KeepRooms, - FailOnCopy, - // SaveAllocs, // Move data if there is enough space in (headroom + size + tailroom) - }; - - TRcBuf() - : Begin(nullptr) - , End(nullptr) - {} - - template<typename T> - TRcBuf(T&& backend, const TContiguousSpan& data) - : Backend(std::forward<T>(backend)) - , Begin(data.data()) - , End(Begin + data.size()) - {} - - explicit TRcBuf(TString s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - explicit TRcBuf(NActors::TSharedData s) - : Backend(std::move(s)) - { - auto span = Backend.GetData(); - Begin = span.data(); - End = Begin + span.size(); - } - - TRcBuf(IContiguousChunk::TPtr backend) - : TRcBuf(backend, backend->GetData()) - {} - - TRcBuf(TPiece, const char *data, size_t size, const TRcBuf& from) - : TRcBuf(from.Backend, {data, size}) - { - Y_ABORT_UNLESS(data >= from.GetData()); - Y_ABORT_UNLESS(data < from.GetData() + from.GetSize()); - Y_ABORT_UNLESS(data + size <= from.GetData() + from.GetSize()); - } - - TRcBuf(TPiece, const char *begin, const char *end, const TRcBuf& from) - : TRcBuf(Piece, begin, end - begin, from) - {} - - TRcBuf(const TRcBuf& other) - : Backend(other.Backend) - , Begin(other.Begin) - , End(other.End) - {} - - TRcBuf(TRcBuf&& other) - : Backend(std::move(other.Backend)) - , Begin(other.Begin) - , End(other.End) - {} - - TRcBuf& operator =(const TRcBuf&) = default; - TRcBuf& operator =(TRcBuf&&) = default; - - static TRcBuf Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0) - { - if (size == 0) { - return TRcBuf(); - } - - if (headroom == 0 && tailroom == 0) { - TInternalBackend res = TInternalBackend::Uninitialized(size); - return TRcBuf( - OwnedPiece, - res.data(), - res.data() + res.size(), - TRcBuf(res)); - } - - TInternalBackend res = TInternalBackend::Uninitialized(size, headroom, tailroom); - return TRcBuf(res, res.data() + headroom, size); - } - - static TRcBuf Copy(TContiguousSpan data, size_t headroom = 0, size_t tailroom = 0) { - TRcBuf res = Uninitialized(data.size(), headroom, tailroom); - std::memcpy(res.UnsafeGetDataMut(), data.GetData(), data.GetSize()); - return res; - } - - static TRcBuf Copy(const char* data, size_t size, size_t headroom = 0, size_t tailroom = 0) { - return Copy({data, size}, headroom, tailroom); - } - - template <class TType> - bool ContainsNativeType() const { - return Backend.ContainsNativeType<TType>(); - } - - bool CanGrowFront() const noexcept { - return Backend.CanGrowFront(Begin); - } - - bool CanGrowBack() const noexcept { - return Backend.CanGrowBack(End); - } - - size_t GetSize() const { - return End - Begin; - } - - size_t Size() const { - return End - Begin; - } - - size_t GetOccupiedMemorySize() const { - return Backend.GetOccupiedMemorySize(); - } - - const char* GetData() const { - return Begin; - } - - char* GetDataMut(size_t headroom = 0, size_t tailroom = 0) { - const TContiguousSpan backendData = Backend.GetData(); - if (IsPrivate() || (backendData.data() == GetData() && backendData.size() == GetSize())) { // if we own container or reference it whole - const char* oldBegin = backendData.data(); - ptrdiff_t offset = Begin - oldBegin; - size_t size = GetSize(); - char* newBegin = Backend.GetDataMut().data(); - Begin = newBegin + offset; - End = Begin + size; - return newBegin + offset; - } else { // make a copy of referenced data - *this = Copy(GetContiguousSpan(), headroom, tailroom); - return Backend.GetDataMut().data(); - } - } - - char* UnsafeGetDataMut() { - const char* oldBegin = Backend.GetData().data(); - ptrdiff_t offset = Begin - oldBegin; - size_t size = GetSize(); - char* newBegin = Backend.UnsafeGetDataMut().data(); - Begin = newBegin + offset; - End = Begin + size; - return newBegin + offset; - } - - template <class TResult> - TResult ExtractUnderlyingContainerOrCopy() const { - static_assert(std::is_same_v<TResult, TString> || - std::is_same_v<TResult, NActors::TSharedData> || - std::is_same_v<TResult, TInternalBackend>); - - constexpr bool isSharedData = std::is_same_v<TResult, NActors::TSharedData>; - TResult res; - - const bool found = Backend.ApplySpecificValue<TResult>([&](const TResult *raw) { - if (raw && raw->data() == Begin && (isSharedData ? End <= Begin + raw->size() : End == Begin + raw->size())) { - if constexpr (isSharedData) { - raw->TrimBack(size()); - } - res = TResult(*raw); - return true; - } - return false; - }); - - if (!found) { - res = TResult::Uninitialized(GetSize()); - char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res); - std::memcpy(data, GetData(), GetSize()); - } - - return res; - } - - TContiguousSpan GetContiguousSpan() const { - return {GetData(), GetSize()}; - } - - TStringBuf Slice(size_t pos = 0, size_t len = Max<size_t>()) const noexcept { - pos = Min(pos, size()); - len = Min(len, size() - pos); - return {const_cast<TRcBuf*>(this)->UnsafeGetDataMut() + pos, len}; - } - - explicit operator TStringBuf() const noexcept { - return Slice(); - } - - TMutableContiguousSpan GetContiguousSpanMut() { - return {GetDataMut(), GetSize()}; - } - - TMutableContiguousSpan UnsafeGetContiguousSpanMut() { - return {UnsafeGetDataMut(), GetSize()}; - } - - bool HasBuffer() const { - return static_cast<bool>(Backend); - } - - size_t size() const { - return GetSize(); - } - - bool empty() const { - return !static_cast<bool>(Backend); - } - - operator bool() const { - return !empty(); - } - - const char* data() const { - return GetData(); - } - - const char* Data() const { - return GetData(); - } - - const char* begin() const { - return Begin; - } - - const char* end() const { - return End; - } - - char& operator[](size_t pos) { - return UnsafeGetDataMut()[pos]; - } - - const char& operator[](size_t pos) const { - return GetData()[pos]; - } - - void reserve(size_t size) { - ReserveTailroom(size); - } - - void ReserveHeadroom(size_t size) { - if (Headroom() >= size) { - return; - } - auto newData = TRcBuf::Uninitialized(GetSize(), size, UnsafeTailroom()); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - void ReserveTailroom(size_t size) { - if (Tailroom() >= size) { - return; - } - auto newData = TRcBuf::Uninitialized(GetSize(), UnsafeHeadroom(), size); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - void ReserveBidi(size_t headroom, size_t tailroom) { - if (Headroom() >= headroom && Tailroom() >= tailroom) { - return; - } - auto newData = TRcBuf::Uninitialized( - GetSize(), - std::max(UnsafeHeadroom(), headroom), - std::max(UnsafeTailroom(), tailroom)); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - } - - EResizeResult GrowFront(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - if (Headroom() >= size && Backend.UpdateCookiesBegin(Begin, Begin - size)) { - Begin -= size; - return EResizeResult::NoAlloc; - } else { - if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) { - Y_ABORT("Fail on grow"); - } - auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom() > size ? UnsafeHeadroom() - size : 0, UnsafeTailroom()); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut() + size, GetData(), GetSize()); - } - *this = std::move(newData); - return EResizeResult::Alloc; - } - } - - EResizeResult GrowBack(size_t size, EResizeStrategy strategy = EResizeStrategy::KeepRooms) { - if (Tailroom() > size && Backend.UpdateCookiesEnd(End, End + size)) { - End += size; - return EResizeResult::NoAlloc; - } else { - if (strategy == EResizeStrategy::FailOnCopy && static_cast<bool>(Backend)) { - Y_ABORT("Fail on grow"); - } - auto newData = TRcBuf::Uninitialized(size + GetSize(), UnsafeHeadroom(), UnsafeTailroom() > size ? UnsafeTailroom() - size : 0); - if (auto data = GetData(); data) { - std::memcpy(newData.UnsafeGetDataMut(), GetData(), GetSize()); - } - *this = std::move(newData); - return EResizeResult::Alloc; - } - } - - void TrimBack(size_t size) { - Y_ABORT_UNLESS(size <= GetSize()); - End = End - (GetSize() - size); - } - - void TrimFront(size_t size) { - Y_ABORT_UNLESS(size <= GetSize()); - Begin = Begin + (GetSize() - size); - } - - char* Detach() { - return GetDataMut(); - } - - bool IsPrivate() const { - return Backend.IsPrivate(); - } - - size_t UnsafeHeadroom() const { - return Begin - Backend.GetData().data(); - } - - size_t UnsafeTailroom() const { - auto span = Backend.GetData(); - return (span.GetData() + span.GetSize()) - End; - } - - size_t Headroom() const { - if (Backend.CanGrowFront(Begin)) { - return UnsafeHeadroom(); - } - - return 0; - } - - size_t Tailroom() const { - if (Backend.CanGrowBack(End)) { - return UnsafeTailroom(); - } - - return 0; - } - - operator TContiguousSpan() const noexcept { - return TContiguousSpan(GetData(), GetSize()); - } - - explicit operator TMutableContiguousSpan() noexcept { - return TMutableContiguousSpan(GetDataMut(), GetSize()); - } -}; diff --git a/library/cpp/actors/util/rc_buf_backend.h b/library/cpp/actors/util/rc_buf_backend.h deleted file mode 100644 index 9cb8616554..0000000000 --- a/library/cpp/actors/util/rc_buf_backend.h +++ /dev/null @@ -1,230 +0,0 @@ -#pragma once - -#include <atomic> - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/types.h> -#include <util/system/compiler.h> -#include <util/generic/array_ref.h> -#include <util/system/sys_alloc.h> - -namespace NDetail { - -struct TRcBufInternalBackend { -public: - struct TCookies { - using TSelf = TCookies; - std::atomic<const char*> Begin; - std::atomic<const char*> End; - - static size_t BytesToAligned(size_t size) { - bool misaligned = size % alignof(TSelf); - return misaligned ? alignof(TSelf) - size % alignof(TSelf) : 0; - } - - static size_t BytesToAlloc(size_t size) { - return size + BytesToAligned(size) + sizeof(TSelf); - } - }; -private: - // to be binary compatible with TSharedData - struct THeader : public TCookies { - TAtomic RefCount; - ui64 Zero = 0; - }; - - enum : size_t { - HeaderSize = sizeof(THeader), - OverheadSize = HeaderSize, - MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize) - }; - -public: - TRcBufInternalBackend() noexcept - : Data_(nullptr) - , Size_(0) - { } - - ~TRcBufInternalBackend() noexcept { - Release(); - } - - TRcBufInternalBackend(const TRcBufInternalBackend& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - AddRef(); - } - - TRcBufInternalBackend(TRcBufInternalBackend&& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - other.Data_ = nullptr; - other.Size_ = 0; - } - - TRcBufInternalBackend& operator=(const TRcBufInternalBackend& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - AddRef(); - } - return *this; - } - - TRcBufInternalBackend& operator=(TRcBufInternalBackend&& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - other.Data_ = nullptr; - other.Size_ = 0; - } - return *this; - } - - Y_FORCE_INLINE explicit operator bool() const { return Size_ > 0; } - - Y_FORCE_INLINE char* mutable_data() { return Data(); } - Y_FORCE_INLINE char* mutable_begin() { return Data(); } - Y_FORCE_INLINE char* mutable_end() { return Data() + Size_; } - - Y_FORCE_INLINE const char* data() const { return Data(); } - Y_FORCE_INLINE const char* begin() const { return Data(); } - Y_FORCE_INLINE const char* end() const { return Data() + Size_; } - - Y_FORCE_INLINE size_t size() const { return Size_; } - - /** - * Copies data to new allocated buffer if data is shared - * New container loses original owner - * Returns pointer to mutable buffer - */ - char* Detach() { - if (IsShared()) { - *this = TRcBufInternalBackend::Copy(data(), size()); - } - return Data_; - } - - bool IsPrivate() const { - return Data_ ? IsPrivate(Header()) : true; - } - - bool IsShared() const { - return !IsPrivate(); - } - - TString ToString() const { - return TString(data(), size()); - } - - TCookies* GetCookies() { - return Header(); - } - - /** - * Attach to pre-allocated data with a preceding THeader - */ - static TRcBufInternalBackend AttachUnsafe(char* data, size_t size) noexcept { - TRcBufInternalBackend result; - result.Data_ = data; - result.Size_ = size; - return result; - } - - /** - * Make uninitialized buffer of the specified size - */ - static TRcBufInternalBackend Uninitialized(size_t size, size_t headroom = 0, size_t tailroom = 0) { - size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom)); - return AttachUnsafe(Allocate(size, headroom, tailroom), fullSize); - } - - /** - * Make a copy of the specified data - */ - static TRcBufInternalBackend Copy(const void* data, size_t size) { - TRcBufInternalBackend result = Uninitialized(size); - if (size) { - ::memcpy(result.Data(), data, size); - } - return result; - } - -private: - Y_FORCE_INLINE THeader* Header() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return reinterpret_cast<THeader*>(Data_); - } - - Y_FORCE_INLINE char* Data() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return Data_ + OverheadSize; - } - - static bool IsPrivate(THeader* header) noexcept { - return 1 == AtomicGet(header->RefCount); - } - - void AddRef() noexcept { - if (Data_) { - AtomicIncrement(Header()->RefCount); - } - } - - void Release() noexcept { - if (Data_) { - auto* header = Header(); - if (IsPrivate(header) || 0 == AtomicDecrement(header->RefCount)) { - Deallocate(Data_); - } - } - } - -private: - static size_t checkedSum(size_t a, size_t b) { - if (a > std::numeric_limits<size_t>::max() - b) { - throw std::length_error("Allocate size overflow"); - } - return a + b; - } - - static char* Allocate(size_t size, size_t headroom = 0, size_t tailroom = 0) { - char* data = nullptr; - size_t fullSize = checkedSum(size, checkedSum(headroom, tailroom)); - if (fullSize > 0) { - if (fullSize >= MaxDataSize) { - throw std::length_error("Allocate size overflow"); - } - auto allocSize = OverheadSize + fullSize; - char* raw = reinterpret_cast<char*>(y_allocate(allocSize)); - - auto* header = reinterpret_cast<THeader*>(raw); - header->Begin = raw + OverheadSize + headroom; - header->End = raw + allocSize - tailroom; - header->RefCount = 1; - - data = raw; - } - - return data; - } - - static void Deallocate(char* data) noexcept { - if (data) { - char* raw = data; - - y_deallocate(raw); - } - } - -private: - char* Data_; - size_t Size_; -}; - -} // namespace NDetail diff --git a/library/cpp/actors/util/rc_buf_ut.cpp b/library/cpp/actors/util/rc_buf_ut.cpp deleted file mode 100644 index c23e8b68d0..0000000000 --- a/library/cpp/actors/util/rc_buf_ut.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "rc_buf.h" -#include "ut_helpers.h" -#include "rope.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -Y_UNIT_TEST_SUITE(TRcBuf) { - Y_UNIT_TEST(TypeSize) { - UNIT_ASSERT_EQUAL(sizeof(TRcBuf), 4 * sizeof(uintptr_t)); - } - - Y_UNIT_TEST(Slice) { - auto data = TRcBuf::Copy("Hello", 5); - UNIT_ASSERT_VALUES_EQUAL(TString(TStringBuf(data)), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 3)), TString("ell")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 100)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(0, 4)), TString("Hell")); - } - - Y_UNIT_TEST(CrossCompare) { - TString str = "some very long string"; - const TString constStr(str); - TStringBuf strbuf = str; - const TStringBuf constStrbuf = str; - TContiguousSpan span(str); - const TContiguousSpan constSpan(str); - TMutableContiguousSpan mutableSpan(const_cast<char*>(str.data()), str.size()); - const TMutableContiguousSpan constMutableSpan(const_cast<char*>(str.data()), str.size()); - TRcBuf data(str); - const TRcBuf constData(str); - TArrayRef<char> arrRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<char> constArrRef(const_cast<char*>(str.data()), str.size()); - TArrayRef<const char> arrConstRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<const char> constArrConstRef(const_cast<char*>(str.data()), str.size()); - NActors::TSharedData sharedData = NActors::TSharedData::Copy(str.data(), str.size()); - const NActors::TSharedData constSharedData(sharedData); - - Permutate( - [](auto& arg1, auto& arg2) { - UNIT_ASSERT(arg1 == arg2); - }, - str, - constStr, - strbuf, - constStrbuf, - span, - constSpan, - mutableSpan, - constMutableSpan, - data, - constData, - arrRef, - constArrRef, - arrConstRef, - constArrConstRef, - sharedData, - constSharedData); - } - - Y_UNIT_TEST(Detach) { - TRcBuf data = TRcBuf::Copy(TString("test")); - TRcBuf data2 = data; - char* res = data2.Detach(); - UNIT_ASSERT_UNEQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(res, data2.GetData()); - UNIT_ASSERT_EQUAL(::memcmp(res, "test", 4), 0); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - } - - Y_UNIT_TEST(Resize) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowFront(5); - UNIT_ASSERT_EQUAL(data.size(), 15); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.size(), 20); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowFront(21); - UNIT_ASSERT_EQUAL(data.size(), 41); - UNIT_ASSERT_EQUAL(data.Headroom(), 0); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 66); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - data.GrowBack(32); - UNIT_ASSERT_EQUAL(data.size(), 73); - UNIT_ASSERT_EQUAL(data.Headroom(), 0); - UNIT_ASSERT_EQUAL(data.Tailroom(), 0); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 73); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), data.size() + data.Headroom() + data.Tailroom()); - } - - Y_UNIT_TEST(ResizeUnshare) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(data); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - UNIT_ASSERT_EQUAL(otherData.size(), 10); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 20); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 60); - data.GrowFront(5); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.data() + 5, otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 20); - UNIT_ASSERT_EQUAL(data.Headroom(), 15); - UNIT_ASSERT_EQUAL(data.Tailroom(), 25); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - otherData.GrowFront(5); - UNIT_ASSERT_UNEQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(otherData.size(), 15); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 15); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 30); - UNIT_ASSERT_EQUAL(otherData.GetOccupiedMemorySize(), 60); - data.TrimBack(15); - data.TrimFront(10); - UNIT_ASSERT_EQUAL(data.size(), 10); - UNIT_ASSERT_EQUAL(data.Headroom(), 20); - UNIT_ASSERT_EQUAL(data.Tailroom(), 30); - UNIT_ASSERT_EQUAL(data.GetOccupiedMemorySize(), 60); - } - - Y_UNIT_TEST(Trim) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(data); - otherData.TrimBack(5); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 20); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 0); - TRcBuf otherData2(data); - otherData2.TrimBack(2); - otherData2.TrimFront(1); - UNIT_ASSERT_EQUAL(data.data() + 1, otherData2.data()); - UNIT_ASSERT_EQUAL(otherData2.Headroom(), 0); - UNIT_ASSERT_EQUAL(otherData2.Tailroom(), 0); - otherData.TrimBack(2); - otherData.TrimFront(1); - UNIT_ASSERT_EQUAL(otherData.data(), otherData2.data()); - data.GrowFront(5); - data.GrowBack(5); - UNIT_ASSERT_EQUAL(data.data() + 6, otherData2.data()); - UNIT_ASSERT_EQUAL(data.data() + 6, otherData.data()); - otherData.GrowFront(1); - UNIT_ASSERT_UNEQUAL(data.data() + 7, otherData.data()); - otherData2.GrowBack(1); - UNIT_ASSERT_UNEQUAL(data.data() + 6, otherData2.data()); - data = TRcBuf::Uninitialized(10); - otherData = data; - data.TrimBack(5); - UNIT_ASSERT_EQUAL(data.data(), otherData.data()); - UNIT_ASSERT_EQUAL(data.size(), 5); - } - - Y_UNIT_TEST(SliceUnshare) { - TRcBuf data = TRcBuf::Uninitialized(10, 20, 30); - TRcBuf otherData(TRcBuf::Piece, data.data() + 1, data.size() - 2, data); - UNIT_ASSERT_EQUAL(otherData.Headroom(), 0); - UNIT_ASSERT_EQUAL(otherData.Tailroom(), 0); - } - - Y_UNIT_TEST(Reserve) { - TRcBuf data = TRcBuf::Copy("test", 4, 5, 6); - TRcBuf data2 = data; - data.reserve(1); - data.ReserveTailroom(6); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - data.ReserveHeadroom(5); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Headroom(), 5); - data.ReserveBidi(5, 6); - UNIT_ASSERT_EQUAL(data.GetData(), data2.GetData()); - UNIT_ASSERT_EQUAL(data.GetSize(), data2.GetSize()); - UNIT_ASSERT_EQUAL(data.Headroom(), 5); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - data.ReserveHeadroom(6); - UNIT_ASSERT_EQUAL(data.Headroom(), 6); - UNIT_ASSERT_EQUAL(data.Tailroom(), 6); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - data.ReserveTailroom(7); - UNIT_ASSERT_EQUAL(data.Headroom(), 6); - UNIT_ASSERT_EQUAL(data.Tailroom(), 7); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - data.ReserveBidi(7, 8); - UNIT_ASSERT_EQUAL(data.Headroom(), 7); - UNIT_ASSERT_EQUAL(data.Tailroom(), 8); - UNIT_ASSERT_EQUAL(::memcmp(data.GetData(), "test", 4), 0); - } -} diff --git a/library/cpp/actors/util/recentwnd.h b/library/cpp/actors/util/recentwnd.h deleted file mode 100644 index 0f5ee17fa0..0000000000 --- a/library/cpp/actors/util/recentwnd.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include <util/generic/deque.h> - -template <typename TElem, - template <typename, typename...> class TContainer = TDeque> -class TRecentWnd { -public: - TRecentWnd(ui32 wndSize) - : MaxWndSize_(wndSize) - { - } - - void Push(const TElem& elem) { - if (Window_.size() == MaxWndSize_) - Window_.erase(Window_.begin()); - Window_.emplace_back(elem); - } - - void Push(TElem&& elem) { - if (Window_.size() == MaxWndSize_) - Window_.erase(Window_.begin()); - Window_.emplace_back(std::move(elem)); - } - - TElem& Last() { - return Window_.back(); - } - const TElem& Last() const { - return Window_.back(); - } - bool Full() const { - return Window_.size() == MaxWndSize_; - } - ui64 Size() const { - return Window_.size(); - } - - using const_iterator = typename TContainer<TElem>::const_iterator; - - const_iterator begin() { - return Window_.begin(); - } - const_iterator end() { - return Window_.end(); - } - - void Reset(ui32 wndSize = 0) { - Window_.clear(); - if (wndSize != 0) { - MaxWndSize_ = wndSize; - } - } - - void ResetWnd(ui32 wndSize) { - Y_ABORT_UNLESS(wndSize != 0); - MaxWndSize_ = wndSize; - if (Window_.size() > MaxWndSize_) { - Window_.erase(Window_.begin(), - Window_.begin() + Window_.size() - MaxWndSize_); - } - } - -private: - TContainer<TElem> Window_; - ui32 MaxWndSize_; -}; diff --git a/library/cpp/actors/util/rope.cpp b/library/cpp/actors/util/rope.cpp deleted file mode 100644 index 0927774099..0000000000 --- a/library/cpp/actors/util/rope.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "rope.h" -#include <library/cpp/containers/absl_flat_hash/flat_hash_set.h> - -size_t TRope::GetOccupiedMemorySize() const { - size_t res = 0; - absl::flat_hash_set<const void*> chunks; - for (const auto& chunk : Chain) { - if (const auto [it, inserted] = chunks.insert(chunk.Backend.UniqueId()); inserted) { - res += chunk.Backend.GetOccupiedMemorySize(); - } - } - return res; -} diff --git a/library/cpp/actors/util/rope.h b/library/cpp/actors/util/rope.h deleted file mode 100644 index b092d502cd..0000000000 --- a/library/cpp/actors/util/rope.h +++ /dev/null @@ -1,1148 +0,0 @@ -#pragma once - -#include <util/generic/ptr.h> -#include <util/generic/string.h> -#include <util/generic/hash_set.h> -#include <util/generic/scope.h> -#include <util/stream/zerocopy.h> -#include <util/stream/str.h> -#include <util/system/sanitizers.h> -#include <util/system/valgrind.h> - -// exactly one of them must be included -#include "rope_cont_embedded_list.h" -//#include "rope_cont_list.h" -//#include "rope_cont_deque.h" - -#include "rc_buf.h" - -class TRopeAlignedBuffer : public IContiguousChunk { - static constexpr size_t Alignment = 16; - static constexpr size_t MallocAlignment = sizeof(size_t); - - ui32 Size; - const ui32 Capacity; - const ui32 Offset; - alignas(Alignment) char Data[]; - - TRopeAlignedBuffer(size_t size) - : Size(size) - , Capacity(size) - , Offset((Alignment - reinterpret_cast<uintptr_t>(Data)) & (Alignment - 1)) - { - Y_ABORT_UNLESS(Offset <= Alignment - MallocAlignment); - } - -public: - static TIntrusivePtr<TRopeAlignedBuffer> Allocate(size_t size) { - return new(malloc(sizeof(TRopeAlignedBuffer) + size + Alignment - MallocAlignment)) TRopeAlignedBuffer(size); - } - - void *operator new(size_t) { - Y_ABORT(); - } - - void *operator new(size_t, void *ptr) { - return ptr; - } - - void operator delete(void *ptr) { - free(ptr); - } - - void operator delete(void* p, void* ptr) { - Y_UNUSED(p); - Y_UNUSED(ptr); - } - - TContiguousSpan GetData() const override { - return {Data + Offset, Size}; - } - - TMutableContiguousSpan GetDataMut() override { - return {Data + Offset, Size}; - } - - size_t GetOccupiedMemorySize() const override { - return Capacity; - } - - size_t GetCapacity() const { - return Capacity; - } - - char *GetBuffer() { - return Data + Offset; - } -}; - -namespace NRopeDetails { - - template<bool IsConst, typename TRope, typename TList> - struct TIteratorTraits; - - template<typename TRope, typename TList> - struct TIteratorTraits<true, TRope, TList> { - using TRopePtr = const TRope*; - using TListIterator = typename TList::const_iterator; - }; - - template<typename TRope, typename TList> - struct TIteratorTraits<false, TRope, TList> { - using TRopePtr = TRope*; - using TListIterator = typename TList::iterator; - }; - -} // NRopeDetails - -class TRopeArena; - -template<typename T> -struct always_false : std::false_type {}; - -class TRope { - friend class TRopeArena; - - using TChunkList = NRopeDetails::TChunkList<TRcBuf>; - -private: - // we use list here to store chain items as we have to keep valid iterators when erase/insert operations are invoked; - // iterator uses underlying container's iterator, so we have to use container that keeps valid iterators on delete, - // thus, the list - TChunkList Chain; - size_t Size = 0; - -private: - template<bool IsConst> - class TIteratorImpl { - using TTraits = NRopeDetails::TIteratorTraits<IsConst, TRope, TChunkList>; - - typename TTraits::TRopePtr Rope; - typename TTraits::TListIterator Iter; - const char *Ptr; // ptr is always nullptr when iterator is positioned at the rope end - -#ifndef NDEBUG - ui32 ValidityToken; -#endif - - private: - TIteratorImpl(typename TTraits::TRopePtr rope, typename TTraits::TListIterator iter, const char *ptr = nullptr) - : Rope(rope) - , Iter(iter) - , Ptr(ptr) -#ifndef NDEBUG - , ValidityToken(Rope->GetValidityToken()) -#endif - {} - - public: - TIteratorImpl() - : Rope(nullptr) - , Ptr(nullptr) - {} - - template<bool IsOtherConst> - TIteratorImpl(const TIteratorImpl<IsOtherConst>& other) - : Rope(other.Rope) - , Iter(other.Iter) - , Ptr(other.Ptr) -#ifndef NDEBUG - , ValidityToken(other.ValidityToken) -#endif - {} - - void CheckValid() const { -#ifndef NDEBUG - Y_ABORT_UNLESS(ValidityToken == Rope->GetValidityToken()); - Y_ABORT_UNLESS(Iter == Rope->Chain.end() || Iter->Backend); -#endif - } - - TIteratorImpl& operator +=(size_t amount) { - CheckValid(); - - while (amount) { - Y_DEBUG_ABORT_UNLESS(Valid()); - const size_t max = ContiguousSize(); - const size_t num = std::min(amount, max); - amount -= num; - Ptr += num; - if (Ptr == Iter->End) { - AdvanceToNextContiguousBlock(); - } - } - - return *this; - } - - TIteratorImpl operator +(size_t amount) const { - CheckValid(); - - return TIteratorImpl(*this) += amount; - } - - TIteratorImpl& operator -=(size_t amount) { - CheckValid(); - - while (amount) { - const size_t num = Ptr ? std::min<size_t>(amount, Ptr - Iter->Begin) : 0; - amount -= num; - Ptr -= num; - if (amount) { - Y_DEBUG_ABORT_UNLESS(Iter != GetChainBegin()); - --Iter; - Ptr = Iter->End; - } - } - - return *this; - } - - TIteratorImpl operator -(size_t amount) const { - CheckValid(); - return TIteratorImpl(*this) -= amount; - } - - std::pair<const char*, size_t> operator *() const { - return {ContiguousData(), ContiguousSize()}; - } - - TIteratorImpl& operator ++() { - AdvanceToNextContiguousBlock(); - return *this; - } - - TIteratorImpl operator ++(int) const { - auto it(*this); - it.AdvanceToNextContiguousBlock(); - return it; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operation with contiguous data - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - // Get the pointer to the contiguous block of data; valid locations are [Data; Data + Size). - const char *ContiguousData() const { - CheckValid(); - return Ptr; - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - char *ContiguousDataMut() { - CheckValid(); - return GetChunk().GetDataMut(); - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - char *UnsafeContiguousDataMut() { - CheckValid(); - return GetChunk().UnsafeGetDataMut(); - } - - // Get the amount of contiguous block. - size_t ContiguousSize() const { - CheckValid(); - return Ptr ? Iter->End - Ptr : 0; - } - - size_t ChunkOffset() const { - return Ptr ? Ptr - Iter->Begin : 0; - } - - // Advance to next contiguous block of data. - void AdvanceToNextContiguousBlock() { - CheckValid(); - Y_DEBUG_ABORT_UNLESS(Valid()); - ++Iter; - Ptr = Iter != GetChainEnd() ? Iter->Begin : nullptr; - } - - // Extract some data and advance. Size is not checked here, to it must be provided valid. - void ExtractPlainDataAndAdvance(void *buffer, size_t len) { - CheckValid(); - - while (len) { - Y_DEBUG_ABORT_UNLESS(Ptr); - - // calculate amount of bytes we need to move - const size_t max = ContiguousSize(); - const size_t num = std::min(len, max); - - // copy data to the buffer and advance buffer pointers - memcpy(buffer, Ptr, num); - buffer = static_cast<char*>(buffer) + num; - len -= num; - - // advance iterator itself - Ptr += num; - if (Ptr == Iter->End) { - AdvanceToNextContiguousBlock(); - } - } - } - - // Checks if the iterator points to the end of the rope or not. - bool Valid() const { - CheckValid(); - return Ptr; - } - - template<bool IsOtherConst> - bool operator ==(const TIteratorImpl<IsOtherConst>& other) const { - Y_DEBUG_ABORT_UNLESS(Rope == other.Rope); - CheckValid(); - other.CheckValid(); - return Iter == other.Iter && Ptr == other.Ptr; - } - - template<bool IsOtherConst> - bool operator !=(const TIteratorImpl<IsOtherConst>& other) const { - CheckValid(); - other.CheckValid(); - return !(*this == other); - } - - private: - friend class TRope; - - typename TTraits::TListIterator operator ->() const { - CheckValid(); - return Iter; - } - - const TRcBuf& GetChunk() const { - CheckValid(); - return *Iter; - } - - template<bool Mut = !IsConst, std::enable_if_t<Mut, bool> = true> - TRcBuf& GetChunk() { - CheckValid(); - return *Iter; - } - - typename TTraits::TListIterator GetChainBegin() const { - CheckValid(); - return Rope->Chain.begin(); - } - - typename TTraits::TListIterator GetChainEnd() const { - CheckValid(); - return Rope->Chain.end(); - } - - bool PointsToChunkMiddle() const { - CheckValid(); - return Ptr && Ptr != Iter->Begin; - } - }; - -public: -#ifndef NDEBUG - ui32 ValidityToken = 0; - ui32 GetValidityToken() const { return ValidityToken; } - void InvalidateIterators() { ++ValidityToken; } -#else - void InvalidateIterators() {} -#endif - -public: - using TConstIterator = TIteratorImpl<true>; - using TIterator = TIteratorImpl<false>; - -public: - TRope() = default; - TRope(const TRope& rope) = default; - - TRope(const TRcBuf& data) { - if(!data.HasBuffer()) { - return; - } - Size = data.GetSize(); - Chain.PutToEnd(data); - } - - TRope(TRcBuf&& data) { - if(!data.HasBuffer()) { - return; - } - Size = data.GetSize(); - Chain.PutToEnd(std::move(data)); - } - - TRope(TRope&& rope) - : Chain(std::move(rope.Chain)) - , Size(std::exchange(rope.Size, 0)) - { - rope.InvalidateIterators(); - } - - explicit TRope(TString s) { - if (s) { - Size = s.size(); - if (s.capacity() < 32) { - s.reserve(32); - } - Chain.PutToEnd(std::move(s)); - } - } - - explicit TRope(NActors::TSharedData s) { - Size = s.size(); - Chain.PutToEnd(std::move(s)); - } - - TRope(IContiguousChunk::TPtr item) { - Size = item->GetData().size(); - Chain.PutToEnd(std::move(item)); - } - - TRope(TConstIterator begin, TConstIterator end) { - Y_DEBUG_ABORT_UNLESS(begin.Rope == end.Rope); - if (begin.Rope == this) { - TRope temp(begin, end); - *this = std::move(temp); - return; - } - - while (begin.Iter != end.Iter) { - const size_t size = begin.ContiguousSize(); - Chain.PutToEnd(TRcBuf::Piece, begin.ContiguousData(), size, begin.GetChunk()); - begin.AdvanceToNextContiguousBlock(); - Size += size; - } - - if (begin != end && end.PointsToChunkMiddle()) { - Chain.PutToEnd(TRcBuf::Piece, begin.Ptr, end.Ptr, begin.GetChunk()); - Size += end.Ptr - begin.Ptr; - } - } - - ~TRope() { - } - - // creates a copy of rope with chunks with inefficient storage ratio being copied with arena allocator - static TRope CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena); - - TRope& operator=(const TRope& other) { - Chain = other.Chain; - Size = other.Size; - return *this; - } - - TRope& operator=(TRope&& other) { - Chain = std::move(other.Chain); - Size = std::exchange(other.Size, 0); - InvalidateIterators(); - other.InvalidateIterators(); - return *this; - } - - size_t GetSize() const { - return Size; - } - - size_t size() const { - return Size; - } - - size_t capacity() const { - return Size; - } - - bool IsEmpty() const { - return !Size; - } - - bool empty() const { - return IsEmpty(); - } - - operator bool() const { - return Chain; - } - - TIterator Begin() { - return *this ? TIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End(); - } - - TIterator End() { - return TIterator(this, Chain.end()); - } - - TIterator Iterator(TChunkList::iterator it) { - return TIterator(this, it, it != Chain.end() ? it->Begin : nullptr); - } - - TIterator Position(size_t index) { - return Begin() + index; - } - - TConstIterator Begin() const { - return *this ? TConstIterator(this, Chain.begin(), Chain.GetFirstChunk().Begin) : End(); - } - - TConstIterator End() const { - return TConstIterator(this, Chain.end()); - } - - TConstIterator Position(size_t index) const { - return Begin() + index; - } - - TConstIterator begin() const { return Begin(); } - TConstIterator end() const { return End(); } - - void Erase(TIterator begin, TIterator end) { - Cut(begin, end, nullptr); - } - - TRope Extract(TIterator begin, TIterator end) { - TRope res; - Cut(begin, end, &res); - return res; - } - - void ExtractFront(size_t num, TRope *dest) { - Y_ABORT_UNLESS(Size >= num); - if (num == Size && !*dest) { - *dest = std::move(*this); - return; - } - Size -= num; - dest->Size += num; - - TChunkList::iterator first = Chain.begin(); - - if (num >= first->GetSize() && dest->Chain) { // see if we can glue first chunk to the destination rope - auto& last = dest->Chain.GetLastChunk(); - if (last.Backend == first->Backend && last.End == first->Begin) { - last.End = first->End; - num -= first->GetSize(); - first = Chain.Erase(first); - } - } - - TChunkList::iterator it; - for (it = first; num && num >= it->GetSize(); ++it) { - num -= it->GetSize(); - } - first = dest->Chain.Splice(dest->Chain.end(), Chain, first, it); - - if (num) { // still more data to extract - if (dest->Chain) { - auto& last = dest->Chain.GetLastChunk(); - if (last.Backend == first->Backend && last.End == first->Begin) { - first->Begin += num; - last.End = first->Begin; - return; - } - } - dest->Chain.PutToEnd(TRcBuf::Piece, first->Begin, first->Begin + num, *first); - first->Begin += num; - } - } - - void Insert(TIterator pos, TRope&& rope) { - Y_DEBUG_ABORT_UNLESS(this == pos.Rope); - Y_DEBUG_ABORT_UNLESS(this != &rope); - - if (!rope) { - return; // do nothing for empty rope - } - - // adjust size - Size += std::exchange(rope.Size, 0); - - // check if we have to split the block - if (pos.PointsToChunkMiddle()) { - pos.Iter = Chain.InsertBefore(pos.Iter, TRcBuf::Piece, pos->Begin, pos.Ptr, pos.GetChunk()); - ++pos.Iter; - pos->Begin = pos.Ptr; - } - - // perform glueing if possible - TRcBuf *ropeLeft = &rope.Chain.GetFirstChunk(); - TRcBuf *ropeRight = &rope.Chain.GetLastChunk(); - bool gluedLeft = false, gluedRight = false; - if (pos.Iter != Chain.begin()) { // glue left part whenever possible - // obtain iterator to previous chunk - auto prev(pos.Iter); - --prev; - if (prev->End == ropeLeft->Begin && prev->Backend == ropeLeft->Backend) { // it is glueable - prev->End = ropeLeft->End; - gluedLeft = true; - } - } - if (pos.Iter != Chain.end() && ropeRight->End == pos->Begin && ropeRight->Backend == pos->Backend) { - pos->Begin = ropeRight->Begin; - gluedRight = true; - } - if (gluedLeft) { - rope.Chain.EraseFront(); - } - if (gluedRight) { - if (rope) { - rope.Chain.EraseBack(); - } else { // it looks like double-glueing for the same chunk, we have to drop previous one - auto prev(pos.Iter); - --prev; - pos->Begin = prev->Begin; - pos.Iter = Chain.Erase(prev); - } - } - if (rope) { // insert remains - Chain.Splice(pos.Iter, rope.Chain, rope.Chain.begin(), rope.Chain.end()); - } - Y_DEBUG_ABORT_UNLESS(!rope); - InvalidateIterators(); - } - - void EraseFront(size_t len) { - Y_DEBUG_ABORT_UNLESS(Size >= len); - Size -= len; - - while (len) { - Y_DEBUG_ABORT_UNLESS(Chain); - TRcBuf& item = Chain.GetFirstChunk(); - const size_t itemSize = item.GetSize(); - if (len >= itemSize) { - Chain.EraseFront(); - len -= itemSize; - } else { - item.Begin += len; - break; - } - } - - InvalidateIterators(); - } - - void EraseBack(size_t len) { - Y_DEBUG_ABORT_UNLESS(Size >= len); - Size -= len; - - while (len) { - Y_DEBUG_ABORT_UNLESS(Chain); - TRcBuf& item = Chain.GetLastChunk(); - const size_t itemSize = item.GetSize(); - if (len >= itemSize) { - Chain.EraseBack(); - len -= itemSize; - } else { - item.End -= len; - break; - } - } - - InvalidateIterators(); - } - - bool ExtractFrontPlain(void *buffer, size_t len) { - // check if we have enough data in the rope - if (Size < len) { - return false; - } - Size -= len; - while (len) { - auto& chunk = Chain.GetFirstChunk(); - Y_DEBUG_ABORT_UNLESS(chunk.Backend); - const size_t num = Min(len, chunk.GetSize()); - memcpy(buffer, chunk.Begin, num); - buffer = static_cast<char*>(buffer) + num; - len -= num; - chunk.Begin += num; - if (chunk.Begin == chunk.End) { - Chain.EraseFront(); - } - } - InvalidateIterators(); - return true; - } - - bool FetchFrontPlain(char **ptr, size_t *remain) { - const size_t num = Min(*remain, Size); - ExtractFrontPlain(*ptr, num); - *ptr += num; - *remain -= num; - return !*remain; - } - - static int Compare(const TRope& x, const TRope& y) { - TConstIterator xIter = x.Begin(), yIter = y.Begin(); - while (xIter.Valid() && yIter.Valid()) { - const size_t step = std::min(xIter.ContiguousSize(), yIter.ContiguousSize()); - if (int res = memcmp(xIter.ContiguousData(), yIter.ContiguousData(), step)) { - return res; - } - xIter += step; - yIter += step; - } - return xIter.Valid() - yIter.Valid(); - } - - static int Compare(const TRope& x, const TContiguousSpan& y) { - TConstIterator xIter = x.Begin(); - const char* yData = y.data(); - size_t yOffset = 0; - while (xIter.Valid() && yOffset != y.size()) { - const size_t step = std::min(xIter.ContiguousSize(), y.size() - yOffset); - if (int res = memcmp(xIter.ContiguousData(), yData + yOffset, step)) { - return res; - } - xIter += step; - yOffset += step; - } - return xIter.Valid() - (yOffset != y.size()); - } - - static int Compare(const TContiguousSpan& x, const TRope& y) { - return -Compare(y, x); - } - - // Use this method carefully -- it may significantly reduce performance when misused. - TString ConvertToString() const { - return ExtractUnderlyingContainerOrCopy<TString>(); - } - - /** - * WARN: this method supports extracting only for natively supported types for any other type the data *will* be copied - */ - template <class TResult> - TResult ExtractUnderlyingContainerOrCopy() const { - if (Chain.begin() != Chain.end() && ++Chain.begin() == Chain.end()) { - return Chain.GetFirstChunk().ExtractUnderlyingContainerOrCopy<TResult>(); - } - - const size_t size = GetSize(); - TResult res = TResult::Uninitialized(size); - char* data = NContiguousDataDetails::TContainerTraits<TResult>::UnsafeGetDataMut(res); - Begin().ExtractPlainDataAndAdvance(data, size); - return res; - } - - void clear() { - Erase(Begin(), End()); - } - - bool IsContiguous() const { - if(Begin() == End() || (++Begin() == End())) { - return true; - } - return false; - } - - void Compact(size_t headroom = 0, size_t tailroom = 0) { - if(!IsContiguous()) { - // TODO(innokentii): use better container, when most outer users stop use TString - TRcBuf res = TRcBuf::Uninitialized(GetSize(), headroom, tailroom); - Begin().ExtractPlainDataAndAdvance(res.UnsafeGetDataMut(), res.size()); - Erase(Begin(), End()); - Insert(End(), TRope(res)); - } - } - - static TRope Uninitialized(size_t size) - { - TRcBuf res = TRcBuf::Uninitialized(size); - return TRope(res); - } - - /** - * Compacts data and calls GetData() on undelying container - * WARN: Will copy if data isn't contiguous - */ - TContiguousSpan GetContiguousSpan() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->GetContiguousSpan(); - } - - /** - * Compacts data and calls GetDataMut() on undelying container - * WARN: Will copy if data isn't contiguous - */ - TMutableContiguousSpan GetContiguousSpanMut() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->GetContiguousSpanMut(); - } - - /** - * Compacts data and calls UnsafeGetDataMut() on undelying container - * WARN: Will copy if data isn't contiguous - * WARN: Even if underlying container is shared - returns reference to its underlying data - */ - TMutableContiguousSpan UnsafeGetContiguousSpanMut() { - if(Begin() == End()) { - return {nullptr, 0}; - } - Compact(); - return Begin()->UnsafeGetContiguousSpanMut(); - } - - TString DebugString() const { - TStringStream s; - s << "{Size# " << Size; - for (const auto& chunk : Chain) { - const char *data; - data = chunk.Backend.GetData().data(); - s << " [" << chunk.Begin - data << ", " << chunk.End - data << ")@" << chunk.Backend.UniqueId(); - } - s << "}"; - return s.Str(); - } - - explicit operator TRcBuf() { - if(GetSize() == 0) { - return TRcBuf(); - } - Compact(); - return TRcBuf(Begin().GetChunk()); - } - - size_t GetOccupiedMemorySize() const; - - friend bool operator==(const TRope& x, const TRope& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TRope& x, const TRope& y) { return Compare(x, y) != 0; } - friend bool operator< (const TRope& x, const TRope& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TRope& x, const TRope& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TRope& x, const TRope& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TRope& x, const TRope& y) { return Compare(x, y) >= 0; } - - friend bool operator==(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) != 0; } - friend bool operator< (const TRope& x, const TContiguousSpan& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TRope& x, const TContiguousSpan& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TRope& x, const TContiguousSpan& y) { return Compare(x, y) >= 0; } - - friend bool operator==(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) == 0; } - friend bool operator!=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) != 0; } - friend bool operator< (const TContiguousSpan& x, const TRope& y) { return Compare(x, y) < 0; } - friend bool operator<=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) <= 0; } - friend bool operator> (const TContiguousSpan& x, const TRope& y) { return Compare(x, y) > 0; } - friend bool operator>=(const TContiguousSpan& x, const TRope& y) { return Compare(x, y) >= 0; } - - // FIXME(innokentii) temporary hack - friend bool operator==(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) == 0; } - friend bool operator!=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) != 0; } - friend bool operator< (const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) < 0; } - friend bool operator<=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) <= 0; } - friend bool operator> (const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) > 0; } - friend bool operator>=(const TRope& x, const TRcBuf& y) { return Compare(x, y.GetContiguousSpan()) >= 0; } - - friend bool operator==(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) == 0; } - friend bool operator!=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) != 0; } - friend bool operator< (const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) < 0; } - friend bool operator<=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) <= 0; } - friend bool operator> (const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) > 0; } - friend bool operator>=(const TRcBuf& x, const TRope& y) { return Compare(x.GetContiguousSpan(), y) >= 0; } - - -private: - void Cut(TIterator begin, TIterator end, TRope *target) { - // ensure all iterators are belong to us - Y_DEBUG_ABORT_UNLESS(this == begin.Rope && this == end.Rope); - - // if begin and end are equal, we do nothing -- checking this case allows us to find out that begin does not - // point to End(), for example - if (begin == end) { - return; - } - - auto addBlock = [&](const TRcBuf& from, const char *begin, const char *end) { - if (target) { - target->Chain.PutToEnd(TRcBuf::Piece, begin, end, from); - target->Size += end - begin; - } - Size -= end - begin; - }; - - // consider special case -- when begin and end point to the same block; in this case we have to split up this - // block into two parts - if (begin.Iter == end.Iter) { - TRcBuf chunkToSplit = begin.GetChunk(); - addBlock(chunkToSplit, begin.Ptr, end.Ptr); - const char *firstChunkBegin = begin.PointsToChunkMiddle() ? begin->Begin : nullptr; - begin->Begin = end.Ptr; // this affects both begin and end iterator pointed values - if (firstChunkBegin) { - Chain.InsertBefore(begin.Iter, TRcBuf::Piece, firstChunkBegin, begin.Ptr, chunkToSplit); - } - } else { - // check the first iterator -- if it starts not from the begin of the block, we have to adjust end of the - // first block to match begin iterator and switch to next block - if (begin.PointsToChunkMiddle()) { - addBlock(begin.GetChunk(), begin.Ptr, begin->End); - begin->End = begin.Ptr; - begin.AdvanceToNextContiguousBlock(); - } - - // now drop full blocks - size_t rangeSize = 0; - for (auto it = begin.Iter; it != end.Iter; ++it) { - Y_DEBUG_ABORT_UNLESS(it->GetSize()); - rangeSize += it->GetSize(); - } - if (rangeSize) { - if (target) { - end.Iter = target->Chain.Splice(target->Chain.end(), Chain, begin.Iter, end.Iter); - target->Size += rangeSize; - } else { - end.Iter = Chain.Erase(begin.Iter, end.Iter); - } - Size -= rangeSize; - } - - // and cut the last block if necessary - if (end.PointsToChunkMiddle()) { - addBlock(end.GetChunk(), end->Begin, end.Ptr); - end->Begin = end.Ptr; - } - } - - InvalidateIterators(); - } -}; - -class TRopeArena { - using TAllocateCallback = std::function<TIntrusivePtr<IContiguousChunk>()>; - - TAllocateCallback Allocator; - TRope Arena; - -public: - TRopeArena(TAllocateCallback&& allocator) - : Allocator(std::move(allocator)) - {} - - TRope CreateRope(const void *buffer, size_t len) { - TRope res; - - while (len) { - if (Arena) { - auto iter = Arena.Begin(); - Y_DEBUG_ABORT_UNLESS(iter.Valid()); - char *dest = const_cast<char*>(iter.ContiguousData()); - const size_t bytesToCopy = std::min(len, iter.ContiguousSize()); - memcpy(dest, buffer, bytesToCopy); - buffer = static_cast<const char*>(buffer) + bytesToCopy; - len -= bytesToCopy; - res.Insert(res.End(), Arena.Extract(Arena.Begin(), Arena.Position(bytesToCopy))); - } else { - Arena.Insert(Arena.End(), TRope(Allocator())); - } - } - - // align arena on 8-byte boundary - const size_t align = 8; - if (const size_t padding = Arena.GetSize() % align) { - Arena.EraseFront(padding); - } - - return res; - } -}; - -struct TRopeUtils { - static void Memset(TRope::TConstIterator dst, char c, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid()); - size_t len = std::min(size, dst.ContiguousSize()); - memset(const_cast<char*>(dst.ContiguousData()), c, len); - dst += len; - size -= len; - } - } - - static void Memcpy(TRope::TConstIterator dst, TRope::TConstIterator src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid() && src.Valid(), - "Invalid iterator in memcpy: dst.Valid() - %" PRIu32 ", src.Valid() - %" PRIu32, - (ui32)dst.Valid(), (ui32)src.Valid()); - size_t len = std::min(size, std::min(dst.ContiguousSize(), src.ContiguousSize())); - memcpy(const_cast<char*>(dst.ContiguousData()), src.ContiguousData(), len); - dst += len; - src += len; - size -= len; - } - } - - static void Memcpy(TRope::TConstIterator dst, const char* src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(dst.Valid()); - size_t len = std::min(size, dst.ContiguousSize()); - memcpy(const_cast<char*>(dst.ContiguousData()), src, len); - size -= len; - dst += len; - src += len; - } - } - - static void Memcpy(char* dst, TRope::TConstIterator src, size_t size) { - while (size) { - Y_DEBUG_ABORT_UNLESS(src.Valid()); - size_t len = std::min(size, src.ContiguousSize()); - memcpy(dst, src.ContiguousData(), len); - size -= len; - dst += len; - src += len; - } - } - - // copy less or equal to sizeBound bytes, until src is valid - static size_t SafeMemcpy(char* dst, TRope::TIterator src, size_t sizeBound) { - size_t origSize = sizeBound; - while (sizeBound && src.Valid()) { - size_t len = Min(sizeBound, src.ContiguousSize()); - memcpy(dst, src.ContiguousData(), len); - sizeBound -= len; - dst += len; - src += len; - } - return origSize - sizeBound; - } -}; - -template<size_t BLOCK, size_t ALIGN = 16> -class TRopeSlideView { - alignas(ALIGN) char Slide[BLOCK]; // use if distance from current point and next chunk is less than BLOCK - TRope::TIterator Position; // current position at rope - size_t Size; - char* Head; // points to data, it might be current rope chunk or Slide - -private: - void FillBlock() { - size_t chunkSize = Position.ContiguousSize(); - if (chunkSize >= BLOCK) { - Size = chunkSize; - Head = const_cast<char*>(Position.ContiguousData()); - } else { - Size = TRopeUtils::SafeMemcpy(Slide, Position, BLOCK); - Head = Slide; - } - } - -public: - TRopeSlideView(TRope::TIterator position) - : Position(position) - { - FillBlock(); - } - - TRopeSlideView(TRope &rope) - : TRopeSlideView(rope.Begin()) - {} - - // if view on slide then copy slide to rope - void FlushBlock() { - if (Head == Slide) { - TRopeUtils::Memcpy(Position, Head, Size); - } - } - - TRope::TIterator operator+=(size_t amount) { - Position += amount; - FillBlock(); - return Position; - } - - TRope::TIterator GetPosition() const { - return Position; - } - - char* GetHead() const { - return Head; - } - - ui8* GetUi8Head() const { - return reinterpret_cast<ui8*>(Head); - } - - size_t ContiguousSize() const { - return Size; - } - - bool IsOnChunk() const { - return Head != Slide; - } -}; - -class TRopeZeroCopyInput : public IZeroCopyInput { - TRope::TConstIterator Iter; - const char* Data = nullptr; - size_t Len = 0; - -private: - size_t DoNext(const void** ptr, size_t len) override { - Y_DEBUG_ABORT_UNLESS(ptr); - if (Len == 0) { - if (Iter.Valid()) { - Data = Iter.ContiguousData(); - Len = Iter.ContiguousSize(); - Y_DEBUG_ABORT_UNLESS(Len); - Y_DEBUG_ABORT_UNLESS(Data); - ++Iter; - } else { - Data = nullptr; - } - } - - size_t chunk = std::min(Len, len); - *ptr = Data; - Data += chunk; - Len -= chunk; - return chunk; - } - -public: - explicit TRopeZeroCopyInput(TRope::TConstIterator iter) - : Iter(iter) - { - } -}; - -inline TRope TRope::CopySpaceOptimized(TRope&& origin, size_t worstRatioPer1k, TRopeArena& arena) { - TRope res; - for (TRcBuf& chunk : origin.Chain) { - size_t ratio = chunk.GetSize() * 1024 / chunk.GetOccupiedMemorySize(); - if (ratio < 1024 - worstRatioPer1k) { - res.Insert(res.End(), arena.CreateRope(chunk.Begin, chunk.GetSize())); - } else { - res.Chain.PutToEnd(std::move(chunk)); - } - } - res.Size = origin.Size; - origin = TRope(); - return res; -} - - -#if defined(WITH_VALGRIND) || defined(_msan_enabled_) - -inline void CheckRopeIsDefined(TRope::TConstIterator begin, ui64 size) { - while (size) { - ui64 contiguousSize = Min(size, begin.ContiguousSize()); -# if defined(WITH_VALGRIND) - VALGRIND_CHECK_MEM_IS_DEFINED(begin.ContiguousData(), contiguousSize); -# endif -# if defined(_msan_enabled_) - NSan::CheckMemIsInitialized(begin.ContiguousData(), contiguousSize); -# endif - size -= contiguousSize; - begin += contiguousSize; - } -} - -# define CHECK_ROPE_IS_DEFINED(begin, size) CheckRopeIsDefined(begin, size) - -#else - -# define CHECK_ROPE_IS_DEFINED(begin, size) do {} while (false) - -#endif diff --git a/library/cpp/actors/util/rope_cont_embedded_list.h b/library/cpp/actors/util/rope_cont_embedded_list.h deleted file mode 100644 index 294599538f..0000000000 --- a/library/cpp/actors/util/rope_cont_embedded_list.h +++ /dev/null @@ -1,391 +0,0 @@ -#pragma once - -#include <util/generic/intrlist.h> - -#include <util/random/random.h> - -namespace NRopeDetails { - -template<typename TChunk> -class TChunkList { - struct TItem : TChunk { - TItem *Next = nullptr; - TItem *Prev = nullptr; -#ifndef NDEBUG - ui64 ValidityToken = RandomNumber<ui64>(); -#endif - - template<typename... TArgs> TItem(TArgs&&... args) : TChunk(std::forward<TArgs>(args)...) {} - - ~TItem() { - Invalidate(); - if (IsInUse()) { - Unlink(); - } - } - - void LinkBefore(TItem *item) { - Next = item; - Prev = item->Prev; - Next->Prev = Prev->Next = this; - } - - void Unlink() { - Next->Prev = Prev; - Prev->Next = Next; - } - - bool IsInUse() const { - return Next != nullptr; - } - - void ClearSingleItem() { - Y_DEBUG_ABORT_UNLESS(Next == this && Prev == this); - static_cast<TChunk&>(*this) = {}; - Next = Prev = nullptr; - } - - template<typename... TArgs> - TItem *PrepareForUse(TArgs&&... args) { - Y_DEBUG_ABORT_UNLESS(!IsInUse()); - static_cast<TChunk&>(*this) = TChunk(std::forward<TArgs>(args)...); - Next = Prev = this; - Invalidate(); - return this; - } - - static void TransferRange(TItem *insertBefore, TItem *first, TItem *last) { // [first, last] -> insertBefore - first->Prev->Next = last->Next; - last->Next->Prev = first->Prev; - first->Prev = insertBefore->Prev; - last->Next = insertBefore; - first->Prev->Next = first; - last->Next->Prev = last; - } - - void Invalidate() { -#ifndef NDEBUG - ValidityToken = RandomNumber<ui64>(); -#endif - } - }; - - // There are three possible states for the list: - // 1. It is empty. Next = Prev = nullptr, TChunk is default-constructed. - // 2. It contains single item. Next = Prev = &Root, TChunk contains data. - // 3. It has more than one item. Next and Prev make up a double-linked list starting with Root item; TChunk contains - // first item. - // This container scheme leads to the following properties: - // 1. Deleting first item in the list invalidates iterators to the first two items. - // 2. Inserting something before the first item also invalidates iterators to the first two items. - // This happens because Root is always the first element of the list and when inserting before the Root, we have to - // shift original Root element to the allocated item and replace Root with newly inserted value. - // This also makes right-to-left traversing more efficient in some cases. - TItem Root; - - template<typename... TArgs> - TItem *AllocateItem(TArgs&&... args) { - return Root.IsInUse() - ? new TItem{std::forward<TArgs>(args)...} - : Root.PrepareForUse(std::forward<TArgs>(args)...); - } - -private: - template<bool IsConst> - class TIterator { - friend class TChunkList; - - using TChunkListType = std::conditional_t<IsConst, const TChunkList, TChunkList>; - using TItemType = std::conditional_t<IsConst, const TItem, TItem>; - using TChunkType = std::conditional_t<IsConst, const TChunk, TChunk>; - - TChunkListType *Cont = nullptr; - TItemType *Item = nullptr; -#ifndef NDEBUG - ui64 ValidityToken = 0; -#endif - - private: - TIterator(TChunkListType *cont, TItemType *item) - : Cont(cont) - , Item(item) - { - UpdateValidityToken(); - } - - public: - TIterator() = default; - - template<bool OtherIsConst, typename = std::enable_if_t<OtherIsConst <= IsConst>> - TIterator(const TIterator<OtherIsConst>& other) - : Cont(other.Cont) - , Item(other.Item) - { - UpdateValidityToken(); - } - - TChunkType& operator *() const { - CheckValid(); - return *Item; - } - - TChunkType *operator ->() const { - CheckValid(); - return Item; - } - - TIterator& operator++() { - CheckValid(); - Y_DEBUG_ABORT_UNLESS(Item); - Item = Item->Next; - if (Item == &Cont->Root) { - Item = nullptr; // make it end - } - UpdateValidityToken(); - return *this; - } - - TIterator operator ++(int) { - TIterator res(*this); - ++*this; - return res; - } - - TIterator& operator--() { - CheckValid(); - if (!Item) { - Y_DEBUG_ABORT_UNLESS(*Cont); - Item = Cont->Root.Prev; - } else { - Y_DEBUG_ABORT_UNLESS(Item != &Cont->Root); - Item = Item->Prev; - } - UpdateValidityToken(); - return *this; - } - - TIterator operator --(int) { - TIterator res(*this); - --*this; - return res; - } - - friend bool operator ==(const TIterator& x, const TIterator& y) { - Y_DEBUG_ABORT_UNLESS(x.Cont == y.Cont); - x.CheckValid(); - y.CheckValid(); - return x.Item == y.Item; - } - - friend bool operator !=(const TIterator& x, const TIterator& y) { - return !(x == y); - } - - private: - void CheckValid() const { -#ifndef NDEBUG - Y_DEBUG_ABORT_UNLESS(ValidityToken == (Item ? Item->ValidityToken : 0)); - Y_DEBUG_ABORT_UNLESS(Cont && (Item != &Cont->Root || *Cont)); -#endif - } - - void UpdateValidityToken() { -#ifndef NDEBUG - ValidityToken = Item ? Item->ValidityToken : 0; -#endif - CheckValid(); - } - }; - -public: - using iterator = TIterator<false>; - using const_iterator = TIterator<true>; - -public: - TChunkList() - {} - - ~TChunkList() { - Erase(begin(), end()); - Y_DEBUG_ABORT_UNLESS(!*this); - } - - TChunkList(const TChunkList& other) { - *this = other; - } - - TChunkList(TChunkList&& other) { - *this = std::move(other); - } - - TChunkList& operator=(const TChunkList& other) { - if (this != &other) { - Erase(begin(), end()); - for (const TChunk& chunk : other) { - PutToEnd(TChunk(chunk)); - } - } - return *this; - } - - TChunkList& operator=(TChunkList&& other) { - if (this != &other) { - Erase(begin(), end()); - Y_DEBUG_ABORT_UNLESS(!*this); - if (other.Root.IsInUse()) { // do we have something to move? - Root.PrepareForUse(std::move(static_cast<TChunk&>(other.Root))); - if (other.Root.Next != &other.Root) { // does other contain more than one item? - TItem::TransferRange(&Root, other.Root.Next, other.Root.Prev); - } - other.Root.ClearSingleItem(); - } - } - return *this; - } - - template<typename... TArgs> - void PutToEnd(TArgs&&... args) { - InsertBefore(end(), std::forward<TArgs>(args)...); - } - - template<typename... TArgs> - iterator InsertBefore(iterator pos, TArgs&&... args) { - TItem *item = AllocateItem<TArgs...>(std::forward<TArgs>(args)...); - if (item == &Root) { - // this is the first item, we don't do anything about it - } else if (pos.Item != &Root) { - item->LinkBefore(pos.Item ? pos.Item : &Root); - } else { - item->LinkBefore(Root.Next); - std::swap(static_cast<TChunk&>(*item), static_cast<TChunk&>(Root)); - item = &Root; - Root.Invalidate(); - } - return {this, item}; - } - - iterator Erase(iterator pos) { - Pop(pos); - return pos; - } - - iterator Erase(iterator first, iterator last) { - if (first == last) { - return last; - } - for (;;) { - if (last == begin()) { - EraseFront(); - return begin(); - } else if (--last == first) { - return Erase(last); - } else { - last = Erase(last); - } - } - } - - void EraseFront() { - PopFront(); - } - - void EraseBack() { - Y_DEBUG_ABORT_UNLESS(*this); - if (Root.Prev != &Root) { - delete Root.Prev; - } else { - EraseFront(); - } - } - - // Splice moves elements from the 'from' list in the range [first, last) to *this, inserting them before 'pos'. It - // returns iterator of the next remaining item in the 'from' list. - iterator Splice(iterator pos, TChunkList& from, iterator first, iterator last) { - if (first == last) { // the source range is empty - return last; - } - - const bool fromBegin = first == from.begin(); - if (fromBegin) { // remember we have to transfer the first item before returning - ++first; - } - - // 'first' here either equals to 'last' or points to the middle of the 'from' list - - const bool toBegin = pos == begin(); - if (toBegin && first != last) { - // we are inserting item to the begin of the list, so move the first item of the range; it is important here - // that 'last' iterator doesn't get invalidated - pos = InsertBefore(begin(), from.Pop(first)); - ++pos; - } - - const auto temp = last; - if (first != last) { - --last; // set 'last' pointing to the actual last element of the source range - - Y_DEBUG_ABORT_UNLESS(first.Item != &from.Root); - Y_DEBUG_ABORT_UNLESS(pos.Item != &Root); - - TItem* const firstItem = first.Item; - TItem* const lastItem = last.Item; - TItem* const posItem = pos.Item ? pos.Item : &Root; - - TItem::TransferRange(posItem, firstItem, lastItem); - - // adjust 'pos' to point to the first inserted item - pos = {this, firstItem}; - } - - if (fromBegin) { - InsertBefore(toBegin ? begin() : pos, from.PopFront()); - return from.begin(); - } else { - return temp; - } - } - - operator bool() const { return Root.IsInUse(); } - - TChunk& GetFirstChunk() { Y_DEBUG_ABORT_UNLESS(*this); return Root; } - const TChunk& GetFirstChunk() const { Y_DEBUG_ABORT_UNLESS(*this); return Root; } - TChunk& GetLastChunk() { Y_DEBUG_ABORT_UNLESS(*this); return *Root.Prev; } - - iterator begin() { return *this ? iterator(this, &Root) : end(); } - const_iterator begin() const { return *this ? const_iterator(this, &Root) : end(); } - iterator end() { return {this, nullptr}; } - const_iterator end() const { return {this, nullptr}; } - -private: - TChunk Pop(iterator& pos) { - pos.CheckValid(); - Y_DEBUG_ABORT_UNLESS(pos.Item); - - if (pos.Item == &Root) { - TChunk res = PopFront(); - pos = begin(); - return res; - } else { - Y_DEBUG_ABORT_UNLESS(pos != end()); - TItem* const item = pos++.Item; - TChunk res = std::move(static_cast<TChunk&>(*item)); - delete item; - return res; - } - } - - TChunk PopFront() { - Y_DEBUG_ABORT_UNLESS(*this); - TChunk res = std::move(static_cast<TChunk&>(Root)); - if (Root.Next != &Root) { - static_cast<TChunk&>(Root) = std::move(static_cast<TChunk&>(*Root.Next)); - delete Root.Next; - Root.Invalidate(); - } else { - Root.ClearSingleItem(); - } - return res; - } -}; - -} // NRopeDetails diff --git a/library/cpp/actors/util/rope_ut.cpp b/library/cpp/actors/util/rope_ut.cpp deleted file mode 100644 index 0ff85d6c59..0000000000 --- a/library/cpp/actors/util/rope_ut.cpp +++ /dev/null @@ -1,418 +0,0 @@ -#include "rope.h" -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include "ut_helpers.h" - -class TRopeStringBackend : public IContiguousChunk { - TString Buffer; - -public: - TRopeStringBackend(TString buffer) - : Buffer(std::move(buffer)) - {} - - TContiguousSpan GetData() const override { - return {Buffer.data(), Buffer.size()}; - } - - TMutableContiguousSpan GetDataMut() override { - return {Buffer.Detach(), Buffer.size()}; - } - - TMutableContiguousSpan UnsafeGetDataMut() override { - return {const_cast<char*>(Buffer.data()), Buffer.size()}; - } - - size_t GetOccupiedMemorySize() const override { - return Buffer.capacity(); - } -}; - -TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - res.Insert(res.End(), TRope(MakeIntrusive<TRopeStringBackend>(s.substr(i, len)))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; -} - -TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; -} - -TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - -Y_UNIT_TEST_SUITE(TRope) { - Y_UNIT_TEST(StringCompare) { - TRope rope = CreateRope(Text, 10); - UNIT_ASSERT_EQUAL(rope, Text); - UNIT_ASSERT_EQUAL(Text, rope); - rope.Erase(rope.Begin() + 10, rope.Begin() + 11); - UNIT_ASSERT_UNEQUAL(rope, Text); - UNIT_ASSERT_UNEQUAL(Text, rope); - TString str("aa"); - rope = TRope(TString("ab")); - UNIT_ASSERT_LT(str, rope); - UNIT_ASSERT_GT(rope, str); - str = TString("aa"); - rope = TRope(TString("a")); - UNIT_ASSERT_LT(rope, str); - UNIT_ASSERT_GT(str, rope); - str = TString("a"); - rope = TRope(TString("aa")); - UNIT_ASSERT_LT(str, rope); - UNIT_ASSERT_GT(rope, str); - } - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(Compacted) { - TRope rope = CreateRope(Text, 10); - UNIT_ASSERT_EQUAL(rope.UnsafeGetContiguousSpanMut(), Text); - UNIT_ASSERT(rope.IsContiguous()); - } - -#ifndef TSTRING_IS_STD_STRING - Y_UNIT_TEST(ExtractZeroCopy) { - TString str = Text; - TRope packed(str); - TString extracted = packed.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_EQUAL(str.data(), extracted.data()); - } - - Y_UNIT_TEST(ExtractZeroCopySlice) { - TString str = Text; - TRope sliced(str); - sliced.EraseFront(1); - TString extracted = sliced.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_UNEQUAL(str.data(), extracted.data()); - TRope sliced2(str); - sliced2.EraseBack(1); - TString extracted2 = sliced2.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_UNEQUAL(str.data(), extracted2.data()); - } - - Y_UNIT_TEST(TStringDetach) { - TRope pf; - TRope rope; - TString string = TString(Text.data(), Text.size()); - rope = TRope(string); - pf = rope; - pf.GetContiguousSpanMut(); - UNIT_ASSERT(!string.IsDetached()); - rope.GetContiguousSpanMut(); - UNIT_ASSERT(string.IsDetached()); - } - - Y_UNIT_TEST(TStringUnsafeShared) { - TRope pf; - TRope rope; - TString string = TString(Text.data(), Text.size()); - rope = TRope(string); - pf = rope; - UNIT_ASSERT(pf.IsContiguous()); - UNIT_ASSERT_EQUAL(pf.UnsafeGetContiguousSpanMut().data(), string.data()); - UNIT_ASSERT(!string.IsDetached()); - } - - Y_UNIT_TEST(ContiguousDataInterop) { - TString string = "Some long-long text needed for not sharing data and testing"; - TRcBuf data(string); - UNIT_ASSERT_EQUAL(data.UnsafeGetDataMut(), &(*string.cbegin())); - TRope rope(data); // check operator TRope - UNIT_ASSERT_EQUAL(rope.UnsafeGetContiguousSpanMut().data(), &(*string.cbegin())); - TRcBuf otherData(rope); - UNIT_ASSERT_EQUAL(otherData.UnsafeGetDataMut(), &(*string.cbegin())); - TString extractedBack = otherData.ExtractUnderlyingContainerOrCopy<TString>(); - UNIT_ASSERT_EQUAL(extractedBack.data(), &(*string.cbegin())); - } -#endif - Y_UNIT_TEST(CrossCompare) { - TString str = "some very long string"; - const TString constStr(str); - TStringBuf strbuf = str; - const TStringBuf constStrbuf = str; - TContiguousSpan span(str); - const TContiguousSpan constSpan(str); - TMutableContiguousSpan mutableSpan(const_cast<char*>(str.data()), str.size()); - const TMutableContiguousSpan constMutableSpan(const_cast<char*>(str.data()), str.size()); - TRcBuf data(str); - const TRcBuf constData(str); - TArrayRef<char> arrRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<char> constArrRef(const_cast<char*>(str.data()), str.size()); - TArrayRef<const char> arrConstRef(const_cast<char*>(str.data()), str.size()); - const TArrayRef<const char> constArrConstRef(const_cast<char*>(str.data()), str.size()); - NActors::TSharedData sharedData = NActors::TSharedData::Copy(str.data(), str.size()); - const NActors::TSharedData constSharedData(sharedData); - TRope rope(str); - const TRope constRope(str); - - Permutate( - [](auto& arg1, auto& arg2) { - UNIT_ASSERT(arg1 == arg2); - }, - str, - constStr, - strbuf, - constStrbuf, - span, - constSpan, - mutableSpan, - constMutableSpan, - data, - constData, - arrRef, - constArrRef, - arrConstRef, - constArrConstRef, - sharedData, - constSharedData, - rope, - constRope); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - rope.ExtractFrontPlain(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(FetchFrontPlain) { - char s[10]; - char *data = s; - size_t remain = sizeof(s); - TRope rope = TRope(TString("HELLO")); - UNIT_ASSERT(!rope.FetchFrontPlain(&data, &remain)); - UNIT_ASSERT(!rope); - rope.Insert(rope.End(), TRope(TString("WORLD!!!"))); - UNIT_ASSERT(rope.FetchFrontPlain(&data, &remain)); - UNIT_ASSERT(!remain); - UNIT_ASSERT(rope.GetSize() == 3); - UNIT_ASSERT_VALUES_EQUAL(rope.ConvertToString(), "!!!"); - UNIT_ASSERT(!strncmp(s, "HELLOWORLD", 10)); - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope == y, x == y); - UNIT_ASSERT_VALUES_EQUAL(x == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope != y, x != y); - UNIT_ASSERT_VALUES_EQUAL(x != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope < y, x < y); - UNIT_ASSERT_VALUES_EQUAL(x < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= y, x <= y); - UNIT_ASSERT_VALUES_EQUAL(x <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope > y, x > y); - UNIT_ASSERT_VALUES_EQUAL(x > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= y, x >= y); - UNIT_ASSERT_VALUES_EQUAL(x >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - Y_UNIT_TEST(RopeZeroCopyInputBasic) { - TRope rope = CreateRope(Text, 3); - TRopeZeroCopyInput input(rope.Begin()); - - TString result; - TStringOutput output(result); - TransferData(&input, &output); - UNIT_ASSERT_EQUAL(result, Text); - } - - Y_UNIT_TEST(RopeZeroCopyInput) { - TRope rope; - rope.Insert(rope.End(), TRope{"abc"}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{"de"}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{TString{}}); - rope.Insert(rope.End(), TRope{"fghi"}); - - TRopeZeroCopyInput input(rope.Begin()); - - const char* data = nullptr; - size_t len; - - len = input.Next(&data, 2); - UNIT_ASSERT_EQUAL("ab", TStringBuf(data, len)); - - len = input.Next(&data, 3); - UNIT_ASSERT_EQUAL("c", TStringBuf(data, len)); - - len = input.Next(&data, 3); - UNIT_ASSERT_EQUAL("de", TStringBuf(data, len)); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL("fghi", TStringBuf(data, len)); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL(len, 0); - - len = input.Next(&data); - UNIT_ASSERT_EQUAL(len, 0); - } -} diff --git a/library/cpp/actors/util/shared_data.cpp b/library/cpp/actors/util/shared_data.cpp deleted file mode 100644 index 51311ce7a3..0000000000 --- a/library/cpp/actors/util/shared_data.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "shared_data.h" - -#include "memory_tracker.h" - -#include <util/system/sys_alloc.h> -#include <util/system/sanitizers.h> - -namespace NActors { - - static constexpr char MemoryLabelSharedData[] = "Tablet/TSharedData/Buffers"; - - char* TSharedData::Allocate(size_t size) { - char* data = nullptr; - if (size > 0) { - if (size >= MaxDataSize) { - throw std::length_error("Allocate size overflow"); - } - auto allocSize = OverheadSize + size; - char* raw = reinterpret_cast<char*>(y_allocate(allocSize)); - - auto* privateHeader = reinterpret_cast<TPrivateHeader*>(raw); - privateHeader->AllocSize = allocSize; - NActors::NMemory::TLabel<MemoryLabelSharedData>::Add(allocSize); - - auto* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - header->RefCount = 1; - header->Owner = nullptr; - - data = raw + OverheadSize; - NSan::Poison(data, size); - } - return data; - } - - void TSharedData::Deallocate(char* data) noexcept { - if (data) { - char* raw = data - OverheadSize; - - auto* privateHeader = reinterpret_cast<TPrivateHeader*>(raw); - NActors::NMemory::TLabel<MemoryLabelSharedData>::Sub(privateHeader->AllocSize); - - auto* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - Y_DEBUG_ABORT_UNLESS(header->Owner == nullptr); - - y_deallocate(raw); - } - } - -} diff --git a/library/cpp/actors/util/shared_data.h b/library/cpp/actors/util/shared_data.h deleted file mode 100644 index bd9afb00a5..0000000000 --- a/library/cpp/actors/util/shared_data.h +++ /dev/null @@ -1,227 +0,0 @@ -#pragma once - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/types.h> -#include <util/system/compiler.h> -#include <util/generic/array_ref.h> - -namespace NActors { - - class TSharedData { - public: - class IOwner { - public: - virtual ~IOwner() = default; - - virtual void Deallocate(char*) noexcept = 0; - }; - - struct TPrivateHeader { - size_t AllocSize; - size_t Pad; - }; - - static_assert(sizeof(TPrivateHeader) == 16, "TPrivateHeader has an unexpected size"); - - struct THeader { - TAtomic RefCount; - IOwner* Owner; - }; - - static_assert(sizeof(THeader) == 16, "THeader has an unexpected size"); - - enum : size_t { - PrivateHeaderSize = sizeof(TPrivateHeader), - HeaderSize = sizeof(THeader), - OverheadSize = PrivateHeaderSize + HeaderSize, - MaxDataSize = (std::numeric_limits<size_t>::max() - OverheadSize) - }; - - public: - TSharedData() noexcept - : Data_(nullptr) - , Size_(0) - { } - - ~TSharedData() noexcept { - Release(); - } - - TSharedData(const TSharedData& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - AddRef(); - } - - TSharedData(TSharedData&& other) noexcept - : Data_(other.Data_) - , Size_(other.Size_) - { - other.Data_ = nullptr; - other.Size_ = 0; - } - - TSharedData& operator=(const TSharedData& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - AddRef(); - } - return *this; - } - - TSharedData& operator=(TSharedData&& other) noexcept { - if (this != &other) { - Release(); - Data_ = other.Data_; - Size_ = other.Size_; - other.Data_ = nullptr; - other.Size_ = 0; - } - return *this; - } - - Y_FORCE_INLINE explicit operator bool() const { return Size_ > 0; } - - Y_FORCE_INLINE char* mutable_data() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_; } - Y_FORCE_INLINE char* mutable_begin() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_; } - Y_FORCE_INLINE char* mutable_end() { Y_DEBUG_ABORT_UNLESS(IsPrivate()); return Data_ + Size_; } - - Y_FORCE_INLINE const char* data() const { return Data_; } - Y_FORCE_INLINE const char* begin() const { return Data_; } - Y_FORCE_INLINE const char* end() const { return Data_ + Size_; } - - Y_FORCE_INLINE size_t size() const { return Size_; } - - /** - * Trims data to the specified size - * Underlying data is not reallocated - * Returns trimmed amount in bytes - */ - size_t TrimBack(size_t size) noexcept { - size_t trimmed = 0; - if (Size_ > size) { - trimmed = Size_ - size; - if (!size) { - Release(); - Data_ = nullptr; - } - Size_ = size; - } - return trimmed; - } - - /** - * Copies data to new allocated buffer if data is shared - * New container loses original owner - * Returns pointer to mutable buffer - */ - char* Detach() { - if (IsShared()) { - *this = TSharedData::Copy(data(), size()); - } - return Data_; - } - - /** - * Returns a view of underlying data starting with pos and up to len bytes - */ - TStringBuf Slice(size_t pos = 0, size_t len = -1) const noexcept { - pos = Min(pos, Size_); - len = Min(len, Size_ - pos); - return { Data_ + pos, len }; - } - - explicit operator TStringBuf() const noexcept { - return Slice(); - } - - bool IsPrivate() const { - return Data_ ? IsPrivate(Header()) : true; - } - - bool IsShared() const { - return !IsPrivate(); - } - - TString ToString() const { - return TString(data(), size()); - } - - /** - * Attach to pre-allocated data with a preceding THeader - */ - static TSharedData AttachUnsafe(char* data, size_t size) noexcept { - TSharedData result; - result.Data_ = data; - result.Size_ = size; - return result; - } - - /** - * Make uninitialized buffer of the specified size - */ - static TSharedData Uninitialized(size_t size) { - return AttachUnsafe(Allocate(size), size); - } - - /** - * Make a copy of the specified data - */ - static TSharedData Copy(const void* data, size_t size) { - TSharedData result = Uninitialized(size); - if (size) { - ::memcpy(result.Data_, data, size); - } - return result; - } - - /** - * Make a copy of the specified data - */ - static TSharedData Copy(TArrayRef<const char> data) { - return Copy(data.data(), data.size()); - } - - private: - Y_FORCE_INLINE THeader* Header() const noexcept { - Y_DEBUG_ABORT_UNLESS(Data_); - return reinterpret_cast<THeader*>(Data_ - sizeof(THeader)); - } - - static bool IsPrivate(THeader* header) noexcept { - return 1 == AtomicGet(header->RefCount); - } - - void AddRef() noexcept { - if (Data_) { - AtomicIncrement(Header()->RefCount); - } - } - - void Release() noexcept { - if (Data_) { - auto* header = Header(); - if (IsPrivate(header) || 0 == AtomicDecrement(header->RefCount)) { - if (auto* owner = header->Owner) { - owner->Deallocate(Data_); - } else { - Deallocate(Data_); - } - } - } - } - - private: - static char* Allocate(size_t size); - static void Deallocate(char* data) noexcept; - - private: - char* Data_; - size_t Size_; - }; - -} diff --git a/library/cpp/actors/util/shared_data_backtracing_owner.h b/library/cpp/actors/util/shared_data_backtracing_owner.h deleted file mode 100644 index ea479d5fd1..0000000000 --- a/library/cpp/actors/util/shared_data_backtracing_owner.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include <util/system/sys_alloc.h> -#include <util/system/backtrace.h> - -#include "shared_data.h" - -class TBackTracingOwner : public NActors::TSharedData::IOwner { - using THeader = NActors::TSharedData::THeader; - using TSelf = TBackTracingOwner; - using IOwner = NActors::TSharedData::IOwner; - - static constexpr size_t PrivateHeaderSize = NActors::TSharedData::PrivateHeaderSize; - static constexpr size_t HeaderSize = NActors::TSharedData::HeaderSize; - static constexpr size_t OverheadSize = NActors::TSharedData::OverheadSize; - - IOwner* RealOwner = nullptr; - TBackTrace BackTrace; - const char* Info; -public: - - static constexpr const char* INFO_FROM_SHARED_DATA = "FROM_SHARED_DATA"; - static constexpr const char* INFO_COPIED_STRING = "COPIED_STRING"; - static constexpr const char* INFO_ALLOC_UNINITIALIZED = "ALLOC_UNINITIALIZED"; - static constexpr const char* INFO_ALLOC_UNINIT_ROOMS = "ALLOC_UNINIT_ROOMS"; - - static char* Allocate(size_t size, const char* info = nullptr) { - char* raw = reinterpret_cast<char*>(y_allocate(OverheadSize + size)); - THeader* header = reinterpret_cast<THeader*>(raw + PrivateHeaderSize); - TSelf* btOwner = new TSelf; - btOwner->BackTrace.Capture(); - btOwner->Info = info; - header->RefCount = 1; - header->Owner = btOwner; - char* data = raw + OverheadSize; - return data; - } - - static void FakeOwner(const NActors::TSharedData& data, const char* info = nullptr) { - THeader* header = Header(data); - if (header) { - TSelf* btOwner = new TSelf(); - btOwner->BackTrace.Capture(); - btOwner->Info = info; - if (header->Owner) { - btOwner->RealOwner = header->Owner; - } - header->Owner = btOwner; - } - } - - static void UnsafePrintBackTrace(NActors::TSharedData& data) { - THeader* header = Header(data); - if(header->Owner) { - TSelf* owner = static_cast<TSelf*>(header->Owner); - owner->PrintBackTrace(); - } - } - - void Deallocate(char* data) noexcept override { - if (!RealOwner) { - char* raw = data - OverheadSize; - y_deallocate(raw); - } else { - RealOwner->Deallocate(data); - } - - delete this; - } - - IOwner* GetRealOwner() const { - return RealOwner; - } - - void PrintBackTrace() { - Cerr << "Deallocate TSharedData with info# " << Info << Endl; - BackTrace.PrintTo(Cerr); - } -private: - static Y_FORCE_INLINE THeader* Header(const NActors::TSharedData& d) noexcept { - char* data = const_cast<char*>(d.data()); - if (data) { - return reinterpret_cast<THeader*>(data - HeaderSize); - } else { - return nullptr; - } - } -}; diff --git a/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp b/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp deleted file mode 100644 index 4939403454..0000000000 --- a/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -#include "shared_data_rope_backend.h" - -namespace NActors { - - namespace { - - TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - auto str = s.substr(i, len); - res.Insert(res.End(), TRope( - TSharedData::Copy(str.data(), str.size()))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; - } - - TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; - } - - TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - - } - - Y_UNIT_TEST_SUITE(TRopeSharedDataNativeBackend) { - - // Same tests as in TRope but with new CreateRope using TSharedData backend - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - auto it = rope.Begin(); - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - it.ExtractPlainDataAndAdvance(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(it, rope.End())), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - // Specific TSharedDataRopeBackend tests - - Y_UNIT_TEST(RopeOnlyBorrows) { - TSharedData data = TSharedData::Copy(Text.data(), Text.size()); - { - TRope rope; - rope.Insert(rope.End(), TRope(data)); - UNIT_ASSERT(data.IsShared()); - TSharedData dataCopy = data; - UNIT_ASSERT(dataCopy.IsShared()); - UNIT_ASSERT_EQUAL(dataCopy.data(), data.data()); - rope.Insert(rope.End(), TRope(data)); - rope.Insert(rope.End(), TRope(data)); - dataCopy.TrimBack(10); - UNIT_ASSERT_EQUAL(rope.GetSize(), data.size() * 3); - } - UNIT_ASSERT(data.IsPrivate()); - } - } - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_rope_backend.h b/library/cpp/actors/util/shared_data_rope_backend.h deleted file mode 100644 index a221ae668b..0000000000 --- a/library/cpp/actors/util/shared_data_rope_backend.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <library/cpp/actors/util/rc_buf.h> - -#include "shared_data.h" - -namespace NActors { - -class TRopeSharedDataBackend : public IContiguousChunk { - TSharedData Buffer; - -public: - TRopeSharedDataBackend(TSharedData buffer) - : Buffer(std::move(buffer)) - {} - - TContiguousSpan GetData() const override { - return {Buffer.data(), Buffer.size()}; - } - - TMutableContiguousSpan GetDataMut() override { - if(Buffer.IsShared()) { - Buffer = TSharedData::Copy(Buffer.data(), Buffer.size()); - } - return {Buffer.mutable_data(), Buffer.size()}; - } - - TMutableContiguousSpan UnsafeGetDataMut() override { - return {const_cast<char *>(Buffer.data()), Buffer.size()}; - } - - bool IsPrivate() const override { - return Buffer.IsPrivate(); - } - - size_t GetOccupiedMemorySize() const override { - return Buffer.size(); - } -}; - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_rope_backend_ut.cpp b/library/cpp/actors/util/shared_data_rope_backend_ut.cpp deleted file mode 100644 index b2b4e04634..0000000000 --- a/library/cpp/actors/util/shared_data_rope_backend_ut.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include <library/cpp/actors/util/rope.h> -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> - -#include "shared_data_rope_backend.h" - -namespace NActors { - - namespace { - - TRope CreateRope(TString s, size_t sliceSize) { - TRope res; - for (size_t i = 0; i < s.size(); ) { - size_t len = std::min(sliceSize, s.size() - i); - if (i % 2) { - auto str = s.substr(i, len); - res.Insert(res.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>( - TSharedData::Copy(str.data(), str.size())))); - } else { - res.Insert(res.End(), TRope(s.substr(i, len))); - } - i += len; - } - return res; - } - - TString RopeToString(const TRope& rope) { - TString res; - auto iter = rope.Begin(); - while (iter != rope.End()) { - res.append(iter.ContiguousData(), iter.ContiguousSize()); - iter.AdvanceToNextContiguousBlock(); - } - - UNIT_ASSERT_VALUES_EQUAL(rope.GetSize(), res.size()); - - TString temp = TString::Uninitialized(rope.GetSize()); - rope.Begin().ExtractPlainDataAndAdvance(temp.Detach(), temp.size()); - UNIT_ASSERT_VALUES_EQUAL(temp, res); - - return res; - } - - TString Text = "No elements are copied or moved, only the internal pointers of the list nodes are re-pointed."; - - } - - Y_UNIT_TEST_SUITE(TRopeSharedDataBackend) { - - // Same tests as in TRope but with new CreateRope using TSharedData backend - - Y_UNIT_TEST(Leak) { - const size_t begin = 10, end = 20; - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - } - - Y_UNIT_TEST(BasicRange) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope::TIterator rBegin = rope.Begin() + begin; - TRope::TIterator rEnd = rope.Begin() + end; - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(rBegin, rEnd)), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(Erase) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - rope.Erase(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - } - } - } - - Y_UNIT_TEST(Insert) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope part = TRope(rope.Begin() + begin, rope.Begin() + end); - for (size_t where = 0; where <= Text.size(); ++where) { - TRope x(rope); - x.Insert(x.Begin() + where, TRope(part)); - UNIT_ASSERT_VALUES_EQUAL(x.GetSize(), rope.GetSize() + part.GetSize()); - TString text = Text; - text.insert(text.begin() + where, Text.begin() + begin, Text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(x), text); - } - } - } - } - - Y_UNIT_TEST(Extract) { - for (size_t begin = 0; begin < Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TRope rope = CreateRope(Text, 10); - TRope part = rope.Extract(rope.Begin() + begin, rope.Begin() + end); - TString text = Text; - text.erase(text.begin() + begin, text.begin() + end); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), text); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(part), Text.substr(begin, end - begin)); - } - } - } - - Y_UNIT_TEST(EraseFront) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseFront(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(pos)); - } - } - - Y_UNIT_TEST(EraseBack) { - for (size_t pos = 0; pos <= Text.size(); ++pos) { - TRope rope = CreateRope(Text, 10); - rope.EraseBack(pos); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text.substr(0, Text.size() - pos)); - } - } - - Y_UNIT_TEST(ExtractFront) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TRope out; - while (const size_t len = Min(step, rope.GetSize())) { - rope.ExtractFront(len, &out); - UNIT_ASSERT(rope.GetSize() + out.GetSize() == Text.size()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(out), Text.substr(0, out.GetSize())); - } - } - } - - Y_UNIT_TEST(ExtractFrontPlain) { - for (size_t step = 1; step <= Text.size(); ++step) { - TRope rope = CreateRope(Text, 10); - TString buffer = Text; - auto it = rope.Begin(); - size_t remain = rope.GetSize(); - while (const size_t len = Min(step, remain)) { - TString data = TString::Uninitialized(len); - it.ExtractPlainDataAndAdvance(data.Detach(), data.size()); - UNIT_ASSERT_VALUES_EQUAL(data, buffer.substr(0, len)); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(TRope(it, rope.End())), buffer.substr(len)); - buffer = buffer.substr(len); - remain -= len; - } - } - } - - Y_UNIT_TEST(Glueing) { - TRope rope = CreateRope(Text, 10); - for (size_t begin = 0; begin <= Text.size(); ++begin) { - for (size_t end = begin; end <= Text.size(); ++end) { - TString repr = rope.DebugString(); - TRope temp = rope.Extract(rope.Position(begin), rope.Position(end)); - rope.Insert(rope.Position(begin), std::move(temp)); - UNIT_ASSERT_VALUES_EQUAL(repr, rope.DebugString()); - UNIT_ASSERT_VALUES_EQUAL(RopeToString(rope), Text); - } - } - } - - Y_UNIT_TEST(IterWalk) { - TRope rope = CreateRope(Text, 10); - for (size_t step1 = 0; step1 <= rope.GetSize(); ++step1) { - for (size_t step2 = 0; step2 <= step1; ++step2) { - TRope::TConstIterator iter = rope.Begin(); - iter += step1; - iter -= step2; - UNIT_ASSERT(iter == rope.Position(step1 - step2)); - } - } - } - - Y_UNIT_TEST(Compare) { - auto check = [](const TString& x, const TString& y) { - const TRope xRope = CreateRope(x, 7); - const TRope yRope = CreateRope(y, 11); - UNIT_ASSERT_VALUES_EQUAL(xRope == yRope, x == y); - UNIT_ASSERT_VALUES_EQUAL(xRope != yRope, x != y); - UNIT_ASSERT_VALUES_EQUAL(xRope < yRope, x < y); - UNIT_ASSERT_VALUES_EQUAL(xRope <= yRope, x <= y); - UNIT_ASSERT_VALUES_EQUAL(xRope > yRope, x > y); - UNIT_ASSERT_VALUES_EQUAL(xRope >= yRope, x >= y); - }; - - TVector<TString> pool; - for (size_t k = 0; k < 10; ++k) { - size_t len = RandomNumber<size_t>(100) + 100; - TString s = TString::Uninitialized(len); - char *p = s.Detach(); - for (size_t j = 0; j < len; ++j) { - *p++ = RandomNumber<unsigned char>(); - } - pool.push_back(std::move(s)); - } - - for (const TString& x : pool) { - for (const TString& y : pool) { - check(x, y); - } - } - } - - // Specific TSharedDataRopeBackend tests - - Y_UNIT_TEST(RopeOnlyBorrows) { - TSharedData data = TSharedData::Copy(Text.data(), Text.size()); - { - TRope rope; - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - UNIT_ASSERT(data.IsShared()); - TSharedData dataCopy = data; - UNIT_ASSERT(dataCopy.IsShared()); - UNIT_ASSERT_EQUAL(dataCopy.data(), data.data()); - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - rope.Insert(rope.End(), TRope(MakeIntrusive<TRopeSharedDataBackend>(data))); - dataCopy.TrimBack(10); - UNIT_ASSERT_EQUAL(rope.GetSize(), data.size() * 3); - } - UNIT_ASSERT(data.IsPrivate()); - } - } - -} // namespace NActors diff --git a/library/cpp/actors/util/shared_data_ut.cpp b/library/cpp/actors/util/shared_data_ut.cpp deleted file mode 100644 index 2f7dc2ccc8..0000000000 --- a/library/cpp/actors/util/shared_data_ut.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "shared_data.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/generic/hash.h> -#include <util/generic/deque.h> -#include <util/system/sys_alloc.h> - -namespace NActors { - - Y_UNIT_TEST_SUITE(TSharedDataTest) { - - Y_UNIT_TEST(BasicBehavior) { - auto data = TSharedData::Copy("Hello", 5); - UNIT_ASSERT(data.IsPrivate()); - UNIT_ASSERT(!data.IsShared()); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 5u); - UNIT_ASSERT_VALUES_EQUAL(data.end() - data.begin(), 5u); - UNIT_ASSERT_VALUES_EQUAL(data.mutable_end() - data.mutable_begin(), 5u); - UNIT_ASSERT(data.begin() == data.data()); - UNIT_ASSERT(data.mutable_data() == data.data()); - UNIT_ASSERT(data.mutable_begin() == data.mutable_data()); - - UNIT_ASSERT_VALUES_EQUAL(data.ToString(), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(::memcmp(data.data(), "Hello", 5), 0); - - auto link = data; - UNIT_ASSERT(!link.IsPrivate()); - UNIT_ASSERT(!data.IsPrivate()); - UNIT_ASSERT(link.IsShared()); - UNIT_ASSERT(data.IsShared()); - UNIT_ASSERT(link.data() == data.data()); - UNIT_ASSERT(link.size() == data.size()); - - link = { }; - UNIT_ASSERT(link.IsPrivate()); - UNIT_ASSERT(data.IsPrivate()); - UNIT_ASSERT(!link.IsShared()); - UNIT_ASSERT(!data.IsShared()); - - UNIT_ASSERT_VALUES_EQUAL(TString(TStringBuf(data)), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString("Hello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 3)), TString("ell")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(1, 100)), TString("ello")); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice(0, 4)), TString("Hell")); - - link = data; - UNIT_ASSERT(link.data() == data.data()); - UNIT_ASSERT_VALUES_UNEQUAL(link.Detach(), data.data()); - UNIT_ASSERT_EQUAL(data.size(), link.size()); - UNIT_ASSERT_VALUES_EQUAL(TString(data.Slice()), TString(link.Slice())); - } - - Y_UNIT_TEST(TrimBehavior) { - auto data = TSharedData::Uninitialized(42); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - UNIT_ASSERT(data.data() != nullptr); - - // Trim to non-zero does not change addresses - const char* ptr1 = data.data(); - data.TrimBack(31); - const char* ptr2 = data.data(); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 31u); - UNIT_ASSERT(ptr1 == ptr2); - - // Trim to zero releases underlying data - data.TrimBack(0); - - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - } - - class TCustomOwner : public TSharedData::IOwner { - using THeader = TSharedData::THeader; - - public: - TSharedData Allocate(size_t size) { - char* raw = reinterpret_cast<char*>(y_allocate(sizeof(THeader) + size)); - THeader* header = reinterpret_cast<THeader*>(raw); - header->RefCount = 1; - header->Owner = this; - char* data = raw + sizeof(THeader); - Y_ABORT_UNLESS(Allocated_.insert(data).second); - return TSharedData::AttachUnsafe(data, size); - } - - void Deallocate(char* data) noexcept { - Y_ABORT_UNLESS(Allocated_.erase(data) > 0); - char* raw = data - sizeof(THeader); - y_deallocate(raw); - Deallocated_.push_back(data); - } - - char* NextDeallocated() { - char* result = nullptr; - if (Deallocated_) { - result = Deallocated_.front(); - Deallocated_.pop_front(); - } - return result; - } - - private: - THashSet<void*> Allocated_; - TDeque<char*> Deallocated_; - }; - - Y_UNIT_TEST(CustomOwner) { - TCustomOwner owner; - const char* ptr; - - // Test destructor releases data - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test assignment releases data - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - data = { }; - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test copies keep references correctly - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - auto copy = data; - UNIT_ASSERT_VALUES_EQUAL(copy.size(), 42u); - UNIT_ASSERT(copy.data() == ptr); - data = { }; - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test assignment releases correct data - { - auto data1 = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data1.size(), 42u); - auto data2 = owner.Allocate(31); - UNIT_ASSERT_VALUES_EQUAL(data2.size(), 31u); - ptr = data1.data(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - data1 = data2; - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - ptr = data2.data(); - UNIT_ASSERT_VALUES_EQUAL(data1.size(), 31u); - UNIT_ASSERT(data1.data() == ptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test moves don't produce dangling references - { - auto data = owner.Allocate(42); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 42u); - ptr = data.data(); - auto moved = std::move(data); - UNIT_ASSERT_VALUES_EQUAL(moved.size(), 42u); - UNIT_ASSERT(moved.data() == ptr); - UNIT_ASSERT_VALUES_EQUAL(data.size(), 0u); - UNIT_ASSERT(data.data() == nullptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - // Test Detach copies correctly and doesn't affect owned data - { - auto data = owner.Allocate(42); - auto disowned = data; - disowned.Detach(); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - } - - UNIT_ASSERT(owner.NextDeallocated() == ptr); - UNIT_ASSERT(owner.NextDeallocated() == nullptr); - - } - - } - -} diff --git a/library/cpp/actors/util/should_continue.cpp b/library/cpp/actors/util/should_continue.cpp deleted file mode 100644 index 258e6a0aff..0000000000 --- a/library/cpp/actors/util/should_continue.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "should_continue.h" - -void TProgramShouldContinue::ShouldRestart() { - AtomicSet(State, Restart); -} - -void TProgramShouldContinue::ShouldStop(int returnCode) { - AtomicSet(ReturnCode, returnCode); - AtomicSet(State, Stop); -} - -TProgramShouldContinue::EState TProgramShouldContinue::PollState() { - return static_cast<EState>(AtomicGet(State)); -} - -int TProgramShouldContinue::GetReturnCode() { - return static_cast<int>(AtomicGet(ReturnCode)); -} - -void TProgramShouldContinue::Reset() { - AtomicSet(ReturnCode, 0); - AtomicSet(State, Continue); -} diff --git a/library/cpp/actors/util/should_continue.h b/library/cpp/actors/util/should_continue.h deleted file mode 100644 index 76acc40dc4..0000000000 --- a/library/cpp/actors/util/should_continue.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "defs.h" - -class TProgramShouldContinue { -public: - enum EState { - Continue, - Stop, - Restart, - }; - - void ShouldRestart(); - void ShouldStop(int returnCode = 0); - - EState PollState(); - int GetReturnCode(); - - void Reset(); -private: - TAtomic ReturnCode = 0; - TAtomic State = Continue; -}; diff --git a/library/cpp/actors/util/thread.h b/library/cpp/actors/util/thread.h deleted file mode 100644 index d742c8c585..0000000000 --- a/library/cpp/actors/util/thread.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include <util/generic/strbuf.h> -#include <util/stream/str.h> -#include <util/system/execpath.h> -#include <util/system/thread.h> -#include <util/system/thread.h> -#include <time.h> - -inline void SetCurrentThreadName(const TString& name, - const ui32 maxCharsFromProcessName = 8) { -#if defined(_linux_) - // linux limits threadname by 15 + \0 - - TStringBuf procName(GetExecPath()); - procName = procName.RNextTok('/'); - procName = procName.SubStr(0, maxCharsFromProcessName); - - TStringStream linuxName; - linuxName << procName << "." << name; - TThread::SetCurrentThreadName(linuxName.Str().data()); -#else - Y_UNUSED(maxCharsFromProcessName); - TThread::SetCurrentThreadName(name.data()); -#endif -} diff --git a/library/cpp/actors/util/thread_load_log.h b/library/cpp/actors/util/thread_load_log.h deleted file mode 100644 index 132e99a52d..0000000000 --- a/library/cpp/actors/util/thread_load_log.h +++ /dev/null @@ -1,363 +0,0 @@ -#pragma once - -#include "defs.h" - -#include <util/system/types.h> - -#include <type_traits> -#include <algorithm> -#include <atomic> -#include <limits> -#include <queue> - -template <ui64 TIME_SLOT_COUNT, ui64 TIME_SLOT_LENGTH_NS = 131'072, typename Type = std::uint8_t> -class TThreadLoad { -public: - using TimeSlotType = Type; - -private: - static constexpr auto TIME_SLOT_MAX_VALUE = std::numeric_limits<TimeSlotType>::max(); - static constexpr ui64 TIME_SLOT_PART_COUNT = TIME_SLOT_MAX_VALUE + 1; - static constexpr auto TIME_SLOT_PART_LENGTH_NS = TIME_SLOT_LENGTH_NS / TIME_SLOT_PART_COUNT; - - template <typename T> - static void AtomicAddBound(std::atomic<T>& val, i64 inc) { - if (inc == 0) { - return; - } - - auto newVal = val.load(); - auto oldVal = newVal; - - do { - static constexpr auto MAX_VALUE = std::numeric_limits<T>::max(); - - if (oldVal >= MAX_VALUE) { - return; - } - newVal = std::min<i64>(MAX_VALUE, static_cast<i64>(oldVal) + inc); - } while (!val.compare_exchange_weak(oldVal, newVal)); - } - - template <typename T> - static void AtomicSubBound(std::atomic<T>& val, i64 sub) { - if (sub == 0) { - return; - } - - auto newVal = val.load(); - auto oldVal = newVal; - - do { - if (oldVal == 0) { - return; - } - newVal = std::max<i64>(0, static_cast<i64>(oldVal) - sub); - } while (!val.compare_exchange_weak(oldVal, newVal)); - } - - void UpdateCompleteTimeSlots(ui64 firstSlotNumber, ui64 lastSlotNumber, TimeSlotType timeSlotValue) { - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - const ui64 firstTimeSlotsPass = firstSlotNumber / TIME_SLOT_COUNT; - const ui64 lastTimeSlotsPass = lastSlotNumber / TIME_SLOT_COUNT; - - if (firstTimeSlotsPass == lastTimeSlotsPass) { - // first and last time slots are in the same pass - for (auto slotNumber = firstSlotNumber + 1; slotNumber < lastSlotNumber; ++slotNumber) { - auto slotIndex = slotNumber % TIME_SLOT_COUNT; - TimeSlots[slotIndex] = timeSlotValue; - } - } else if (firstTimeSlotsPass + 1 == lastTimeSlotsPass) { - for (auto slotIndex = (firstSlotNumber + 1) % TIME_SLOT_COUNT; firstSlotIndex < slotIndex && slotIndex < TIME_SLOT_COUNT; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - for (auto slotIndex = 0u; slotIndex < lastSlotIndex; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - } else { - for (auto slotIndex = 0u; slotIndex < TIME_SLOT_COUNT; ++slotIndex) { - TimeSlots[slotIndex] = timeSlotValue; - } - } - } - -public: - std::atomic<ui64> LastTimeNs; - std::atomic<TimeSlotType> TimeSlots[TIME_SLOT_COUNT]; - std::atomic<bool> LastRegisteredPeriodIsBusy = false; - - explicit TThreadLoad(ui64 timeNs = 0) { - static_assert(std::is_unsigned<TimeSlotType>::value); - - LastTimeNs = timeNs; - for (size_t i = 0; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = 0; - } - } - - static constexpr auto GetTimeSlotCount() { - return TIME_SLOT_COUNT; - } - - static constexpr auto GetTimeSlotLengthNs() { - return TIME_SLOT_LENGTH_NS; - } - - static constexpr auto GetTimeSlotPartLengthNs() { - return TIME_SLOT_PART_LENGTH_NS; - } - - static constexpr auto GetTimeSlotPartCount() { - return TIME_SLOT_PART_COUNT; - } - - static constexpr auto GetTimeSlotMaxValue() { - return TIME_SLOT_MAX_VALUE; - } - - static constexpr auto GetTimeWindowLengthNs() { - return TIME_SLOT_COUNT * TIME_SLOT_LENGTH_NS; - } - - void RegisterBusyPeriod(ui64 timeNs) { - RegisterBusyPeriod<true>(timeNs, LastTimeNs.load()); - } - - template <bool ModifyLastTime> - void RegisterBusyPeriod(ui64 timeNs, ui64 lastTimeNs) { - LastRegisteredPeriodIsBusy = true; - - if (timeNs < lastTimeNs) { - // when time goes back, mark all time slots as 'free' - for (size_t i = 0u; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = 0; - } - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - - return; - } - - // lastTimeNs <= timeNs - ui64 firstSlotNumber = lastTimeNs / TIME_SLOT_LENGTH_NS; - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui64 lastSlotNumber = timeNs / TIME_SLOT_LENGTH_NS; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - if (firstSlotNumber == lastSlotNumber) { - ui32 slotLengthNs = timeNs - lastTimeNs; - ui32 slotPartsCount = (slotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - AtomicAddBound(TimeSlots[firstSlotIndex], slotPartsCount); - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - return; - } - - ui32 firstSlotLengthNs = TIME_SLOT_LENGTH_NS - (lastTimeNs % TIME_SLOT_LENGTH_NS); - ui32 firstSlotPartsCount = (firstSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - ui32 lastSlotLengthNs = timeNs % TIME_SLOT_LENGTH_NS; - ui32 lastSlotPartsCount = (lastSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - - // process first time slot - AtomicAddBound(TimeSlots[firstSlotIndex], firstSlotPartsCount); - - // process complete time slots - UpdateCompleteTimeSlots(firstSlotNumber, lastSlotNumber, TIME_SLOT_MAX_VALUE); - - // process last time slot - AtomicAddBound(TimeSlots[lastSlotIndex], lastSlotPartsCount); - - if (ModifyLastTime) { - LastTimeNs = timeNs; - } - } - - void RegisterIdlePeriod(ui64 timeNs) { - LastRegisteredPeriodIsBusy = false; - - ui64 lastTimeNs = LastTimeNs.load(); - if (timeNs < lastTimeNs) { - // when time goes back, mark all time slots as 'busy' - for (size_t i = 0u; i < TIME_SLOT_COUNT; ++i) { - TimeSlots[i] = TIME_SLOT_MAX_VALUE; - } - LastTimeNs = timeNs; - return; - } - - // lastTimeNs <= timeNs - ui64 firstSlotNumber = lastTimeNs / TIME_SLOT_LENGTH_NS; - ui32 firstSlotIndex = firstSlotNumber % TIME_SLOT_COUNT; - ui64 lastSlotNumber = timeNs / TIME_SLOT_LENGTH_NS; - ui32 lastSlotIndex = lastSlotNumber % TIME_SLOT_COUNT; - - if (firstSlotNumber == lastSlotNumber) { - ui32 slotLengthNs = timeNs - lastTimeNs; - ui32 slotPartsCount = slotLengthNs / TIME_SLOT_PART_LENGTH_NS; - - AtomicSubBound(TimeSlots[firstSlotIndex], slotPartsCount); - - LastTimeNs = timeNs; - return; - } - - ui32 firstSlotLengthNs = TIME_SLOT_LENGTH_NS - (lastTimeNs % TIME_SLOT_LENGTH_NS); - ui32 firstSlotPartsCount = (firstSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - ui32 lastSlotLengthNs = timeNs % TIME_SLOT_LENGTH_NS; - ui32 lastSlotPartsCount = (lastSlotLengthNs + TIME_SLOT_PART_LENGTH_NS - 1) / TIME_SLOT_PART_LENGTH_NS; - - // process first time slot - AtomicSubBound(TimeSlots[firstSlotIndex], firstSlotPartsCount); - - // process complete time slots - UpdateCompleteTimeSlots(firstSlotNumber, lastSlotNumber, 0); - - // process last time slot - AtomicSubBound(TimeSlots[lastSlotIndex], lastSlotPartsCount); - - LastTimeNs = timeNs; - } -}; - -class TMinusOneThreadEstimator { -private: - template <typename T, int MaxSize> - class TArrayQueue { - public: - bool empty() const { - return FrontIndex == -1; - } - - bool full() const { - return (RearIndex + 1) % MaxSize == FrontIndex; - } - - T& front() { - return Data[FrontIndex]; - } - - bool push(T &&t) { - if (full()) { - return false; - } - - if (FrontIndex == -1) { - FrontIndex = 0; - } - - RearIndex = (RearIndex + 1) % MaxSize; - Data[RearIndex] = std::move(t); - return true; - } - - bool pop() { - if (empty()) { - return false; - } - - if (FrontIndex == RearIndex) { - FrontIndex = RearIndex = -1; - } else { - FrontIndex = (FrontIndex + 1) % MaxSize; - } - - return true; - } - - private: - int FrontIndex = -1; - int RearIndex = -1; - T Data[MaxSize]; - }; - -public: - template <typename T> - ui64 MaxLatencyIncreaseWithOneLessCpu(T **threadLoads, ui32 threadCount, ui64 timeNs, ui64 periodNs) { - Y_ABORT_UNLESS(threadCount > 0); - - struct TTimeSlotData { - typename T::TimeSlotType Load; - ui64 Index; - }; - - ui64 lastTimeNs = timeNs; - for (auto threadIndex = 0u; threadIndex < threadCount; ++threadIndex) { - if (threadLoads[threadIndex]->LastRegisteredPeriodIsBusy.load()) { - lastTimeNs = std::min(lastTimeNs, threadLoads[threadIndex]->LastTimeNs.load()); - } else { - // make interval [lastTimeNs, timeNs] 'busy' - threadLoads[threadIndex]->template RegisterBusyPeriod<false>(timeNs, threadLoads[threadIndex]->LastTimeNs.load()); - } - } - - periodNs = std::min(T::GetTimeWindowLengthNs(), periodNs); - - ui64 beginTimeNs = periodNs < timeNs ? timeNs - periodNs : 0; - - ui64 firstSlotNumber = beginTimeNs / T::GetTimeSlotLengthNs(); - ui64 lastSlotNumber = (lastTimeNs + T::GetTimeSlotLengthNs() - 1) / T::GetTimeSlotLengthNs(); - - ui64 maxTimeSlotShiftCount = 0u; - TArrayQueue<TTimeSlotData, T::GetTimeSlotCount()> firstThreadLoadDataQueue; - - for (auto slotNumber = firstSlotNumber; slotNumber < lastSlotNumber; ++slotNumber) { - ui64 slotIndex = slotNumber % T::GetTimeSlotCount(); - - typename T::TimeSlotType firstThreadTimeSlotValue = threadLoads[0]->TimeSlots[slotIndex].load(); - - // distribute previous load of the first thread by other threads - auto foundIdleThread = false; - - for (auto threadIndex = 1u; threadIndex < threadCount; ++threadIndex) { - typename T::TimeSlotType thisThreadAvailableTimeSlotLoad = threadLoads[threadIndex]->GetTimeSlotMaxValue() - threadLoads[threadIndex]->TimeSlots[slotIndex].load(); - - while (!firstThreadLoadDataQueue.empty() && thisThreadAvailableTimeSlotLoad > 0) { - auto& firstThreadLoadData = firstThreadLoadDataQueue.front(); - - auto distributedLoad = std::min(thisThreadAvailableTimeSlotLoad, firstThreadLoadData.Load); - - thisThreadAvailableTimeSlotLoad -= distributedLoad; - firstThreadLoadData.Load -= distributedLoad; - - if (firstThreadLoadData.Load == 0) { - auto timeSlotShiftCount = slotIndex - firstThreadLoadData.Index; - maxTimeSlotShiftCount = std::max(maxTimeSlotShiftCount, timeSlotShiftCount); - auto res = firstThreadLoadDataQueue.pop(); - Y_ABORT_UNLESS(res); - } - } - - if (thisThreadAvailableTimeSlotLoad == threadLoads[threadIndex]->GetTimeSlotMaxValue()) { - foundIdleThread = true; - } - } - - // distribute current load of the first thread by other threads - if (firstThreadTimeSlotValue > 0) { - if (foundIdleThread) { - // The current load of the first thead can be - // moved to the idle thread so there is nothing to do - } else { - // The current load of the first thread can be later - // processed by the following time slots of other threads - auto res = firstThreadLoadDataQueue.push({firstThreadTimeSlotValue, slotIndex}); - Y_ABORT_UNLESS(res); - } - } - } - - if (!firstThreadLoadDataQueue.empty()) { - const auto& timeSlotData = firstThreadLoadDataQueue.front(); - auto timeSlotShiftCount = T::GetTimeSlotCount() - timeSlotData.Index; - maxTimeSlotShiftCount = std::max(maxTimeSlotShiftCount, timeSlotShiftCount); - } - - return maxTimeSlotShiftCount * T::GetTimeSlotLengthNs(); - } -}; diff --git a/library/cpp/actors/util/thread_load_log_ut.cpp b/library/cpp/actors/util/thread_load_log_ut.cpp deleted file mode 100644 index 20e776cff6..0000000000 --- a/library/cpp/actors/util/thread_load_log_ut.cpp +++ /dev/null @@ -1,966 +0,0 @@ -#include "thread_load_log.h" - -#include <library/cpp/testing/unittest/registar.h> - -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/thread.h> -#include <util/system/types.h> -#include <util/system/sanitizers.h> - -#include <limits> - -Y_UNIT_TEST_SUITE(ThreadLoadLog) { - - Y_UNIT_TEST(TThreadLoad8BitSlotType) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint8_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeWindowLengthNs(), timeWindowLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotLengthNs(), timeSlotLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotCount(), timeSlotCount); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotMaxValue(), std::numeric_limits<TSlotType>::max()); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<TSlotType>::max() + 1); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartLengthNs(), T::GetTimeSlotLengthNs() / T::GetTimeSlotPartCount()); - } - - Y_UNIT_TEST(TThreadLoad16BitSlotType) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint16_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeWindowLengthNs(), timeWindowLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotLengthNs(), timeSlotLengthNs); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotCount(), timeSlotCount); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotMaxValue(), std::numeric_limits<TSlotType>::max()); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<TSlotType>::max() + 1); - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartLengthNs(), T::GetTimeSlotLengthNs() / T::GetTimeSlotPartCount()); - } - - Y_UNIT_TEST(TThreadLoad8BitSlotTypeWindowBusy) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint8_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - T threadLoad; - threadLoad.RegisterBusyPeriod(T::GetTimeWindowLengthNs()); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), T::GetTimeSlotMaxValue()); - } - } - - Y_UNIT_TEST(TThreadLoad16BitSlotTypeWindowBusy) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using TSlotType = std::uint16_t; - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, TSlotType>; - - T threadLoad; - threadLoad.RegisterBusyPeriod(T::GetTimeWindowLengthNs()); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), T::GetTimeSlotMaxValue()); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot2) { - using T = TThreadLoad<38400>; - - ui32 startNs = 2 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot3) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTimeSlot4) { - using T = TThreadLoad<38400>; - - ui32 startNs = 2 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), (timeNs - startNs) / T::GetTimeSlotPartLengthNs()); - - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTwoTimeSlots1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstTwoTimeSlots2) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots1) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots2) { - TThreadLoad<38400> threadLoad; - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterBusyPeriodFirstThreeTimeSlots3) { - using T = TThreadLoad<38400>; - - ui32 startNs = 3 * T::GetTimeSlotPartLengthNs(); - T threadLoad(startNs); - - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 0; - threadLoad.RegisterBusyPeriod(timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot1) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot2) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 3); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTimeSlot3) { - using T = TThreadLoad<38400>; - - ui64 timeNs = T::GetTimeSlotPartLengthNs(); - T threadLoad(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 3 * T::GetTimeSlotPartLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 4 * T::GetTimeSlotPartLengthNs() - 2; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 5 * T::GetTimeSlotPartLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 3); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots1) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots2) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstTwoTimeSlots3) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs() - 1; - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 1); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots1) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots2) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 1u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots3) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots4) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = threadLoad.GetTimeSlotLengthNs() + 2 * threadLoad.GetTimeSlotPartLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - timeNs = 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotPartCount() - 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 3u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodFirstThreeTimeSlots5) { - using T = TThreadLoad<38400>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 2 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 2u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = timeNs + threadLoad.GetTimeWindowLengthNs() + threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(TThreadLoadRegisterIdlePeriodOverTimeWindow) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint8_t>; - - T threadLoad; - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), 0); - for (auto slotIndex = 0u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - ui64 timeNs = 5 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[3].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[4].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 5u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - - timeNs = timeNs + threadLoad.GetTimeWindowLengthNs() - 3 * threadLoad.GetTimeSlotLengthNs(); - threadLoad.RegisterIdlePeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoad.LastTimeNs.load(), timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[0].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[1].load(), 0); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[2].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[3].load(), threadLoad.GetTimeSlotMaxValue()); - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[4].load(), threadLoad.GetTimeSlotMaxValue()); - for (auto slotIndex = 5u; slotIndex < threadLoad.GetTimeSlotCount(); ++slotIndex) { - UNIT_ASSERT_VALUES_EQUAL(threadLoad.TimeSlots[slotIndex].load(), 0); - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsZeroShiftNs) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - UNIT_ASSERT_VALUES_EQUAL(T::GetTimeSlotPartCount(), (ui64)std::numeric_limits<std::uint16_t>::max() + 1); - - T *threadLoads[2]; - threadLoads[0] = new T; - threadLoads[1] = new T; - - for (ui64 i = 1; i < timeSlotCount; i += 2) { - threadLoads[0]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - threadLoads[0]->RegisterBusyPeriod((i + 1) * T::GetTimeSlotLengthNs()); - } - - for (ui64 i = 1; i < timeSlotCount; i += 2) { - threadLoads[1]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - threadLoads[1]->RegisterIdlePeriod((i + 1) * T::GetTimeSlotLengthNs()); - } - - TMinusOneThreadEstimator estimator; - ui64 value = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, 2, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - UNIT_ASSERT_VALUES_EQUAL(value, 0); - - delete threadLoads[0]; - delete threadLoads[1]; - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsOneTimeSlotShift1) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 2; i < threadLoads[t]->GetTimeSlotCount(); i += 2) { - threadLoads[t]->RegisterIdlePeriod((i - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterIdlePeriod((threadLoads[t]->GetTimeSlotCount() - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsOneTimeSlotShift2) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 2; i < threadLoads[t]->GetTimeSlotCount(); i += 2) { - threadLoads[t]->RegisterBusyPeriod((i - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterBusyPeriod((threadLoads[t]->GetTimeSlotCount() - 1) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 0) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 2 == 0) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift1) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 4; i < threadLoads[t]->GetTimeSlotCount(); i += 4) { - threadLoads[t]->RegisterIdlePeriod((i - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterIdlePeriod((threadLoads[t]->GetTimeSlotCount() - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterBusyPeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 2 || s % 4 == 3) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 2 || s % 4 == 3) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[s].load(), 0); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift2) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - for (ui64 i = 4; i < threadLoads[t]->GetTimeSlotCount(); i += 4) { - threadLoads[t]->RegisterBusyPeriod((i - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(i * T::GetTimeSlotLengthNs()); - } - - threadLoads[t]->RegisterBusyPeriod((threadLoads[t]->GetTimeSlotCount() - 2) * T::GetTimeSlotLengthNs()); - threadLoads[t]->RegisterIdlePeriod(threadLoads[t]->GetTimeSlotCount() * T::GetTimeSlotLengthNs()); - - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 0 || s % 4 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (ui64 t = 0; t < threadCount; ++t) { - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - if (s % 4 == 0 || s % 4 == 1) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } else { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimatorTwoThreadLoadsTwoTimeSlotsShift3) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 2; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - - auto timeNs = T::GetTimeWindowLengthNs() - 1.5 * T::GetTimeSlotLengthNs(); - threadLoads[t]->RegisterIdlePeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - - timeNs = T::GetTimeWindowLengthNs(); - threadLoads[t]->RegisterBusyPeriod(timeNs); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - - for (ui64 s = 0; s + 2 < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 2].load(), T::GetTimeSlotPartCount() / 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 1].load(), T::GetTimeSlotMaxValue()); - } - - TMinusOneThreadEstimator estimator; - auto result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - for (ui64 s = 0; s + 2 < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), 0, ToString(s).c_str()); - } - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 2].load(), T::GetTimeSlotPartCount() / 2); - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->TimeSlots[timeSlotCount - 1].load(), T::GetTimeSlotMaxValue()); - } - - UNIT_ASSERT_VALUES_EQUAL(result, 2 * T::GetTimeSlotLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - - Y_UNIT_TEST(MinusOneThreadEstimator16ThreadLoadsAllTimeSlots) { - constexpr auto timeWindowLengthNs = 5368709120ull; // 5 * 2 ^ 30 ~5 sec - constexpr auto timeSlotLengthNs = 524288ull; // 2 ^ 19 ns ~ 512 usec - constexpr auto timeSlotCount = timeWindowLengthNs / timeSlotLengthNs; - constexpr auto threadCount = 16; - constexpr auto estimatesCount = 16; - - using T = TThreadLoad<timeSlotCount, timeSlotLengthNs, std::uint16_t>; - - for (auto e = 0u; e < estimatesCount; ++e) { - T *threadLoads[threadCount]; - - for (auto t = 0u; t < threadCount; ++t) { - threadLoads[t] = new T; - auto timeNs = threadLoads[t]->GetTimeWindowLengthNs(); - threadLoads[t]->RegisterBusyPeriod(timeNs); - - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), timeNs); - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } - } - - ui64 result = 0; - { - THPTimer timer; - TMinusOneThreadEstimator estimator; - result = estimator.MaxLatencyIncreaseWithOneLessCpu(threadLoads, threadCount, T::GetTimeWindowLengthNs(), T::GetTimeWindowLengthNs()); - // output in microseconds - auto passed = timer.Passed() * 1000000; - Y_UNUSED(passed); - // Cerr << "timer : " << passed << " " << __LINE__ << Endl; - } - - for (ui64 t = 0; t < threadCount; ++t) { - UNIT_ASSERT_VALUES_EQUAL(threadLoads[t]->LastTimeNs.load(), T::GetTimeWindowLengthNs()); - for (ui64 s = 0; s < threadLoads[t]->GetTimeSlotCount(); ++s) { - UNIT_ASSERT_VALUES_EQUAL_C(threadLoads[t]->TimeSlots[s].load(), T::GetTimeSlotMaxValue(), ToString(s).c_str()); - } - } - - UNIT_ASSERT_VALUES_EQUAL(result, T::GetTimeWindowLengthNs()); - - for (auto t = 0u; t < threadCount; ++t) { - delete threadLoads[t]; - } - } - } -} diff --git a/library/cpp/actors/util/threadparkpad.cpp b/library/cpp/actors/util/threadparkpad.cpp deleted file mode 100644 index b939d6b61a..0000000000 --- a/library/cpp/actors/util/threadparkpad.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "threadparkpad.h" -#include <util/system/winint.h> - -#ifdef _linux_ - -#include "futex.h" - -namespace NActors { - class TThreadParkPad::TImpl { - volatile bool Interrupted; - int Futex; - - public: - TImpl() - : Interrupted(false) - , Futex(0) - { - } - ~TImpl() { - } - - bool Park() noexcept { - __atomic_fetch_sub(&Futex, 1, __ATOMIC_SEQ_CST); - while (__atomic_load_n(&Futex, __ATOMIC_ACQUIRE) == -1) - SysFutex(&Futex, FUTEX_WAIT_PRIVATE, -1, nullptr, nullptr, 0); - return IsInterrupted(); - } - - void Unpark() noexcept { - const int old = __atomic_fetch_add(&Futex, 1, __ATOMIC_SEQ_CST); - if (old == -1) - SysFutex(&Futex, FUTEX_WAKE_PRIVATE, -1, nullptr, nullptr, 0); - } - - void Interrupt() noexcept { - __atomic_store_n(&Interrupted, true, __ATOMIC_SEQ_CST); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return __atomic_load_n(&Interrupted, __ATOMIC_ACQUIRE); - } - }; - -#elif defined _win32_ -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/generic/bt_exception.h> -#include <util/generic/yexception.h> - -namespace NActors { - class TThreadParkPad::TImpl { - TAtomic Interrupted; - HANDLE EvHandle; - - public: - TImpl() - : Interrupted(false) - { - EvHandle = ::CreateEvent(0, false, false, 0); - if (!EvHandle) - ythrow TWithBackTrace<yexception>() << "::CreateEvent failed"; - } - ~TImpl() { - if (EvHandle) - ::CloseHandle(EvHandle); - } - - bool Park() noexcept { - ::WaitForSingleObject(EvHandle, INFINITE); - return AtomicGet(Interrupted); - } - - void Unpark() noexcept { - ::SetEvent(EvHandle); - } - - void Interrupt() noexcept { - AtomicSet(Interrupted, true); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return AtomicGet(Interrupted); - } - }; - -#else - -#include <library/cpp/deprecated/atomic/atomic.h> - -#include <util/system/event.h> - -namespace NActors { - class TThreadParkPad::TImpl { - TAtomic Interrupted; - TSystemEvent Ev; - - public: - TImpl() - : Interrupted(false) - , Ev(TSystemEvent::rAuto) - { - } - ~TImpl() { - } - - bool Park() noexcept { - Ev.Wait(); - return AtomicGet(Interrupted); - } - - void Unpark() noexcept { - Ev.Signal(); - } - - void Interrupt() noexcept { - AtomicSet(Interrupted, true); - Unpark(); - } - - bool IsInterrupted() const noexcept { - return AtomicGet(Interrupted); - } - }; -#endif - - TThreadParkPad::TThreadParkPad() - : Impl(new TThreadParkPad::TImpl()) - { - } - - TThreadParkPad::~TThreadParkPad() { - } - - bool TThreadParkPad::Park() noexcept { - return Impl->Park(); - } - - void TThreadParkPad::Unpark() noexcept { - Impl->Unpark(); - } - - void TThreadParkPad::Interrupt() noexcept { - Impl->Interrupt(); - } - - bool TThreadParkPad::Interrupted() const noexcept { - return Impl->IsInterrupted(); - } - -} diff --git a/library/cpp/actors/util/threadparkpad.h b/library/cpp/actors/util/threadparkpad.h deleted file mode 100644 index 5b574ccf34..0000000000 --- a/library/cpp/actors/util/threadparkpad.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include <util/generic/ptr.h> - -namespace NActors { - class TThreadParkPad { - private: - class TImpl; - THolder<TImpl> Impl; - - public: - TThreadParkPad(); - ~TThreadParkPad(); - - bool Park() noexcept; - void Unpark() noexcept; - void Interrupt() noexcept; - bool Interrupted() const noexcept; - }; - -} diff --git a/library/cpp/actors/util/ticket_lock.h b/library/cpp/actors/util/ticket_lock.h deleted file mode 100644 index 30355c3390..0000000000 --- a/library/cpp/actors/util/ticket_lock.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "intrinsics.h" -#include <util/system/guard.h> -#include <util/system/yassert.h> - -class TTicketLock : TNonCopyable { - ui32 TicketIn; - ui32 TicketOut; - -public: - TTicketLock() - : TicketIn(0) - , TicketOut(0) - { - } - - void Release() noexcept { - AtomicUi32Increment(&TicketOut); - } - - ui32 Acquire() noexcept { - ui32 revolves = 0; - const ui32 ticket = AtomicUi32Increment(&TicketIn) - 1; - while (ticket != AtomicLoad(&TicketOut)) { - Y_DEBUG_ABORT_UNLESS(ticket >= AtomicLoad(&TicketOut)); - SpinLockPause(); - ++revolves; - } - return revolves; - } - - bool TryAcquire() noexcept { - const ui32 x = AtomicLoad(&TicketOut); - if (x == AtomicLoad(&TicketIn) && AtomicUi32Cas(&TicketIn, x + 1, x)) - return true; - else - return false; - } - - bool IsLocked() noexcept { - const ui32 ticketIn = AtomicLoad(&TicketIn); - const ui32 ticketOut = AtomicLoad(&TicketOut); - return (ticketIn != ticketOut); - } - - typedef ::TGuard<TTicketLock> TGuard; -}; diff --git a/library/cpp/actors/util/timerfd.h b/library/cpp/actors/util/timerfd.h deleted file mode 100644 index 78ae27e2ee..0000000000 --- a/library/cpp/actors/util/timerfd.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "datetime.h" - -#include <util/generic/noncopyable.h> - -#ifdef _linux_ - -#include <util/system/yassert.h> -#include <errno.h> -#include <sys/timerfd.h> - -struct TTimerFd: public TNonCopyable { - int Fd; - - TTimerFd() { - Fd = timerfd_create(CLOCK_MONOTONIC, 0); - Y_ABORT_UNLESS(Fd != -1, "timerfd_create(CLOCK_MONOTONIC, 0) -> -1; errno:%d: %s", int(errno), strerror(errno)); - } - - ~TTimerFd() { - close(Fd); - } - - void Set(ui64 ts) { - ui64 now = GetCycleCountFast(); - Arm(now >= ts? 1: NHPTimer::GetSeconds(ts - now) * 1e9); - } - - void Reset() { - Arm(0); // disarm timer - } - - void Wait() { - ui64 expirations; - ssize_t s = read(Fd, &expirations, sizeof(ui64)); - Y_UNUSED(s); // Y_ABORT_UNLESS(s == sizeof(ui64)); - } - - void Wake() { - Arm(1); - } -private: - void Arm(ui64 ns) { - struct itimerspec spec; - spec.it_value.tv_sec = ns / 1'000'000'000; - spec.it_value.tv_nsec = ns % 1'000'000'000; - spec.it_interval.tv_sec = 0; - spec.it_interval.tv_nsec = 0; - int ret = timerfd_settime(Fd, 0, &spec, nullptr); - Y_ABORT_UNLESS(ret != -1, "timerfd_settime(%d, 0, %" PRIu64 "ns, 0) -> %d; errno:%d: %s", Fd, ns, ret, int(errno), strerror(errno)); - } -}; - -#else - -struct TTimerFd: public TNonCopyable { - int Fd = 0; - void Set(ui64) {} - void Reset() {} - void Wait() {} - void Wake() {} -}; - -#endif diff --git a/library/cpp/actors/util/unordered_cache.h b/library/cpp/actors/util/unordered_cache.h deleted file mode 100644 index 40794fc04b..0000000000 --- a/library/cpp/actors/util/unordered_cache.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "defs.h" -#include "queue_chunk.h" - -template <typename T, ui32 Size = 512, ui32 ConcurrencyFactor = 1, typename TChunk = TQueueChunk<T, Size>> -class TUnorderedCache : TNonCopyable { - static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "expect std::is_integral<T>::value || std::is_pointer<T>::value"); - -public: - static constexpr ui32 Concurrency = ConcurrencyFactor * 4; - -private: - struct TReadSlot { - TChunk* volatile ReadFrom; - volatile ui32 ReadPosition; - char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line - }; - - struct TWriteSlot { - TChunk* volatile WriteTo; - volatile ui32 WritePosition; - char Padding[64 - sizeof(TChunk*) - sizeof(ui32)]; // 1 slot per cache line - }; - - static_assert(sizeof(TReadSlot) == 64, "expect sizeof(TReadSlot) == 64"); - static_assert(sizeof(TWriteSlot) == 64, "expect sizeof(TWriteSlot) == 64"); - -private: - TReadSlot ReadSlots[Concurrency]; - TWriteSlot WriteSlots[Concurrency]; - - static_assert(sizeof(TChunk*) == sizeof(TAtomic), "expect sizeof(TChunk*) == sizeof(TAtomic)"); - -private: - struct TLockedWriter { - TWriteSlot* Slot; - TChunk* WriteTo; - - TLockedWriter() - : Slot(nullptr) - , WriteTo(nullptr) - { } - - TLockedWriter(TWriteSlot* slot, TChunk* writeTo) - : Slot(slot) - , WriteTo(writeTo) - { } - - ~TLockedWriter() noexcept { - Drop(); - } - - void Drop() { - if (Slot) { - AtomicStore(&Slot->WriteTo, WriteTo); - Slot = nullptr; - } - } - - TLockedWriter(const TLockedWriter&) = delete; - TLockedWriter& operator=(const TLockedWriter&) = delete; - - TLockedWriter(TLockedWriter&& rhs) - : Slot(rhs.Slot) - , WriteTo(rhs.WriteTo) - { - rhs.Slot = nullptr; - } - - TLockedWriter& operator=(TLockedWriter&& rhs) { - if (Y_LIKELY(this != &rhs)) { - Drop(); - Slot = rhs.Slot; - WriteTo = rhs.WriteTo; - rhs.Slot = nullptr; - } - return *this; - } - }; - -private: - TLockedWriter LockWriter(ui64 writerRotation) { - ui32 cycle = 0; - for (;;) { - TWriteSlot* slot = &WriteSlots[writerRotation % Concurrency]; - if (AtomicLoad(&slot->WriteTo) != nullptr) { - if (TChunk* writeTo = AtomicSwap(&slot->WriteTo, nullptr)) { - return TLockedWriter(slot, writeTo); - } - } - ++writerRotation; - - // Do a spinlock pause after a full cycle - if (++cycle == Concurrency) { - SpinLockPause(); - cycle = 0; - } - } - } - - void WriteOne(TLockedWriter& lock, T x) { - Y_DEBUG_ABORT_UNLESS(x != 0); - - const ui32 pos = AtomicLoad(&lock.Slot->WritePosition); - if (pos != TChunk::EntriesCount) { - AtomicStore(&lock.Slot->WritePosition, pos + 1); - AtomicStore(&lock.WriteTo->Entries[pos], x); - } else { - TChunk* next = new TChunk(); - AtomicStore(&next->Entries[0], x); - AtomicStore(&lock.Slot->WritePosition, 1u); - AtomicStore(&lock.WriteTo->Next, next); - lock.WriteTo = next; - } - } - -public: - TUnorderedCache() { - for (ui32 i = 0; i < Concurrency; ++i) { - ReadSlots[i].ReadFrom = new TChunk(); - ReadSlots[i].ReadPosition = 0; - - WriteSlots[i].WriteTo = ReadSlots[i].ReadFrom; - WriteSlots[i].WritePosition = 0; - } - } - - ~TUnorderedCache() { - Y_ABORT_UNLESS(!Pop(0)); - - for (ui64 i = 0; i < Concurrency; ++i) { - if (ReadSlots[i].ReadFrom) { - delete ReadSlots[i].ReadFrom; - ReadSlots[i].ReadFrom = nullptr; - } - WriteSlots[i].WriteTo = nullptr; - } - } - - T Pop(ui64 readerRotation) noexcept { - ui64 readerIndex = readerRotation; - const ui64 endIndex = readerIndex + Concurrency; - for (; readerIndex != endIndex; ++readerIndex) { - TReadSlot* slot = &ReadSlots[readerIndex % Concurrency]; - if (AtomicLoad(&slot->ReadFrom) != nullptr) { - if (TChunk* readFrom = AtomicSwap(&slot->ReadFrom, nullptr)) { - const ui32 pos = AtomicLoad(&slot->ReadPosition); - if (pos != TChunk::EntriesCount) { - if (T ret = AtomicLoad(&readFrom->Entries[pos])) { - AtomicStore(&slot->ReadPosition, pos + 1); - AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk - return ret; // found, return - } else { - AtomicStore(&slot->ReadFrom, readFrom); // release lock with same chunk - } - } else if (TChunk* next = AtomicLoad(&readFrom->Next)) { - if (T ret = AtomicLoad(&next->Entries[0])) { - AtomicStore(&slot->ReadPosition, 1u); - AtomicStore(&slot->ReadFrom, next); // release lock with next chunk - delete readFrom; - return ret; - } else { - AtomicStore(&slot->ReadPosition, 0u); - AtomicStore(&slot->ReadFrom, next); // release lock with new chunk - delete readFrom; - } - } else { - // nothing in old chunk and no next chunk, just release lock with old chunk - AtomicStore(&slot->ReadFrom, readFrom); - } - } - } - } - - return 0; // got nothing after full cycle, return - } - - void Push(T x, ui64 writerRotation) { - TLockedWriter lock = LockWriter(writerRotation); - WriteOne(lock, x); - } - - void PushBulk(T* x, ui32 xcount, ui64 writerRotation) { - for (;;) { - // Fill no more then one queue chunk per round - const ui32 xround = Min(xcount, (ui32)TChunk::EntriesCount); - - { - TLockedWriter lock = LockWriter(writerRotation++); - for (T* end = x + xround; x != end; ++x) - WriteOne(lock, *x); - } - - if (xcount <= TChunk::EntriesCount) - break; - - xcount -= TChunk::EntriesCount; - } - } -}; diff --git a/library/cpp/actors/util/unordered_cache_ut.cpp b/library/cpp/actors/util/unordered_cache_ut.cpp deleted file mode 100644 index 37865f2f91..0000000000 --- a/library/cpp/actors/util/unordered_cache_ut.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "unordered_cache.h" - -#include <library/cpp/testing/unittest/registar.h> -#include <util/random/random.h> -#include <util/system/hp_timer.h> -#include <util/system/sanitizers.h> -#include <util/system/thread.h> - -Y_UNIT_TEST_SUITE(UnorderedCache) { - - void DoOnePushOnePop(ui64 count) { - TUnorderedCache<ui64> queue; - - ui64 readRotation = 0; - ui64 writeRotation = 0; - - auto popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - for (ui64 i = 0; i < count; ++i) { - queue.Push(i + 1, writeRotation++); - popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, i + 1); - - popped = queue.Pop(readRotation++); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - } - } - - Y_UNIT_TEST(OnePushOnePop) { - DoOnePushOnePop(1); - } - - Y_UNIT_TEST(OnePushOnePop_Repeat1M) { - DoOnePushOnePop(1000000); - } - - /** - * Simplified thread spawning for testing - */ - class TWorkerThread : public ISimpleThread { - private: - std::function<void()> Func; - double Time = 0.0; - - public: - TWorkerThread(std::function<void()> func) - : Func(std::move(func)) - { } - - double GetTime() const { - return Time; - } - - static THolder<TWorkerThread> Spawn(std::function<void()> func) { - THolder<TWorkerThread> thread = MakeHolder<TWorkerThread>(std::move(func)); - thread->Start(); - return thread; - } - - private: - void* ThreadProc() noexcept override { - THPTimer timer; - Func(); - Time = timer.Passed(); - return nullptr; - } - }; - - void DoConcurrentPushPop(size_t threads, ui64 perThreadCount) { - // Concurrency factor 4 is up to 16 threads - TUnorderedCache<ui64, 512, 4> queue; - - auto workerFunc = [&](size_t threadIndex) { - ui64 readRotation = 0; - ui64 writeRotation = 0; - ui64 readsDone = 0; - ui64 writesDone = 0; - for (;;) { - bool canRead = readsDone < writesDone; - bool canWrite = writesDone < perThreadCount; - if (!canRead && !canWrite) { - break; - } - if (canRead && canWrite) { - // Randomly choose between read and write - if (RandomNumber<ui64>(2)) { - canRead = false; - } else { - canWrite = false; - } - } - if (canRead) { - ui64 popped = queue.Pop(readRotation++); - if (popped) { - ++readsDone; - } - } - if (canWrite) { - queue.Push(1 + writesDone * threads + threadIndex, writeRotation++); - ++writesDone; - } - } - }; - - TVector<THolder<TWorkerThread>> workers(threads); - for (size_t i = 0; i < threads; ++i) { - workers[i] = TWorkerThread::Spawn([workerFunc, i]() { - workerFunc(i); - }); - } - - double maxTime = 0; - for (size_t i = 0; i < threads; ++i) { - workers[i]->Join(); - maxTime = Max(maxTime, workers[i]->GetTime()); - } - - auto popped = queue.Pop(0); - UNIT_ASSERT_VALUES_EQUAL(popped, 0u); - - Cerr << "Concurrent with " << threads << " threads: " << maxTime << " seconds" << Endl; - } - - void DoConcurrentPushPop_3times(size_t threads, ui64 perThreadCount) { - for (size_t i = 0; i < 3; ++i) { - DoConcurrentPushPop(threads, perThreadCount); - } - } - - static constexpr ui64 PER_THREAD_COUNT = NSan::PlainOrUnderSanitizer(1000000, 100000); - - Y_UNIT_TEST(ConcurrentPushPop_1thread) { DoConcurrentPushPop_3times(1, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_2threads) { DoConcurrentPushPop_3times(2, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_4threads) { DoConcurrentPushPop_3times(4, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_8threads) { DoConcurrentPushPop_3times(8, PER_THREAD_COUNT); } - Y_UNIT_TEST(ConcurrentPushPop_16threads) { DoConcurrentPushPop_3times(16, PER_THREAD_COUNT); } -} diff --git a/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt b/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt deleted file mode 100644 index 9b02cd1836..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.darwin-arm64.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt deleted file mode 100644 index f02b2d926c..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.darwin-x86_64.txt +++ /dev/null @@ -1,75 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -Wl,-platform_version,macos,11.0,11.0 - -fPIC - -fPIC - -framework - CoreFoundation -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt b/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt deleted file mode 100644 index 27ff864fef..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.linux-aarch64.txt +++ /dev/null @@ -1,78 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - cpp-malloc-jemalloc -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt deleted file mode 100644 index d1143a475b..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.linux-x86_64.txt +++ /dev/null @@ -1,80 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-linux-headers - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_link_options(library-cpp-actors-util-ut PRIVATE - -ldl - -lrt - -Wl,--no-as-needed - -fPIC - -fPIC - -lpthread - -lrt - -ldl -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - cpp-malloc-tcmalloc - libs-tcmalloc-no_percpu_cache -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/CMakeLists.txt b/library/cpp/actors/util/ut/CMakeLists.txt deleted file mode 100644 index 2dce3a77fe..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-aarch64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - include(CMakeLists.darwin-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - include(CMakeLists.darwin-arm64.txt) -elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) - include(CMakeLists.windows-x86_64.txt) -elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) - include(CMakeLists.linux-x86_64.txt) -endif() diff --git a/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt b/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt deleted file mode 100644 index 3af5d98ef0..0000000000 --- a/library/cpp/actors/util/ut/CMakeLists.windows-x86_64.txt +++ /dev/null @@ -1,68 +0,0 @@ - -# This file was generated by the build system used internally in the Yandex monorepo. -# Only simple modifications are allowed (adding source-files to targets, adding simple properties -# like target_include_directories). These modifications will be ported to original -# ya.make files by maintainers. Any complex modifications which can't be ported back to the -# original buildsystem will not be accepted. - - - -add_executable(library-cpp-actors-util-ut) -target_include_directories(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util -) -target_link_libraries(library-cpp-actors-util-ut PUBLIC - contrib-libs-cxxsupp - yutil - library-cpp-cpuid_check - cpp-testing-unittest_main - cpp-actors-util -) -target_sources(library-cpp-actors-util-ut PRIVATE - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/cpu_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/memory_tracker_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/thread_load_log_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rope_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/rc_buf_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/shared_data_native_rope_backend_ut.cpp - ${CMAKE_SOURCE_DIR}/library/cpp/actors/util/unordered_cache_ut.cpp -) -set_property( - TARGET - library-cpp-actors-util-ut - PROPERTY - SPLIT_FACTOR - 1 -) -add_yunittest( - NAME - library-cpp-actors-util-ut - TEST_TARGET - library-cpp-actors-util-ut - TEST_ARG - --print-before-suite - --print-before-test - --fork-tests - --print-times - --show-fails -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - LABELS - SMALL -) -set_yunittest_property( - TEST - library-cpp-actors-util-ut - PROPERTY - PROCESSORS - 1 -) -target_allocator(library-cpp-actors-util-ut - system_allocator -) -vcs_info(library-cpp-actors-util-ut) diff --git a/library/cpp/actors/util/ut/ya.make b/library/cpp/actors/util/ut/ya.make deleted file mode 100644 index 9ac8504751..0000000000 --- a/library/cpp/actors/util/ut/ya.make +++ /dev/null @@ -1,20 +0,0 @@ -UNITTEST_FOR(library/cpp/actors/util) - -IF (WITH_VALGRIND) - TIMEOUT(600) - SIZE(MEDIUM) -ENDIF() - -SRCS( - cpu_load_log_ut.cpp - memory_tracker_ut.cpp - thread_load_log_ut.cpp - rope_ut.cpp - rc_buf_ut.cpp - shared_data_ut.cpp - shared_data_rope_backend_ut.cpp - shared_data_native_rope_backend_ut.cpp - unordered_cache_ut.cpp -) - -END() diff --git a/library/cpp/actors/util/ut_helpers.h b/library/cpp/actors/util/ut_helpers.h deleted file mode 100644 index d3fe873233..0000000000 --- a/library/cpp/actors/util/ut_helpers.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -// calls TCallback for all args permutations including (id, id) -template <class TCallback, class... TArgs> -void Permutate(TCallback&& fn, TArgs&&... args) -{ - auto forAll = [&](auto& arg){ - (fn(std::forward<decltype(arg)>(arg), std::forward<decltype(args)>(args)), ...); - }; - - (forAll(std::forward<decltype(args)>(args)), ...); -} diff --git a/library/cpp/actors/util/ya.make b/library/cpp/actors/util/ya.make deleted file mode 100644 index 48d595c156..0000000000 --- a/library/cpp/actors/util/ya.make +++ /dev/null @@ -1,50 +0,0 @@ -LIBRARY() - -SRCS( - affinity.cpp - affinity.h - cpu_load_log.h - cpumask.h - datetime.h - defs.h - funnel_queue.h - futex.h - intrinsics.h - local_process_key.h - named_tuple.h - queue_chunk.h - queue_oneone_inplace.h - memory_track.cpp - memory_track.h - memory_tracker.cpp - memory_tracker.h - recentwnd.h - rope.cpp - rope.h - rc_buf.cpp - rc_buf.h - shared_data.h - shared_data.cpp - shared_data_rope_backend.h - should_continue.cpp - should_continue.h - thread.h - threadparkpad.cpp - threadparkpad.h - thread_load_log.h - ticket_lock.h - timerfd.h - unordered_cache.h -) - -PEERDIR( - library/cpp/containers/absl_flat_hash - library/cpp/deprecated/atomic - library/cpp/pop_count -) - -END() - -RECURSE_FOR_TESTS( - ut -) |