Skip to content

Instantly share code, notes, and snippets.

@tianchaijz
Forked from aktau/fs-read-method-bench.cpp
Created July 25, 2016 02:52
Show Gist options
  • Select an option

  • Save tianchaijz/12fdb9a2020c65b4f5bff9d04bb8b662 to your computer and use it in GitHub Desktop.

Select an option

Save tianchaijz/12fdb9a2020c65b4f5bff9d04bb8b662 to your computer and use it in GitHub Desktop.
benchmark fread/read/mmap/std::streams
// @aktau: this is not my file, I tried to find the original article this was from but couldn't, I'm pasting it here for posterity
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
using namespace std;
// write N * 512 integers
void fillFile(int N, char * name) {
FILE * fd = ::fopen(name, "wb");
if (fd == NULL) {
cerr << "problem" << endl;
return;
}
int numbers[512];
for(int k = 0; k < 512; ++k)
numbers[k] = k; // whatever
for(int t = 0; t < N; ++t) {
int size = 512;
size_t realsize;
int err, error;
if((realsize = fwrite(&size, sizeof(int),1,fd))!=1) {
err = errno;
error = ferror(fd);
if(error) {
cout<< "We written only " << realsize << " bytes" << endl;
cout<< "[ERROR] " << strerror(err) <<endl;
exit (EXIT_FAILURE);
}
return;
}
if((realsize = fwrite(&numbers[0], sizeof(int),512,fd))!=512) {
err = errno;
error = ferror(fd);
if(error) {
cout<< "We written only" << realsize << "bytes" << endl;
cout<< "[ERROR] " << strerror(err) <<endl;
exit (EXIT_FAILURE);
}
return;
}
}
::fclose(fd);
}
int doSomeComputation(int * numbers, size_t size) {
int answer = 0;
// totally arbitrary
for(size_t k = 0; k < size; k+= 2) {
answer += numbers[k];
}
for(size_t k = 1; k < size; k+= 2) {
answer += numbers[k] * 2;
}
return answer;
}
int testfread(char * name, int N) {
int answer = 0;
FILE * fd = ::fopen(name, "rb");
if (fd == NULL) {
cerr << "problem" << endl;
return -1;
}
vector<int> numbers(512);
for(int t = 0; t < N; ++t) {
int size = 0;
if(fread(&size, sizeof(int),1,fd)!=1) {
cout<<"Data can't be read???"<<endl;
return -1;
}
numbers.resize(size);
if(fread(&numbers[0], sizeof(int),numbers.size(),fd)!=numbers.size()) {
cout<<"Data can't be read???"<<endl;
return -1;
}
answer += doSomeComputation(&numbers[0],numbers.size());
}
::fclose(fd);
return answer;
}
int testwithCpp(char * name, int N) {
int answer = 0;
ifstream in(name,ios::binary);
vector<int> numbers(512);
for(int t = 0; t < N; ++t) {
int size = 0;
in.read(reinterpret_cast<char *>(&size),sizeof(int));
numbers.resize(size);
in.read(reinterpret_cast<char *>(&numbers[0]),sizeof(int)*size);
answer += doSomeComputation(&numbers[0],numbers.size());
}
in.close();
return answer;
}
int testfreadwithsetbuffer(char * name, int N) {
int answer = 0;
FILE * fd = ::fopen(name, "rb");
setvbuf (fd , NULL , _IOFBF , 1024*4 ); // large buffer
if (fd == NULL) {
cerr << "problem" << endl;
return -1;
}
vector<int> numbers(512);
for(int t = 0; t < N; ++t) {
int size = 0;
if(fread(&size, sizeof(int),1,fd)!=1) {
cout<<"Data can't be read???"<<endl;
return -1;
}
numbers.resize(size);
if(fread(&numbers[0], sizeof(int),numbers.size(),fd)!=numbers.size()) {
cout<<"Data can't be read???"<<endl;
return -1;
}
answer += doSomeComputation(&numbers[0],numbers.size());
}
::fclose(fd);
return answer;
}
int testfreadwithlargebuffer(char * name, int N) {
int answer = 0;
FILE * fd = ::fopen(name, "rb");
setvbuf (fd , NULL , _IOFBF , 1024*1024*32 ); // large buffer
if (fd == NULL) {
cerr << "problem" << endl;
return -1;
}
vector<int> numbers(512);
for(int t = 0; t < N; ++t) {
int size = 0;
if(fread(&size, sizeof(int),1,fd)!=1) {
cout<<"Data can't be read???"<<endl;
return -1;
}
numbers.resize(size);
if(fread(&numbers[0], sizeof(int),numbers.size(),fd)!=numbers.size()) {
cout<<"Data can't be read???"<<endl;
return -1;
}
answer += doSomeComputation(&numbers[0],numbers.size());
}
::fclose(fd);
return answer;
}
int testwmmap(char * name, int N, bool advise, bool shared) {
int answer = 0;
int fd = ::open(name, O_RDONLY);
size_t length = N * (512 + 1) * 4;
// for Linux:
#ifdef __linux__
int * addr = reinterpret_cast<int *>(mmap(NULL, length, PROT_READ, MAP_FILE | (shared?MAP_SHARED:MAP_PRIVATE) | MAP_POPULATE , fd, 0));
#else
int * addr = reinterpret_cast<int *>(mmap(NULL, length, PROT_READ, MAP_FILE | (shared?MAP_SHARED:MAP_PRIVATE), fd, 0));
#endif
int * initaddr = addr;
if (addr == MAP_FAILED) {
cout<<"Data can't be mapped???"<<endl;
return -1;
}
if(advise)
if(madvise(addr,length,MADV_SEQUENTIAL|MADV_WILLNEED)!=0)
cerr<<" Couldn't set hints"<<endl;
close(fd);
for(int t = 0; t < N; ++t) {
int size = *addr++;
answer += doSomeComputation(addr,size);
addr+=size;
}
munmap(initaddr,length);
return answer;
}
int testread(char * name, int N) {
int answer = 0;
int fd = ::open(name, O_RDONLY);
if (fd < 0) {
cerr << "problem" << endl;
return -1;
}
vector<int> numbers(512);
for(int t = 0; t < N; ++t) {
int size = 0;
if(read(fd,&size, sizeof(int))!=sizeof(int)) {
cout<<"Data can't be read???"<<endl;
return -1;
}
numbers.resize(size);
if(read(fd,&numbers[0], sizeof(int)*numbers.size())!=sizeof(int)*numbers.size()) {
cout<<"Data can't be read???"<<endl;
return -1;
}
answer += doSomeComputation(&numbers[0],numbers.size());
}
::close(fd);
return answer;
}
class WallClockTimer {
public:
struct timeval t1, t2;
WallClockTimer() :
t1(), t2() {
gettimeofday(&t1, 0);
t2 = t1;
}
void reset() {
gettimeofday(&t1, 0);
t2 = t1;
}
unsigned long long elapsed() {
return ((t2.tv_sec - t1.tv_sec) * 1000ULL * 1000ULL) + ((t2.tv_usec - t1. tv_usec));
}
unsigned long long split() {
gettimeofday(&t2, 0);
return elapsed();
}
};
class CPUTimer {
public:
//clock_t t1, t2;
struct rusage t1,t2;
CPUTimer() :
t1(), t2() {
getrusage(RUSAGE_SELF, &t1);
//t1 = clock();
t2 = t1;
}
void reset() {
getrusage(RUSAGE_SELF, &t1);
//t1 = clock();
t2 = t1;
}
// proxy for userelapsed
unsigned long long elapsed() {
return totalelapsed();//userelapsed();
}
unsigned long long totalelapsed() {
return userelapsed() + systemelapsed();
}
// returns the *user* CPU time in micro seconds (mu s)
unsigned long long userelapsed() {
return ((t2.ru_utime.tv_sec - t1.ru_utime.tv_sec) * 1000ULL * 1000ULL) + ((t2.ru_utime.tv_usec - t1.ru_utime.tv_usec)
);
}
// returns the *system* CPU time in micro seconds (mu s)
unsigned long long systemelapsed() {
return ((t2.ru_stime.tv_sec - t1.ru_stime.tv_sec) * 1000ULL * 1000ULL) + ((t2.ru_stime.tv_usec - t1.ru_stime.tv_usec)
);
}
unsigned long long split() {
getrusage(RUSAGE_SELF, &t2);
return elapsed();
}
};
int main() {
printf("starting benchmark");
const int N = 16384*32;
int tot = 0;
CPUTimer cput;
WallClockTimer wct;
for (int T = 0; T < 2; ++T) {
char * name = tmpnam(NULL);// unsafe but for these purposes, ok
fillFile(N,name);
printf("filled file");
cout<<endl;
// don't report times
tot += testread(name,N);
// fread
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testfread(name,N);
cout<<"fread\t\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// fread with set buffer
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testfreadwithsetbuffer(name,N);
cout<<"fread w sbuffer\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// fread with large buffer
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testfreadwithlargebuffer(name,N);
cout<<"fread w lbuffer\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// read
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testread(name,N);
cout<<"read2 \t\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// mmap
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testwmmap(name,N,false,false);
cout<<"mmap \t\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// fancy mmap
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testwmmap(name,N,true,false);
cout<<"fancy mmap \t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// mmap
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testwmmap(name,N,false,true);
cout<<"mmap (shared) \t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// fancy mmap
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testwmmap(name,N,true,true);
cout<<"fancy mmap (shared) \t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
// C++
cput.reset();wct.reset();
for(int x = 0; x<10; ++x) tot += testwithCpp(name,N);
cout<<"Cpp\t\t\t"<<512*N*1.0/cput.split()<<" "<<512*N*1.0/wct.split()<<endl;
::remove(name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment