Optimize file writing by using a memory buffer. (#3461)

This commit is contained in:
Mariusz Glebocki 2022-07-04 16:23:31 +02:00 committed by GitHub
parent 31a83cb0d8
commit 2873dbe154
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 4 deletions

View File

@ -68,6 +68,7 @@ Lukasz Dalek
Maarten De Braekeleer
Maciej Sobkowski
Marco Widmer
Mariusz Glebocki
Markus Krause
Marlon James
Marshal Qiao

View File

@ -951,7 +951,8 @@ void EmitCSyms::emitSymImp() {
}
closeSplit();
VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr);
m_ofp = nullptr;
VL_DO_CLEAR(delete m_ofpBase, m_ofpBase = nullptr);
}
//######################################################################

View File

@ -920,13 +920,16 @@ void V3OutFormatter::printf(const char* fmt...) {
// V3OutFormatter: A class for printing to a file, with automatic indentation of C++ code.
V3OutFile::V3OutFile(const string& filename, V3OutFormatter::Language lang)
: V3OutFormatter{filename, lang} {
: V3OutFormatter{filename, lang}
, m_bufferp{new std::array<char, WRITE_BUFFER_SIZE_BYTES>{}} {
if ((m_fp = V3File::new_fopen_w(filename)) == nullptr) {
v3fatal("Cannot write " << filename);
}
}
V3OutFile::~V3OutFile() {
writeBlock();
if (m_fp) fclose(m_fp);
m_fp = nullptr;
}

View File

@ -22,6 +22,7 @@
#include "V3Error.h"
#include <array>
#include <stack>
#include <set>
#include <list>
@ -183,18 +184,56 @@ public:
// V3OutFile: A class for printing to a file, with automatic indentation of C++ code.
class V3OutFile VL_NOT_FINAL : public V3OutFormatter {
// Size of m_bufferp.
// 128kB has been experimentally determined to be in the zone of buffer sizes that work best.
// It is also considered to be the smallest I/O buffer size in GNU coreutils (io_blksize) that
// allows to best minimize syscall overhead.
// The hard boundaries are CPU L2/L3 cache size on the top and filesystem block size
// on the bottom.
static constexpr std::size_t WRITE_BUFFER_SIZE_BYTES = 128 * 1024;
// MEMBERS
std::unique_ptr<std::array<char, WRITE_BUFFER_SIZE_BYTES>> m_bufferp; // Write buffer
std::size_t m_usedBytes = 0; // Number of bytes stored in m_bufferp
FILE* m_fp = nullptr;
public:
V3OutFile(const string& filename, V3OutFormatter::Language lang);
V3OutFile(const V3OutFile&) = delete;
V3OutFile& operator=(const V3OutFile&) = delete;
V3OutFile(V3OutFile&&) = delete;
V3OutFile& operator=(V3OutFile&&) = delete;
virtual ~V3OutFile() override;
void putsForceIncs();
private:
void writeBlock() {
if (VL_LIKELY(m_usedBytes > 0)) fwrite(m_bufferp->data(), m_usedBytes, 1, m_fp);
m_usedBytes = 0;
}
// CALLBACKS
virtual void putcOutput(char chr) override { fputc(chr, m_fp); }
virtual void putsOutput(const char* str) override { fputs(str, m_fp); }
virtual void putcOutput(char chr) override {
m_bufferp->at(m_usedBytes++) = chr;
if (VL_UNLIKELY(m_usedBytes >= WRITE_BUFFER_SIZE_BYTES)) writeBlock();
}
virtual void putsOutput(const char* str) override {
std::size_t len = strlen(str);
std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes;
while (VL_UNLIKELY(len >= availableBytes)) {
memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes);
m_usedBytes = WRITE_BUFFER_SIZE_BYTES;
writeBlock();
str += availableBytes;
len -= availableBytes;
availableBytes = WRITE_BUFFER_SIZE_BYTES;
}
if (len > 0) {
memcpy(m_bufferp->data() + m_usedBytes, str, len);
m_usedBytes += len;
}
}
};
class V3OutCFile VL_NOT_FINAL : public V3OutFile {