Last active
April 11, 2016 03:35
-
-
Save dodheim/cb4c5de8a2a8a32851a6ecfdab4e958c to your computer and use it in GitHub Desktop.
Add new approach to code at https://cristianadam.eu/20160410/c-plus-plus-i-slash-o-benchmark/
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 <stdio.h> | |
#include <fcntl.h> | |
#if defined(__unix__) || defined (__CYGWIN__) | |
#include <unistd.h> | |
#else | |
#include <io.h> | |
#endif | |
#ifndef O_BINARY | |
#define O_BINARY 0 | |
#endif | |
#include <chrono> | |
#include <iostream> | |
#include <functional> | |
#include <fstream> | |
#include <map> | |
#include <string> | |
#include <vector> | |
using namespace std::chrono; | |
struct measure | |
{ | |
template<typename F, typename ...Args> | |
static std::chrono::milliseconds::rep ms(F func, Args&&... args) | |
{ | |
auto start = system_clock::now(); | |
func(std::forward<Args>(args)...); | |
auto stop = system_clock::now(); | |
return duration_cast<milliseconds>(stop - start).count(); | |
} | |
}; | |
void testCFileIO(const char* inFile, const char* outFile, std::vector<char>& inBuffer) | |
{ | |
FILE* in = ::fopen(inFile, "rb"); | |
if (!in) | |
{ | |
std::cout << "Can't open input file: " << inFile << std::endl; | |
return; | |
} | |
FILE* out = ::fopen(outFile, "wb"); | |
if (!out) | |
{ | |
std::cout << "Can't open output file: " << outFile << std::endl; | |
return; | |
} | |
fseek(in, 0, SEEK_END); | |
size_t inFileSize = ::ftell(in); | |
fseek(in, 0, SEEK_SET); | |
for (size_t bytesLeft = inFileSize, chunk = inBuffer.size(); bytesLeft > 0; bytesLeft -= chunk) | |
{ | |
if (bytesLeft < chunk) | |
{ | |
chunk = bytesLeft; | |
} | |
::fread(&inBuffer[0], 1, chunk, in); | |
::fwrite(&inBuffer[0], 1, chunk, out); | |
} | |
::fclose(out); | |
::fclose(in); | |
} | |
void testCppIO(const char* inFile, const char* outFile, std::vector<char>& inBuffer) | |
{ | |
std::ifstream in(inFile, std::ifstream::binary); | |
if (!in.is_open()) | |
{ | |
std::cout << "Can't open input file: " << inFile << std::endl; | |
return; | |
} | |
std::ofstream out(outFile, std::ofstream::binary); | |
if (!out.is_open()) | |
{ | |
std::cout << "Can't open output file: " << outFile << std::endl; | |
return; | |
} | |
in.seekg(0, std::ifstream::end); | |
size_t inFileSize = in.tellg(); | |
in.seekg(0, std::ifstream::beg); | |
for (size_t bytesLeft = inFileSize, chunk = inBuffer.size(); bytesLeft > 0; bytesLeft -= chunk) | |
{ | |
if (bytesLeft < chunk) | |
{ | |
chunk = bytesLeft; | |
} | |
in.read(&inBuffer[0], chunk); | |
out.write(&inBuffer[0], chunk); | |
} | |
} | |
void testCppIO2(const char* inFile, const char* outFile, std::vector<char>& inBuffer) | |
{ | |
std::filebuf in; | |
if (!in.open(inFile, std::ios::binary | std::ios::in)) | |
{ | |
std::cout << "Can't open input file: " << inFile << std::endl; | |
return; | |
} | |
std::filebuf out; | |
if (!out.open(outFile, std::ios::binary | std::ios::out)) | |
{ | |
std::cout << "Can't open output file: " << outFile << std::endl; | |
return; | |
} | |
while (auto chunk = in.sgetn(inBuffer.data(), inBuffer.size())) | |
{ | |
out.sputn(inBuffer.data(), chunk); | |
} | |
} | |
void testPosixIO(const char* inFile, const char* outFile, std::vector<char>& inBuffer) | |
{ | |
int in = ::_open(inFile, O_RDONLY | O_BINARY); | |
if (in < 0) | |
{ | |
std::cout << "Can't open input file: " << inFile << std::endl; | |
return; | |
} | |
int out = ::_open(outFile, O_CREAT | O_WRONLY | O_BINARY, 0666); | |
if (out < 0) | |
{ | |
std::cout << "Can't open output file: " << outFile << std::endl; | |
return; | |
} | |
size_t inFileSize = ::_lseek(in, 0, SEEK_END); | |
::_lseek(in, 0, SEEK_SET); | |
for (size_t bytesLeft = inFileSize, chunk = inBuffer.size(); bytesLeft > 0; bytesLeft -= chunk) | |
{ | |
if (bytesLeft < chunk) | |
{ | |
chunk = bytesLeft; | |
} | |
::_read(in, &inBuffer[0], static_cast<unsigned>(chunk)); | |
::_write(out, &inBuffer[0], static_cast<unsigned>(chunk)); | |
} | |
::_close(out); | |
::_close(in); | |
} | |
int main(int argc, char* argv[]) | |
{ | |
std::vector<std::string> args(argv, argv + argc); | |
if (args.size() != 4) | |
{ | |
std::cout << "Usage: " << args[0] << " copy_method (c, posix, c++, c++2) in_file number_of_times" << std::endl; | |
return 1; | |
} | |
typedef std::map<std::string, std::function<void (const char*, const char*, std::vector<char>&)>> FuncMap; | |
FuncMap funcMap { {"c", testCFileIO}, {"posix", testPosixIO}, {"c++", testCppIO}, {"c++2", testCppIO2}}; | |
auto it = funcMap.find(args[1]); | |
if (it != funcMap.end()) | |
{ | |
std::vector<char> inBuffer(1024 * 1024); | |
auto dest = args[2] + ".copy"; | |
const auto times = std::stoul(args[3]); | |
milliseconds::rep total = 0; | |
for (unsigned int i = 0; i < times; ++i) | |
{ | |
total += measure::ms(it->second, args[2].c_str(), dest.c_str(), inBuffer); | |
::_unlink(dest.c_str()); | |
} | |
std::cout << "Average " << args[1] << " I/O took: " << total / double(times) << "ms" << std::endl; | |
} | |
else | |
{ | |
std::cout << "Not supported copy method: " << args[1] << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Revision 1 = original code from blog