0%

TreeLine为C++项目,使用VSCode远程连接linux并实现debug。

部署

工具

  • VSCode

  • gdb12.1

步骤

  • VSCode远程连接linux服务器并打开存放TreeLine的文件夹

  • 修改项目目录下的.vscode/launch.json文件为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    {
    "version": "0.2.0",
    "configurations": [

    {
    "name": "(gdb) 启动", //debug名称
    "type": "cppdbg",
    "request": "launch",
    "program": "${workspaceFolder}/build/bench/run_custom", //要debug的可执行文件的存放位置
    "args": [], //参数(待定)
    "stopAtEntry": false,
    "cwd": "${workspaceFolder}",
    "environment": [],
    "externalConsole": false,
    "MIMode": "gdb",
    "miDebuggerPath":"/usr/local/bin/gdb", //linux中gdb的路径
    "setupCommands": [
    {
    "description": "为 gdb 启用整齐打印",
    "text": "-enable-pretty-printing",
    "ignoreFailures": true
    },
    {
    "description": "将反汇编风格设置为 Intel",
    "text": "-gdb-set disassembly-flavor intel",
    "ignoreFailures": true
    }
    ]
    }

    ]
    }

编译源文件

TreeLine中的编译过程一致,但需修改部分:

  • 在编译之前,将treeline文件夹更名为treeline-debug,并修改treeline-debug/CMakeLists.txt文件,在第三行后加入:

    1
    2
    3
    SET(CMAKE_BUILD_TYPE "Debug")
    SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
    SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

    以使得编译好的可执行文件中含有gdb需要的信息

  • 在编译时,将-DCMAKE_BUILD_TYPE=Release选项去掉

debug

  • 获取运行时参数

    首先修改treeline-debug/scripts/ycsb_v2/COND文件,使得运行cond命令时只运行某一个特定的实验

    将treeline-debug/scripts/ycsb_v2/run.sh的内容复制一份,给treeline-debug/scripts/ycsb_v2/run_copy.sh

    1
    2
    cd treeline-debug
    cp scripts/ycsb_v2/run.sh scripts/ycsb_v2/run_copy.sh

    将run_copy.sh中../../build/bench/run_custom \及其之后的所有语句都删掉,并在run_copy.sh的末尾加上

    1
    2
    3
    4
    5
    args+=("--workload_config=$COND_OUT/workload.yml")
    args+=("--output_path=$COND_OUT")
    echo ------------------------------------------------------------------------------------------------------------
    echo ${args[@]}
    echo ------------------------------------------------------------------------------------------------------------

    修改COND文件:将相应的cond运行命令描述中的run="./run.sh",改为run="./run_copy.sh",

    执行cond命令,获取参数,参数会被打印在两条分割线之间,打印参数后cond执行完毕,程序结束

    1
    cond run //scripts/ycsb_v2: [command]
  • 将获取到的参数以如下形式全部填入launch.json文件中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    {
    "version": "0.2.0",
    "configurations": [

    {
    "name": "(gdb) 启动", //debug名称
    "type": "cppdbg",
    "request": "launch",
    "program": "${workspaceFolder}/build/bench/run_custom", //要debug的可执行文件的存放位置
    "args": ["--bg_threads=4", "--latency_sample_period=10", "--bypass_wal=true", "--use_direct_io=true", "--rdb_bloom_bits=10", "--rdb_prefix_bloom_size=3", "--reorg_length=2", "--deferral_autotuning=true", "--max_deferrals=1", "--optimistic_rec_caching=false", "--pg_use_pgm_builder=true", "--record_size_bytes=64", "--tl_page_fill_pct=70", "--records_per_page_goal=44", "--records_per_page_epsilon=5", "--rec_cache_use_lru=false", "--cache_size_mib=1143", "--pg_parallelize_final_flush=true", "--db=pg_llsm", "--custom_dataset=/mnt/data2/datasets/amazon_reviews.txt", "--threads=16", "--verbose", "--db_path=/mnt/data2/flash2/llsm", "--seed=42", "--notify_after_init", "--skip_load", "--workload_config=/home/xlx/treeline-debug/cond-out/scripts/ycsb_v2/amzn-pg_llsm-64B-a-zipfian-16.task.1692001938/workload.yml", "--output_path=/home/xlx/treeline-debug/cond-out/scripts/ycsb_v2/amzn-pg_llsm-64B-a-zipfian-16.task.1692001938"],
    "stopAtEntry": false,
    "cwd": "${workspaceFolder}",
    "environment": [],
    "externalConsole": false,
    "MIMode": "gdb",
    "miDebuggerPath":"/usr/local/bin/gdb", //linux中gdb的路径
    "setupCommands": [
    {
    "description": "为 gdb 启用整齐打印",
    "text": "-enable-pretty-printing",
    "ignoreFailures": true
    },
    {
    "description": "将反汇编风格设置为 Intel",
    "text": "-gdb-set disassembly-flavor intel",
    "ignoreFailures": true
    }
    ]
    }

    ]
    }
  • 设置断点

    源文件所在路径为treeline-debug/bench/run_custom.cpp,在这个文件上打断点

  • 启动debug

    首先点击左侧栏的运行和调试,然后选择对应的debug名称(launch.json中为(gdb)启动),最后点击小三角或者F5启动调试

    启动成功,在第一个断点处停下,左侧为变量、调用堆栈、监控和断点

gperftools是Google开源的一款包含多线程下高性能内存分配器tcmalloc和其他性能分析工具的集合。共分为四个部分,TCmalloc:一个优化的内存管理算法;Heap_Check:检测程序运行过程中是否发生内存泄漏的工具;Heap_Profile:监控程序运行过程中的内存分配情况的工具;Cpu_Profile:监控程序运行过程中的cpu消耗时间的工具;部分工具以treeline为例介绍其使用方法;

安装gperftools

安装所需工具

1
sudo apt autoconf automake libtool

安装libunwind

下载源码并解压

1
2
wget http://download.savannah.gnu.org/releases/libunwind/libunwind-1.6.0.tar.gz
tar -zxvf libunwind-1.6.0.tar.gz

编译并安装,默认安装在/usr/local目录下

1
2
3
4
cd libunwind-1.6.0
./configure
make
sudo make install

安装图形可视化工具gv

1
sudo apt install graphviz gv

安装gperftools

下载源码并解压

1
2
wget https://sourceforge.net/projects/gperftools.mirror/files/gperftools-2.10/gperftools-2.10.tar.gz
tar -zxvf gperftools-2.10.tar.gz

编译并安装,默认安装在/usr/local目录下

1
2
3
4
5
cd gperftools-2.10
./autogen.sh
./configure
make
sudo make instal

打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

将目录/usr/local/bin和/usr/local/lib添加进环境变量,在文件末尾追加

1
2
3
export PATH=/usr/local/bin:$PATH
export PPROF_PATH=/usr/local/bin
export LD_LIBRAR_PATH=/usr/local/lib:$LD_LIBRAR_PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

使用gperftools

TCMalloc

  • 简介

    tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,对 C 的 malloc() 和 C++ 的 operator new 自定义了实现,用于替代系统的内存分配相关的函数(malloc、free,new,new[]等)。

    TCMalloc (google-perftools) 是用于优化C++写的多线程应用,比glibc 2.3的malloc快。

  • 使用方法

    方法1:编译源文件时链接-ltcmalloc 库

    1
    2
    gcc/g++ [source_file] -g -o [exe_file] -ltcmalloc
    ./[exe_file]

    方法2:在运行别人编译好的程序时,可以通过设置环境变量使用tcmalloc(不推荐)

    1
    2
    export LD_PRELOAD=/usr/local/lib/libtcmalloc.so
    ./[exe_file]

    1
    LD_PRELOAD=/usr/local/lib/libtcmalloc.so ./[exe_file]
  • 更多信息请见官方文档

Heap_Checker

  • 简介

    用来检测 C++ 程序中内存泄漏的堆检查器,检测进程整个生命周期的内存泄露。

    heap_checker的检测方式有4种,按检测的严格程度依次为:minimal,normal,strict,draconian ,normal模式适用于大多数内存泄露检查。

    使用它有三个步骤:将库链接到程序、运行代码和分析输出。

  • 使用方法(不包括分析输出)

    方法1:

    编译源文件时链接-ltcmalloc 库,加上-g选项可以定位内存泄漏的行数

    1
    gcc/g++ [source_file] -g -o [exe_file] -ltcmalloc

    设置环境变量并运行程序

    1
    2
    export HEAPCHECK=normal 
    ./[exe_file]

    也可以写在一行

    1
    env HEAPCHECK=normal ./[exe_file]

    方法2:在运行别人编译好的程序时,可以通过设置环境变量使用tcmalloc

    1
    LD_PRELOAD="/usr/local/lib/libtcmalloc.so" env HEAPCHECK=normal ./[exe_file]
  • 使用示例

    leak.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <iostream>
    #include <unistd.h>
    using namespace std;

    void test1()
    {
    char *s = new char[5 * 1024];
    }

    void test2()
    {
    int *n = new int[2*1024];
    }

    int main()
    {
    test1();
    test2();
    char *s = new char[5 * 1024];
    int *n = new int[2*1024];
    sleep(3);
    return 0;
    }

    使用heap_checker

    1
    2
    g++ leak.cpp -g -o leak -ltcmalloc
    env HEAPCHECK=normal ./leak

    输出

    绿框中的输出表示,leak.cpp有4处内存泄露:分别泄露8192bytes、8192bytes、5120bytes和5120bytes

    另外,heap_checker提示我们可以执行红框中的语句实现可视化分析

    通过pprof工具进行可视化分析

    1
    pprof ./leak "/tmp/leak.10448._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

    每个灰色方框表示一处内存泄露,方框包含函数名称cpp文件位置内存泄漏发生在cpp文件中的具体行数。指向它们的白色方框中包含的是调用发生内存泄漏的函数的函数信息,也包含函数名称cpp文件位置调用发生在cpp文件中的具体行数

    由可视化结果可知,发生四处内存泄露:

    第一处内存泄漏在leak.cpp的第7行,函数名为test1,这个函数被leak.cpp中的main函数调用,调用发生在leak.cpp的第17行
    
    第二处内存泄漏在leak.cpp的第19行,函数名为main
    
    第三处内存泄漏在leak.cpp的第25行,函数名为main
    
    第四处内存泄漏在leak.cpp的第12行,函数名为test2,这个函数被leak.cpp中的main函数调用,调用发生在leak.cpp的第18行
    

    除此之外,可以选择以其他方式查看结果(只需将--gv改为以下选项)

    --text     生成文字报告

    --stack     生成堆栈跟踪

    --web     以网页的形式展示

    --pdf     生成pdf到标准输出 (较快,推荐)

    更多查看结果的方式请使用 pprof --help 命令查阅

    例如:以text形式查看分析结果

    1
    pprof ./leak "/tmp/leak.10448._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --text

    以pdf形似查看分析结果

    1
    pprof ./leak "/tmp/leak.10448._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --pdf > leak.pdf

    leak.pdf与gv显示的结果一样

  • 部分调优参数

参数 默认值 说明
HEAP_CHECK_MAX_LEAKS 20 能打印到 stderr 的最大泄漏数(所有泄漏仍会在 pprof 可视化的时候显示)。 如果为负数或零,则打印所有发现的泄漏
HEAP_CHECK_TEST_POINTER_ALIGNMENT false 如果为真,检查泄漏是否可能是由于使用了未对齐的指针造成的
HEAP_CHECK_POINTER_SOURCE_ALIGNMENT sizeof(void*) 内存中所有指针应该位于的对齐方式。如果任何对齐都可以,请使用 1
HEAP_CHECK_DUMP_DIRECTORY /tmp 内存检测文件的生成位置

Heap_Profile

  • 简介

    heap_profile监控程序运行过程中的内存使用情况,会在程序运行时不断生成.heap文件,记录某时刻程序所使用的内存大小和详细信息。

    用来分析程序运行中的内存消耗瓶颈,也可以通过比较不同时刻的内存使用量来定位内存泄露。

    使用它有三个步骤:将库链接到程序、运行代码和分析输出。

  • 使用方法

    • 链接及运行部分(最终会生成.heap文件)

      方法1:

      编译源文件时链接-ltcmalloc 库

      1
      gcc/g++ [source_file]  -o [exe_file] -ltcmalloc

      设置环境变量并运行程序 (xxx为生成.heap文件的文件名,自定义)

      1
      2
      export HEAPPROFILE=xxx.hprof
      ./[exe_file]

      也可以写在一行

      1
      env HEAPPROFILE=xxx.hprof ./[exe_file]

      方法2:在运行别人编译好的程序时,可以通过设置环境变量使用tcmalloc

      1
      LD_PRELOAD="/usr/local/lib/libtcmalloc.so" env HEAPPROFILE=xxx.hprof ./[exe_file]
    • 分析输出

      单独分析一个.heap文件(可以选择gv,pdf,text或其他形式显示分析结果):

      1
      pprof [exe_file] [heap_file] --gv / --pdf > xxx.pdf / --text / ... 

      将两个.heap文件进行比较:

      1
      pprof --base=[heap_file1] [exe_file] [heap_file2] 
  • 代码插桩

    加入头文件,并使用HeapProfilerStart("xxx"),HeapProfilerStop()可以指定要监督的代码段,本例中heap_profile只会检测代码段2的内存使用情况,并生成xxx.*.heap文件

    1
    2
    3
    4
    5
    6
    #include <gperftools/heap-profiler.h>
    //代码段1
    HeapProfilerStart("xxx");
    //代码段2
    HeapProfilerStop();
    //代码段3

    编译并运行程序

    1
    2
    gcc/g++ [source_file]  -o [exe_file] -ltcmalloc
    ./[exe_file]

    分析输出部分与上文所述相同

  • 使用示例

    以treeline为例,在treeline/scripts/ycsb_v2/run.sh中将

    1
    ../../build/bench/run_custom \

    修改为

    1
    LD_PRELOAD="/usr/local/lib/libtcmalloc.so" env HEAPPROFILE=amzn_64B_a_heapprofile.hprof  ../../build/bench/run_custom \

    并在COND文件中修改实验配置:工作负载为A、记录大小为64B,线程数为16

    在treeline目录下,运行

    1
    cond run //scripts/ycsb_v2:amzn

    单独分析一个.heap文件

    程序运行过程中,生成了11个.heap文件,分别记录了在运行过程中的十一个时刻的内存使用情况,将其移动到treeline/scripts/ycsb_v2/heapprofile文件夹下

    以pdf的形式分析第十个生成文件amzn_64B_a_heapprofile.hprof.0010.heap

    1
    pprof build/bench/run_custom scripts/ycsb_v2/heapprofile/amzn_64B_a_heapprofile.hprof.0011.heap --pdf >amzn_64B_a_heapprofile.hprof.0010.heap.pdf

    生成amzn_64B_a_heapprofile.hprof.0010.heap.pdf文件在treeline/下,可以看到内存消耗较多的函数为LoadDatasetFromTextFile,ExtractDirty,Put,_M_default_append,优化程序使用内存时可以重点关注这几个函数

    左上角显示元信息:

    可执行程序的名称为run_custom,在生成amzn_64B_a_heapprofile.hprof.0010.heap文件的这一时刻,程序总共使用了1773.9MB内存,被关注的函数所占内存为1773.9MB(没有使用--foucs关注特定函数则默认全部关注),此外,一些不重要的节点和边被丢弃以减少混乱。

    有向图所含信息:

    图中的每个方框代表一个函数,有向边表示调用关系,有向边旁边的数字代表被其直接和间接调用的函数所使用的所有内存,方框中的信息从上到下依次是:

    Class Name
    
    Method Name
    
    local (percentage)  //此函数本身所使用的内存大小(及其占比)
    
    of cumulative (percentage)  //此函数本身和其直接及间接调用的所有函数所使用的内存大小(及其占比)
    

    以下面的amzn_64B_a_heapprofile.hprof.0010.heap.pdf的局部有向图为例:

    Manager函数自身使用15.8MB内存,占比为0.9%,此函数本身和其直接及间接调用的所有函数所使用的内存大小为23.8MB,占比为1.3%,其调用的函数所使用的内存为23.8MB-15.8MB=8.0MB;

    RecordCache函数自身使用0MB内存,占比为0.0%,此函数本身和其直接及间接调用的所有函数所使用的内存大小为687.8MB,占比为38.8%,其调用的函数所使用的内存为687.8MB-0MB=687.8MB;

    这两个函数都调用了_M_default_append函数,将两个有向边上的数字相加,得到_M_default_append函数使用8.0MB+685.8MB=693.8MB内存,占比为39.1%;

    将两个.heap文件相比较

    1
    pprof --base=scripts/ycsb_v2/heapprofile/amzn_64B_a_heapprofile.hprof.0011.heap build/bench/run_custom scripts/ycsb_v2/heapprofile/amzn_64B_a_heapprofile.hprof.0010.heap 

    此时会进入交互窗口,输入top20,显示前20个内存大小变化最大的函数

    记生成amzn_64B_a_heapprofile.hprof.0010.heap的时刻为t10,生成amzn_64B_a_heapprofile.hprof.0011.heap的时刻为t11,程序在t10比在t11多使用1613.7MB内存

    函数_M_default_append在t10比在t11多使用693.8MB内存,占1613.7MB的43%

    函数Put在t10比在t11多使用299.6MB内存,占1613.7MB的18.6%

    ……

    可在交互窗口输入help查看更多信息

  • 更多信息请见官方文档

CPU_Profile

  • 简介

    cpu_profile记录程序执行过程中各函数的cpu消耗时间,并生成函数调用图,用来定位热点函数

    使用它有三个步骤:将库链接到程序、运行代码和分析输出。

  • 使用方法

    • 链接及运行部分(最终会生成.prof文件)

      方法1:

      编译源文件时链接-lprofiler 库

      1
      gcc/g++ [source_file]  -o [exe_file] -lprofiler

      设置环境变量并运行程序 (xxx为生成.prof文件的文件名,自定义)

      1
      2
      export CPUPROFILE=xxx.prof
      ./[exe_file]

      也可以写在一行

      1
      env CPUPROFILE=xxx.prof ./[exe_file]

      方法2:在运行别人编译好的程序时,可以通过设置环境变量使用cpu_profile

      1
      LD_PRELOAD="/usr/local/lib/libprofiler.so" env CPUPROFILE=xxx.prof ./[exe_file]
    • 分析输出

      分析生成的.prof文件(可以选择gv,pdf,text或其他形式显示分析结果):

      1
      pprof [exe_file] [prof_file] --gv / --pdf > xxx.pdf / --text / ... 
  • 代码插桩

    加入头文件,并使用ProfilerStart("xxx.prof"),ProfilerStop()可以指定要监督的代码段,本例中cpu_profile只会检测代码段2的cpu消耗时间,并生成xxx.prof

    1
    2
    3
    4
    5
    6
    #include <gperftools/profiler.h>
    //代码段1
    ProfilerStart("xxx.prof");
    //代码段2
    ProfilerStop();
    //代码段3

    编译并运行程序

    1
    2
    gcc/g++ [source_file]  -o [exe_file] -lprofiler
    ./[exe_file]

    分析输出部分与上文所述相同同

  • 使用示例

    以treeline为例,在treeline/scripts/ycsb_v2/run.sh中将

    1
    ../../build/bench/run_custom \

    修改为

    1
    LD_PRELOAD="/usr/local/lib/libprofiler.so" env CPUPROFILE=amzn_64B_a_16_cpu.prof  ../../build/bench/run_custom \

    并在COND文件中修改实验配置:工作负载为A、记录大小为64B,线程数为16

    在treeline目录下,运行

    1
    cond run //scripts/ycsb_v2:amzn

    程序运行结束后,会生成amzn_64B_a_16_cpu.prof文件,记录了在运行过程中各函数的cpu消耗时间和调用关系,将其移动到treeline/scripts/ycsb_v2/cpuprofile文件夹下

    以pdf的形式生成结果分析报告

    1
    pprof build/bench/run_custom scripts/ycsb_v2/cpuprofile/amzn_64B_a_16_cpu.prof --pdf >amzn_64B_a_16_cpu.pdf

    生成amzn_64B_a_16_cpu.pdf文件在treeline/下,可以看到cpu消耗时间较长的函数为GetCacheIndex,__pread_nocancel,__pwrite_nocancel等,说明这几个函数为热点函数,优化程序时可以重点关注这几个函数

    顶部显示元信息:

    可执行程序的名称为run_custom,默认每1s采样100次,共采样18128,说明程序执行了181.28s。采样到的被关注的函数次数为18128(没有使用--foucs关注特定函数则默认全部关注),此外,一些不重要的节点和边被丢弃以减少混乱。

    有向图所含信息:

    图中的每个方框代表一个函数,有向边表示调用关系,有向边旁边的数字代表采样到的被其直接和间接调用的函数的次数,方框中的信息从上到下依次是:

    Class Name
    
    Method Name
    
    local (percentage)  //此函数本身被采样到的次数(及其占比)
    
    of cumulative (percentage)  //此函数本身和其直接及间接调用的所有函数被采样到的次数(及其占比)
    

    以下面的amzn_64B_a_16_cpu.pdf的局部有向图为例:

    main函数自身消耗0s,占比为0.0%,此函数本身和其直接及间接调用的所有函数所消耗的时间为13.12s,占比为7.2%,其调用的函数所消耗的时间为13.12s-0s=13.12s;

    main函数直接调用了三个函数,分别为LoadDatasetFromTextFile,LoadFrom,SetCustomLoadDataset

    LoadDatasetFromTextFile函数消耗2.15s,占比为1.2%,此函数本身和其直接及间接调用的所有函数所消耗的时间为70.2s,占比为3.9%,其调用的函数所消耗的时间为7.02s-2.15s=4.87s;

  • 更多信息请见官方文档

随着现代存储技术的发展,对于NVMe SSDs来说,随机写的开销与顺序写的开销已经不像传统存储器那样差距明显了。基于LSM结构的KV数据库,如rocksdb、leanstore都采用顺序写,会牺牲部分读性能;而2021年被提出来的TreeLine则采用随机写,是一个原地更新的KV存储系统,并提出三个关键思想提高读写性能。

准备环境

安装Cmake

要求:version >= 3.17

下载源码并解压

1
2
wget https://cmake.org/files/v3.24/cmake-3.24.0.tar.gz
tar -zxvf cmake-3.24.0.tar.gz

编译并安装,- -prefix=/usr/local/cmake-3.24.0表示将cmake安装到目录/uar/local/cmake-3.24.0,可自定义目录,但要与下文中的环境变量目录相对应

1
2
3
4
cd cmake-3.24.0
./bootstrap --prefix=/usr/local/cmake-3.24.0
make
sudo make install

打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

将目录/usr/local/cmake-3.24.0/bin添加进环境变量,在文件末尾追加

1
export PATH=/usr/local/cmake-3.24.0/bin:$PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

安装gcc/g++

要求:必须支持C++17

下载源码并解压

1
2
wget https://mirror.tuna.tsinghua.edu.cn/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz
tar -zxvf gcc-9.3.0.tar.gz

下载所需依赖

1
2
cd gcc-9.3.0
./contrib/download_prerequisites

编译并安装,将gcc/g++安装到/usr/local/gcc-9.3.0下

1
2
3
./configure --prefix=/usr/local/gcc-9.3.0  --enable-bootstrap --enable-languages=c,c++ --enable-checking=release --disable-multilib
make -j4
sudo make install

打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

添加进环境变量,在文件末尾追加

1
2
3
export PATH=/usr/local/gcc-9.3.0/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/gcc-9.3.0/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/gcc-9.3.0/lib64:$LD_LIBRARY_PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

安装Python

要求:version >= 3.8

下载所需工具和库

1
sudo apt install build-essential libssl-dev zlib1g-dev libncurses5-dev libncursesw5-dev libreadline-dev libsqlite3-dev libgdbm-dev libdb5.3-dev libbz2-dev libexpat1-dev liblzma-dev tk-dev libffi-dev

下载源码并解压

1
2
wget https://www.python.org/ftp/python/3.8.16/Python-3.8.16.tgz
tar -xf Python-3.8.16.tgz

编译并安装,安装到/usr/local/python-3.8.16目录下

1
2
3
4
cd Python-3.8.16
./configure --prefix=/usr/local/python-3.8.16 --enable-optimizations
make
sudo make install

打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

将目录/usr/local/python-3.8.16/bin添加进环境变量,在文件末尾追加

1
export PATH=/usr/local/python-3.8.16/bin:$PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

下载其他所需依赖

1
sudo apt install libtbb-dev autoconf libjemalloc-dev

若无法使用此方法安装libtbb-dev和libjemalloc-dev,也可以选择下载源码并编译安装,参考下文中的“安装tbb库”和“安装jemalloc库”

安装tbb库

下载源码

1
git clone https://github.com/oneapi-src/oneTBB.git

编译并安装,安装目录为/tmp/my_installed_onetbb

1
2
3
4
5
cd oneTBB
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/tmp/my_installed_onetbb -DTBB_TEST=OFF ..
cmake --build .
cmake --install .

将所需头文件及依赖复制到/usr/local/gcc-9.3.0/include/c++/9.3.0/和/usr/local/gcc-9.3.0/lib64/下

1
2
3
4
cd /tem/my_installed_onetbb
sudo cp -r include/tbb /usr/local/gcc-9.3.0/include/c++/9.3.0/ //复制头文件
cd lib64
sudo cp *.so *.2 *.11 *.12 /usr/local/gcc-9.3.0/lib64/ //复制依赖

安装jemalloc库

下载源码并解压

1
2
wget https://github.com/jemalloc/jemalloc/archive/5.2.1.tar.gz
tar -zxvf 5.2.1.tar.gz

编译并安装,安装目录默认为/usr/local

1
2
3
4
5
6
cd jemalloc-5.2.1
./autogen.sh
./configure --with-version="5.2.1-0-g0"
make dist
make
sudo make install

打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

将目录/usr/local/bin和/usr/local/lib添加进环境变量,在文件末尾追加

1
2
export PATH=/usr/local/bin:$PATH
export LD_LIBRAR_PATH=/usr/local/lib:$LD_LIBRAR_PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

下载TreeLine源码

1
git clone https://github.com/mitdbg/treeline.git

编译

创建build文件夹存放编译后的文件

1
mkdir build && cd build

执行编译(不包括treeline/tests/和treeline/benchmarks/目录下的文件)

1
cmake -DCMAKE_BUILD_TYPE=Release .. && make -j

若也要编译treeline/tests/下的文件,则编译命令可换为

1
cmake -DCMAKE_BUILD_TYPE=Release -DTL_BUILD_TESTS=ON .. && make -j

同样地,若也要编译treeline/benchmarks/下的文件,则编译命令可换为

1
cmake -DCMAKE_BUILD_TYPE=Release -DTL_BUILD_BENCHMARKS=ON .. && make -j

也可将treeline/下的文件全部编译:

1
cmake -DCMAKE_BUILD_TYPE=Release -DTL_BUILD_TESTS=ON -DTL_BUILD_BENCHMARKS=ON .. && make -j

编译后的运行benchmark的可执行文件为treeline/build/bench/run_custom

运行

下载cond

使用cond命令能够批量执行任务,treeline/scripts/ycsb_v2/COND中已经写好了批量运行benchmark的实验命令

1
2
apt install python3-pip  //先下载pip
pip install conductor-cli

命令行输入cond,若显示Command cond not found,打开~/.bashrc文件添加环境变量

1
vim ~/.bashrc

将cond所在目录/home/xxx/.local/bin添加进环境变量,在文件末尾追加(xxx为用户名)

1
export PATH=/home/xxx/.local/bin:$PATH

使~/.bashrc文件立即生效

1
source ~/.bashrc

设置checkpoint存储路径

每个数据库会从空开始加载相同的数据集,做相同次数的更新操作,并截取此时的数据库作为checkpoint;在跑benchmark之前,会提取每个数据库的cheakpoint作为实验的起点;

在treeline/scripts/下创建experiment_config.sh文件

1
2
cd treeline/scripts
touch experiment_config.sh

将treeline/scripts/experiment_config_example.sh的内容复制给experiment_config.sh

修改experiment_config.sh文件

1
2
3
4
5
6
#存储checkpoint的路径
DB_CHECKPOINT_PATH = xxxx/llsm-checkpoint
#加载checkpoint的路径
DB_PATH = xxxx/llsm
#自定义数据集存储路径
TP_DATASET_PATH = xxxx/datasets

修改实验配置

实验参数和cond运行命令写在treeline/scripts/ycsb_v2/COND中

可以通过修改此COND文件中的WORKLOADS,DBS,DISTRIBUTIONS,THREADS,CONFIGS等来修改运行的工作负载类型、数据库、数据分布类型、线程数、记录大小等

例:

1
2
3
4
5
6
7
8
9
WORKLOADS = ["a","b",]  
DBS = [
"leanstore",
"pg_llsm",
"rocksdb"
]
DISTRIBUTIONS = ["zipfian"]
THREADS = [1, 2, 4, 8, 16]
CONFIGS = [CONFIG_64B]

表示只运行工作负载A和B类型,在所示三个数据库上进行测试,数据分布类型为zipfian,并分别使用1,2,4,8,16线程跑五次,一个记录大小为64B。于是一共会执行2×3×1×5×1=30次实验。

COND文件中也已经写好了相应的cond运行命令(下面是文件中其中一个cond运行命令的描述)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
run_experiment_group(
name="synth",
run="./run.sh",
experiments=[
# e.g. synth-pg_llsm-64B-a-zipfian-1
ExperimentInstance(
name="synth-{}-{}-{}-{}-{}".format(db, config["name"], workload, dist, threads),
options={
**COMMON_OPTIONS,
**process_config(db, config, SYNTH_DATASET, workload=workload),
"db": db,
"checkpoint_name": "ycsb-synth-{}-{}".format(db, config["name"]),
"threads": threads,
"gen_template": "workloads/{}.yml".format(workload),
"gen_distribution": dist,
},
)
for db, config, workload, dist, threads in product(
DBS,
CONFIGS,
WORKLOADS,
DISTRIBUTIONS,
THREADS,
)
# The uniform and zipfian "d" workloads are the same, so just run one.
if not (workload == "d" and dist == "uniform")
],
deps=[
# e.g. :preload-synth-pg_llsm-64B
":preload-synth-{}-{}".format(db, config["name"])
for db, config in product(DBS, CONFIGS)
],
)

其中name表示的是command的名称,options是传递给run.sh的参数(包含实验参数)

执行cond run //scripts/ycsb_v2: synth后,会将options中的值作为参数运行run.sh,但在运行run.sh之前,会先执行deps中的任务,也就是装载checkpoint

实验参数修改完成后,通过替换下文“运行benchmark”中的command,可实现特定的一个或数个任务

1
2
3
command = synth   //在合成数据集上测试
command = amzn //在amzn数据集上测试
command = osm //在osm数据集上测试

更多“command”可取值详见COND文件

运行benchmark

使用cond命令运行

1
2
cd treeline
cond run //scripts/ycsb_v2: [command]

结果保存在treeline/cond-out/下