• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
6 #define V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
7 
8 #include <deque>
9 #include <map>
10 #include <set>
11 #include "include/v8-profiler.h"
12 #include "src/heap/heap.h"
13 #include "src/profiler/strings-storage.h"
14 
15 namespace v8 {
16 
17 namespace base {
18 class RandomNumberGenerator;
19 }
20 
21 namespace internal {
22 
23 class SamplingAllocationObserver;
24 
25 class AllocationProfile : public v8::AllocationProfile {
26  public:
AllocationProfile()27   AllocationProfile() : nodes_() {}
28 
GetRootNode()29   v8::AllocationProfile::Node* GetRootNode() override {
30     return nodes_.size() == 0 ? nullptr : &nodes_.front();
31   }
32 
nodes()33   std::deque<v8::AllocationProfile::Node>& nodes() { return nodes_; }
34 
35  private:
36   std::deque<v8::AllocationProfile::Node> nodes_;
37 
38   DISALLOW_COPY_AND_ASSIGN(AllocationProfile);
39 };
40 
41 class SamplingHeapProfiler {
42  public:
43   SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate,
44                        int stack_depth, v8::HeapProfiler::SamplingFlags flags);
45   ~SamplingHeapProfiler();
46 
47   v8::AllocationProfile* GetAllocationProfile();
48 
names()49   StringsStorage* names() const { return names_; }
50 
51   class AllocationNode;
52 
53   struct Sample {
54    public:
SampleSample55     Sample(size_t size_, AllocationNode* owner_, Local<Value> local_,
56            SamplingHeapProfiler* profiler_)
57         : size(size_),
58           owner(owner_),
59           global(Global<Value>(
60               reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_)),
61           profiler(profiler_) {}
~SampleSample62     ~Sample() { global.Reset(); }
63     const size_t size;
64     AllocationNode* const owner;
65     Global<Value> global;
66     SamplingHeapProfiler* const profiler;
67 
68    private:
69     DISALLOW_COPY_AND_ASSIGN(Sample);
70   };
71 
72   class AllocationNode {
73    public:
AllocationNode(AllocationNode * parent,const char * name,int script_id,int start_position)74     AllocationNode(AllocationNode* parent, const char* name, int script_id,
75                    int start_position)
76         : parent_(parent),
77           script_id_(script_id),
78           script_position_(start_position),
79           name_(name),
80           pinned_(false) {}
~AllocationNode()81     ~AllocationNode() {
82       for (auto child : children_) {
83         delete child.second;
84       }
85     }
86 
87    private:
88     typedef uint64_t FunctionId;
function_id(int script_id,int start_position,const char * name)89     static FunctionId function_id(int script_id, int start_position,
90                                   const char* name) {
91       // script_id == kNoScriptId case:
92       //   Use function name pointer as an id. Names derived from VM state
93       //   must not collide with the builtin names. The least significant bit
94       //   of the id is set to 1.
95       if (script_id == v8::UnboundScript::kNoScriptId) {
96         return reinterpret_cast<intptr_t>(name) | 1;
97       }
98       // script_id != kNoScriptId case:
99       //   Use script_id, start_position pair to uniquelly identify the node.
100       //   The least significant bit of the id is set to 0.
101       DCHECK(static_cast<unsigned>(start_position) < (1u << 31));
102       return (static_cast<uint64_t>(script_id) << 32) + (start_position << 1);
103     }
104     AllocationNode* FindOrAddChildNode(const char* name, int script_id,
105                                        int start_position);
106     // TODO(alph): make use of unordered_map's here. Pay attention to
107     // iterator invalidation during TranslateAllocationNode.
108     std::map<size_t, unsigned int> allocations_;
109     std::map<FunctionId, AllocationNode*> children_;
110     AllocationNode* const parent_;
111     const int script_id_;
112     const int script_position_;
113     const char* const name_;
114     bool pinned_;
115 
116     friend class SamplingHeapProfiler;
117 
118     DISALLOW_COPY_AND_ASSIGN(AllocationNode);
119   };
120 
121  private:
heap()122   Heap* heap() const { return heap_; }
123 
124   void SampleObject(Address soon_object, size_t size);
125 
126   static void OnWeakCallback(const WeakCallbackInfo<Sample>& data);
127 
128   // Methods that construct v8::AllocationProfile.
129 
130   // Translates the provided AllocationNode *node* returning an equivalent
131   // AllocationProfile::Node. The newly created AllocationProfile::Node is added
132   // to the provided AllocationProfile *profile*. Line numbers, column numbers,
133   // and script names are resolved using *scripts* which maps all currently
134   // loaded scripts keyed by their script id.
135   v8::AllocationProfile::Node* TranslateAllocationNode(
136       AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
137       const std::map<int, Handle<Script>>& scripts);
138   v8::AllocationProfile::Allocation ScaleSample(size_t size,
139                                                 unsigned int count);
140   AllocationNode* AddStack();
141 
142   Isolate* const isolate_;
143   Heap* const heap_;
144   base::SmartPointer<SamplingAllocationObserver> new_space_observer_;
145   base::SmartPointer<SamplingAllocationObserver> other_spaces_observer_;
146   StringsStorage* const names_;
147   AllocationNode profile_root_;
148   std::set<Sample*> samples_;
149   const int stack_depth_;
150   const uint64_t rate_;
151   v8::HeapProfiler::SamplingFlags flags_;
152 
153   friend class SamplingAllocationObserver;
154 };
155 
156 class SamplingAllocationObserver : public AllocationObserver {
157  public:
SamplingAllocationObserver(Heap * heap,intptr_t step_size,uint64_t rate,SamplingHeapProfiler * profiler,base::RandomNumberGenerator * random)158   SamplingAllocationObserver(Heap* heap, intptr_t step_size, uint64_t rate,
159                              SamplingHeapProfiler* profiler,
160                              base::RandomNumberGenerator* random)
161       : AllocationObserver(step_size),
162         profiler_(profiler),
163         heap_(heap),
164         random_(random),
165         rate_(rate) {}
~SamplingAllocationObserver()166   virtual ~SamplingAllocationObserver() {}
167 
168  protected:
Step(int bytes_allocated,Address soon_object,size_t size)169   void Step(int bytes_allocated, Address soon_object, size_t size) override {
170     USE(heap_);
171     DCHECK(heap_->gc_state() == Heap::NOT_IN_GC);
172     DCHECK(soon_object);
173     profiler_->SampleObject(soon_object, size);
174   }
175 
GetNextStepSize()176   intptr_t GetNextStepSize() override { return GetNextSampleInterval(rate_); }
177 
178  private:
179   intptr_t GetNextSampleInterval(uint64_t rate);
180   SamplingHeapProfiler* const profiler_;
181   Heap* const heap_;
182   base::RandomNumberGenerator* const random_;
183   uint64_t const rate_;
184 };
185 
186 }  // namespace internal
187 }  // namespace v8
188 
189 #endif  // V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
190