LCOV - code coverage report
Current view: top level - toolkit/components/telemetry - KeyedStackCapturer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 69 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 8 0.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 "KeyedStackCapturer.h"
       8             : #include "nsPrintfCString.h"
       9             : #include "mozilla/StackWalk.h"
      10             : #include "ProcessedStack.h"
      11             : #include "jsapi.h"
      12             : 
      13             : namespace {
      14             : 
      15             : /** Defines the size of the keyed stack dictionary. */
      16             : const uint8_t kMaxKeyLength = 50;
      17             : 
      18             : /** The maximum number of captured stacks that we're keeping. */
      19             : const size_t kMaxCapturedStacksKept = 50;
      20             : 
      21             : /**
      22             :  * Checks if a single character of the key string is valid.
      23             :  *
      24             :  * @param aChar a character to validate.
      25             :  * @return True, if the char is valid, False - otherwise.
      26             :  */
      27             : bool
      28           0 : IsKeyCharValid(const char aChar)
      29             : {
      30           0 :   return (aChar >= 'A' && aChar <= 'Z')
      31           0 :       || (aChar >= 'a' && aChar <= 'z')
      32           0 :       || (aChar >= '0' && aChar <= '9')
      33           0 :       || aChar == '-';
      34             : }
      35             : 
      36             : /**
      37             :  * Checks if a given string is a valid telemetry key.
      38             :  *
      39             :  * @param aKey is the key string.
      40             :  * @return True, if the key is valid, False - otherwise.
      41             :  */
      42             : bool
      43           0 : IsKeyValid(const nsACString& aKey)
      44             : {
      45             :   // Check key length.
      46           0 :   if (aKey.Length() > kMaxKeyLength) {
      47           0 :     return false;
      48             :   }
      49             : 
      50             :   // Check key characters.
      51           0 :   const char* cur = aKey.BeginReading();
      52           0 :   const char* end = aKey.EndReading();
      53             : 
      54           0 :   for (; cur < end; ++cur) {
      55           0 :       if (!IsKeyCharValid(*cur)) {
      56           0 :         return false;
      57             :       }
      58             :   }
      59           0 :   return true;
      60             : }
      61             : 
      62             : } // anonymous namespace
      63             : 
      64             : namespace mozilla {
      65             : namespace Telemetry {
      66             : 
      67           0 : void KeyedStackCapturer::Capture(const nsACString& aKey) {
      68           0 :   MutexAutoLock captureStackMutex(mStackCapturerMutex);
      69             : 
      70             :   // Check if the key is ok.
      71           0 :   if (!IsKeyValid(aKey)) {
      72           0 :     NS_WARNING(nsPrintfCString(
      73             :       "Invalid key is used to capture stack in telemetry: '%s'",
      74             :       PromiseFlatCString(aKey).get()
      75           0 :     ).get());
      76           0 :     return;
      77             :   }
      78             : 
      79             :   // Trying to find and update the stack information.
      80           0 :   StackFrequencyInfo* info = mStackInfos.Get(aKey);
      81           0 :   if (info) {
      82             :     // We already recorded this stack before, only increase the count.
      83           0 :     info->mCount++;
      84           0 :     return;
      85             :   }
      86             : 
      87             :   // Check if we have room for new captures.
      88           0 :   if (mStackInfos.Count() >= kMaxCapturedStacksKept) {
      89             :     // Addressed by Bug 1316793.
      90           0 :     return;
      91             :   }
      92             : 
      93             :   // We haven't captured a stack for this key before, do it now.
      94             :   // Note that this does a stackwalk and is an expensive operation.
      95           0 :   std::vector<uintptr_t> rawStack;
      96           0 :   auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
      97             :     std::vector<uintptr_t>* stack =
      98           0 :       static_cast<std::vector<uintptr_t>*>(aClosure);
      99           0 :     stack->push_back(reinterpret_cast<uintptr_t>(aPC));
     100           0 :   };
     101           0 :   MozStackWalk(callback, /* skipFrames */ 0,
     102           0 :               /* maxFrames */ 0, reinterpret_cast<void*>(&rawStack), 0, nullptr);
     103           0 :   ProcessedStack stack = GetStackAndModules(rawStack);
     104             : 
     105             :   // Store the new stack info.
     106           0 :   size_t stackIndex = mStacks.AddStack(stack);
     107           0 :   mStackInfos.Put(aKey, new StackFrequencyInfo(1, stackIndex));
     108             : }
     109             : 
     110             : NS_IMETHODIMP
     111           0 : KeyedStackCapturer::ReflectCapturedStacks(JSContext *cx, JS::MutableHandle<JS::Value> ret)
     112             : {
     113           0 :   MutexAutoLock capturedStackMutex(mStackCapturerMutex);
     114             : 
     115             :   // this adds the memoryMap and stacks properties.
     116           0 :   JS::RootedObject fullReportObj(cx, CreateJSStackObject(cx, mStacks));
     117           0 :   if (!fullReportObj) {
     118           0 :     return NS_ERROR_FAILURE;
     119             :   }
     120             : 
     121           0 :   JS::RootedObject keysArray(cx, JS_NewArrayObject(cx, 0));
     122           0 :   if (!keysArray) {
     123           0 :     return NS_ERROR_FAILURE;
     124             :   }
     125             : 
     126           0 :   bool ok = JS_DefineProperty(cx, fullReportObj, "captures",
     127           0 :                               keysArray, JSPROP_ENUMERATE);
     128           0 :   if (!ok) {
     129           0 :     return NS_ERROR_FAILURE;
     130             :   }
     131             : 
     132           0 :   size_t keyIndex = 0;
     133           0 :   for (auto iter = mStackInfos.ConstIter(); !iter.Done(); iter.Next(), ++keyIndex) {
     134           0 :     const StackFrequencyInfo* info = iter.Data();
     135             : 
     136           0 :     JS::RootedObject infoArray(cx, JS_NewArrayObject(cx, 0));
     137           0 :     if (!keysArray) {
     138           0 :       return NS_ERROR_FAILURE;
     139             :     }
     140           0 :     JS::RootedString str(cx, JS_NewStringCopyZ(cx,
     141           0 :                          PromiseFlatCString(iter.Key()).get()));
     142           0 :     if (!str ||
     143           0 :         !JS_DefineElement(cx, infoArray, 0, str, JSPROP_ENUMERATE) ||
     144           0 :         !JS_DefineElement(cx, infoArray, 1, info->mIndex, JSPROP_ENUMERATE) ||
     145           0 :         !JS_DefineElement(cx, infoArray, 2, info->mCount, JSPROP_ENUMERATE) ||
     146           0 :         !JS_DefineElement(cx, keysArray, keyIndex, infoArray, JSPROP_ENUMERATE)) {
     147           0 :       return NS_ERROR_FAILURE;
     148             :     }
     149             :   }
     150             : 
     151           0 :   ret.setObject(*fullReportObj);
     152           0 :   return NS_OK;
     153             : }
     154             : 
     155             : void
     156           0 : KeyedStackCapturer::Clear()
     157             : {
     158           0 :   MutexAutoLock captureStackMutex(mStackCapturerMutex);
     159           0 :   mStackInfos.Clear();
     160           0 :   mStacks.Clear();
     161           0 : }
     162             : 
     163             : } // namespace Telemetry
     164             : } // namespace mozilla

Generated by: LCOV version 1.13