Compare commits
9 Commits
82f454d7ca
...
blobdb
| Author | SHA1 | Date | |
|---|---|---|---|
|
cede3452b4
|
|||
|
a90a0377e7
|
|||
|
1bb175101c
|
|||
|
07baaae51e
|
|||
|
d9b969f644
|
|||
|
e74d42ca2f
|
|||
|
6a39746498
|
|||
|
95c66c3f47
|
|||
|
b2b4f72524
|
+4
-1
@@ -3,9 +3,12 @@
|
||||
/scripts/include
|
||||
/scripts/lib
|
||||
/scripts/lib64
|
||||
/scripts/shares/
|
||||
/scripts/share/
|
||||
/scripts/.gitignore
|
||||
*.png
|
||||
*.csv
|
||||
pyvenv.cfg
|
||||
Cargo.lock
|
||||
free.txt
|
||||
alloc.txt
|
||||
*.zst
|
||||
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'kv_bench'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=kv_bench",
|
||||
"--package=kv_bench"
|
||||
],
|
||||
"filter": {
|
||||
"name": "kv_bench",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [
|
||||
"--path",
|
||||
"/home/abby/mace_bench",
|
||||
"--threads",
|
||||
"1",
|
||||
"--iterations",
|
||||
"100000",
|
||||
"--mode",
|
||||
"insert",
|
||||
"--key-size",
|
||||
"1024",
|
||||
"--value-size",
|
||||
"16"
|
||||
],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'kv_bench'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=kv_bench",
|
||||
"--package=kv_bench"
|
||||
],
|
||||
"filter": {
|
||||
"name": "kv_bench",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
+9
-5
@@ -4,13 +4,17 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# mace = { git = "https://git.o2c.fun/abby/mace.git", branch = "task-64-1" }
|
||||
mace = { path = "/home/workspace/gits/github/mace"}
|
||||
clap = { version = "4.5.42", features = ["derive"] }
|
||||
mace = { git = "https://github.com/abbycin/mace" }
|
||||
clap = { version = "4.5.48", features = ["derive"] }
|
||||
rand = "0.9.2"
|
||||
log = "0.4.22"
|
||||
coreid = { path = "coreid"}
|
||||
logger = { path = "logger"}
|
||||
coreid = { path = "coreid" }
|
||||
logger = { path = "logger" }
|
||||
myalloc = { path = "heap_trace" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
custom_alloc = []
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "myalloc"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
backtrace = "0.3.76"
|
||||
@@ -0,0 +1,233 @@
|
||||
use std::{
|
||||
alloc::{GlobalAlloc, System},
|
||||
cell::Cell,
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
fmt::Display,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
ptr,
|
||||
sync::{LazyLock, Mutex, atomic::AtomicBool},
|
||||
};
|
||||
|
||||
pub struct MyAlloc;
|
||||
|
||||
fn trace(size: usize, is_alloc: bool) -> Option<String> {
|
||||
let mut key = String::new();
|
||||
backtrace::trace(|f| {
|
||||
backtrace::resolve_frame(f, |sym| {
|
||||
if let Some(filename) = sym.filename()
|
||||
&& let Some(line) = sym.lineno()
|
||||
{
|
||||
if let Some(name) = filename.to_str()
|
||||
&& name.contains("mace")
|
||||
{
|
||||
if name.len() > 10 {
|
||||
// sometime name maybe empty
|
||||
let x = format!("{}:{}\n", name, line);
|
||||
key.extend(x.chars().into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
true
|
||||
});
|
||||
if !key.is_empty() {
|
||||
let mut lk = G_MAP.lock().unwrap();
|
||||
let tmp = key.clone();
|
||||
match lk.entry(tmp) {
|
||||
Entry::Vacant(v) => {
|
||||
if is_alloc {
|
||||
v.insert(Status {
|
||||
nr_alloc: 1,
|
||||
alloc_size: size,
|
||||
nr_free: 0,
|
||||
free_size: 0,
|
||||
});
|
||||
} else {
|
||||
v.insert(Status {
|
||||
nr_alloc: 0,
|
||||
alloc_size: 0,
|
||||
nr_free: 1,
|
||||
free_size: size,
|
||||
});
|
||||
}
|
||||
}
|
||||
Entry::Occupied(mut o) => {
|
||||
let s = o.get_mut();
|
||||
if is_alloc {
|
||||
s.nr_alloc += 1;
|
||||
s.alloc_size += size;
|
||||
} else {
|
||||
s.nr_free += 1;
|
||||
s.free_size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Status {
|
||||
nr_alloc: usize,
|
||||
alloc_size: usize,
|
||||
nr_free: usize,
|
||||
free_size: usize,
|
||||
}
|
||||
|
||||
impl Display for Status {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{:?}", self))
|
||||
}
|
||||
}
|
||||
|
||||
static G_STOP: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
static G_MAP: LazyLock<Mutex<HashMap<String, Status>>> =
|
||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
static G_TRACE: LazyLock<Mutex<HashMap<u64, String>>> =
|
||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
const META_LEN: usize = 8;
|
||||
|
||||
thread_local! {
|
||||
static G_SELF: Cell<bool> = const { Cell::new(false) };
|
||||
}
|
||||
|
||||
const fn real_size(layout: &std::alloc::Layout) -> usize {
|
||||
if META_LEN > layout.align() {
|
||||
META_LEN.checked_add(layout.size()).unwrap()
|
||||
} else {
|
||||
layout.align().checked_add(layout.size()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn new_layout(layout: std::alloc::Layout) -> std::alloc::Layout {
|
||||
let align = layout.align().max(align_of::<u64>());
|
||||
let sz = real_size(&layout);
|
||||
std::alloc::Layout::from_size_align(sz, align).unwrap()
|
||||
}
|
||||
|
||||
fn write_hash(x: *mut u8, align: usize, s: Option<String>) -> *mut u8 {
|
||||
let r = unsafe { x.add(META_LEN.max(align)) };
|
||||
if !G_SELF.with(|x| x.get()) {
|
||||
G_SELF.with(|x| x.set(true));
|
||||
let p = x.cast::<u64>();
|
||||
if let Some(s) = s {
|
||||
let mut stat = DefaultHasher::new();
|
||||
s.hash(&mut stat);
|
||||
let h = stat.finish();
|
||||
unsafe { p.write_unaligned(h) };
|
||||
let mut lk = G_TRACE.lock().unwrap();
|
||||
lk.insert(h, s);
|
||||
} else {
|
||||
unsafe { p.write_unaligned(u64::MAX) };
|
||||
}
|
||||
G_SELF.with(|x| x.set(false));
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn read_hash(x: *mut u8, align: usize) -> *mut u8 {
|
||||
let (h, p) = unsafe {
|
||||
let p = x.sub(META_LEN.max(align)).cast::<u64>();
|
||||
(p.read_unaligned(), p.cast::<u8>())
|
||||
};
|
||||
|
||||
if h == u64::MAX {
|
||||
return p;
|
||||
}
|
||||
if !G_SELF.with(|x| x.get()) {
|
||||
G_SELF.with(|x| x.set(true));
|
||||
let mut lk = G_TRACE.lock().unwrap();
|
||||
lk.remove(&h);
|
||||
G_SELF.with(|x| x.set(false));
|
||||
}
|
||||
p
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for MyAlloc {
|
||||
unsafe fn alloc(&self, layout: std::alloc::Layout) -> *mut u8 {
|
||||
let s = if !G_SELF.with(|x| x.get()) && !G_STOP.load(std::sync::atomic::Ordering::Acquire) {
|
||||
G_SELF.with(|x| x.set(true));
|
||||
let x = trace(layout.size(), true);
|
||||
G_SELF.with(|x| x.set(false));
|
||||
x
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let new = new_layout(layout);
|
||||
let x = unsafe { System.alloc(new) };
|
||||
write_hash(x, new.align(), s)
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: std::alloc::Layout) {
|
||||
if !G_SELF.with(|x| x.get()) && !G_STOP.load(std::sync::atomic::Ordering::Acquire) {
|
||||
G_SELF.with(|x| x.set(true));
|
||||
trace(layout.size(), false);
|
||||
G_SELF.with(|x| x.set(false));
|
||||
}
|
||||
let new = new_layout(layout);
|
||||
let p = read_hash(ptr, new.align());
|
||||
unsafe { System.dealloc(p, new) };
|
||||
}
|
||||
|
||||
unsafe fn alloc_zeroed(&self, layout: std::alloc::Layout) -> *mut u8 {
|
||||
let p = unsafe { self.alloc(layout) };
|
||||
if !p.is_null() {
|
||||
unsafe { ptr::write_bytes(p, 0, layout.size()) };
|
||||
}
|
||||
p
|
||||
}
|
||||
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: std::alloc::Layout, new_size: usize) -> *mut u8 {
|
||||
let s = if !G_SELF.with(|x| x.get()) && !G_STOP.load(std::sync::atomic::Ordering::Acquire) {
|
||||
G_SELF.with(|x| x.set(true));
|
||||
let x = trace(layout.size(), true);
|
||||
G_SELF.with(|x| x.set(false));
|
||||
x
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let old_layout = new_layout(layout);
|
||||
let raw = ptr.sub(META_LEN.max(old_layout.align()));
|
||||
let new_total_size = META_LEN + new_size;
|
||||
|
||||
let new_raw = System.realloc(raw, old_layout, new_total_size);
|
||||
if new_raw.is_null() {
|
||||
return new_raw;
|
||||
}
|
||||
write_hash(new_raw, old_layout.align(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_filtered_trace<F>(f: F)
|
||||
where
|
||||
F: Fn(&str, &Status),
|
||||
{
|
||||
G_STOP.store(true, std::sync::atomic::Ordering::Release);
|
||||
let lk = G_MAP.lock().unwrap();
|
||||
let t = G_TRACE.lock().unwrap();
|
||||
|
||||
for (_, v) in t.iter() {
|
||||
if let Some(s) = lk.get(v) {
|
||||
f(v, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_all_trace<F>(f: F)
|
||||
where
|
||||
F: Fn(&str, &Status),
|
||||
{
|
||||
G_STOP.store(true, std::sync::atomic::Ordering::Release);
|
||||
let lk = G_MAP.lock().unwrap();
|
||||
|
||||
lk.iter().for_each(|(k, v)| f(k, v));
|
||||
}
|
||||
@@ -10,12 +10,14 @@ endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||
|
||||
find_package(CLI11 CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(RocksDB CONFIG REQUIRED)
|
||||
|
||||
add_executable(rocksdb_bench main.cpp
|
||||
instant.h)
|
||||
|
||||
target_include_directories(rocksdb_bench PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||
target_link_libraries(rocksdb_bench rocksdb CLI11::CLI11)
|
||||
target_link_libraries(rocksdb_bench PRIVATE RocksDB::rocksdb CLI11::CLI11 fmt::fmt)
|
||||
|
||||
file(GLOB ALL_SOURCE_FILES *.cpp *.h)
|
||||
add_custom_target(format
|
||||
|
||||
+48
-20
@@ -1,10 +1,14 @@
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <print>
|
||||
#include <cstdint>
|
||||
#include <fmt/format.h>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <rocksdb/cache.h>
|
||||
#include <rocksdb/db.h>
|
||||
#include <rocksdb/env.h>
|
||||
#include <rocksdb/options.h>
|
||||
#include <rocksdb/table.h>
|
||||
#include <rocksdb/utilities/optimistic_transaction_db.h>
|
||||
#include <rocksdb/utilities/transaction.h>
|
||||
#include <rocksdb/utilities/transaction_db.h>
|
||||
@@ -52,41 +56,55 @@ int main(int argc, char *argv[]) {
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
if (args.path.empty()) {
|
||||
std::println("path is empty");
|
||||
fmt::println("path is empty");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(args.path)) {
|
||||
std::println("path `{}` already exists", args.path);
|
||||
fmt::println("path `{}` already exists", args.path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args.mode != "insert" && args.mode != "get" && args.mode != "mixed") {
|
||||
std::println("Error: Invalid mode");
|
||||
fmt::println("Error: Invalid mode");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args.key_size < 16 || args.value_size < 16) {
|
||||
std::println("Error: key_size or value_size too small, must >= 16");
|
||||
fmt::println("Error: key_size or value_size too small, must >= 16");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args.insert_ratio > 100) {
|
||||
std::println("Error: Insert ratio must be between 0 and 100");
|
||||
fmt::println("Error: Insert ratio must be between 0 and 100");
|
||||
return 1;
|
||||
}
|
||||
|
||||
rocksdb::Options options;
|
||||
rocksdb::ColumnFamilyOptions cfo{};
|
||||
cfo.enable_blob_files = true;
|
||||
cfo.min_blob_size = 8192;
|
||||
// use 1GB block cache
|
||||
auto cache = rocksdb::NewLRUCache(1 << 30);
|
||||
rocksdb::BlockBasedTableOptions table_options{};
|
||||
table_options.block_cache = cache;
|
||||
cfo.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
// the following three options makes it not trigger GC in test
|
||||
cfo.level0_file_num_compaction_trigger = 10000;
|
||||
cfo.write_buffer_size = 64 << 20;
|
||||
cfo.max_write_buffer_number = 16;
|
||||
|
||||
std::vector<rocksdb::ColumnFamilyDescriptor> cfd{};
|
||||
cfd.push_back(rocksdb::ColumnFamilyDescriptor("default", cfo));
|
||||
|
||||
rocksdb::DBOptions options;
|
||||
options.create_if_missing = true;
|
||||
options.allow_concurrent_memtable_write = true;
|
||||
options.enable_pipelined_write = true;
|
||||
// the following three options makes it not trigger GC in test
|
||||
options.level0_file_num_compaction_trigger = 1000;
|
||||
options.write_buffer_size = 1 << 30;
|
||||
options.max_write_buffer_number = 5;
|
||||
options.env->SetBackgroundThreads(4, rocksdb::Env::Priority::HIGH);
|
||||
|
||||
auto ropt = rocksdb::ReadOptions();
|
||||
auto wopt = rocksdb::WriteOptions();
|
||||
wopt.no_slowdown = true;
|
||||
// wopt.disableWAL = true;
|
||||
std::vector<std::thread> wg;
|
||||
std::vector<std::vector<std::string>> keys{};
|
||||
@@ -94,7 +112,8 @@ int main(int argc, char *argv[]) {
|
||||
rocksdb::OptimisticTransactionDB *db;
|
||||
auto b = nm::Instant::now();
|
||||
std::mutex mtx{};
|
||||
auto s = rocksdb::OptimisticTransactionDB::Open(options, args.path, &db);
|
||||
std::vector<rocksdb::ColumnFamilyHandle *> handles{};
|
||||
auto s = rocksdb::OptimisticTransactionDB::Open(options, args.path, cfd, &handles, &db);
|
||||
assert(s.ok());
|
||||
std::barrier barrier{static_cast<ptrdiff_t>(args.threads)};
|
||||
|
||||
@@ -117,19 +136,27 @@ int main(int argc, char *argv[]) {
|
||||
keys.emplace_back(std::move(key));
|
||||
}
|
||||
|
||||
auto *handle = handles[0];
|
||||
|
||||
if (args.mode == "get") {
|
||||
auto *kv = db->BeginTransaction(wopt);
|
||||
for (size_t tid = 0; tid < args.threads; ++tid) {
|
||||
auto *tk = &keys[tid];
|
||||
for (auto &key: *tk) {
|
||||
kv->Put(key, val);
|
||||
kv->Put(handle, key, val);
|
||||
}
|
||||
}
|
||||
kv->Commit();
|
||||
delete kv;
|
||||
delete handle;
|
||||
delete db;
|
||||
handles.clear();
|
||||
// re-open db
|
||||
s = rocksdb::OptimisticTransactionDB::Open(options, args.path, cfd, &handles, &db);
|
||||
assert(s.ok());
|
||||
}
|
||||
|
||||
handle = handles[0];
|
||||
for (size_t tid = 0; tid < args.threads; ++tid) {
|
||||
auto *tk = &keys[tid];
|
||||
wg.emplace_back([&] {
|
||||
@@ -143,7 +170,7 @@ int main(int argc, char *argv[]) {
|
||||
if (args.mode == "insert") {
|
||||
for (auto &key: *tk) {
|
||||
auto *kv = db->BeginTransaction(wopt);
|
||||
kv->Put(key, val);
|
||||
kv->Put(handle, key, val);
|
||||
kv->Commit();
|
||||
delete kv;
|
||||
}
|
||||
@@ -151,7 +178,7 @@ int main(int argc, char *argv[]) {
|
||||
} else if (args.mode == "get") {
|
||||
for (auto &key: *tk) {
|
||||
auto *kv = db->BeginTransaction(wopt);
|
||||
kv->Get(ropt, key, &rval);
|
||||
kv->Get(ropt, handle, key, &rval);
|
||||
kv->Commit();
|
||||
delete kv;
|
||||
}
|
||||
@@ -160,9 +187,9 @@ int main(int argc, char *argv[]) {
|
||||
auto is_insert = dist(gen) < args.insert_ratio;
|
||||
auto *kv = db->BeginTransaction(wopt);
|
||||
if (is_insert) {
|
||||
kv->Put(key, val);
|
||||
kv->Put(handle, key, val);
|
||||
} else {
|
||||
kv->Get(ropt, key, &rval); // not found
|
||||
kv->Get(ropt, handle, key, &rval); // not found
|
||||
}
|
||||
kv->Commit();
|
||||
delete kv;
|
||||
@@ -180,9 +207,10 @@ int main(int argc, char *argv[]) {
|
||||
return args.insert_ratio;
|
||||
return args.mode == "insert" ? 100 : 0;
|
||||
}();
|
||||
double ops = static_cast<double>(total_op.load(std::memory_order_relaxed)) / b.elapse_sec();
|
||||
std::println("{},{},{},{},{},{:.2f},{}", args.mode, args.threads, args.key_size, args.value_size, ratio, ops,
|
||||
b.elapse_ms());
|
||||
uint64_t ops = total_op.load(std::memory_order_relaxed) / b.elapse_sec();
|
||||
fmt::println("{},{},{},{},{},{},{}", args.mode, args.threads, args.key_size, args.value_size, ratio, (uint64_t) ops,
|
||||
(uint64_t) b.elapse_ms());
|
||||
delete handle;
|
||||
delete db;
|
||||
std::filesystem::remove_all(args.path);
|
||||
}
|
||||
|
||||
+10
-1
@@ -1,5 +1,14 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"cli11"
|
||||
"cli11",
|
||||
"rocksdb",
|
||||
"fmt"
|
||||
],
|
||||
"builtin-baseline": "120deac3062162151622ca4860575a33844ba10b",
|
||||
"overrides": [
|
||||
{
|
||||
"name": "rocksdb",
|
||||
"version": "10.4.2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
python3 -m venv .
|
||||
./bin/pip3 install pandas matplotlib adjustText
|
||||
rm -f .gitignore
|
||||
|
||||
+6
-4
@@ -5,26 +5,28 @@ cd ..
|
||||
cargo build --release 1>/dev/null 2> /dev/null
|
||||
|
||||
function samples() {
|
||||
kv_sz=(16 16 100 1024 1024 1024)
|
||||
export RUST_BACKTRACE=full
|
||||
kv_sz=(16 16 100 1024 1024 1024 16 10240)
|
||||
# set -x
|
||||
|
||||
cnt=10000
|
||||
for ((i = 1; i <= $(nproc); i *= 2))
|
||||
do
|
||||
for ((j = 0; j < ${#kv_sz[@]}; j += 2))
|
||||
do
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations 100000 --mode insert --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations $cnt --mode insert --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "insert threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
exit 1
|
||||
fi
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations 100000 --mode get --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations $cnt --mode get --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "get threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
exit 1
|
||||
fi
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations 100000 --mode mixed --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]} --insert-ratio 30
|
||||
./target/release/kv_bench --path /home/abby/mace_bench --threads $i --iterations $cnt --mode mixed --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]} --insert-ratio 30
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "mixed threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
|
||||
assert(len(sys.argv) == 2)
|
||||
|
||||
f = open(sys.argv[1])
|
||||
lines = []
|
||||
|
||||
allocs = []
|
||||
|
||||
while True:
|
||||
line = f.readline()
|
||||
if len(line) < 10:
|
||||
break
|
||||
if line.find('INFO') != -1:
|
||||
continue
|
||||
pos = line.find('Status')
|
||||
if pos < 0:
|
||||
pos = line.find('mace')
|
||||
if pos != 0:
|
||||
lines.append(line[pos:])
|
||||
else:
|
||||
lines.append(line)
|
||||
else:
|
||||
cleaned = line[pos+6:].strip().strip('{}')
|
||||
pairs = cleaned.split(',')
|
||||
tl = [tuple(pair.split(': ')) for pair in pairs]
|
||||
tl = [(k.strip(), int(v)) for k, v in tl]
|
||||
allocs.append((tl, ''.join(lines)))
|
||||
lines.clear()
|
||||
|
||||
# sort by alloc_size
|
||||
allocs.sort(key=lambda x: x[0][1][1], reverse=True)
|
||||
|
||||
with open('alloc.txt', 'w') as o:
|
||||
for x in allocs:
|
||||
o.write(f'{x[0]}\n{x[1]}\n')
|
||||
# sort by free_size
|
||||
allocs.sort(key=lambda x: x[0][3][1], reverse=True)
|
||||
|
||||
with open('free.txt', 'w') as o:
|
||||
for x in allocs:
|
||||
o.write(f'{x[0]}\n{x[1]}\n')
|
||||
|
||||
alloc_size = 0
|
||||
free_size = 0
|
||||
|
||||
for x in allocs:
|
||||
alloc_size += x[0][1][1]
|
||||
free_size += x[0][3][1]
|
||||
|
||||
print(f"total_alloc {alloc_size} total_free {free_size}")
|
||||
+5
-5
@@ -6,26 +6,26 @@ cmake --preset release 1>/dev/null 2>/dev/null
|
||||
cmake --build --preset release 1>/dev/null 2>/dev/null
|
||||
|
||||
function samples() {
|
||||
kv_sz=(16 16 100 1024 1024 1024)
|
||||
kv_sz=(16 16 100 1024 1024 1024 16 10240)
|
||||
# set -x
|
||||
|
||||
cnt=10000
|
||||
for ((i = 1; i <= $(nproc); i *= 2))
|
||||
do
|
||||
for ((j = 0; j < ${#kv_sz[@]}; j += 2))
|
||||
do
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations 100000 --mode insert --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations $cnt --mode insert --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "insert threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
exit 1
|
||||
fi
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations 100000 --mode get --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations $cnt --mode get --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]}
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "get threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
exit 1
|
||||
fi
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations 100000 --mode mixed --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]} --insert-ratio 30
|
||||
./build/release/rocksdb_bench --path /home/abby/rocksdb_tmp --threads $i --iterations $cnt --mode mixed --key-size ${kv_sz[j]} --value-size ${kv_sz[j+1]} --insert-ratio 30
|
||||
if test $? -ne 0
|
||||
then
|
||||
echo "mixed threads $i ksz ${kv_sz[j]} vsz ${kv_sz[j+1]} fail"
|
||||
|
||||
+31
-11
@@ -2,12 +2,19 @@ use clap::Parser;
|
||||
#[cfg(target_os = "linux")]
|
||||
use logger::Logger;
|
||||
use mace::{Mace, Options};
|
||||
#[cfg(feature = "custom_alloc")]
|
||||
use myalloc::{MyAlloc, print_filtered_trace};
|
||||
use rand::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
use std::time::Instant;
|
||||
|
||||
#[cfg(feature = "custom_alloc")]
|
||||
#[global_allocator]
|
||||
static GLOBAL: MyAlloc = MyAlloc;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
@@ -34,12 +41,15 @@ struct Args {
|
||||
|
||||
#[arg(long, default_value = "false")]
|
||||
random: bool,
|
||||
|
||||
#[arg(long, default_value = "8192")]
|
||||
blob_size: usize,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
Logger::init().add_file("/tmp/x.log", true);
|
||||
Logger::init().add_file("/Data/x.log", true);
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
}
|
||||
let args = Args::parse();
|
||||
@@ -48,31 +58,34 @@ fn main() {
|
||||
|
||||
if args.path.is_empty() {
|
||||
eprintln!("path is empty");
|
||||
return;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if path.exists() {
|
||||
eprintln!("path {:?} already exists", args.path);
|
||||
return;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if args.key_size < 16 || args.value_size < 16 {
|
||||
eprintln!("Error: key_size or value_size too small, must >= 16");
|
||||
return;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if args.insert_ratio > 100 {
|
||||
eprintln!("Error: Insert ratio must be between 0 and 100");
|
||||
return;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let mut keys: Vec<Vec<Vec<u8>>> = Vec::with_capacity(args.threads);
|
||||
let mut opt = Options::new(path);
|
||||
opt.sync_on_write = false;
|
||||
opt.tmp_store = true;
|
||||
opt.gc_timeout = 1000 * 60; // make sure GC will not work
|
||||
// opt.cache_capacity = 3 << 30; // this is very important for large key-value store
|
||||
let db = Mace::new(opt.validate().unwrap()).unwrap();
|
||||
opt.over_provision = true; // large value will use lots of memeory
|
||||
opt.inline_size = args.blob_size;
|
||||
opt.tmp_store = args.mode != "get";
|
||||
let mut saved = opt.clone();
|
||||
saved.tmp_store = false;
|
||||
let mut db = Mace::new(opt.validate().unwrap()).unwrap();
|
||||
db.disable_gc();
|
||||
|
||||
let mut rng = rand::rng();
|
||||
let value = Arc::new(vec![b'0'; args.value_size]);
|
||||
@@ -97,6 +110,10 @@ fn main() {
|
||||
}
|
||||
});
|
||||
pre_tx.commit().unwrap();
|
||||
drop(db);
|
||||
// re-open db
|
||||
saved.tmp_store = true;
|
||||
db = Mace::new(saved.validate().unwrap()).unwrap();
|
||||
}
|
||||
|
||||
let barrier = Arc::new(std::sync::Barrier::new(args.threads));
|
||||
@@ -115,7 +132,7 @@ fn main() {
|
||||
let val = value.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
coreid::bind_core(tid);
|
||||
// coreid::bind_core(tid);
|
||||
barrier.wait();
|
||||
|
||||
{
|
||||
@@ -167,7 +184,7 @@ fn main() {
|
||||
let test_start = start_time.lock().unwrap();
|
||||
let duration = test_start.elapsed();
|
||||
let total = total_ops.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let ops = total as f64 / duration.as_secs_f64();
|
||||
let ops = (total as f64 / duration.as_secs_f64()) as usize;
|
||||
|
||||
// println!("{:<20} {}", "Test Mode:", args.mode);
|
||||
// println!("{:<20} {}", "Threads:", args.threads);
|
||||
@@ -197,4 +214,7 @@ fn main() {
|
||||
ops,
|
||||
duration.as_millis()
|
||||
);
|
||||
drop(db);
|
||||
#[cfg(feature = "custom_alloc")]
|
||||
print_filtered_trace(|x, y| log::info!("{}{}", x, y));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user