Loading 3party/gperftools/CMakeLists.txt +470 −426 File changed.Preview size limit exceeded, changes collapsed. Show changes 3party/gperftools/src/heap-profiler.cc +364 −349 Original line number Diff line number Diff line Loading @@ -47,30 +47,30 @@ #ifdef HAVE_MMAP #include <sys/mman.h> #endif #include <errno.h> #include <assert.h> #include <sys/types.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <algorithm> #include <string> #include <gperftools/heap-profiler.h> #include "base/logging.h" #include "base/basictypes.h"// for PRId64, among other things #include "base/googleinit.h" #include "base/commandlineflags.h" #include "malloc_hook-inl.h" #include "tcmalloc_guard.h" #include <gperftools/malloc_hook.h> #include <gperftools/malloc_extension.h> #include "base/spinlock.h" #include "base/googleinit.h" #include "base/logging.h" #include "base/low_level_alloc.h" #include "base/spinlock.h" #include "base/sysinfo.h"// for GetUniquePathFromEnv() #include "heap-profile-table.h" #include "malloc_hook-inl.h" #include "memory_region_map.h" #include "mmap_hook.h" #include "tcmalloc_guard.h" #include <gperftools/malloc_extension.h> #include <gperftools/malloc_hook.h> #ifndef PATH_MAX #ifdef MAXPATHLEN Loading Loading @@ -110,9 +110,7 @@ DEFINE_int64(heap_profile_time_interval, EnvToInt64("HEAP_PROFILE_TIME_INTERVAL", 0), "If non-zero, dump heap profiling information once every " "specified number of seconds since the last dump."); DEFINE_bool(mmap_log, EnvToBool("HEAP_PROFILE_MMAP_LOG", false), "Should mmap/munmap calls be logged?"); DEFINE_bool(mmap_log, EnvToBool("HEAP_PROFILE_MMAP_LOG", false), "Should mmap/munmap calls be logged?"); DEFINE_bool(mmap_profile, EnvToBool("HEAP_PROFILE_MMAP", false), "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); Loading @@ -121,7 +119,6 @@ DEFINE_bool(only_mmap_profile, "If heap-profiling is on, only profile mmap, mremap, and sbrk; " "do not profile malloc/new/etc"); //---------------------------------------------------------------------- // Locking //---------------------------------------------------------------------- Loading @@ -140,10 +137,15 @@ static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); static LowLevelAlloc::Arena *heap_profiler_memory; static void* ProfilerMalloc(size_t bytes) { static void * ProfilerMalloc(size_t bytes) { return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); } static void ProfilerFree(void* p) { static void ProfilerFree(void *p) { LowLevelAlloc::Free(p); } Loading @@ -157,7 +159,6 @@ static const int kProfileBufferSize = 1 << 20; // HeapProfilerStart. Access to this must be protected by heap_lock. static char *global_profiler_buffer = NULL; //---------------------------------------------------------------------- // Profiling control/state data //---------------------------------------------------------------------- Loading @@ -180,11 +181,12 @@ static HeapProfileTable* heap_profile = NULL; // the heap profile table //---------------------------------------------------------------------- // Input must be a buffer of size at least 1MB. static char* DoGetHeapProfileLocked(char* buf, int buflen) { static char * DoGetHeapProfileLocked(char *buf, int buflen) { // We used to be smarter about estimating the required memory and // then capping it to 1MB and generating the profile into that. if (buf == NULL || buflen < 1) return NULL; if (buf == NULL || buflen < 1) return NULL; RAW_DCHECK(heap_lock.IsHeld(), ""); int bytes_written = 0; Loading @@ -204,7 +206,9 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) { return buf; } extern "C" char* GetHeapProfile() { extern "C" char * GetHeapProfile() { // Use normal malloc: we return the profile to the user to free it: char *buffer = reinterpret_cast<char *>(malloc(kProfileBufferSize)); SpinLockHolder l(&heap_lock); Loading @@ -216,7 +220,9 @@ static void NewHook(const void* ptr, size_t size); static void DeleteHook(const void *ptr); // Helper for HeapProfilerDump. static void DumpProfileLocked(const char* reason) { static void DumpProfileLocked(const char *reason) { RAW_DCHECK(heap_lock.IsHeld(), ""); RAW_DCHECK(is_on, ""); RAW_DCHECK(!dumping, ""); Loading @@ -228,8 +234,7 @@ static void DumpProfileLocked(const char* reason) { // Make file name char file_name[1000]; dump_count++; snprintf(file_name, sizeof(file_name), "%s.%04d%s", filename_prefix, dump_count, HeapProfileTable::kFileExt); snprintf(file_name, sizeof(file_name), "%s.%04d%s", filename_prefix, dump_count, HeapProfileTable::kFileExt); // Dump the profile RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason); Loading @@ -245,12 +250,10 @@ static void DumpProfileLocked(const char* reason) { // This case may be impossible, but it's best to be safe. // It's safe to use the global buffer: we're protected by heap_lock. if (global_profiler_buffer == NULL) { global_profiler_buffer = reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); global_profiler_buffer = reinterpret_cast<char *>(ProfilerMalloc(kProfileBufferSize)); } char* profile = DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); char *profile = DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); RawWrite(fd, profile, strlen(profile)); RawClose(fd); Loading @@ -263,39 +266,41 @@ static void DumpProfileLocked(const char* reason) { // Dump a profile after either an allocation or deallocation, if // the memory use has changed enough since the last dump. static void MaybeDumpProfileLocked() { static void MaybeDumpProfileLocked() { if (!dumping) { const HeapProfileTable::Stats &total = heap_profile->total(); const int64_t inuse_bytes = total.alloc_size - total.free_size; bool need_to_dump = false; char buf[128]; if (FLAGS_heap_profile_allocation_interval > 0 && total.alloc_size >= last_dump_alloc + FLAGS_heap_profile_allocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, " if (FLAGS_heap_profile_allocation_interval > 0 && total.alloc_size >= last_dump_alloc + FLAGS_heap_profile_allocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, " "%" PRId64 " MB currently in use"), total.alloc_size >> 20, inuse_bytes >> 20); total.alloc_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_deallocation_interval > 0 && total.free_size >= last_dump_free + FLAGS_heap_profile_deallocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, " } else if (FLAGS_heap_profile_deallocation_interval > 0 && total.free_size >= last_dump_free + FLAGS_heap_profile_deallocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, " "%" PRId64 " MB currently in use"), total.free_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_inuse_interval > 0 && inuse_bytes > high_water_mark + FLAGS_heap_profile_inuse_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use", total.free_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_inuse_interval > 0 && inuse_bytes > high_water_mark + FLAGS_heap_profile_inuse_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use", inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_time_interval > 0) { int64 current_time = time(NULL); if (current_time - last_dump_time >= FLAGS_heap_profile_time_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump", current_time - last_dump_time); if (current_time - last_dump_time >= FLAGS_heap_profile_time_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump", current_time - last_dump_time); need_to_dump = true; last_dump_time = current_time; } Loading @@ -305,14 +310,15 @@ static void MaybeDumpProfileLocked() { last_dump_alloc = total.alloc_size; last_dump_free = total.free_size; if (inuse_bytes > high_water_mark) high_water_mark = inuse_bytes; if (inuse_bytes > high_water_mark) high_water_mark = inuse_bytes; } } } // Record an allocation in the profile. static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { static void RecordAlloc(const void *ptr, size_t bytes, int skip_count) { // Take the stack trace outside the critical section. void *stack[HeapProfileTable::kMaxStackDepth]; int depth = HeapProfileTable::GetCallerStackTrace(skip_count + 1, stack); Loading @@ -324,7 +330,9 @@ static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { } // Record a deallocation in the profile. static void RecordFree(const void* ptr) { static void RecordFree(const void *ptr) { SpinLockHolder l(&heap_lock); if (is_on) { heap_profile->RecordFree(ptr); Loading @@ -337,42 +345,57 @@ static void RecordFree(const void* ptr) { //---------------------------------------------------------------------- // static void NewHook(const void* ptr, size_t size) { void NewHook(const void *ptr, size_t size) { if (ptr != NULL) RecordAlloc(ptr, size, 0); } // static void DeleteHook(const void* ptr) { void DeleteHook(const void *ptr) { if (ptr != NULL) RecordFree(ptr); } static tcmalloc::MappingHookSpace mmap_logging_hook_space; static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { if (!FLAGS_mmap_log) { return; } static void LogMappingEvent(const tcmalloc::MappingEvent &evt) { if (!FLAGS_mmap_log) { return; } if (evt.file_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mmap(start=0x%" PRIxPTR ", len=%zu, prot=0x%x, flags=0x%x, " "mmap(start=0x%" PRIxPTR ", len=%zu, prot=0x%x, flags=0x%x, " "fd=%d, offset=0x%llx) = 0x%" PRIxPTR "", (uintptr_t) evt.before_address, evt.after_length, evt.prot, evt.flags, evt.file_fd, (unsigned long long) evt.file_off, (uintptr_t) evt.before_address, evt.after_length, evt.prot, evt.flags, evt.file_fd, (unsigned long long) evt.file_off, (uintptr_t) evt.after_address); } else if (evt.after_valid && evt.before_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mremap(old_addr=0x%" PRIxPTR ", old_size=%zu, " "new_size=%zu, flags=0x%x, new_addr=0x%" PRIxPTR ") = " "mremap(old_addr=0x%" PRIxPTR ", old_size=%zu, " "new_size=%zu, flags=0x%x, new_addr=0x%" PRIxPTR ") = " "0x%" PRIxPTR "", (uintptr_t) evt.before_address, evt.before_length, evt.after_length, evt.flags, (uintptr_t) evt.after_address, (uintptr_t) evt.after_address); (uintptr_t) evt.before_address, evt.before_length, evt.after_length, evt.flags, (uintptr_t) evt.after_address, (uintptr_t) evt.after_address); } else if (evt.is_sbrk) { intptr_t increment; uintptr_t result; Loading @@ -384,14 +407,12 @@ static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { result = reinterpret_cast<uintptr_t>(evt.before_address); } RAW_LOG(INFO, "sbrk(inc=%zd) = 0x%" PRIxPTR "", increment, (uintptr_t) result); RAW_LOG(INFO, "sbrk(inc=%zd) = 0x%" PRIxPTR "", increment, (uintptr_t) result); } else if (evt.before_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "munmap(start=0x%" PRIxPTR ", len=%zu)", (uintptr_t) evt.before_address, evt.before_length); RAW_LOG(INFO, "munmap(start=0x%" PRIxPTR ", len=%zu)", (uintptr_t) evt.before_address, evt.before_length); } } Loading @@ -399,7 +420,9 @@ static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { // Starting/stopping/dumping //---------------------------------------------------------------------- extern "C" void HeapProfilerStart(const char* prefix) { extern "C" void HeapProfilerStart(const char *prefix) { SpinLockHolder l(&heap_lock); if (is_on) return; Loading @@ -412,9 +435,7 @@ extern "C" void HeapProfilerStart(const char* prefix) { // call new, and we want that to be accounted for correctly. MallocExtension::Initialize(); if (FLAGS_only_mmap_profile) { FLAGS_mmap_profile = true; } if (FLAGS_only_mmap_profile) { FLAGS_mmap_profile = true; } if (FLAGS_mmap_profile) { // Ask MemoryRegionMap to record all mmap, mremap, and sbrk Loading @@ -428,13 +449,11 @@ extern "C" void HeapProfilerStart(const char* prefix) { tcmalloc::HookMMapEvents(&mmap_logging_hook_space, LogMappingEvent); } heap_profiler_memory = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); heap_profiler_memory = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); // Reserve space now for the heap profiler, so we can still write a // heap profile even if the application runs out of memory. global_profiler_buffer = reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); global_profiler_buffer = reinterpret_cast<char *>(ProfilerMalloc(kProfileBufferSize)); heap_profile = new (ProfilerMalloc(sizeof(HeapProfileTable))) HeapProfileTable(ProfilerMalloc, ProfilerFree, FLAGS_mmap_profile); Loading Loading @@ -462,12 +481,16 @@ extern "C" void HeapProfilerStart(const char* prefix) { filename_prefix[prefix_length] = '\0'; } extern "C" int IsHeapProfilerRunning() { extern "C" int IsHeapProfilerRunning() { SpinLockHolder l(&heap_lock); return is_on ? 1 : 0;// return an int, because C code doesn't have bool } extern "C" void HeapProfilerStop() { extern "C" void HeapProfilerStop() { SpinLockHolder l(&heap_lock); if (!is_on) return; Loading @@ -494,53 +517,47 @@ extern "C" void HeapProfilerStop() { ProfilerFree(filename_prefix); filename_prefix = NULL; if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); } if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); } if (FLAGS_mmap_profile) { MemoryRegionMap::Shutdown(); } if (FLAGS_mmap_profile) { MemoryRegionMap::Shutdown(); } is_on = false; } extern "C" void HeapProfilerDump(const char *reason) { extern "C" void HeapProfilerDump(const char *reason) { SpinLockHolder l(&heap_lock); if (is_on && !dumping) { DumpProfileLocked(reason); } if (is_on && !dumping) { DumpProfileLocked(reason); } } // Signal handler that is registered when a user selectable signal // number is defined in the environment variable HEAPPROFILESIGNAL. static void HeapProfilerDumpSignal(int signal_number) { static void HeapProfilerDumpSignal(int signal_number) { (void) signal_number; if (!heap_lock.TryLock()) { return; } if (is_on && !dumping) { DumpProfileLocked("signal"); } if (!heap_lock.TryLock()) { return; } if (is_on && !dumping) { DumpProfileLocked("signal"); } heap_lock.Unlock(); } //---------------------------------------------------------------------- // Initialization/finalization code //---------------------------------------------------------------------- // Initialization code static void HeapProfilerInit() { static void HeapProfilerInit() { // Everything after this point is for setting up the profiler based on envvar char fname[PATH_MAX]; if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) { return; } if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) { return; } // We do a uid check so we don't write out files in a setuid executable. #ifdef HAVE_GETEUID if (getuid() != geteuid()) { RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because " RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because " "program seems to be setuid\n")); return; } Loading @@ -566,21 +583,19 @@ static void HeapProfilerInit() { // class used for finalization -- dumps the heap-profile at program exit struct HeapProfileEndWriter { ~HeapProfileEndWriter() { ~HeapProfileEndWriter() { char buf[128]; if (heap_profile) { const HeapProfileTable::Stats &total = heap_profile->total(); const int64_t inuse_bytes = total.alloc_size - total.free_size; if ((inuse_bytes >> 20) > 0) { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " MB in use"), inuse_bytes >> 20); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " MB in use"), inuse_bytes >> 20); } else if ((inuse_bytes >> 10) > 0) { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " kB in use"), inuse_bytes >> 10); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " kB in use"), inuse_bytes >> 10); } else { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " bytes in use"), inuse_bytes); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " bytes in use"), inuse_bytes); } } else { snprintf(buf, sizeof(buf), ("Exiting")); Loading CMakeLists.txt +10 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ option(SLED_BUILD_TESTS "Build tests" OFF) option(SLED_BUILD_FUZZ "Build fuzzer test" OFF) option(SLED_LOCATION_PATH "" "sled/src/sled/system/location.cc") option(SLED_BUILD_PROTOC_PLUGIN "Build protoc plugin" OFF) option(SLED_WITH_PROTOBUF "With Protobuf" ON) set(BUILD_STATIC ON) set(BUILD_RTTR_DYNAMIC OFF) Loading @@ -31,10 +32,12 @@ target_include_directories(benchmark_main PUBLIC src/) add_library(sled STATIC "") add_subdirectory(3party/minilua EXCLUDE_FROM_ALL) # add_subdirectory(3party/gperftools EXCLUDE_FROM_ALL) add_subdirectory(3party/gperftools EXCLUDE_FROM_ALL) add_subdirectory(3party/asyncplusplus EXCLUDE_FROM_ALL) # add_subdirectory(3party/cppuprofile EXCLUDE_FROM_ALL) if(SLED_WITH_PROTOBUF) add_subdirectory(3party/protobuf-3.21.12 EXCLUDE_FROM_ALL) endif() if(NOT TARGET marl) add_subdirectory(3party/marl EXCLUDE_FROM_ALL) endif() Loading Loading @@ -109,15 +112,15 @@ target_link_libraries( protobuf::libprotobuf tcmalloc_and_profiler_static # protobuf::libprotoc PRIVATE dl # protobuf::libprotobuf ${WHOLE_ARCHIVE_WRAPPER_START} # tcmalloc_and_profiler_static ${WHOLE_ARCHIVE_WRAPPER_END} ) PRIVATE dl) if(SLED_WITH_PROTOBUF) target_link_libraries(sled PUBLIC protobuf::libprotobuf) endif() # set fPIC set_target_properties(sled PROPERTIES POSITION_INDEPENDENT_CODE ON) if(SLED_BUILD_PROTOC_PLUGIN) if(SLED_WITH_PROTOBUF AND SLED_BUILD_PROTOC_PLUGIN) add_subdirectory(src/protoc_gen_sled) endif() Loading src/sled/futures/future.cc +15 −8 Original line number Diff line number Diff line Loading @@ -14,23 +14,30 @@ DecrementFuturesUsage() }// namespace future_detail static ThreadPool g_default_thread_pool; TaskQueueBase *g_default_scheduler = &g_default_thread_pool; static std::atomic<TaskQueueBase *> g_default_scheduler{nullptr}; // static ThreadPool default_thread_pool; static std::unique_ptr<Thread> g_default_thread; void SetDefaultScheduler(TaskQueueBase *scheduler) noexcept { if (scheduler == nullptr) { g_default_scheduler = &g_default_thread_pool; } else { g_default_scheduler = scheduler; } SLED_ASSERT(scheduler, "scheduler is nullptr"); g_default_scheduler.store(scheduler, std::memory_order_release); } TaskQueueBase * GetDefaultScheduler() noexcept { return g_default_scheduler; static std::once_flag flag; std::call_once(flag, [&] { g_default_thread = sled::Thread::Create(); g_default_thread->Start(); TaskQueueBase *null_scheduler = nullptr; while (g_default_scheduler.load() == nullptr) { g_default_scheduler.compare_exchange_weak(null_scheduler, g_default_thread.get()); } }); return g_default_scheduler.load(std::memory_order_acquire); } }// namespace sled src/sled/log/log.cc +1 −1 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ void SetLogFileName(const char *file_name) { g_log_file_name = file_name; g_log_stream.open(file_name); g_log_stream.open(file_name, std::ios_base::app); } static std::atomic<uint32_t> g_current_id(0); Loading Loading
3party/gperftools/CMakeLists.txt +470 −426 File changed.Preview size limit exceeded, changes collapsed. Show changes
3party/gperftools/src/heap-profiler.cc +364 −349 Original line number Diff line number Diff line Loading @@ -47,30 +47,30 @@ #ifdef HAVE_MMAP #include <sys/mman.h> #endif #include <errno.h> #include <assert.h> #include <sys/types.h> #include <errno.h> #include <signal.h> #include <sys/types.h> #include <algorithm> #include <string> #include <gperftools/heap-profiler.h> #include "base/logging.h" #include "base/basictypes.h"// for PRId64, among other things #include "base/googleinit.h" #include "base/commandlineflags.h" #include "malloc_hook-inl.h" #include "tcmalloc_guard.h" #include <gperftools/malloc_hook.h> #include <gperftools/malloc_extension.h> #include "base/spinlock.h" #include "base/googleinit.h" #include "base/logging.h" #include "base/low_level_alloc.h" #include "base/spinlock.h" #include "base/sysinfo.h"// for GetUniquePathFromEnv() #include "heap-profile-table.h" #include "malloc_hook-inl.h" #include "memory_region_map.h" #include "mmap_hook.h" #include "tcmalloc_guard.h" #include <gperftools/malloc_extension.h> #include <gperftools/malloc_hook.h> #ifndef PATH_MAX #ifdef MAXPATHLEN Loading Loading @@ -110,9 +110,7 @@ DEFINE_int64(heap_profile_time_interval, EnvToInt64("HEAP_PROFILE_TIME_INTERVAL", 0), "If non-zero, dump heap profiling information once every " "specified number of seconds since the last dump."); DEFINE_bool(mmap_log, EnvToBool("HEAP_PROFILE_MMAP_LOG", false), "Should mmap/munmap calls be logged?"); DEFINE_bool(mmap_log, EnvToBool("HEAP_PROFILE_MMAP_LOG", false), "Should mmap/munmap calls be logged?"); DEFINE_bool(mmap_profile, EnvToBool("HEAP_PROFILE_MMAP", false), "If heap-profiling is on, also profile mmap, mremap, and sbrk)"); Loading @@ -121,7 +119,6 @@ DEFINE_bool(only_mmap_profile, "If heap-profiling is on, only profile mmap, mremap, and sbrk; " "do not profile malloc/new/etc"); //---------------------------------------------------------------------- // Locking //---------------------------------------------------------------------- Loading @@ -140,10 +137,15 @@ static SpinLock heap_lock(SpinLock::LINKER_INITIALIZED); static LowLevelAlloc::Arena *heap_profiler_memory; static void* ProfilerMalloc(size_t bytes) { static void * ProfilerMalloc(size_t bytes) { return LowLevelAlloc::AllocWithArena(bytes, heap_profiler_memory); } static void ProfilerFree(void* p) { static void ProfilerFree(void *p) { LowLevelAlloc::Free(p); } Loading @@ -157,7 +159,6 @@ static const int kProfileBufferSize = 1 << 20; // HeapProfilerStart. Access to this must be protected by heap_lock. static char *global_profiler_buffer = NULL; //---------------------------------------------------------------------- // Profiling control/state data //---------------------------------------------------------------------- Loading @@ -180,11 +181,12 @@ static HeapProfileTable* heap_profile = NULL; // the heap profile table //---------------------------------------------------------------------- // Input must be a buffer of size at least 1MB. static char* DoGetHeapProfileLocked(char* buf, int buflen) { static char * DoGetHeapProfileLocked(char *buf, int buflen) { // We used to be smarter about estimating the required memory and // then capping it to 1MB and generating the profile into that. if (buf == NULL || buflen < 1) return NULL; if (buf == NULL || buflen < 1) return NULL; RAW_DCHECK(heap_lock.IsHeld(), ""); int bytes_written = 0; Loading @@ -204,7 +206,9 @@ static char* DoGetHeapProfileLocked(char* buf, int buflen) { return buf; } extern "C" char* GetHeapProfile() { extern "C" char * GetHeapProfile() { // Use normal malloc: we return the profile to the user to free it: char *buffer = reinterpret_cast<char *>(malloc(kProfileBufferSize)); SpinLockHolder l(&heap_lock); Loading @@ -216,7 +220,9 @@ static void NewHook(const void* ptr, size_t size); static void DeleteHook(const void *ptr); // Helper for HeapProfilerDump. static void DumpProfileLocked(const char* reason) { static void DumpProfileLocked(const char *reason) { RAW_DCHECK(heap_lock.IsHeld(), ""); RAW_DCHECK(is_on, ""); RAW_DCHECK(!dumping, ""); Loading @@ -228,8 +234,7 @@ static void DumpProfileLocked(const char* reason) { // Make file name char file_name[1000]; dump_count++; snprintf(file_name, sizeof(file_name), "%s.%04d%s", filename_prefix, dump_count, HeapProfileTable::kFileExt); snprintf(file_name, sizeof(file_name), "%s.%04d%s", filename_prefix, dump_count, HeapProfileTable::kFileExt); // Dump the profile RAW_VLOG(0, "Dumping heap profile to %s (%s)", file_name, reason); Loading @@ -245,12 +250,10 @@ static void DumpProfileLocked(const char* reason) { // This case may be impossible, but it's best to be safe. // It's safe to use the global buffer: we're protected by heap_lock. if (global_profiler_buffer == NULL) { global_profiler_buffer = reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); global_profiler_buffer = reinterpret_cast<char *>(ProfilerMalloc(kProfileBufferSize)); } char* profile = DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); char *profile = DoGetHeapProfileLocked(global_profiler_buffer, kProfileBufferSize); RawWrite(fd, profile, strlen(profile)); RawClose(fd); Loading @@ -263,39 +266,41 @@ static void DumpProfileLocked(const char* reason) { // Dump a profile after either an allocation or deallocation, if // the memory use has changed enough since the last dump. static void MaybeDumpProfileLocked() { static void MaybeDumpProfileLocked() { if (!dumping) { const HeapProfileTable::Stats &total = heap_profile->total(); const int64_t inuse_bytes = total.alloc_size - total.free_size; bool need_to_dump = false; char buf[128]; if (FLAGS_heap_profile_allocation_interval > 0 && total.alloc_size >= last_dump_alloc + FLAGS_heap_profile_allocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, " if (FLAGS_heap_profile_allocation_interval > 0 && total.alloc_size >= last_dump_alloc + FLAGS_heap_profile_allocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB allocated cumulatively, " "%" PRId64 " MB currently in use"), total.alloc_size >> 20, inuse_bytes >> 20); total.alloc_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_deallocation_interval > 0 && total.free_size >= last_dump_free + FLAGS_heap_profile_deallocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, " } else if (FLAGS_heap_profile_deallocation_interval > 0 && total.free_size >= last_dump_free + FLAGS_heap_profile_deallocation_interval) { snprintf(buf, sizeof(buf), ("%" PRId64 " MB freed cumulatively, " "%" PRId64 " MB currently in use"), total.free_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_inuse_interval > 0 && inuse_bytes > high_water_mark + FLAGS_heap_profile_inuse_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use", total.free_size >> 20, inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_inuse_interval > 0 && inuse_bytes > high_water_mark + FLAGS_heap_profile_inuse_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " MB currently in use", inuse_bytes >> 20); need_to_dump = true; } else if (FLAGS_heap_profile_time_interval > 0) { int64 current_time = time(NULL); if (current_time - last_dump_time >= FLAGS_heap_profile_time_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump", current_time - last_dump_time); if (current_time - last_dump_time >= FLAGS_heap_profile_time_interval) { snprintf(buf, sizeof(buf), "%" PRId64 " sec since the last dump", current_time - last_dump_time); need_to_dump = true; last_dump_time = current_time; } Loading @@ -305,14 +310,15 @@ static void MaybeDumpProfileLocked() { last_dump_alloc = total.alloc_size; last_dump_free = total.free_size; if (inuse_bytes > high_water_mark) high_water_mark = inuse_bytes; if (inuse_bytes > high_water_mark) high_water_mark = inuse_bytes; } } } // Record an allocation in the profile. static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { static void RecordAlloc(const void *ptr, size_t bytes, int skip_count) { // Take the stack trace outside the critical section. void *stack[HeapProfileTable::kMaxStackDepth]; int depth = HeapProfileTable::GetCallerStackTrace(skip_count + 1, stack); Loading @@ -324,7 +330,9 @@ static void RecordAlloc(const void* ptr, size_t bytes, int skip_count) { } // Record a deallocation in the profile. static void RecordFree(const void* ptr) { static void RecordFree(const void *ptr) { SpinLockHolder l(&heap_lock); if (is_on) { heap_profile->RecordFree(ptr); Loading @@ -337,42 +345,57 @@ static void RecordFree(const void* ptr) { //---------------------------------------------------------------------- // static void NewHook(const void* ptr, size_t size) { void NewHook(const void *ptr, size_t size) { if (ptr != NULL) RecordAlloc(ptr, size, 0); } // static void DeleteHook(const void* ptr) { void DeleteHook(const void *ptr) { if (ptr != NULL) RecordFree(ptr); } static tcmalloc::MappingHookSpace mmap_logging_hook_space; static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { if (!FLAGS_mmap_log) { return; } static void LogMappingEvent(const tcmalloc::MappingEvent &evt) { if (!FLAGS_mmap_log) { return; } if (evt.file_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mmap(start=0x%" PRIxPTR ", len=%zu, prot=0x%x, flags=0x%x, " "mmap(start=0x%" PRIxPTR ", len=%zu, prot=0x%x, flags=0x%x, " "fd=%d, offset=0x%llx) = 0x%" PRIxPTR "", (uintptr_t) evt.before_address, evt.after_length, evt.prot, evt.flags, evt.file_fd, (unsigned long long) evt.file_off, (uintptr_t) evt.before_address, evt.after_length, evt.prot, evt.flags, evt.file_fd, (unsigned long long) evt.file_off, (uintptr_t) evt.after_address); } else if (evt.after_valid && evt.before_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "mremap(old_addr=0x%" PRIxPTR ", old_size=%zu, " "new_size=%zu, flags=0x%x, new_addr=0x%" PRIxPTR ") = " "mremap(old_addr=0x%" PRIxPTR ", old_size=%zu, " "new_size=%zu, flags=0x%x, new_addr=0x%" PRIxPTR ") = " "0x%" PRIxPTR "", (uintptr_t) evt.before_address, evt.before_length, evt.after_length, evt.flags, (uintptr_t) evt.after_address, (uintptr_t) evt.after_address); (uintptr_t) evt.before_address, evt.before_length, evt.after_length, evt.flags, (uintptr_t) evt.after_address, (uintptr_t) evt.after_address); } else if (evt.is_sbrk) { intptr_t increment; uintptr_t result; Loading @@ -384,14 +407,12 @@ static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { result = reinterpret_cast<uintptr_t>(evt.before_address); } RAW_LOG(INFO, "sbrk(inc=%zd) = 0x%" PRIxPTR "", increment, (uintptr_t) result); RAW_LOG(INFO, "sbrk(inc=%zd) = 0x%" PRIxPTR "", increment, (uintptr_t) result); } else if (evt.before_valid) { // We use PRIxPTR not just '%p' to avoid deadlocks // in pretty-printing of NULL as "nil". // TODO(maxim): instead should use a safe snprintf reimplementation RAW_LOG(INFO, "munmap(start=0x%" PRIxPTR ", len=%zu)", (uintptr_t) evt.before_address, evt.before_length); RAW_LOG(INFO, "munmap(start=0x%" PRIxPTR ", len=%zu)", (uintptr_t) evt.before_address, evt.before_length); } } Loading @@ -399,7 +420,9 @@ static void LogMappingEvent(const tcmalloc::MappingEvent& evt) { // Starting/stopping/dumping //---------------------------------------------------------------------- extern "C" void HeapProfilerStart(const char* prefix) { extern "C" void HeapProfilerStart(const char *prefix) { SpinLockHolder l(&heap_lock); if (is_on) return; Loading @@ -412,9 +435,7 @@ extern "C" void HeapProfilerStart(const char* prefix) { // call new, and we want that to be accounted for correctly. MallocExtension::Initialize(); if (FLAGS_only_mmap_profile) { FLAGS_mmap_profile = true; } if (FLAGS_only_mmap_profile) { FLAGS_mmap_profile = true; } if (FLAGS_mmap_profile) { // Ask MemoryRegionMap to record all mmap, mremap, and sbrk Loading @@ -428,13 +449,11 @@ extern "C" void HeapProfilerStart(const char* prefix) { tcmalloc::HookMMapEvents(&mmap_logging_hook_space, LogMappingEvent); } heap_profiler_memory = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); heap_profiler_memory = LowLevelAlloc::NewArena(0, LowLevelAlloc::DefaultArena()); // Reserve space now for the heap profiler, so we can still write a // heap profile even if the application runs out of memory. global_profiler_buffer = reinterpret_cast<char*>(ProfilerMalloc(kProfileBufferSize)); global_profiler_buffer = reinterpret_cast<char *>(ProfilerMalloc(kProfileBufferSize)); heap_profile = new (ProfilerMalloc(sizeof(HeapProfileTable))) HeapProfileTable(ProfilerMalloc, ProfilerFree, FLAGS_mmap_profile); Loading Loading @@ -462,12 +481,16 @@ extern "C" void HeapProfilerStart(const char* prefix) { filename_prefix[prefix_length] = '\0'; } extern "C" int IsHeapProfilerRunning() { extern "C" int IsHeapProfilerRunning() { SpinLockHolder l(&heap_lock); return is_on ? 1 : 0;// return an int, because C code doesn't have bool } extern "C" void HeapProfilerStop() { extern "C" void HeapProfilerStop() { SpinLockHolder l(&heap_lock); if (!is_on) return; Loading @@ -494,53 +517,47 @@ extern "C" void HeapProfilerStop() { ProfilerFree(filename_prefix); filename_prefix = NULL; if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); } if (!LowLevelAlloc::DeleteArena(heap_profiler_memory)) { RAW_LOG(FATAL, "Memory leak in HeapProfiler:"); } if (FLAGS_mmap_profile) { MemoryRegionMap::Shutdown(); } if (FLAGS_mmap_profile) { MemoryRegionMap::Shutdown(); } is_on = false; } extern "C" void HeapProfilerDump(const char *reason) { extern "C" void HeapProfilerDump(const char *reason) { SpinLockHolder l(&heap_lock); if (is_on && !dumping) { DumpProfileLocked(reason); } if (is_on && !dumping) { DumpProfileLocked(reason); } } // Signal handler that is registered when a user selectable signal // number is defined in the environment variable HEAPPROFILESIGNAL. static void HeapProfilerDumpSignal(int signal_number) { static void HeapProfilerDumpSignal(int signal_number) { (void) signal_number; if (!heap_lock.TryLock()) { return; } if (is_on && !dumping) { DumpProfileLocked("signal"); } if (!heap_lock.TryLock()) { return; } if (is_on && !dumping) { DumpProfileLocked("signal"); } heap_lock.Unlock(); } //---------------------------------------------------------------------- // Initialization/finalization code //---------------------------------------------------------------------- // Initialization code static void HeapProfilerInit() { static void HeapProfilerInit() { // Everything after this point is for setting up the profiler based on envvar char fname[PATH_MAX]; if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) { return; } if (!GetUniquePathFromEnv("HEAPPROFILE", fname)) { return; } // We do a uid check so we don't write out files in a setuid executable. #ifdef HAVE_GETEUID if (getuid() != geteuid()) { RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because " RAW_LOG(WARNING, ("HeapProfiler: ignoring HEAPPROFILE because " "program seems to be setuid\n")); return; } Loading @@ -566,21 +583,19 @@ static void HeapProfilerInit() { // class used for finalization -- dumps the heap-profile at program exit struct HeapProfileEndWriter { ~HeapProfileEndWriter() { ~HeapProfileEndWriter() { char buf[128]; if (heap_profile) { const HeapProfileTable::Stats &total = heap_profile->total(); const int64_t inuse_bytes = total.alloc_size - total.free_size; if ((inuse_bytes >> 20) > 0) { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " MB in use"), inuse_bytes >> 20); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " MB in use"), inuse_bytes >> 20); } else if ((inuse_bytes >> 10) > 0) { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " kB in use"), inuse_bytes >> 10); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " kB in use"), inuse_bytes >> 10); } else { snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " bytes in use"), inuse_bytes); snprintf(buf, sizeof(buf), ("Exiting, %" PRId64 " bytes in use"), inuse_bytes); } } else { snprintf(buf, sizeof(buf), ("Exiting")); Loading
CMakeLists.txt +10 −7 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ option(SLED_BUILD_TESTS "Build tests" OFF) option(SLED_BUILD_FUZZ "Build fuzzer test" OFF) option(SLED_LOCATION_PATH "" "sled/src/sled/system/location.cc") option(SLED_BUILD_PROTOC_PLUGIN "Build protoc plugin" OFF) option(SLED_WITH_PROTOBUF "With Protobuf" ON) set(BUILD_STATIC ON) set(BUILD_RTTR_DYNAMIC OFF) Loading @@ -31,10 +32,12 @@ target_include_directories(benchmark_main PUBLIC src/) add_library(sled STATIC "") add_subdirectory(3party/minilua EXCLUDE_FROM_ALL) # add_subdirectory(3party/gperftools EXCLUDE_FROM_ALL) add_subdirectory(3party/gperftools EXCLUDE_FROM_ALL) add_subdirectory(3party/asyncplusplus EXCLUDE_FROM_ALL) # add_subdirectory(3party/cppuprofile EXCLUDE_FROM_ALL) if(SLED_WITH_PROTOBUF) add_subdirectory(3party/protobuf-3.21.12 EXCLUDE_FROM_ALL) endif() if(NOT TARGET marl) add_subdirectory(3party/marl EXCLUDE_FROM_ALL) endif() Loading Loading @@ -109,15 +112,15 @@ target_link_libraries( protobuf::libprotobuf tcmalloc_and_profiler_static # protobuf::libprotoc PRIVATE dl # protobuf::libprotobuf ${WHOLE_ARCHIVE_WRAPPER_START} # tcmalloc_and_profiler_static ${WHOLE_ARCHIVE_WRAPPER_END} ) PRIVATE dl) if(SLED_WITH_PROTOBUF) target_link_libraries(sled PUBLIC protobuf::libprotobuf) endif() # set fPIC set_target_properties(sled PROPERTIES POSITION_INDEPENDENT_CODE ON) if(SLED_BUILD_PROTOC_PLUGIN) if(SLED_WITH_PROTOBUF AND SLED_BUILD_PROTOC_PLUGIN) add_subdirectory(src/protoc_gen_sled) endif() Loading
src/sled/futures/future.cc +15 −8 Original line number Diff line number Diff line Loading @@ -14,23 +14,30 @@ DecrementFuturesUsage() }// namespace future_detail static ThreadPool g_default_thread_pool; TaskQueueBase *g_default_scheduler = &g_default_thread_pool; static std::atomic<TaskQueueBase *> g_default_scheduler{nullptr}; // static ThreadPool default_thread_pool; static std::unique_ptr<Thread> g_default_thread; void SetDefaultScheduler(TaskQueueBase *scheduler) noexcept { if (scheduler == nullptr) { g_default_scheduler = &g_default_thread_pool; } else { g_default_scheduler = scheduler; } SLED_ASSERT(scheduler, "scheduler is nullptr"); g_default_scheduler.store(scheduler, std::memory_order_release); } TaskQueueBase * GetDefaultScheduler() noexcept { return g_default_scheduler; static std::once_flag flag; std::call_once(flag, [&] { g_default_thread = sled::Thread::Create(); g_default_thread->Start(); TaskQueueBase *null_scheduler = nullptr; while (g_default_scheduler.load() == nullptr) { g_default_scheduler.compare_exchange_weak(null_scheduler, g_default_thread.get()); } }); return g_default_scheduler.load(std::memory_order_acquire); } }// namespace sled
src/sled/log/log.cc +1 −1 Original line number Diff line number Diff line Loading @@ -111,7 +111,7 @@ void SetLogFileName(const char *file_name) { g_log_file_name = file_name; g_log_stream.open(file_name); g_log_stream.open(file_name, std::ios_base::app); } static std::atomic<uint32_t> g_current_id(0); Loading