333 lines
11 KiB
C++
333 lines
11 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* 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 PubL v2 for more details.
|
|
*/
|
|
|
|
#include <malloc.h>
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <gtest/gtest.h>
|
|
#include <limits>
|
|
|
|
#include "lib/alloc/alloc_func.h"
|
|
#define private public
|
|
#include "lib/io/ob_io_benchmark.h"
|
|
#include "ob_io_stress.h"
|
|
#include "lib/file/file_directory_utils.h"
|
|
|
|
using namespace oceanbase::common;
|
|
using namespace oceanbase::lib;
|
|
|
|
#ifdef USE_POSIX_FALLOCATE
|
|
#define FALLOCATE(fd, mode, off, len) \
|
|
({ \
|
|
int rc = posix_fallocate(fd, off, len); \
|
|
if (0 != rc) { \
|
|
errno = rc; \
|
|
} \
|
|
rc; \
|
|
})
|
|
#else
|
|
#define FALLOCATE(fd, mode, off, len) fallocate(fd, mode, off, len)
|
|
#endif
|
|
|
|
namespace oceanbase {
|
|
namespace unittest {
|
|
class TestIOBenchmark : public ::testing::Test {
|
|
public:
|
|
virtual void SetUp();
|
|
virtual void TearDown();
|
|
};
|
|
|
|
void TestIOBenchmark::SetUp()
|
|
{
|
|
system("rm -rf ./etc");
|
|
system("mkdir -p ./etc");
|
|
}
|
|
|
|
void TestIOBenchmark::TearDown()
|
|
{
|
|
system("rm -rf ./etc");
|
|
}
|
|
|
|
TEST_F(TestIOBenchmark, TestObIORunner)
|
|
{
|
|
ObIORunner runner;
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, runner.init(-1, 1 * 1024 * 1024 * 1024L, 64));
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, runner.init(1, 1024 * 1024L, 64));
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, runner.init(1, 0, 64));
|
|
ASSERT_EQ(OB_INVALID_ARGUMENT, runner.init(1, 1 * 1024 * 1024 * 1024L, 0));
|
|
|
|
// lib::set_memory_limit(1024*1024*1024L);
|
|
ASSERT_EQ(OB_SUCCESS, runner.init(1, 1 * 1024 * 1024 * 1024L, 12));
|
|
ASSERT_EQ(OB_INIT_TWICE, runner.init(1, 1 * 1024 * 1024 * 1024L, 64));
|
|
}
|
|
|
|
TEST_F(TestIOBenchmark, result_set)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIOBenchResultSet result_set;
|
|
ObIOBenchResult res;
|
|
double iops = 0;
|
|
double iort = 0;
|
|
|
|
// invalid res
|
|
ret = result_set.add_result(res);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// invalid load
|
|
ret = result_set.load_from_file(NULL);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = result_set.load_from_file("./etc/invalid_file");
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// invalid print
|
|
ret = result_set.print_to_file(NULL);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = result_set.print_to_file("./etc/bench_cfg");
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// not init
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_READ, 1024, iops);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = result_set.get_rt(ObIOMode::IO_MODE_WRITE, 1024, iort);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// normal res
|
|
res.workload_.mode_ = ObIOMode::IO_MODE_READ;
|
|
res.workload_.io_size_ = 16 * 1024;
|
|
res.iops_ = ((double)(1024 * 1024 * 128)) / (double)res.workload_.io_size_;
|
|
res.rt_ = ((double)res.workload_.io_size_) / (double)100;
|
|
ret = result_set.add_result(res);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
// invalid argument;
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_MAX, 1024, iops);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = result_set.get_rt(ObIOMode::IO_MODE_MAX, 1024, iort);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// smaller size
|
|
res.workload_.mode_ = ObIOMode::IO_MODE_READ;
|
|
res.workload_.io_size_ = 8 * 1024;
|
|
res.iops_ = ((double)(1024 * 1024 * 128)) / (double)res.workload_.io_size_;
|
|
res.rt_ = ((double)res.workload_.io_size_) / (double)100;
|
|
ret = result_set.add_result(res);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// normal res
|
|
res.workload_.mode_ = ObIOMode::IO_MODE_READ;
|
|
res.workload_.io_size_ = 32 * 1024;
|
|
res.iops_ = ((double)(1024 * 1024 * 128)) / (double)res.workload_.io_size_;
|
|
res.rt_ = ((double)res.workload_.io_size_) / (double)100;
|
|
ret = result_set.add_result(res);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
result_set.set_complete();
|
|
|
|
ret = result_set.print_to_file("./etc/bench_cfg");
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_READ, 16 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(((double)(1024 * 1024 * 128)) / (double)(16 * 1024), iops);
|
|
ret = result_set.get_rt(ObIOMode::IO_MODE_READ, 32 * 1024, iort);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ((double)(32 * 1024) / (double)100, iort);
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_READ, 64 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ((double)(1024 * 1024 * 128) / (double)(64 * 1024), iops);
|
|
|
|
// load cfg from file and check again
|
|
result_set.reuse();
|
|
ret = result_set.load_from_file("./etc/bench_cfg");
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_READ, 16 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ(((double)(1024 * 1024 * 128)) / (double)(16 * 1024), iops);
|
|
ret = result_set.get_rt(ObIOMode::IO_MODE_READ, 32 * 1024, iort);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ((double)(32 * 1024) / (double)100, iort);
|
|
ret = result_set.get_iops(ObIOMode::IO_MODE_READ, 64 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_EQ((double)(1024 * 1024 * 128) / (double)(64 * 1024), iops);
|
|
}
|
|
|
|
TEST_F(TestIOBenchmark, benchmark)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
double iort = 0;
|
|
double iops = 0;
|
|
|
|
ObIOBenchmark& io_bench = ObIOBenchmark::get_instance();
|
|
|
|
// invalid invoke when not init
|
|
ret = io_bench.get_max_iops(ObIOMode::IO_MODE_READ, 1024, iops);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = io_bench.get_min_rt(ObIOMode::IO_MODE_READ, 1024, iort);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = io_bench.reload_io_bench_res();
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// invalid init
|
|
ret = io_bench.init(NULL);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
ret = io_bench.init("./etc");
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// normal init, first run
|
|
ret = io_bench.init("./etc", "./", 128 * 1024 * 1024L, 4);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
// repeat init
|
|
ret = io_bench.init("./etc", "./", 128 * 1024 * 1024L, 4);
|
|
ASSERT_NE(OB_SUCCESS, ret);
|
|
|
|
// second run, load result from file
|
|
io_bench.destroy();
|
|
int64_t start_time = ObTimeUtility::current_time();
|
|
ASSERT_EQ(OB_SUCCESS, io_bench.init("./etc"));
|
|
ASSERT_TRUE(ObTimeUtility::current_time() - start_time < 1000000);
|
|
|
|
// get value
|
|
ret = io_bench.get_max_iops(ObIOMode::IO_MODE_READ, 16 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(iops > 0);
|
|
ret = io_bench.get_min_rt(ObIOMode::IO_MODE_WRITE, 2 * 1024 * 1024, iort);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(iort > 0);
|
|
|
|
// reload and reget
|
|
ret = io_bench.reload_io_bench_res();
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ret = io_bench.get_max_iops(ObIOMode::IO_MODE_READ, 16 * 1024, iops);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(iops > 0);
|
|
ret = io_bench.get_min_rt(ObIOMode::IO_MODE_WRITE, 2 * 1024 * 1024, iort);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
ASSERT_TRUE(iort > 0);
|
|
|
|
char buf[common::OB_MAX_IO_BENCH_RESULT_LENGTH];
|
|
ASSERT_EQ(ret, io_bench.get_io_bench_result_str(buf, sizeof(buf)));
|
|
COMMON_LOG(INFO, "io bench result = ", K(buf));
|
|
|
|
io_bench.destroy();
|
|
ASSERT_EQ(OB_SUCCESS, io_bench.init("./etc"));
|
|
ASSERT_TRUE(ObTimeUtility::current_time() - start_time < 1000000);
|
|
}
|
|
|
|
TEST_F(TestIOBenchmark, fill_file)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int fd = 0;
|
|
const int64_t MAX_BENCHMARK_FILE_PATH_LEN = 128;
|
|
const char* data_dir = "./";
|
|
const int64_t file_size = 128 << 20;
|
|
int32_t blk_size = 2 << 20;
|
|
const int64_t blk_cnt = file_size / blk_size;
|
|
char data_file_path[MAX_BENCHMARK_FILE_PATH_LEN + 1];
|
|
MEMSET(data_file_path, 0, sizeof(data_file_path));
|
|
ObIORunner io_runner;
|
|
ObIOBenchmark& io_bench = ObIOBenchmark::get_instance();
|
|
int32_t thread_cnt = 4;
|
|
|
|
int n = snprintf(data_file_path, MAX_BENCHMARK_FILE_PATH_LEN, "%s/bench_file", data_dir);
|
|
if (n <= 0 || n >= MAX_BENCHMARK_FILE_PATH_LEN) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "The data dir is too long, ", K(data_dir), K(ret));
|
|
} else if ((fd = ::open(
|
|
data_file_path, O_CREAT | O_TRUNC | O_DIRECT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
|
|
ret = OB_IO_ERROR;
|
|
COMMON_LOG(WARN, "open file error", K(data_file_path), K(errno), KERRMSG, K(ret));
|
|
} else if (OB_FAIL(FALLOCATE(fd, 0 /*MODE*/, 0 /*offset*/, file_size))) {
|
|
ret = OB_IO_ERROR;
|
|
COMMON_LOG(WARN, "allocate file error", K(data_file_path), K(file_size), K(errno), KERRMSG, K(ret));
|
|
} else if (OB_FAIL(ObIOManager::get_instance().add_disk(fd))) {
|
|
COMMON_LOG(WARN, "add disk failed", K(ret), K(fd));
|
|
} else if (OB_FAIL(io_runner.init(fd, file_size, thread_cnt))) {
|
|
COMMON_LOG(WARN, "failed to init io runner");
|
|
} else {
|
|
ret = io_bench.fill_file(io_runner, thread_cnt);
|
|
ASSERT_EQ(OB_SUCCESS, ret);
|
|
|
|
void* base = memalign(512, blk_size);
|
|
memset(base, 'a', blk_size);
|
|
void* buf = memalign(512, blk_size);
|
|
fsync(fd);
|
|
for (int i = 0; i < blk_cnt; ++i) {
|
|
COMMON_LOG(INFO, "iteration ", K(i));
|
|
if (0 > pread(fd, buf, blk_size, blk_size * i)) {
|
|
COMMON_LOG(ERROR, "preaderror", KERRMSG);
|
|
}
|
|
ASSERT_EQ(0, memcmp(base, buf, blk_size));
|
|
}
|
|
}
|
|
io_bench.destroy();
|
|
}
|
|
|
|
TEST(TestIOStress, mystress)
|
|
{
|
|
CHUNK_MGR.set_limit(8L * 1024L * 1024L * 1024L);
|
|
|
|
// prepare file
|
|
const char* file_name = "./io_stress_file";
|
|
const int64_t file_size = 1 * 1024 * 1024 * 1024L;
|
|
int fd = ::open(file_name, O_CREAT | O_TRUNC | O_RDWR | O_DIRECT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
ASSERT_TRUE(fd > 0);
|
|
ASSERT_EQ(0, ftruncate(fd, file_size));
|
|
|
|
// init io manager
|
|
ObIOManager::get_instance().destroy();
|
|
ASSERT_EQ(OB_SUCCESS, ObIOManager::get_instance().init());
|
|
ASSERT_EQ(OB_SUCCESS, OB_IO_MANAGER.add_disk(fd));
|
|
|
|
// init stress
|
|
TestIOStress stress;
|
|
ASSERT_EQ(OB_SUCCESS, stress.init(fd, file_size, 16, 0, 0));
|
|
stress.set_user_iops(50 * 10000);
|
|
|
|
COMMON_LOG(INFO, "start stress", K(stress));
|
|
stress.start();
|
|
for (int i = 0; i < 5; ++i) {
|
|
int64_t round_begin = ObTimeUtility::current_time();
|
|
int64_t succ_cnt_old = stress.get_succeed_count();
|
|
sleep(5);
|
|
int64_t succ_cnt_new = stress.get_succeed_count();
|
|
int64_t round_end = ObTimeUtility::current_time();
|
|
int64_t time = round_end - round_begin;
|
|
int64_t succ_cnt = succ_cnt_new - succ_cnt_old;
|
|
int64_t iops = succ_cnt * 1000L * 1000L / time;
|
|
COMMON_LOG(INFO, "stress audit", K(i), K(time), K(succ_cnt), K(iops));
|
|
}
|
|
stress.stop();
|
|
stress.wait();
|
|
|
|
// destroy io manager and close file
|
|
ASSERT_EQ(OB_SUCCESS, ObIOManager::get_instance().delete_disk(fd));
|
|
::close(fd);
|
|
FileDirectoryUtils::delete_file(file_name);
|
|
}
|
|
|
|
} // namespace unittest
|
|
} // namespace oceanbase
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
OB_LOGGER.set_max_file_size(256 * 1024 * 1024);
|
|
system("rm -f test_io_benchmark.log*");
|
|
OB_LOGGER.set_file_name("test_io_benchmark.log");
|
|
OB_LOGGER.set_log_level("INFO");
|
|
set_memory_limit(40L * 1024L * 1024L * 1024L); // 40GB
|
|
ObIOManager::get_instance().init();
|
|
testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|