测试用例编写
3
.gitignore
vendored
@@ -1,9 +1,6 @@
|
||||
NtyCo/
|
||||
.vscode/
|
||||
img/
|
||||
*.db
|
||||
*.copy
|
||||
|
||||
proactor copy.c
|
||||
ntyco copy.c
|
||||
reactor copy.c
|
||||
|
||||
44
README.md
@@ -10,19 +10,41 @@ save() -> 全保存数据集。
|
||||
1. 会出现大量的内存碎片,实现一个内存池,管理内存数据。
|
||||
2. 对比有内存池和没有内存池的性能差异,以及开源内存池 jemalloc 的性能差别。
|
||||
`sudo apt-get install -y libjemalloc-dev`
|
||||
3. 性能测:
|
||||
1. qps 有没有内存池。
|
||||

|
||||
|
||||
2.虚拟内存的占用情况 htop。插入百万条数据集(KV*100w,set 200w del 100w delete 200w set 100w)。
|
||||

|
||||

|
||||

|
||||

|
||||
无内存池: --> time_used=1488789 ms, ops=6000000, qps=4030
|
||||

|
||||
自实现内存池: --> time_used=1439444 ms, ops=6000000, qps=4168
|
||||
测试:
|
||||
|
||||
虚拟内存的占用情况 htop。插入百万条数据集(KV*100w,set 200w del 100w delete 200w set 100w)。
|
||||
|
||||
##### 单条插入
|
||||
未运行状态 VIRT 24.8M
|
||||

|
||||
|
||||
|
||||
|
||||
无内存池: --> time_used=1488789 ms, ops=6000000, qps=4030\
|
||||
VIRT 105M
|
||||

|
||||
|
||||
自实现内存池: --> time_used=1439444 ms, ops=6000000, qps=4168\
|
||||
VIRT 135M
|
||||

|
||||
|
||||

|
||||
jemalloc: time_used=1502797 ms, ops=6000000, qps=3992\
|
||||
VIRT 99M
|
||||
|
||||
##### 批处理
|
||||
一次执行100条。
|
||||
|
||||
无内存池:--> time_used=142913 ms, ops=6000000, qps=41983\
|
||||
VIRT 99M
|
||||
|
||||
自实现内存池: --> time_used=122754 ms, ops=6000000, qps=48878\
|
||||
VIRT 135M
|
||||
|
||||
jemalloc:--> time_used=122206 ms, ops=6000000, qps=49097\
|
||||
VIRT 99M
|
||||
|
||||
性能分析:
|
||||
1. key :
|
||||
1. A_0: mp_alloc (3+8B) -> 16B, malloc (3B) -> 8B
|
||||
|
||||
BIN
img/jemalloc2000w插入100w删除.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
img/mpalloc200w插入100w删除.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
img/批处理jemalloc.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
img/批处理无内存池.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
img/批处理自实现内存池.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
img/无内存池200w插入100w删除.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
img/未运行状态.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
@@ -26,7 +26,6 @@ void kvs_free(void *ptr) {
|
||||
|
||||
#if MEMORY_SELECT_MALLOC == MEMORY_USE_MYMALLOC
|
||||
mp_pool_t global_mempool = {0};
|
||||
#endif
|
||||
|
||||
// >= x 的第一个2^n
|
||||
uint32_t mp_ceil_pow2_u32(uint32_t x) {
|
||||
@@ -161,4 +160,5 @@ void mp_free(void* ptr){
|
||||
mp_free_node_t* node = (mp_free_node_t*)ptr;
|
||||
node->next = p->buckets[cid].free_list;
|
||||
p->buckets[cid].free_list = node;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define MEMORY_USE_MYMALLOC 1
|
||||
#define MEMORY_USE_JEMALLOC 2
|
||||
|
||||
#define MEMORY_SELECT_MALLOC MEMORY_USE_MYMALLOC
|
||||
#define MEMORY_SELECT_MALLOC MEMORY_USE_JEMALLOC
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#define CMD_SIZE (1024)
|
||||
#define BATCH_SIZE (65536)
|
||||
#define KVS_BATCH_MAX 64
|
||||
#define KVS_BATCH_MAX 128
|
||||
#define TIME_SUB_MS(tv1, tv2) ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)
|
||||
|
||||
// #define PRESP print_response
|
||||
|
||||
@@ -163,7 +163,7 @@ void do_batch_test(int fd, int op, const char *key, const char *value){
|
||||
char bkey[15]={0}, bval[15]={0};
|
||||
|
||||
// 组 batch(最多 64 条)
|
||||
for(int i = 0;i < 48; ++ i){
|
||||
for(int i = 0;i < 100; ++ i){
|
||||
if(value == NULL){
|
||||
int klen = sprintf(bkey, "%s%d", key, i);
|
||||
kvs_batch_add(&batch, op, bkey, klen, NULL, 0);
|
||||
@@ -190,6 +190,64 @@ void do_batch_test(int fd, int op, const char *key, const char *value){
|
||||
}
|
||||
}
|
||||
|
||||
void batch_qps(int connfd) {
|
||||
const int N = 1000000;
|
||||
const int B = 100; // do_batch_test() 里写死 50
|
||||
const char *valA = "va";
|
||||
const char *valB = "vb";
|
||||
const char *valC = "vc";
|
||||
|
||||
struct timeval tv_begin, tv_end;
|
||||
gettimeofday(&tv_begin, NULL);
|
||||
|
||||
// ---------------- Phase 1: ADD 两条 DEL 一条 (100w) ----------------
|
||||
// 每轮:ADD/SET A_i, ADD/SET B_i, DEL A_i
|
||||
// 用 batch:每批处理 idx..idx+49
|
||||
for (int base = 0; base < N; base += B) {
|
||||
// prefix 必须短,避免 do_batch_test 里 bkey[15] 溢出
|
||||
// do_batch_test 会生成: prefix + i (0..49)
|
||||
// 我们把 base 编进 prefix,保证全局 key 唯一
|
||||
char preA[16], preB[16];
|
||||
|
||||
// 例:A123450_0..A123450_49(base=123450)
|
||||
// 注意:这里 prefix 长度要尽量 <= 10 左右
|
||||
snprintf(preA, sizeof(preA), "A%d_", base/100);
|
||||
snprintf(preB, sizeof(preB), "B%d_", base/100);
|
||||
|
||||
do_batch_test(connfd, KVS_CMD_RSET, preA, valA); // 50次 RSET A
|
||||
do_batch_test(connfd, KVS_CMD_RSET, preB, valB); // 50次 RSET B
|
||||
do_batch_test(connfd, KVS_CMD_RDEL, preA, NULL); // 50次 RDEL A
|
||||
|
||||
if (base % 10000 == 0) printf("P1 base:%d\n", base);
|
||||
}
|
||||
printf("phase 1 end\n");
|
||||
|
||||
// ---------------- Phase 2: ADD 一条 DEL 两条 (100w) ----------------
|
||||
// 每轮:ADD/SET C_i, DEL B_i, DEL C_i
|
||||
for (int base = 0; base < N; base += B) {
|
||||
char preB[16], preC[16];
|
||||
snprintf(preB, sizeof(preB), "B%d_", base/100);
|
||||
snprintf(preC, sizeof(preC), "C%d_", base/100);
|
||||
|
||||
do_batch_test(connfd, KVS_CMD_RSET, preC, valC); // 50次 RSET C
|
||||
do_batch_test(connfd, KVS_CMD_RDEL, preB, NULL); // 50次 RDEL B
|
||||
do_batch_test(connfd, KVS_CMD_RDEL, preC, NULL); // 50次 RDEL C
|
||||
|
||||
if (base % 10000 == 0) printf("P2 base:%d\n", base);
|
||||
}
|
||||
printf("phase 2 end\n");
|
||||
|
||||
gettimeofday(&tv_end, NULL);
|
||||
int time_used = TIME_SUB_MS(tv_end, tv_begin);
|
||||
|
||||
// 真实总 ops 还是 6*N (每轮 6 个操作)
|
||||
long long ops = (long long)N * 6;
|
||||
long long qps = (time_used > 0) ? (ops * 1000 / time_used) : 0;
|
||||
|
||||
printf("BATCH(do_batch_test) ADD2-DEL1 then ADD1-DEL2 (N=%d) --> time_used=%d ms, ops=%lld, qps=%lld\n",
|
||||
N, time_used, ops, qps);
|
||||
}
|
||||
|
||||
void save(int connfd){
|
||||
testcase(connfd, KVS_CMD_SAVE, NULL, 0, NULL, 0, KVS_STATUS_OK, NULL, 0, "SAVE");
|
||||
}
|
||||
@@ -303,6 +361,8 @@ int main(int argc, char *argv[]) {
|
||||
do_batch_test(connfd, KVS_CMD_HEXIST, "hash_set", NULL);
|
||||
}else if(mode == -1){
|
||||
save(connfd);
|
||||
}else if(mode == 4){
|
||||
batch_qps(connfd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||