Files
oceanbase/deps/oblib/unittest/lib/io/test_io_benchmark.cpp
gm 4a92b6d7df reformat source code
according to code styles, 'AccessModifierOffset' should be -2.
2021-06-17 10:40:36 +08:00

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();
}