blob: 3a4fb16681f36b6a5fbe883b2b5877c902957aef [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include "io/file_factory.h"
#include "io/fs/benchmark/base_benchmark.h"
#include "io/fs/buffered_reader.h"
#include "io/fs/file_system.h"
#include "io/fs/file_writer.h"
#include "io/fs/s3_file_reader.h"
#include "io/fs/s3_file_system.h"
#include "runtime/exec_env.h"
#include "util/s3_uri.h"
#include "util/slice.h"
namespace doris::io {
class S3Benchmark : public BaseBenchmark {
public:
S3Benchmark(const std::string& name, int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: BaseBenchmark(name, threads, iterations, file_size, conf_map) {}
virtual ~S3Benchmark() = default;
Status get_fs(const std::string& path, std::shared_ptr<io::S3FileSystem>* fs) {
S3URI s3_uri(path);
RETURN_IF_ERROR(s3_uri.parse());
S3Conf s3_conf;
RETURN_IF_ERROR(
S3ClientFactory::convert_properties_to_s3_conf(_conf_map, s3_uri, &s3_conf));
*fs = DORIS_TRY(io::S3FileSystem::create(std::move(s3_conf), io::FileSystem::TMP_FS_ID));
return Status::OK();
}
};
class S3OpenReadBenchmark : public S3Benchmark {
public:
S3OpenReadBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3ReadBenchmark", threads, iterations, file_size, conf_map) {}
virtual ~S3OpenReadBenchmark() = default;
virtual void set_default_file_size() {
if (_file_size <= 0) {
_file_size = 10 * 1024 * 1024; // default 10MB
}
}
Status run(benchmark::State& state) override {
auto file_path = get_file_path(state);
std::shared_ptr<io::S3FileSystem> fs;
RETURN_IF_ERROR(get_fs(file_path, &fs));
io::FileReaderSPtr reader;
io::FileReaderOptions reader_opts;
FileDescription fd;
RETURN_IF_ERROR(fs->open_file(file_path, &reader, &reader_opts));
return read(state, reader);
}
};
// Read a single specified file
class S3SingleReadBenchmark : public S3OpenReadBenchmark {
public:
S3SingleReadBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3OpenReadBenchmark(threads, iterations, file_size, conf_map) {}
virtual ~S3SingleReadBenchmark() = default;
virtual void set_default_file_size() override {}
virtual std::string get_file_path(benchmark::State& state) override {
std::string file_path = _conf_map["file_path"];
bm_log("file_path: {}", file_path);
return file_path;
}
};
// Read a single specified file by prefetch reader
class S3PrefetchReadBenchmark : public S3Benchmark {
public:
S3PrefetchReadBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3PrefetchReadBenchmark", threads, iterations, file_size, conf_map) {}
virtual ~S3PrefetchReadBenchmark() = default;
virtual std::string get_file_path(benchmark::State& state) override {
std::string file_path = _conf_map["file_path"];
bm_log("file_path: {}", file_path);
return file_path;
}
Status run(benchmark::State& state) override {
FileSystemProperties fs_props;
fs_props.system_type = TFileType::FILE_S3;
fs_props.properties = _conf_map;
FileDescription fd;
fd.path = get_file_path(state);
fd.file_size = _file_size;
io::FileReaderOptions reader_options;
auto io_ctx = std::make_shared<IOContext>();
auto reader = DORIS_TRY(io::DelegateReader::create_file_reader(
nullptr, fs_props, fd, reader_options, io::DelegateReader::AccessMode::SEQUENTIAL,
io_ctx));
return read(state, reader);
}
};
class S3CreateWriteBenchmark : public S3Benchmark {
public:
S3CreateWriteBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3CreateWriteBenchmark", threads, iterations, file_size, conf_map) {}
virtual ~S3CreateWriteBenchmark() = default;
Status run(benchmark::State& state) override {
auto file_path = get_file_path(state);
if (_file_size <= 0) {
_file_size = 10 * 1024 * 1024; // default 10MB
}
std::shared_ptr<io::S3FileSystem> fs;
RETURN_IF_ERROR(get_fs(file_path, &fs));
io::FileWriterPtr writer;
RETURN_IF_ERROR(fs->create_file(file_path, &writer));
return write(state, writer.get());
}
};
class S3ListBenchmark : public S3Benchmark {
public:
S3ListBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3ListBenchmark", threads, iterations, file_size, conf_map) {}
virtual ~S3ListBenchmark() = default;
virtual std::string get_file_path(benchmark::State& state) override {
return _conf_map["base_dir"];
}
Status run(benchmark::State& state) override {
auto file_path = get_file_path(state);
std::shared_ptr<io::S3FileSystem> fs;
RETURN_IF_ERROR(get_fs(file_path, &fs));
auto start = std::chrono::high_resolution_clock::now();
std::vector<FileInfo> files;
bool exists = true;
RETURN_IF_ERROR(fs->list(file_path, true, &files, &exists));
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
state.counters["ListCost"] =
benchmark::Counter(1, benchmark::Counter::kIsRate | benchmark::Counter::kInvert);
std::stringstream ss;
int i = 0;
for (auto& file_info : files) {
if (i > 2) {
break;
}
++i;
ss << "[" << file_info.file_name << ", " << file_info.file_size << ", "
<< file_info.is_file << "] ";
}
bm_log("list files: {}", ss.str());
return Status::OK();
}
};
class S3RenameBenchmark : public S3Benchmark {
public:
S3RenameBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3RenameBenchmark", threads, iterations, file_size, conf_map) {
// rename can only do once
set_repetition(1);
}
virtual ~S3RenameBenchmark() = default;
Status run(benchmark::State& state) override {
auto file_path = get_file_path(state);
auto new_file_path = file_path + "_new";
std::shared_ptr<io::S3FileSystem> fs;
RETURN_IF_ERROR(get_fs(file_path, &fs));
auto start = std::chrono::high_resolution_clock::now();
RETURN_IF_ERROR(fs->rename(file_path, new_file_path));
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
state.counters["RenameCost"] =
benchmark::Counter(1, benchmark::Counter::kIsRate | benchmark::Counter::kInvert);
return Status::OK();
}
};
class S3ExistsBenchmark : public S3Benchmark {
public:
S3ExistsBenchmark(int threads, int iterations, size_t file_size,
const std::map<std::string, std::string>& conf_map)
: S3Benchmark("S3ExistsBenchmark", threads, iterations, file_size, conf_map) {}
virtual ~S3ExistsBenchmark() = default;
Status run(benchmark::State& state) override {
auto file_path = get_file_path(state);
std::shared_ptr<io::S3FileSystem> fs;
RETURN_IF_ERROR(get_fs(file_path, &fs));
auto start = std::chrono::high_resolution_clock::now();
bool res = false;
RETURN_IF_ERROR(fs->exists(file_path, &res));
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
state.counters["ExistsCost"] =
benchmark::Counter(1, benchmark::Counter::kIsRate | benchmark::Counter::kInvert);
return Status::OK();
}
};
} // namespace doris::io