[vm] Add buffering of --trace_precompiler_to output in memory

Under certain circumstances we see that gen_snapshot spends significant
portion of time in kernel. This happens with --trace_precompiler_to
option specified on the command line.

This change reduces number of I/O operations required to write
--trace_precompiler_to output by adding a memory buffer for the whole
output.

TEST=pkg/vm_snapshot_analysis/test/precompiler_trace_test.dart

Change-Id: I7c2b3fbf1f6b6bee950c2d23809e68e4698f84f4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175780
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
index 104fe76..2a3b80f 100644
--- a/runtime/platform/text_buffer.cc
+++ b/runtime/platform/text_buffer.cc
@@ -14,10 +14,18 @@
 intptr_t BaseTextBuffer::Printf(const char* format, ...) {
   va_list args;
   va_start(args, format);
+  intptr_t len = VPrintf(format, args);
+  va_end(args);
+  return len;
+}
+
+intptr_t BaseTextBuffer::VPrintf(const char* format, va_list args) {
+  va_list args1;
+  va_copy(args1, args);
   intptr_t remaining = capacity_ - length_;
   ASSERT(remaining >= 0);
-  intptr_t len = Utils::VSNPrint(buffer_ + length_, remaining, format, args);
-  va_end(args);
+  intptr_t len = Utils::VSNPrint(buffer_ + length_, remaining, format, args1);
+  va_end(args1);
   if (len >= remaining) {
     if (!EnsureCapacity(len)) {
       length_ = capacity_ - 1;
@@ -27,7 +35,7 @@
     remaining = capacity_ - length_;
     ASSERT(remaining > len);
     va_list args2;
-    va_start(args2, format);
+    va_copy(args2, args);
     intptr_t len2 =
         Utils::VSNPrint(buffer_ + length_, remaining, format, args2);
     va_end(args2);
diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h
index c44d955..78f8e4f 100644
--- a/runtime/platform/text_buffer.h
+++ b/runtime/platform/text_buffer.h
@@ -20,6 +20,7 @@
   virtual ~BaseTextBuffer() {}
 
   intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+  intptr_t VPrintf(const char* format, va_list args);
   void AddChar(char ch);
   void EscapeAndAddUTF16CodeUnit(uint16_t cu);
   void EscapeAndAddCodeUnit(uint32_t cu);
diff --git a/runtime/vm/compiler/aot/precompiler_tracer.cc b/runtime/vm/compiler/aot/precompiler_tracer.cc
index fcb56b2..96dfbda 100644
--- a/runtime/vm/compiler/aot/precompiler_tracer.cc
+++ b/runtime/vm/compiler/aot/precompiler_tracer.cc
@@ -32,6 +32,7 @@
 PrecompilerTracer::PrecompilerTracer(Precompiler* precompiler, void* stream)
     : zone_(Thread::Current()->zone()),
       precompiler_(precompiler),
+      buffer_(1024),
       stream_(stream),
       strings_(HashTables::New<StringTable>(1024)),
       entities_(HashTables::New<EntityTable>(1024)),
@@ -46,6 +47,11 @@
   Write(",");
   WriteStringTable();
   Write("}\n");
+
+  const intptr_t output_length = buffer_.length();
+  char* output = buffer_.Steal();
+  Dart::file_write_callback()(output, output_length, stream_);
+  free(output);
   Dart::file_close_callback()(stream_);
 
   strings_.Release();
diff --git a/runtime/vm/compiler/aot/precompiler_tracer.h b/runtime/vm/compiler/aot/precompiler_tracer.h
index b654457..3e315bd 100644
--- a/runtime/vm/compiler/aot/precompiler_tracer.h
+++ b/runtime/vm/compiler/aot/precompiler_tracer.h
@@ -119,8 +119,7 @@
   void Write(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) {
     va_list va;
     va_start(va, format);
-    const char* line = OS::VSCreate(zone_, format, va);
-    Dart::file_write_callback()(line, strlen(line), stream_);
+    buffer_.VPrintf(format, va);
     va_end(va);
   }
 
@@ -131,6 +130,7 @@
 
   Zone* zone_;
   Precompiler* precompiler_;
+  TextBuffer buffer_;
   void* stream_;
   StringTable strings_;
   EntityTable entities_;