Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support memory usage monitor #391

Merged
merged 27 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ jobs:
shell: bash
run: bash build.sh debug -DCONCURRENCY=ON -DENABLE_COVERAGE=ON --make -j4

# `memtracer_test` unittest runs in `memtracer-test` action.
- name: Test
shell: bash
run: |
cd build_debug
make test
ctest -E memtracer_test --verbose

- name: lcov
shell: bash
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/clang-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ jobs:
with:
# sources 和 excludes 最终生成的find查找文件的命令大概是这样的
# find . -type f ! -wholename "./src/observer/sql/parser/lex_sql.*" \( -wholename "./**/*.h" -o -wholename "./**/*.cpp" \)
sources: "**/*.h,**/*.cpp,src/**/*.h,src/**/*.cpp,deps/common/**/*.h,deps/common/**/*.cpp"
excludes: "src/observer/sql/parser/lex_sql.*,src/observer/sql/parser/yacc_sql.*"
sources: "**/*.h,**/*.cpp,src/**/*.h,src/**/*.cpp"
excludes: "src/observer/sql/parser/lex_sql.*,src/observer/sql/parser/yacc_sql.*,deps/3rd/**/*.cpp,deps/3rd/**/*.h"
style: "file"
47 changes: 46 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,53 @@ jobs:
sudo bash build.sh init
bash build.sh release -DCONCURRENCY=ON -DWITH_UNIT_TESTS=OFF -DWITH_BENCHMARK=ON

- name: testing
- name: concurrency-test
shell: bash
run: |
cd build_release/bin/
for file in `find ./ -name "*_concurrency_test" -executable`; do $file; if [ $? -ne 0 ]; then exit 1; fi; done
memtracer-test:
strategy:
matrix:
memtracer: ['LD_PRELOAD=./lib/libmemtracer.so', '']
runs-on: ubuntu-latest
steps:
- name: Checkout repository and submodules
uses: actions/checkout@v2

- name: build
shell: bash
run: |
sudo bash build.sh init
bash build.sh release -DWITH_BENCHMARK=ON -DENABLE_ASAN=OFF -DCONCURRENCY=ON

- name: memtracer-performance-test
shell: bash
run: |
cd build_release
${{matrix.memtracer}} ./bin/memtracer_performance_test
- name: memtracer-unittest
shell: bash
run: |
cd build_release
LD_PRELOAD=./lib/libmemtracer.so ./bin/memtracer_test
- name: memtracer-sysbench
shell: bash
run: |
curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.deb.sh -o script.deb.sh
sudo bash script.deb.sh
sudo apt -y install sysbench mariadb-client
nohup sh -c '${{matrix.memtracer}} ./build_release/bin/observer -T one-thread-per-connection -s /tmp/miniob.sock -f etc/observer.ini -P mysql -t mvcc -d disk' &
sleep 10 && echo "wake up"
mysql --version
mysql -S /tmp/miniob.sock -e "show tables"
cd test/sysbench
sysbench --mysql-socket=/tmp/miniob.sock --mysql-ignore-errors=41 --threads=10 miniob_insert prepare
sysbench --mysql-socket=/tmp/miniob.sock --mysql-ignore-errors=41 --threads=10 miniob_insert run
killall observer
cd ../..
nohup ./build_release/bin/observer -T one-thread-per-connection -s /tmp/miniob.sock -f etc/observer.ini -P mysql -t mvcc -d disk &
sleep 10 && echo "wake up"
mysql -S /tmp/miniob.sock -e "show tables"


2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ OPTION(ENABLE_TSAN "Build with thread sanitizer" OFF)
OPTION(ENABLE_UBSAN "Build with undefined behavior sanitizer" OFF)
OPTION(WITH_UNIT_TESTS "Compile miniob with unit tests" ON)
OPTION(WITH_BENCHMARK "Compile benchmark" OFF)
# TODO: support MemTracer with sanitizers, currently MemTracer doesn't work with sanitizers.
OPTION(WITH_MEMTRACER "Compile memtracer" ON)
OPTION(ENABLE_COVERAGE "Enable unittest coverage" OFF)
OPTION(ENABLE_NOPIE "Enable no pie" OFF)
OPTION(CONCURRENCY "Support concurrency operations" OFF)
Expand Down
6 changes: 5 additions & 1 deletion benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ FOREACH (F ${ALL_SRC})
get_filename_component(prjName ${F} NAME_WE)
MESSAGE("Build ${prjName} according to ${F}")
ADD_EXECUTABLE(${prjName} ${F})
TARGET_LINK_LIBRARIES(${prjName} common pthread dl benchmark observer_static)
TARGET_LINK_LIBRARIES(${prjName} common pthread dl benchmark)
if(NOT ${prjName} STREQUAL "memtracer_performance_test")
TARGET_LINK_LIBRARIES(${prjName} observer_static)
endif()

ENDFOREACH (F)
38 changes: 38 additions & 0 deletions benchmark/memtracer_performance_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#include <benchmark/benchmark.h>

static void BM_MallocFree(benchmark::State &state)
{
size_t size = state.range(0);
for (auto _ : state) {
void *ptr = malloc(size);
benchmark::DoNotOptimize(ptr);
free(ptr);
}
state.SetBytesProcessed(static_cast<int64_t>(state.iterations() * size));
}

static void BM_NewDelete(benchmark::State &state)
{
size_t size = state.range(0);
for (auto _ : state) {
char *ptr = new char[size];
benchmark::DoNotOptimize(ptr);
delete[] ptr;
}
state.SetBytesProcessed(static_cast<int64_t>(state.iterations() * size));
}

BENCHMARK(BM_MallocFree)->Arg(8)->Arg(64)->Arg(512)->Arg(1 << 10)->Arg(1 << 20)->Arg(8 << 20)->Arg(1 << 30);
BENCHMARK(BM_NewDelete)->Arg(8)->Arg(64)->Arg(512)->Arg(1 << 10)->Arg(1 << 20)->Arg(8 << 20)->Arg(1 << 30);

BENCHMARK_MAIN();
3 changes: 3 additions & 0 deletions deps/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@

ADD_SUBDIRECTORY(common)
if (WITH_MEMTRACER)
ADD_SUBDIRECTORY(memtracer)
endif()
4 changes: 0 additions & 4 deletions deps/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ MESSAGE(STATUS "This is PROJECT_SOURCE_DIR dir " ${PROJECT_SOURCE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

FILE(GLOB_RECURSE ALL_SRC *.cpp)
FOREACH(F ${ALL_SRC})
SET(SRC_LIST ${SRC_LIST} ${F})
MESSAGE("Use " ${F})
ENDFOREACH(F)

#SHARED,动态库
#STATIC,静态库
Expand Down
19 changes: 19 additions & 0 deletions deps/memtracer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
include(CheckCXXCompilerFlag)

file(GLOB MEMTRACER_SOURCES "*.cpp")

SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
add_library(memtracer SHARED ${MEMTRACER_SOURCES})
#ignore missing attributes
#ref jemalloc: https://github.com/jemalloc/jemalloc/blob/master/configure.ac
CHECK_CXX_COMPILER_FLAG("-Wno-missing-attributes" COMPILER_SUPPORTS_NO_MISSING_ATTRIBUTES)
if(COMPILER_SUPPORTS_NO_MISSING_ATTRIBUTES)
target_compile_options(memtracer PRIVATE -Wno-missing-attributes)
endif()

# hidden memtracer internal interfaces
set_target_properties(memtracer PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
)
target_link_libraries(memtracer pthread)
196 changes: 196 additions & 0 deletions deps/memtracer/allocator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#include "memtracer/allocator.h"
#include <string.h>

// `dlsym` calls `calloc` internally, so here use a dummy buffer
// to avoid infinite loop when hook functions initialized.
// ref:
// https://stackoverflow.com/questions/7910666/problems-with-ld-preload-and-calloc-interposition-for-certain-executables
static unsigned char calloc_buffer[8192];

// only used internally
inline size_t ptr_size(void *ptr)
{
if (ptr == NULL) [[unlikely]] {
return 0;
}
return *((size_t *)ptr - 1);
}

mt_visible void *malloc(size_t size)
{
MT.init_hook_funcs();
size_t *ptr = (size_t *)orig_malloc(size + sizeof(size_t));
if (ptr == NULL) [[unlikely]] {
return NULL;
}
*ptr = size;
MT.alloc(size);
return (void *)(ptr + 1);
}

mt_visible void *calloc(size_t nelem, size_t size)
{
if (orig_malloc == NULL) [[unlikely]] {
return calloc_buffer;
}
size_t alloc_size = nelem * size;
void * ptr = malloc(alloc_size);
if (ptr == NULL) [[unlikely]] {
return NULL;
}
memset(ptr, 0, alloc_size);
return ptr;
}

mt_visible void *realloc(void *ptr, size_t size)
{
if (ptr == NULL) {
return malloc(size);
}
void *res = NULL;
if (ptr_size(ptr) < size) {
res = malloc(size);
if (res == NULL) [[unlikely]] {
return NULL;
}
memcpy(res, ptr, ptr_size(ptr));

free(ptr);
} else {
res = ptr;
}
return res;
}

mt_visible void free(void *ptr)
{
MT.init_hook_funcs();
if (ptr == NULL || ptr == calloc_buffer) [[unlikely]] {
return;
}
MT.free(ptr_size(ptr));
orig_free((size_t *)ptr - 1);
}

mt_visible void cfree(void *ptr) { free(ptr); }

mt_visible void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
MT.init_hook_funcs();
void *res = orig_mmap(addr, length, prot, flags, fd, offset);
if (res != MAP_FAILED) [[likely]] {
MT.alloc(length);
}
return res;
}

mt_visible int munmap(void *addr, size_t length)
{
MT.init_hook_funcs();
int res = orig_munmap(addr, length);
if (res == 0) [[likely]] {
MT.free(length);
}
return res;
}

mt_visible char *strdup(const char *s) MT_THROW
{
size_t len = strlen(s);
char * p = (char *)malloc(len + 1);
if (p == NULL) {
return NULL;
}
memcpy(p, s, len);
p[len] = 0;
return p;
}

mt_visible char *strndup(const char *s, size_t n) MT_THROW
{
const char * end = (const char *)memchr(s, 0, n);
const size_t m = (end != NULL ? (size_t)(end - s) : n);
char * t = (char *)malloc(m + 1);
if (t == NULL)
return NULL;
memcpy(t, s, m);
t[m] = 0;
return t;
}

mt_visible char *realpath(const char *fname, char *resolved_name)
{
MEMTRACER_LOG("realpath not supported\n");
exit(-1);
}
mt_visible void *memalign(size_t alignment, size_t size)
{
MEMTRACER_LOG("memalign not supported\n");
exit(-1);
}

mt_visible void *valloc(size_t size)
{
MEMTRACER_LOG("valloc not supported\n");
exit(-1);
}

mt_visible void *pvalloc(size_t size)
{
MEMTRACER_LOG("valloc not supported\n");
exit(-1);
}

mt_visible int posix_memalign(void **memptr, size_t alignment, size_t size)
{
MEMTRACER_LOG("posix_memalign not supported\n");
exit(-1);
}

mt_visible int brk(void *addr)
{
MEMTRACER_LOG("brk not supported\n");
exit(-1);
}

mt_visible void *sbrk(intptr_t increment)
{
MEMTRACER_LOG("sbrk not supported\n");
exit(-1);
}

mt_visible long int syscall(long int __sysno, ...)
{
MEMTRACER_LOG("syscall not supported\n");
exit(-1);
}

mt_visible void *operator new(std::size_t size) { return malloc(size); }

mt_visible void *operator new[](std::size_t size) { return malloc(size); }

mt_visible void *operator new(std::size_t size, const std::nothrow_t &) noexcept { return malloc(size); }

mt_visible void *operator new[](std::size_t size, const std::nothrow_t &) noexcept { return malloc(size); }

mt_visible void operator delete(void *ptr) noexcept { free(ptr); }

mt_visible void operator delete[](void *ptr) noexcept { free(ptr); }

mt_visible void operator delete(void *ptr, const std::nothrow_t &) noexcept { free(ptr); }

mt_visible void operator delete[](void *ptr, const std::nothrow_t &) noexcept { free(ptr); }

mt_visible void operator delete(void *ptr, std::size_t size) noexcept { free(ptr); }

mt_visible void operator delete[](void *ptr, std::size_t size) noexcept { free(ptr); }
Loading
Loading