Commit fc1ad57b authored by tqcq's avatar tqcq
Browse files

Merge remote-tracking branch 'origin/master'

parents e5bd62a7 54e9a4e1
Loading
Loading
Loading
Loading
+470 −426

File changed.

Preview size limit exceeded, changes collapsed.

+364 −349
Original line number Diff line number Diff line
@@ -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
@@ -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)");
@@ -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
//----------------------------------------------------------------------
@@ -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);
}

@@ -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
//----------------------------------------------------------------------
@@ -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;
@@ -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);
@@ -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, "");
@@ -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);
@@ -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);

@@ -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;
            }
@@ -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);
@@ -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);
@@ -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;
@@ -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);
    }
}

@@ -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;
@@ -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
@@ -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);
@@ -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;
@@ -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;
    }
@@ -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"));
+10 −7
Original line number Diff line number Diff line
@@ -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)
@@ -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()
@@ -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()

+15 −8
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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