diff options
author | Kirill Frolov <k.frolov@samsung.com> | 2023-03-21 17:31:25 +0300 |
---|---|---|
committer | Gleb Balykov/Advanced System SW Lab /SRR/Staff Engineer/Samsung Electronics <g.balykov@samsung.com> | 2023-04-25 11:18:09 +0300 |
commit | bae00003acd55d6b7f68383816cca8b6981db7b7 (patch) | |
tree | 33e2a289072a755589ecd77fd806afc9532f7699 | |
parent | f9ad695ef2118b44d15f74591c9bff9da29ddef1 (diff) | |
download | heaptrack-bae00003acd55d6b7f68383816cca8b6981db7b7.tar.gz heaptrack-bae00003acd55d6b7f68383816cca8b6981db7b7.tar.bz2 heaptrack-bae00003acd55d6b7f68383816cca8b6981db7b7.zip |
Optimizing heaptrack latency
1. heaptrack_interpret: added ifndef NDEBUG around debugging code
2. heaptrack_interpret: using file buffers to avoid frequent syscalls
3. libprofiler.co: enable libc bufferisation for output file
4. fixed diagnostic messages in heaptrack_interpret
-rw-r--r-- | src/interpret/heaptrack_interpret.cpp | 36 | ||||
-rw-r--r-- | src/track/outstream/outstream_file.cpp | 23 | ||||
-rw-r--r-- | src/track/outstream/outstream_file.h | 7 |
3 files changed, 52 insertions, 14 deletions
diff --git a/src/interpret/heaptrack_interpret.cpp b/src/interpret/heaptrack_interpret.cpp index 5a9b539..7340e5c 100644 --- a/src/interpret/heaptrack_interpret.cpp +++ b/src/interpret/heaptrack_interpret.cpp @@ -24,12 +24,14 @@ #include <algorithm> #include <cinttypes> +#include <fstream> #include <iostream> #include <sstream> #include <stdio_ext.h> #include <tuple> #include <unordered_map> #include <vector> +#include <memory> #include <cxxabi.h> @@ -46,6 +48,7 @@ #include "track/outstream/outstream_socket.h" #include <unistd.h> +#include <limits.h> using namespace std; @@ -455,10 +458,10 @@ outStream* createStream(const char* fileName) } if (outputFileName == "-" || outputFileName == "stdout") { - fprintf(stderr, "will write to stdout"); + fprintf(stderr, "will write to stdout\n"); return OpenStream<outStreamFILE, FILE*>(stdout); } else if (outputFileName == "stderr") { - fprintf(stderr, "will write to stderr"); + fprintf(stderr, "will write to stderr\n"), fflush(stdout); return OpenStream<outStreamFILE, FILE*>(stderr); } else if (outputFileName == "socket") { uint16_t Port = outStreamSOCKET::DefaultSocketPort; @@ -515,10 +518,33 @@ outStream* createStream(const char* fileName) int main(int /*argc*/, char** /*argv*/) { // optimize: we only have a single thread - ios_base::sync_with_stdio(false); + // buffers size (around ~32kBytes) + const size_t InputBufferSize = 16UL * LINE_MAX; + const size_t OutputBufferSize = 16UL * LINE_MAX; + + // set buffer for stdout (for libc) + std::unique_ptr<char[]> stdout_buff(new char[OutputBufferSize]); + setvbuf(stdout, &stdout_buff[0], _IOFBF, OutputBufferSize); + +// ios_base::sync_with_stdio(false); __fsetlocking(stdout, FSETLOCKING_BYCALLER); __fsetlocking(stdin, FSETLOCKING_BYCALLER); + // avoid synchronization with libc buffers + std::ios_base::sync_with_stdio(false); + + // don't flush output before input + std::cin.tie(nullptr); + + // use buffered input file `infile': buffer for std::cin can'be + // changed, so we need to open /dev/stdin again, but buffer should + // be set before opening file or call to `pubsetbuf()' will have no effect. + std::ifstream infile; + std::unique_ptr<char[]> stdin_buff(new char[InputBufferSize + 1]); + infile.rdbuf()->pubsetbuf(&stdin_buff[0], InputBufferSize + 1); + infile.open("/dev/stdin"); + if (!infile.is_open()) exit(EXIT_FAILURE); + char *env = getenv("DUMP_HEAPTRACK_INTERPRET_OUTPUT"); outStream* outStream; if (env) { @@ -555,7 +581,7 @@ int main(int /*argc*/, char** /*argv*/) uint64_t leakedManagedAllocations = 0; uint64_t temporaryAllocations = 0; - while (reader.getLine(cin)) { + while (reader.getLine(infile)) { if (reader.mode() == 'x') { reader >> exe; } else if (reader.mode() == 'm') { @@ -733,6 +759,7 @@ int main(int /*argc*/, char** /*argv*/) managedPointersSet.erase(itFromBegin, itFromEnd); +#ifndef NDEBUG for (auto ptr : managedPointersSet) { if(gcManagedPointersSet.find(ptr) != gcManagedPointersSet.end()) { assert(false); @@ -743,6 +770,7 @@ int main(int /*argc*/, char** /*argv*/) assert(false); } } +#endif } else if (reader.mode() == '+') { ++allocations; ++leakedAllocations; diff --git a/src/track/outstream/outstream_file.cpp b/src/track/outstream/outstream_file.cpp index 410cef7..e64ce4a 100644 --- a/src/track/outstream/outstream_file.cpp +++ b/src/track/outstream/outstream_file.cpp @@ -3,12 +3,13 @@ #include <cstdio>
#include <cstring>
#include <stdio_ext.h>
-#include <unistd.h> -#include <fcntl.h> +#include <unistd.h>
+#include <fcntl.h>
#include "outstream_file.h"
outStreamFILE::outStreamFILE(const char *FileName) :
+ m_buffer(new char[BufferSize]),
Stream_(nullptr),
Owner_(false)
{
@@ -20,13 +21,15 @@ outStreamFILE::outStreamFILE(const char *FileName) : throw std::runtime_error("Unable to open stream");
}
- int fd = fileno(Stream_); - if (fd >= 0) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { - fprintf(stderr, "WARNING! Failed to set FD_CLOEXEC mode for file %s: %s\n", FileName, strerror(errno)); - } - } - + if (setvbuf(Stream_, &m_buffer[0], _IOFBF, BufferSize) != 0) perror("setvbuf");
+
+ int fd = fileno(Stream_);
+ if (fd >= 0) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
+ fprintf(stderr, "WARNING! Failed to set FD_CLOEXEC mode for file %s: %s\n", FileName, strerror(errno));
+ }
+ }
+
Owner_ = true;
// from heaptrack code: we do our own locking, this speeds up the writing significantly
__fsetlocking(Stream_, FSETLOCKING_BYCALLER);
@@ -53,7 +56,7 @@ int outStreamFILE::Putc(int Char) noexcept errno = EIO;
return EOF;
}
- return fputc(Char, Stream_);
+ return putc(Char, Stream_);
}
int outStreamFILE::Puts(const char *String) noexcept
diff --git a/src/track/outstream/outstream_file.h b/src/track/outstream/outstream_file.h index 0b0d9f9..f60627e 100644 --- a/src/track/outstream/outstream_file.h +++ b/src/track/outstream/outstream_file.h @@ -1,6 +1,9 @@ #ifndef OUTSTREAMFILE_H #define OUTSTREAMFILE_H +#include <memory> +#include <utility> +#include <limits.h> #include "outstream.h" class outStreamFILE final : public outStream @@ -15,6 +18,7 @@ public: outStreamFILE &operator = (const outStreamFILE &) = delete; outStreamFILE(outStreamFILE &&other) : + m_buffer(std::move(other.m_buffer)), Stream_(other.Stream_), Owner_(other.Owner_) { @@ -24,6 +28,7 @@ public: outStreamFILE &operator = (outStreamFILE &&other) { Stream_ = other.Stream_; Owner_ = other.Owner_; + m_buffer = std::move(other.m_buffer); other.Stream_ = nullptr; other.Owner_ = false; return *this; @@ -34,6 +39,8 @@ public: bool Flush() noexcept override; private: + static const size_t BufferSize = size_t(16) * LINE_MAX; // ~32 kBytes + std::unique_ptr<char[]> m_buffer; FILE *Stream_; bool Owner_; }; |