LCOV - code coverage report
Current view: top level - toolkit/components/telemetry - CombinedStacks.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 6 101 5.9 %
Date: 2017-07-14 16:53:18 Functions: 2 10 20.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CombinedStacks.h"
       8             : #include "HangAnnotations.h"
       9             : #include "mozilla/HangAnnotations.h"
      10             : #include "jsapi.h"
      11             : 
      12             : namespace mozilla {
      13             : namespace Telemetry {
      14             : 
      15             : // The maximum number of chrome hangs stacks that we're keeping.
      16             : const size_t kMaxChromeStacksKept = 50;
      17             : 
      18           9 : CombinedStacks::CombinedStacks()
      19           9 :   : CombinedStacks(kMaxChromeStacksKept)
      20           9 : {}
      21             : 
      22           9 : CombinedStacks::CombinedStacks(size_t aMaxStacksCount)
      23             :   : mNextIndex(0)
      24           9 :   , mMaxStacksCount(aMaxStacksCount)
      25           9 : {}
      26             : 
      27             : size_t
      28           0 : CombinedStacks::GetModuleCount() const {
      29           0 :   return mModules.size();
      30             : }
      31             : 
      32             : const Telemetry::ProcessedStack::Module&
      33           0 : CombinedStacks::GetModule(unsigned aIndex) const {
      34           0 :   return mModules[aIndex];
      35             : }
      36             : 
      37             : size_t
      38           0 : CombinedStacks::AddStack(const Telemetry::ProcessedStack& aStack) {
      39             :   // Advance the indices of the circular queue holding the stacks.
      40           0 :   size_t index = mNextIndex++ % mMaxStacksCount;
      41             :   // Grow the vector up to the maximum size, if needed.
      42           0 :   if (mStacks.size() < mMaxStacksCount) {
      43           0 :     mStacks.resize(mStacks.size() + 1);
      44             :   }
      45             :   // Get a reference to the location holding the new stack.
      46           0 :   CombinedStacks::Stack& adjustedStack = mStacks[index];
      47             :   // If we're using an old stack to hold aStack, clear it.
      48           0 :   adjustedStack.clear();
      49             : 
      50           0 :   size_t stackSize = aStack.GetStackSize();
      51           0 :   for (size_t i = 0; i < stackSize; ++i) {
      52           0 :     const Telemetry::ProcessedStack::Frame& frame = aStack.GetFrame(i);
      53             :     uint16_t modIndex;
      54           0 :     if (frame.mModIndex == std::numeric_limits<uint16_t>::max()) {
      55           0 :       modIndex = frame.mModIndex;
      56             :     } else {
      57             :       const Telemetry::ProcessedStack::Module& module =
      58           0 :         aStack.GetModule(frame.mModIndex);
      59             :       std::vector<Telemetry::ProcessedStack::Module>::iterator modIterator =
      60           0 :         std::find(mModules.begin(), mModules.end(), module);
      61           0 :       if (modIterator == mModules.end()) {
      62           0 :         mModules.push_back(module);
      63           0 :         modIndex = mModules.size() - 1;
      64             :       } else {
      65           0 :         modIndex = modIterator - mModules.begin();
      66             :       }
      67             :     }
      68           0 :     Telemetry::ProcessedStack::Frame adjustedFrame = { frame.mOffset, modIndex };
      69           0 :     adjustedStack.push_back(adjustedFrame);
      70             :   }
      71           0 :   return index;
      72             : }
      73             : 
      74             : const CombinedStacks::Stack&
      75           0 : CombinedStacks::GetStack(unsigned aIndex) const {
      76           0 :   return mStacks[aIndex];
      77             : }
      78             : 
      79             : size_t
      80           0 : CombinedStacks::GetStackCount() const {
      81           0 :   return mStacks.size();
      82             : }
      83             : 
      84             : size_t
      85           0 : CombinedStacks::SizeOfExcludingThis() const {
      86             :   // This is a crude approximation. We would like to do something like
      87             :   // aMallocSizeOf(&mModules[0]), but on linux aMallocSizeOf will call
      88             :   // malloc_usable_size which is only safe on the pointers returned by malloc.
      89             :   // While it works on current libstdc++, it is better to be safe and not assume
      90             :   // that &vec[0] points to one. We could use a custom allocator, but
      91             :   // it doesn't seem worth it.
      92           0 :   size_t n = 0;
      93           0 :   n += mModules.capacity() * sizeof(Telemetry::ProcessedStack::Module);
      94           0 :   n += mStacks.capacity() * sizeof(Stack);
      95           0 :   for (const auto & s : mStacks) {
      96           0 :     n += s.capacity() * sizeof(Telemetry::ProcessedStack::Frame);
      97             :   }
      98           0 :   return n;
      99             : }
     100             : 
     101             : #if defined(MOZ_GECKO_PROFILER)
     102             : void
     103           0 : CombinedStacks::Clear() {
     104           0 :   mNextIndex = 0;
     105           0 :   mStacks.clear();
     106           0 :   mModules.clear();
     107           0 : }
     108             : #endif
     109             : 
     110             : JSObject *
     111           0 : CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) {
     112           0 :   JS::Rooted<JSObject*> ret(cx, JS_NewPlainObject(cx));
     113           0 :   if (!ret) {
     114           0 :     return nullptr;
     115             :   }
     116             : 
     117           0 :   JS::Rooted<JSObject*> moduleArray(cx, JS_NewArrayObject(cx, 0));
     118           0 :   if (!moduleArray) {
     119           0 :     return nullptr;
     120             :   }
     121           0 :   bool ok = JS_DefineProperty(cx, ret, "memoryMap", moduleArray,
     122           0 :                               JSPROP_ENUMERATE);
     123           0 :   if (!ok) {
     124           0 :     return nullptr;
     125             :   }
     126             : 
     127           0 :   const size_t moduleCount = stacks.GetModuleCount();
     128           0 :   for (size_t moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
     129             :     // Current module
     130             :     const Telemetry::ProcessedStack::Module& module =
     131           0 :       stacks.GetModule(moduleIndex);
     132             : 
     133           0 :     JS::Rooted<JSObject*> moduleInfoArray(cx, JS_NewArrayObject(cx, 0));
     134           0 :     if (!moduleInfoArray) {
     135           0 :       return nullptr;
     136             :     }
     137           0 :     if (!JS_DefineElement(cx, moduleArray, moduleIndex, moduleInfoArray,
     138             :                           JSPROP_ENUMERATE)) {
     139           0 :       return nullptr;
     140             :     }
     141             : 
     142           0 :     unsigned index = 0;
     143             : 
     144             :     // Module name
     145           0 :     JS::Rooted<JSString*> str(cx, JS_NewUCStringCopyZ(cx, module.mName.get()));
     146           0 :     if (!str || !JS_DefineElement(cx, moduleInfoArray, index++, str, JSPROP_ENUMERATE)) {
     147           0 :       return nullptr;
     148             :     }
     149             : 
     150             :     // Module breakpad identifier
     151           0 :     JS::Rooted<JSString*> id(cx, JS_NewStringCopyZ(cx, module.mBreakpadId.c_str()));
     152           0 :     if (!id || !JS_DefineElement(cx, moduleInfoArray, index++, id, JSPROP_ENUMERATE)) {
     153           0 :       return nullptr;
     154             :     }
     155             :   }
     156             : 
     157           0 :   JS::Rooted<JSObject*> reportArray(cx, JS_NewArrayObject(cx, 0));
     158           0 :   if (!reportArray) {
     159           0 :     return nullptr;
     160             :   }
     161           0 :   ok = JS_DefineProperty(cx, ret, "stacks", reportArray, JSPROP_ENUMERATE);
     162           0 :   if (!ok) {
     163           0 :     return nullptr;
     164             :   }
     165             : 
     166           0 :   const size_t length = stacks.GetStackCount();
     167           0 :   for (size_t i = 0; i < length; ++i) {
     168             :     // Represent call stack PCs as (module index, offset) pairs.
     169           0 :     JS::Rooted<JSObject*> pcArray(cx, JS_NewArrayObject(cx, 0));
     170           0 :     if (!pcArray) {
     171           0 :       return nullptr;
     172             :     }
     173             : 
     174           0 :     if (!JS_DefineElement(cx, reportArray, i, pcArray, JSPROP_ENUMERATE)) {
     175           0 :       return nullptr;
     176             :     }
     177             : 
     178           0 :     const CombinedStacks::Stack& stack = stacks.GetStack(i);
     179           0 :     const uint32_t pcCount = stack.size();
     180           0 :     for (size_t pcIndex = 0; pcIndex < pcCount; ++pcIndex) {
     181           0 :       const Telemetry::ProcessedStack::Frame& frame = stack[pcIndex];
     182           0 :       JS::Rooted<JSObject*> framePair(cx, JS_NewArrayObject(cx, 0));
     183           0 :       if (!framePair) {
     184           0 :         return nullptr;
     185             :       }
     186           0 :       int modIndex = (std::numeric_limits<uint16_t>::max() == frame.mModIndex) ?
     187           0 :         -1 : frame.mModIndex;
     188           0 :       if (!JS_DefineElement(cx, framePair, 0, modIndex, JSPROP_ENUMERATE)) {
     189           0 :         return nullptr;
     190             :       }
     191           0 :       if (!JS_DefineElement(cx, framePair, 1, static_cast<double>(frame.mOffset),
     192             :                             JSPROP_ENUMERATE)) {
     193           0 :         return nullptr;
     194             :       }
     195           0 :       if (!JS_DefineElement(cx, pcArray, pcIndex, framePair, JSPROP_ENUMERATE)) {
     196           0 :         return nullptr;
     197             :       }
     198             :     }
     199             :   }
     200             : 
     201           0 :   return ret;
     202             : }
     203             : 
     204             : } // namespace Telemetry
     205             : } // namespace mozilla

Generated by: LCOV version 1.13