LCOV - code coverage report
Current view: top level - src/profiler - sampling-heap-profiler.h (source / functions) Hit Total Coverage
Test: app.info Lines: 23 23 100.0 %
Date: 2019-01-20 Functions: 9 10 90.0 %

          Line data    Source code
       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 <memory>
      11             : #include <unordered_map>
      12             : #include "include/v8-profiler.h"
      13             : #include "src/heap/heap.h"
      14             : #include "src/profiler/strings-storage.h"
      15             : 
      16             : namespace v8 {
      17             : 
      18             : namespace base {
      19             : class RandomNumberGenerator;
      20             : }
      21             : 
      22             : namespace internal {
      23             : 
      24             : class SamplingAllocationObserver;
      25             : 
      26         256 : class AllocationProfile : public v8::AllocationProfile {
      27             :  public:
      28          64 :   AllocationProfile() = default;
      29             : 
      30          73 :   v8::AllocationProfile::Node* GetRootNode() override {
      31          73 :     return nodes_.size() == 0 ? nullptr : &nodes_.front();
      32             :   }
      33             : 
      34          25 :   const std::vector<v8::AllocationProfile::Sample>& GetSamples() override {
      35          25 :     return samples_;
      36             :   }
      37             : 
      38             :  private:
      39             :   std::deque<v8::AllocationProfile::Node> nodes_;
      40             :   std::vector<v8::AllocationProfile::Sample> samples_;
      41             : 
      42             :   friend class SamplingHeapProfiler;
      43             : 
      44             :   DISALLOW_COPY_AND_ASSIGN(AllocationProfile);
      45             : };
      46             : 
      47             : class SamplingHeapProfiler {
      48             :  public:
      49         684 :   class AllocationNode {
      50             :    public:
      51             :     typedef uint64_t FunctionId;
      52             :     AllocationNode(AllocationNode* parent, const char* name, int script_id,
      53             :                    int start_position, uint32_t id)
      54             :         : parent_(parent),
      55             :           script_id_(script_id),
      56             :           script_position_(start_position),
      57             :           name_(name),
      58         342 :           id_(id) {}
      59             : 
      60             :     AllocationNode* FindChildNode(FunctionId id) {
      61             :       auto it = children_.find(id);
      62      156239 :       return it != children_.end() ? it->second.get() : nullptr;
      63             :     }
      64             : 
      65             :     AllocationNode* AddChildNode(FunctionId id,
      66             :                                  std::unique_ptr<AllocationNode> node) {
      67             :       return children_.emplace(id, std::move(node)).first->second.get();
      68             :     }
      69             : 
      70             :     static FunctionId function_id(int script_id, int start_position,
      71             :                                   const char* name) {
      72             :       // script_id == kNoScriptId case:
      73             :       //   Use function name pointer as an id. Names derived from VM state
      74             :       //   must not collide with the builtin names. The least significant bit
      75             :       //   of the id is set to 1.
      76      156243 :       if (script_id == v8::UnboundScript::kNoScriptId) {
      77       48477 :         return reinterpret_cast<intptr_t>(name) | 1;
      78             :       }
      79             :       // script_id != kNoScriptId case:
      80             :       //   Use script_id, start_position pair to uniquelly identify the node.
      81             :       //   The least significant bit of the id is set to 0.
      82             :       DCHECK(static_cast<unsigned>(start_position) < (1u << 31));
      83      107766 :       return (static_cast<uint64_t>(script_id) << 32) + (start_position << 1);
      84             :     }
      85             : 
      86             :    private:
      87             :     // TODO(alph): make use of unordered_map's here. Pay attention to
      88             :     // iterator invalidation during TranslateAllocationNode.
      89             :     std::map<size_t, unsigned int> allocations_;
      90             :     std::map<FunctionId, std::unique_ptr<AllocationNode>> children_;
      91             :     AllocationNode* const parent_;
      92             :     const int script_id_;
      93             :     const int script_position_;
      94             :     const char* const name_;
      95             :     uint32_t id_;
      96             :     bool pinned_ = false;
      97             : 
      98             :     friend class SamplingHeapProfiler;
      99             : 
     100             :     DISALLOW_COPY_AND_ASSIGN(AllocationNode);
     101             :   };
     102             : 
     103             :   struct Sample {
     104             :     Sample(size_t size_, AllocationNode* owner_, Local<Value> local_,
     105             :            SamplingHeapProfiler* profiler_, uint64_t sample_id)
     106             :         : size(size_),
     107             :           owner(owner_),
     108             :           global(Global<Value>(
     109             :               reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_)),
     110             :           profiler(profiler_),
     111      209566 :           sample_id(sample_id) {}
     112      209566 :     ~Sample() { global.Reset(); }
     113             :     const size_t size;
     114             :     AllocationNode* const owner;
     115             :     Global<Value> global;
     116             :     SamplingHeapProfiler* const profiler;
     117             :     const uint64_t sample_id;
     118             : 
     119             :    private:
     120             :     DISALLOW_COPY_AND_ASSIGN(Sample);
     121             :   };
     122             : 
     123             :   SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate,
     124             :                        int stack_depth, v8::HeapProfiler::SamplingFlags flags);
     125             :   ~SamplingHeapProfiler();
     126             : 
     127             :   v8::AllocationProfile* GetAllocationProfile();
     128             :   StringsStorage* names() const { return names_; }
     129             : 
     130             :  private:
     131             :   void SampleObject(Address soon_object, size_t size);
     132             : 
     133             :   const std::vector<v8::AllocationProfile::Sample> BuildSamples() const;
     134             : 
     135             :   AllocationNode* FindOrAddChildNode(AllocationNode* parent, const char* name,
     136             :                                      int script_id, int start_position);
     137             :   static void OnWeakCallback(const WeakCallbackInfo<Sample>& data);
     138             : 
     139         342 :   uint32_t next_node_id() { return ++last_node_id_; }
     140      104783 :   uint64_t next_sample_id() { return ++last_sample_id_; }
     141             : 
     142             :   // Methods that construct v8::AllocationProfile.
     143             : 
     144             :   // Translates the provided AllocationNode *node* returning an equivalent
     145             :   // AllocationProfile::Node. The newly created AllocationProfile::Node is added
     146             :   // to the provided AllocationProfile *profile*. Line numbers, column numbers,
     147             :   // and script names are resolved using *scripts* which maps all currently
     148             :   // loaded scripts keyed by their script id.
     149             :   v8::AllocationProfile::Node* TranslateAllocationNode(
     150             :       AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
     151             :       const std::map<int, Handle<Script>>& scripts);
     152             :   v8::AllocationProfile::Allocation ScaleSample(size_t size,
     153             :                                                 unsigned int count) const;
     154             :   AllocationNode* AddStack();
     155             : 
     156             :   Isolate* const isolate_;
     157             :   Heap* const heap_;
     158             :   uint64_t last_sample_id_ = 0;
     159             :   uint32_t last_node_id_ = 0;
     160             :   std::unique_ptr<SamplingAllocationObserver> new_space_observer_;
     161             :   std::unique_ptr<SamplingAllocationObserver> other_spaces_observer_;
     162             :   StringsStorage* const names_;
     163             :   AllocationNode profile_root_;
     164             :   std::unordered_map<Sample*, std::unique_ptr<Sample>> samples_;
     165             :   const int stack_depth_;
     166             :   const uint64_t rate_;
     167             :   v8::HeapProfiler::SamplingFlags flags_;
     168             : 
     169             :   friend class SamplingAllocationObserver;
     170             : 
     171             :   DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler);
     172             : };
     173             : 
     174             : class SamplingAllocationObserver : public AllocationObserver {
     175             :  public:
     176             :   SamplingAllocationObserver(Heap* heap, intptr_t step_size, uint64_t rate,
     177             :                              SamplingHeapProfiler* profiler,
     178             :                              base::RandomNumberGenerator* random)
     179             :       : AllocationObserver(step_size),
     180             :         profiler_(profiler),
     181             :         heap_(heap),
     182             :         random_(random),
     183         118 :         rate_(rate) {}
     184         236 :   ~SamplingAllocationObserver() override = default;
     185             : 
     186             :  protected:
     187      104788 :   void Step(int bytes_allocated, Address soon_object, size_t size) override {
     188             :     USE(heap_);
     189             :     DCHECK(heap_->gc_state() == Heap::NOT_IN_GC);
     190      104788 :     if (soon_object) {
     191             :       // TODO(ofrobots): it would be better to sample the next object rather
     192             :       // than skipping this sample epoch if soon_object happens to be null.
     193      104783 :       profiler_->SampleObject(soon_object, size);
     194             :     }
     195      104788 :   }
     196             : 
     197      104788 :   intptr_t GetNextStepSize() override { return GetNextSampleInterval(rate_); }
     198             : 
     199             :  private:
     200             :   intptr_t GetNextSampleInterval(uint64_t rate);
     201             :   SamplingHeapProfiler* const profiler_;
     202             :   Heap* const heap_;
     203             :   base::RandomNumberGenerator* const random_;
     204             :   uint64_t const rate_;
     205             : };
     206             : 
     207             : }  // namespace internal
     208             : }  // namespace v8
     209             : 
     210             : #endif  // V8_PROFILER_SAMPLING_HEAP_PROFILER_H_

Generated by: LCOV version 1.10