Index: src/profiler/heap-profiler.h |
diff --git a/src/profiler/heap-profiler.h b/src/profiler/heap-profiler.h |
index 9a04e83af4b0ca2f3725f8a10fcdabd322ba41b7..f43832c68cb05704744cfdc43810c50de9533f6e 100644 |
--- a/src/profiler/heap-profiler.h |
+++ b/src/profiler/heap-profiler.h |
@@ -5,6 +5,7 @@ |
#ifndef V8_PROFILER_HEAP_PROFILER_H_ |
#define V8_PROFILER_HEAP_PROFILER_H_ |
+#include "include/v8-util.h" |
#include "src/base/smart-pointers.h" |
#include "src/isolate.h" |
#include "src/list.h" |
@@ -16,6 +17,7 @@ namespace internal { |
class AllocationTracker; |
class HeapObjectsMap; |
class HeapSnapshot; |
+class SamplingHeapProfiler; |
class StringsStorage; |
class HeapProfiler { |
@@ -29,6 +31,10 @@ class HeapProfiler { |
v8::ActivityControl* control, |
v8::HeapProfiler::ObjectNameResolver* resolver); |
+ bool StartSamplingHeapProfiler(uint64_t sample_interval, int stack_depth); |
+ void StopSamplingHeapProfiler(); |
+ void GetHeapSample(OutputStream* stream); |
+ |
void StartHeapObjectsTracking(bool track_allocations); |
void StopHeapObjectsTracking(); |
AllocationTracker* allocation_tracker() const { |
@@ -79,6 +85,103 @@ class HeapProfiler { |
base::SmartPointer<AllocationTracker> allocation_tracker_; |
bool is_tracking_object_moves_; |
base::Mutex profiler_mutex_; |
+ base::SmartPointer<SamplingHeapProfiler> sampling_heap_profiler_; |
+}; |
+ |
+template <int bytes> |
+struct MaxDecimalDigitsIn; |
+template <> |
+struct MaxDecimalDigitsIn<4> { |
+ static const int kSigned = 11; |
+ static const int kUnsigned = 10; |
+}; |
+template <> |
+struct MaxDecimalDigitsIn<8> { |
+ static const int kSigned = 20; |
+ static const int kUnsigned = 20; |
+}; |
+ |
+class OutputStreamWriter { |
+ public: |
+ explicit OutputStreamWriter(v8::OutputStream* stream) |
+ : stream_(stream), |
+ chunk_size_(stream->GetChunkSize()), |
+ chunk_(chunk_size_), |
+ chunk_pos_(0), |
+ aborted_(false) { |
+ DCHECK(chunk_size_ > 0); |
+ } |
+ bool aborted() { return aborted_; } |
+ void AddCharacter(char c) { |
+ DCHECK(c != '\0'); |
+ DCHECK(chunk_pos_ < chunk_size_); |
+ chunk_[chunk_pos_++] = c; |
+ MaybeWriteChunk(); |
+ } |
+ void AddString(const char* s) { AddSubstring(s, StrLength(s)); } |
+ void AddSubstring(const char* s, int n) { |
+ if (n <= 0) return; |
+ DCHECK(static_cast<size_t>(n) <= strlen(s)); |
+ const char* s_end = s + n; |
+ while (s < s_end) { |
+ int s_chunk_size = |
+ Min(chunk_size_ - chunk_pos_, static_cast<int>(s_end - s)); |
+ DCHECK(s_chunk_size > 0); |
+ MemCopy(chunk_.start() + chunk_pos_, s, s_chunk_size); |
+ s += s_chunk_size; |
+ chunk_pos_ += s_chunk_size; |
+ MaybeWriteChunk(); |
+ } |
+ } |
+ void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); } |
+ void Finalize() { |
+ if (aborted_) return; |
+ DCHECK(chunk_pos_ < chunk_size_); |
+ if (chunk_pos_ != 0) { |
+ WriteChunk(); |
+ } |
+ stream_->EndOfStream(); |
+ } |
+ |
+ private: |
+ template <typename T> |
+ void AddNumberImpl(T n, const char* format) { |
+ // Buffer for the longest value plus trailing \0 |
+ static const int kMaxNumberSize = |
+ MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1; |
+ if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) { |
+ int result = |
+ SNPrintF(chunk_.SubVector(chunk_pos_, chunk_size_), format, n); |
+ DCHECK(result != -1); |
+ chunk_pos_ += result; |
+ MaybeWriteChunk(); |
+ } else { |
+ EmbeddedVector<char, kMaxNumberSize> buffer; |
+ int result = SNPrintF(buffer, format, n); |
+ USE(result); |
+ DCHECK(result != -1); |
+ AddString(buffer.start()); |
+ } |
+ } |
+ void MaybeWriteChunk() { |
+ DCHECK(chunk_pos_ <= chunk_size_); |
+ if (chunk_pos_ == chunk_size_) { |
+ WriteChunk(); |
+ } |
+ } |
+ void WriteChunk() { |
+ if (aborted_) return; |
+ if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) == |
+ v8::OutputStream::kAbort) |
+ aborted_ = true; |
+ chunk_pos_ = 0; |
+ } |
+ |
+ v8::OutputStream* stream_; |
+ int chunk_size_; |
+ ScopedVector<char> chunk_; |
+ int chunk_pos_; |
+ bool aborted_; |
}; |
} // namespace internal |