-
-
Save DrMcCoy/10cac8ffdbc1775717ca7a5b0ad2e395 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/stat.h> | |
#include <sys/mman.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <iostream> | |
#include <chrono> | |
#include <fstream> | |
#include <io> | |
#include <experimental/random> | |
class FILE_write_bench final | |
{ | |
std::FILE* m_file; | |
public: | |
constexpr static std::string_view name = "std::FILE write"; | |
FILE_write_bench() | |
{ | |
m_file = std::fopen("test_FILE.bin", "wb"); | |
if (m_file == nullptr) | |
{ | |
throw std::runtime_error{"std::fopen() failed."}; | |
} | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
for (const auto& i : data) | |
{ | |
if (std::fwrite(&i, sizeof(i), 1, m_file) < 1) | |
{ | |
throw std::runtime_error{"std::fwrite() failed."}; | |
} | |
} | |
if (std::fclose(m_file) == EOF) | |
{ | |
throw std::runtime_error{"std::fclose() failed."}; | |
} | |
} | |
}; | |
class FILE_read_bench final | |
{ | |
std::FILE* m_file; | |
public: | |
constexpr static std::string_view name = "std::FILE read"; | |
FILE_read_bench() | |
{ | |
m_file = std::fopen("test_FILE.bin", "rb"); | |
if (m_file == nullptr) | |
{ | |
throw std::runtime_error{"std::fopen() failed."}; | |
} | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
typename T::value_type i; | |
for (const auto& j : data) | |
{ | |
if (std::fread(&i, sizeof(i), 1, m_file) < 1) | |
{ | |
throw std::runtime_error{"std::fread() failed."}; | |
} | |
if (i != j) | |
{ | |
std::fclose(m_file); | |
throw std::runtime_error{"Files don't match."}; | |
} | |
} | |
} | |
}; | |
class mmap_read_bench final | |
{ | |
int m_fd { -1 }; | |
char *m_mapped { static_cast<char *>(MAP_FAILED) }; | |
size_t m_size; | |
public: | |
constexpr static std::string_view name = "mmap read"; | |
mmap_read_bench() | |
{ | |
m_fd = open("test_FILE.bin", O_RDONLY); | |
if (m_fd < 0) | |
{ | |
throw std::runtime_error{"open() failed."}; | |
} | |
struct stat s; | |
int status = fstat(m_fd, &s); | |
if (status < 0) | |
{ | |
throw std::runtime_error{"fstat() failed."}; | |
} | |
m_size = s.st_size; | |
m_mapped = static_cast<char *>(mmap(0, m_size, PROT_READ, MAP_PRIVATE, m_fd, 0)); | |
if (m_mapped == static_cast<char *>(MAP_FAILED)) | |
{ | |
throw std::runtime_error{"mmap() failed."}; | |
} | |
} | |
~mmap_read_bench() | |
{ | |
if (m_mapped != MAP_FAILED) | |
{ | |
munmap(m_mapped, m_size); | |
} | |
if (m_fd >= 0) | |
{ | |
close(m_fd); | |
} | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
typename T::value_type i; | |
size_t x = 0; | |
for (const auto& j : data) | |
{ | |
i = reinterpret_cast<typename T::value_type *>(m_mapped)[x++]; | |
if (i != j) | |
{ | |
throw std::runtime_error{"Files don't match."}; | |
} | |
} | |
} | |
}; | |
class filebuf_write_bench final | |
{ | |
std::filebuf m_file; | |
public: | |
constexpr static std::string_view name = "std::filebuf write"; | |
filebuf_write_bench() | |
{ | |
auto result = m_file.open("test_filebuf.bin", | |
std::ios_base::out | std::ios_base::binary); | |
if (result == nullptr) | |
{ | |
throw std::runtime_error{"std::filebuf.open() failed."}; | |
} | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
std::streamsize bytes_written; | |
for (const auto& i : data) | |
{ | |
bytes_written = m_file.sputn(reinterpret_cast<const char*>(&i), | |
sizeof(i)); | |
if (bytes_written < sizeof(i)) | |
{ | |
throw std::runtime_error{"std::filebuf.sputn() failed."}; | |
} | |
} | |
if (m_file.pubsync() == -1) | |
{ | |
throw std::runtime_error{"std::filebuf.pubsync() failed."}; | |
} | |
} | |
}; | |
class filebuf_read_bench final | |
{ | |
std::filebuf m_file; | |
public: | |
constexpr static std::string_view name = "std::filebuf read"; | |
filebuf_read_bench() | |
{ | |
auto result = m_file.open("test_filebuf.bin", | |
std::ios_base::in | std::ios_base::binary); | |
if (result == nullptr) | |
{ | |
throw std::runtime_error{"std::filebuf.open() failed."}; | |
} | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
typename T::value_type i; | |
std::streamsize bytes_read; | |
for (const auto& j : data) | |
{ | |
bytes_read = m_file.sgetn(reinterpret_cast<char*>(&i), sizeof(i)); | |
if (bytes_read < sizeof(i)) | |
{ | |
throw std::runtime_error{"std::filebuf.sgetn() failed."}; | |
} | |
if (i != j) | |
{ | |
throw std::runtime_error{"Files don't match."}; | |
} | |
} | |
} | |
}; | |
class ofstream_bench final | |
{ | |
std::ofstream m_stream; | |
public: | |
constexpr static std::string_view name = "std::ofstream"; | |
ofstream_bench() | |
: m_stream{"test_fstream.bin", | |
std::ios_base::out | std::ios_base::binary} | |
{ | |
m_stream.exceptions(std::ios_base::failbit | std::ios_base::badbit); | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
for (const auto& i : data) | |
{ | |
m_stream.write(reinterpret_cast<const char*>(&i), sizeof(i)); | |
} | |
m_stream.flush(); | |
} | |
}; | |
class ifstream_bench final | |
{ | |
std::ifstream m_stream; | |
public: | |
constexpr static std::string_view name = "std::ifstream"; | |
ifstream_bench() | |
: m_stream{"test_fstream.bin", | |
std::ios_base::in | std::ios_base::binary} | |
{ | |
m_stream.exceptions(std::ios_base::failbit | std::ios_base::badbit); | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
typename T::value_type i; | |
for (const auto& j : data) | |
{ | |
m_stream.read(reinterpret_cast<char*>(&i), sizeof(i)); | |
if (i != j) | |
{ | |
throw std::runtime_error{"Files don't match."}; | |
} | |
} | |
} | |
}; | |
class output_file_stream_bench final | |
{ | |
std::io::output_file_stream m_stream; | |
std::io::default_context<std::io::output_file_stream> m_context; | |
public: | |
constexpr static std::string_view name = "Buffered std::io::output_file_stream"; | |
output_file_stream_bench() | |
: m_stream{"test_file_stream.bin", std::io::creation::always_new}, | |
m_context{m_stream} | |
{ | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
for (const auto& i : data) | |
{ | |
std::io::write(i, m_context); | |
} | |
m_stream.flush(); | |
} | |
}; | |
class input_file_stream_bench final | |
{ | |
std::io::input_file_stream m_stream; | |
std::io::default_context<std::io::input_file_stream> m_context; | |
public: | |
constexpr static std::string_view name = "Buffered std::io::input_file_stream"; | |
input_file_stream_bench() | |
: m_stream{"test_file_stream.bin"}, | |
m_context{m_stream} | |
{ | |
} | |
template <typename T> | |
void Run(const T& data) | |
{ | |
typename T::value_type i; | |
for (const auto& j : data) | |
{ | |
std::io::read(i, m_context); | |
if (i != j) | |
{ | |
throw std::runtime_error{"Files don't match."}; | |
} | |
} | |
} | |
}; | |
template <typename B> | |
void Benchmark(const auto& data) | |
{ | |
std::cout << B::name; | |
B b; | |
auto start_time = std::chrono::high_resolution_clock::now(); | |
try | |
{ | |
b.Run(data); | |
} | |
catch (std::exception& e) | |
{ | |
std::cout << ": FAILED\n"; | |
std::cout << "Reason: " << e.what() << '\n'; | |
return; | |
} | |
catch (...) | |
{ | |
std::cout << ": FAILED\n"; | |
std::cout << "Reason: Unknown exception.\n"; | |
return; | |
} | |
auto end_time = std::chrono::high_resolution_clock::now(); | |
std::chrono::duration<double, std::milli> time_elapsed = end_time - | |
start_time; | |
std::cout << ": " << time_elapsed.count() << " ms\n"; | |
} | |
int main() | |
{ | |
std::vector<std::size_t> numbers; | |
numbers.resize(10'000'000); | |
for (auto&& number : numbers) | |
{ | |
number = std::experimental::randint<std::size_t>( | |
std::numeric_limits<std::size_t>::min(), | |
std::numeric_limits<std::size_t>::max()); | |
} | |
Benchmark<FILE_write_bench>(numbers); | |
Benchmark<FILE_read_bench>(numbers); | |
Benchmark<mmap_read_bench>(numbers); | |
Benchmark<filebuf_write_bench>(numbers); | |
Benchmark<filebuf_read_bench>(numbers); | |
Benchmark<ofstream_bench>(numbers); | |
Benchmark<ifstream_bench>(numbers); | |
Benchmark<output_file_stream_bench>(numbers); | |
Benchmark<input_file_stream_bench>(numbers); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment