Last active
June 1, 2020 01:46
-
-
Save kghose/04f7a23599d06ffce1ddc626011d341a to your computer and use it in GitHub Desktop.
File writing buffering experiment
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
/* | |
g++ --std=c++17 -O3 doublebuffer.cpp -odoublebuffer | |
*/ | |
#include <chrono> | |
#include <ctype.h> | |
#include <fstream> | |
#include <string> | |
#include <thread> | |
const size_t buf_size = 50000; | |
class DoubleBuffer { | |
enum BufferId { one = 0, two = 1, neither = 3 }; | |
public: | |
DoubleBuffer(std::string fname) | |
{ | |
_buffer[0] = new size_t[buf_size]; | |
_buffer[1] = new size_t[buf_size]; | |
_buffer_to_write_to = BufferId::one; | |
_buffer_being_flushed = BufferId::neither; | |
file.open(fname, std::ios::binary | std::ios::out); | |
} | |
void _write_out_buffer() | |
{ | |
if (_writer.joinable()) { | |
_writer.join(); | |
} | |
_buffer_being_flushed = _buffer_to_write_to; | |
_writer = std::thread( | |
&std::ofstream::write, | |
&file, | |
(char*)_buffer[_buffer_being_flushed], | |
sizeof(size_t) * _buf_idx); | |
_buffer_to_write_to = _buffer_to_write_to == BufferId::one | |
? BufferId::two | |
: BufferId::one; | |
_buf_idx = 0; | |
} | |
~DoubleBuffer() | |
{ | |
_write_out_buffer(); | |
_writer.join(); | |
delete[] _buffer[0]; | |
delete[] _buffer[1]; | |
} | |
void write(const size_t k) | |
{ | |
if (_buf_idx == buf_size) { | |
_write_out_buffer(); | |
} | |
_buffer[_buffer_to_write_to][_buf_idx] = k; | |
_buf_idx++; | |
} | |
private: | |
std::ofstream file; | |
size_t* _buffer[2]; | |
BufferId _buffer_to_write_to; | |
BufferId _buffer_being_flushed; | |
size_t _buf_idx = 0; | |
std::thread _writer; | |
}; | |
int main(int argc, char* argv[]) | |
{ | |
DoubleBuffer buffer("test.bin"); | |
for (size_t j = 0; j < (1 << 27); j++) { | |
size_t k = (size_t)(j * 1.5 - j * 1.1 + j / 3.2); | |
buffer.write(k); | |
} | |
} |
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
/* | |
g++ --std=c++17 -O3 doublebuffer2.cpp -odoublebuffer2 | |
*/ | |
#include <fstream> | |
#include <mutex> | |
#include <thread> | |
const size_t buf_size = 50000; | |
template <typename T> class ThreadedBuffer { | |
public: | |
ThreadedBuffer(std::string fname) | |
{ | |
buffer[0] = new T[buf_size]; | |
buffer[1] = new T[buf_size]; | |
idx[0] = idx[1] = 0; | |
write_b = 0; | |
file.open(fname, std::ios::binary | std::ios::out); | |
saver = std::thread(&ThreadedBuffer::save_buffer_to_disk, this); | |
} | |
~ThreadedBuffer() | |
{ | |
wait_for(saved); | |
run = false; | |
set(go); | |
saver.join(); | |
delete[] buffer[0]; | |
delete[] buffer[1]; | |
} | |
void write(const T& k) | |
{ | |
buffer[write_b][idx[write_b]] = k; | |
idx[write_b]++; | |
if (idx[write_b] == buf_size) { | |
wait_for(saved); | |
write_b = 1 - write_b; | |
idx[write_b] = 0; | |
set(go); | |
} | |
} | |
private: | |
std::ofstream file; | |
T* buffer[2]; | |
size_t idx[2]; | |
size_t write_b = 0; | |
bool go; | |
bool saved; | |
bool run = true; | |
std::mutex m; | |
std::condition_variable cv; | |
std::thread saver; | |
void save_buffer_to_disk() | |
{ | |
set(saved); | |
size_t save_b = 0; | |
do { | |
wait_for(go); | |
file.write((char*)buffer[save_b], sizeof(T) * idx[save_b]); | |
save_b = 1 - save_b; | |
set(saved); | |
} while (run); | |
} | |
void set(bool& v) | |
{ | |
{ | |
std::unique_lock<std::mutex> lk(m); | |
v = true; | |
} | |
cv.notify_one(); | |
} | |
void wait_for(bool& v) | |
{ | |
std::unique_lock<std::mutex> lk(m); | |
cv.wait(lk, [&] { return v; }); | |
v = false; | |
} | |
}; | |
int main(int argc, char* argv[]) | |
{ | |
ThreadedBuffer<size_t> buffer("test.bin"); | |
for (size_t j = 0; j < (1 << 27); j++) { | |
size_t k = (size_t)(j * 1.5 - j * 1.1 + j / 3.2); | |
buffer.write(k); | |
} | |
} |
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
/* | |
g++ --std=c++17 -O3 nobuffer.cpp -onobuffer | |
*/ | |
#include <ctype.h> | |
#include <fstream> | |
int main(int argc, char* argv[]) | |
{ | |
std::ofstream buffer("test.bin", std::ios::binary | std::ios::out); | |
for (size_t j = 0; j < (1 << 27); j++) { | |
size_t k = (size_t)(j * 1.5 - j * 1.1 + j / 3.2); | |
buffer.write((char*)&k, sizeof(size_t)); | |
} | |
} |
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
/* | |
g++ --std=c++17 -O3 singlebuffer.cpp -osinglebuffer | |
*/ | |
#include <ctype.h> | |
#include <fstream> | |
#include <string> | |
const size_t buf_size = 2048; | |
class Buffer { | |
public: | |
Buffer(std::string fname) | |
{ | |
file.open(fname, std::ios::binary | std::ios::out); | |
} | |
void _write() { file.write((char*)_buffer, sizeof(size_t) * _buf_idx); } | |
~Buffer() { _write(); } | |
void write(const size_t k) | |
{ | |
if (_buf_idx == buf_size) { | |
_write(); | |
_buf_idx = 0; | |
} | |
_buffer[_buf_idx] = k; | |
_buf_idx++; | |
} | |
private: | |
std::ofstream file; | |
size_t _buffer[buf_size]; | |
size_t _buf_idx = 0; | |
}; | |
int main(int argc, char* argv[]) | |
{ | |
Buffer buffer("test.bin"); | |
for (size_t j = 0; j < (1 << 27); j++) { | |
size_t k = (size_t)(j * 1.5 - j * 1.1 + j / 3.2); | |
buffer.write(k); | |
} | |
} |
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
@startuml nobuffer | |
concise "Main Thread" as MT | |
@0 | |
MT is compute | |
@2 | |
MT is save | |
@5 | |
MT is compute | |
@7 | |
MT is save | |
@enduml | |
@startuml buffer | |
concise "Main Thread" as MT | |
@0 | |
MT is "compute x N" | |
@4 | |
MT is save | |
@10 | |
MT is "compute x N" | |
@14 | |
MT is save | |
@enduml | |
@startuml doublebuffer | |
concise "Main Thread" as MT | |
concise "Writer Thread" as WT | |
@0 | |
MT is "compute x N" | |
@4 | |
MT -> WT : Write | |
WT is init | |
MT is "compute x N" | |
@5 | |
WT is save | |
@8 | |
MT is {-} | |
@11 | |
WT -> MT : Done | |
MT -> WT : Write | |
WT is init | |
MT is "compute x N" | |
@12 | |
WT is save | |
@15 | |
MT is {-} | |
@18 | |
WT -> MT : Done | |
WT is init | |
MT is "compute x N" | |
@18 | |
WT is save | |
@enduml | |
@startuml persistentdoublebuffer | |
concise "Main Thread" as MT | |
concise "Writer Thread" as WT | |
@0 | |
MT is "compute x N" | |
WT is init | |
@1 | |
WT is {-} | |
@4 | |
MT -> WT : Write | |
WT is save | |
MT is "compute x N" | |
@8 | |
MT is {-} | |
@10 | |
WT -> MT : Done | |
MT -> WT : Write | |
WT is save | |
MT is "compute x N" | |
@14 | |
MT is {-} | |
@16 | |
WT -> MT : Done | |
WT is save | |
MT is "compute x N" | |
@enduml |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment