LCOV - code coverage report
Current view: top level - tools/profiler/core - ProfileBufferEntry.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 70 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 48 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; 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             : #ifndef ProfileBufferEntry_h
       8             : #define ProfileBufferEntry_h
       9             : 
      10             : #include <ostream>
      11             : #include "GeckoProfiler.h"
      12             : #include "platform.h"
      13             : #include "ProfileJSONWriter.h"
      14             : #include "ProfilerBacktrace.h"
      15             : #include "mozilla/RefPtr.h"
      16             : #include <string>
      17             : #include <map>
      18             : #include "js/ProfilingFrameIterator.h"
      19             : #include "js/TrackedOptimizationInfo.h"
      20             : #include "nsHashKeys.h"
      21             : #include "nsDataHashtable.h"
      22             : #include "mozilla/Maybe.h"
      23             : #include "mozilla/Vector.h"
      24             : #include "gtest/MozGtestFriend.h"
      25             : #include "mozilla/HashFunctions.h"
      26             : #include "mozilla/UniquePtr.h"
      27             : 
      28             : class ProfilerMarker;
      29             : 
      30             : #define FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(macro) \
      31             :   macro(Category,              int) \
      32             :   macro(Label,                 const char*) \
      33             :   macro(DynamicStringFragment, char*) /* char[kNumChars], really */ \
      34             :   macro(JitReturnAddr,         void*) \
      35             :   macro(LineNumber,            int) \
      36             :   macro(NativeLeafAddr,        void*) \
      37             :   macro(Marker,                ProfilerMarker*) \
      38             :   macro(ResidentMemory,        double) \
      39             :   macro(Responsiveness,        double) \
      40             :   macro(ThreadId,              int) \
      41             :   macro(Time,                  double) \
      42             :   macro(UnsharedMemory,        double)
      43             : 
      44             : // NB: Packing this structure has been shown to cause SIGBUS issues on ARM.
      45             : #if !defined(GP_ARCH_arm)
      46             : #pragma pack(push, 1)
      47             : #endif
      48             : 
      49             : class ProfileBufferEntry
      50             : {
      51             : public:
      52             :   enum class Kind : uint8_t {
      53             :     INVALID = 0,
      54             :     #define KIND(k, t) k,
      55             :     FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(KIND)
      56             :     #undef KIND
      57             :     LIMIT
      58             :   };
      59             : 
      60             :   ProfileBufferEntry();
      61             : 
      62             :   // This is equal to sizeof(double), which is the largest non-char variant in
      63             :   // |u|.
      64             :   static const size_t kNumChars = 8;
      65             : 
      66             : private:
      67             :   // aString must be a static string.
      68             :   ProfileBufferEntry(Kind aKind, const char *aString);
      69             :   ProfileBufferEntry(Kind aKind, char aChars[kNumChars]);
      70             :   ProfileBufferEntry(Kind aKind, void *aPtr);
      71             :   ProfileBufferEntry(Kind aKind, ProfilerMarker *aMarker);
      72             :   ProfileBufferEntry(Kind aKind, double aDouble);
      73             :   ProfileBufferEntry(Kind aKind, int aInt);
      74             : 
      75             : public:
      76             :   #define CTOR(k, t) \
      77             :     static ProfileBufferEntry k(t aVal) { \
      78             :       return ProfileBufferEntry(Kind::k, aVal); \
      79             :     }
      80           0 :   FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(CTOR)
      81             :   #undef CTOR
      82             : 
      83           0 :   Kind GetKind() const { return mKind; }
      84             : 
      85             :   #define IS_KIND(k, t) bool Is##k() const { return mKind == Kind::k; }
      86           0 :   FOR_EACH_PROFILE_BUFFER_ENTRY_KIND(IS_KIND)
      87             :   #undef IS_KIND
      88             : 
      89             : private:
      90             :   FRIEND_TEST(ThreadProfile, InsertOneEntry);
      91             :   FRIEND_TEST(ThreadProfile, InsertOneEntryWithTinyBuffer);
      92             :   FRIEND_TEST(ThreadProfile, InsertEntriesNoWrap);
      93             :   FRIEND_TEST(ThreadProfile, InsertEntriesWrap);
      94             :   FRIEND_TEST(ThreadProfile, MemoryMeasure);
      95             :   friend class ProfileBuffer;
      96             : 
      97             :   Kind mKind;
      98             :   union {
      99             :     const char*     mString;
     100             :     char            mChars[kNumChars];
     101             :     void*           mPtr;
     102             :     ProfilerMarker* mMarker;
     103             :     double          mDouble;
     104             :     int             mInt;
     105             :   } u;
     106             : };
     107             : 
     108             : #if !defined(GP_ARCH_arm)
     109             : // Packed layout: 1 byte for the tag + 8 bytes for the value.
     110             : static_assert(sizeof(ProfileBufferEntry) == 9, "bad ProfileBufferEntry size");
     111             : #pragma pack(pop)
     112             : #endif
     113             : 
     114           0 : class UniqueJSONStrings
     115             : {
     116             : public:
     117           0 :   UniqueJSONStrings() {
     118           0 :     mStringTableWriter.StartBareList();
     119           0 :   }
     120             : 
     121           0 :   void SpliceStringTableElements(SpliceableJSONWriter& aWriter) {
     122           0 :     aWriter.TakeAndSplice(mStringTableWriter.WriteFunc());
     123           0 :   }
     124             : 
     125           0 :   void WriteProperty(mozilla::JSONWriter& aWriter, const char* aName, const char* aStr) {
     126           0 :     aWriter.IntProperty(aName, GetOrAddIndex(aStr));
     127           0 :   }
     128             : 
     129           0 :   void WriteElement(mozilla::JSONWriter& aWriter, const char* aStr) {
     130           0 :     aWriter.IntElement(GetOrAddIndex(aStr));
     131           0 :   }
     132             : 
     133             :   uint32_t GetOrAddIndex(const char* aStr);
     134             : 
     135             :   struct StringKey {
     136             : 
     137           0 :     explicit StringKey(const char* aStr)
     138           0 :      : mStr(strdup(aStr))
     139             :     {
     140           0 :       mHash = mozilla::HashString(mStr);
     141           0 :     }
     142             : 
     143           0 :     StringKey(const StringKey& aOther)
     144           0 :       : mStr(strdup(aOther.mStr))
     145             :     {
     146           0 :       mHash = aOther.mHash;
     147           0 :     }
     148             : 
     149           0 :     ~StringKey() {
     150           0 :       free(mStr);
     151           0 :     }
     152             : 
     153             :     uint32_t Hash() const;
     154             :     bool operator==(const StringKey& aOther) const {
     155             :       return strcmp(mStr, aOther.mStr) == 0;
     156             :     }
     157           0 :     bool operator<(const StringKey& aOther) const {
     158           0 :       return mHash < aOther.mHash;
     159             :     }
     160             : 
     161             :   private:
     162             :     uint32_t mHash;
     163             :     char* mStr;
     164             :   };
     165             : private:
     166             :   SpliceableChunkedJSONWriter mStringTableWriter;
     167             :   std::map<StringKey, uint32_t> mStringToIndexMap;
     168             : };
     169             : 
     170           0 : class UniqueStacks
     171             : {
     172             : public:
     173           0 :   struct FrameKey {
     174             :     // This cannot be a std::string, as it is not memmove compatible, which
     175             :     // is used by nsHashTable
     176             :     nsCString mLocation;
     177             :     mozilla::Maybe<unsigned> mLine;
     178             :     mozilla::Maybe<unsigned> mCategory;
     179             :     mozilla::Maybe<void*> mJITAddress;
     180             :     mozilla::Maybe<uint32_t> mJITDepth;
     181             : 
     182           0 :     explicit FrameKey(const char* aLocation)
     183           0 :      : mLocation(aLocation)
     184             :     {
     185           0 :       mHash = Hash();
     186           0 :     }
     187             : 
     188           0 :     FrameKey(const FrameKey& aToCopy)
     189           0 :      : mLocation(aToCopy.mLocation)
     190             :      , mLine(aToCopy.mLine)
     191             :      , mCategory(aToCopy.mCategory)
     192             :      , mJITAddress(aToCopy.mJITAddress)
     193           0 :      , mJITDepth(aToCopy.mJITDepth)
     194             :     {
     195           0 :       mHash = Hash();
     196           0 :     }
     197             : 
     198           0 :     FrameKey(void* aJITAddress, uint32_t aJITDepth)
     199           0 :      : mJITAddress(mozilla::Some(aJITAddress))
     200           0 :      , mJITDepth(mozilla::Some(aJITDepth))
     201             :     {
     202           0 :       mHash = Hash();
     203           0 :     }
     204             : 
     205             :     uint32_t Hash() const;
     206             :     bool operator==(const FrameKey& aOther) const;
     207             :     bool operator<(const FrameKey& aOther) const {
     208             :       return mHash < aOther.mHash;
     209             :     }
     210             : 
     211             :   private:
     212             :     uint32_t mHash;
     213             :   };
     214             : 
     215             :   // A FrameKey that holds a scoped reference to a JIT FrameHandle.
     216           0 :   struct MOZ_STACK_CLASS OnStackFrameKey : public FrameKey {
     217           0 :     explicit OnStackFrameKey(const char* aLocation)
     218           0 :       : FrameKey(aLocation)
     219           0 :       , mJITFrameHandle(nullptr)
     220           0 :     { }
     221             : 
     222             :     OnStackFrameKey(const OnStackFrameKey& aToCopy)
     223             :       : FrameKey(aToCopy)
     224             :       , mJITFrameHandle(aToCopy.mJITFrameHandle)
     225             :     { }
     226             : 
     227             :     const JS::ForEachProfiledFrameOp::FrameHandle* mJITFrameHandle;
     228             : 
     229           0 :     OnStackFrameKey(void* aJITAddress, unsigned aJITDepth)
     230           0 :       : FrameKey(aJITAddress, aJITDepth)
     231           0 :       , mJITFrameHandle(nullptr)
     232           0 :     { }
     233             : 
     234           0 :     OnStackFrameKey(void* aJITAddress, unsigned aJITDepth,
     235             :                     const JS::ForEachProfiledFrameOp::FrameHandle& aJITFrameHandle)
     236           0 :       : FrameKey(aJITAddress, aJITDepth)
     237           0 :       , mJITFrameHandle(&aJITFrameHandle)
     238           0 :     { }
     239             :   };
     240             : 
     241           0 :   struct StackKey {
     242             :     mozilla::Maybe<uint32_t> mPrefixHash;
     243             :     mozilla::Maybe<uint32_t> mPrefix;
     244             :     uint32_t mFrame;
     245             : 
     246           0 :     explicit StackKey(uint32_t aFrame)
     247           0 :      : mFrame(aFrame)
     248             :     {
     249           0 :       mHash = Hash();
     250           0 :     }
     251             : 
     252             :     uint32_t Hash() const;
     253             :     bool operator==(const StackKey& aOther) const;
     254             :     bool operator<(const StackKey& aOther) const {
     255             :       return mHash < aOther.mHash;
     256             :     }
     257             : 
     258           0 :     void UpdateHash(uint32_t aPrefixHash, uint32_t aPrefix, uint32_t aFrame) {
     259           0 :       mPrefixHash = mozilla::Some(aPrefixHash);
     260           0 :       mPrefix = mozilla::Some(aPrefix);
     261           0 :       mFrame = aFrame;
     262           0 :       mHash = Hash();
     263           0 :     }
     264             : 
     265             :   private:
     266             :     uint32_t mHash;
     267             :   };
     268             : 
     269           0 :   class Stack {
     270             :   public:
     271             :     Stack(UniqueStacks& aUniqueStacks, const OnStackFrameKey& aRoot);
     272             : 
     273             :     void AppendFrame(const OnStackFrameKey& aFrame);
     274             :     uint32_t GetOrAddIndex() const;
     275             : 
     276             :   private:
     277             :     UniqueStacks& mUniqueStacks;
     278             :     StackKey mStack;
     279             :   };
     280             : 
     281             :   explicit UniqueStacks(JSContext* aContext);
     282             : 
     283             :   Stack BeginStack(const OnStackFrameKey& aRoot);
     284             :   uint32_t LookupJITFrameDepth(void* aAddr);
     285             :   void AddJITFrameDepth(void* aAddr, unsigned depth);
     286             :   void SpliceFrameTableElements(SpliceableJSONWriter& aWriter);
     287             :   void SpliceStackTableElements(SpliceableJSONWriter& aWriter);
     288             : 
     289             : private:
     290             :   uint32_t GetOrAddFrameIndex(const OnStackFrameKey& aFrame);
     291             :   uint32_t GetOrAddStackIndex(const StackKey& aStack);
     292             :   void StreamFrame(const OnStackFrameKey& aFrame);
     293             :   void StreamStack(const StackKey& aStack);
     294             : 
     295             : public:
     296             :   UniqueJSONStrings mUniqueStrings;
     297             : 
     298             : private:
     299             :   JSContext* mContext;
     300             : 
     301             :   // To avoid incurring JitcodeGlobalTable lookup costs for every JIT frame,
     302             :   // we cache the depth of frames keyed by JIT code address. If an address a
     303             :   // maps to a depth d, then frames keyed by a for depths 0 to d are
     304             :   // guaranteed to be in mFrameToIndexMap.
     305             :   std::map<void*, uint32_t> mJITFrameDepthMap;
     306             : 
     307             :   uint32_t mFrameCount;
     308             :   SpliceableChunkedJSONWriter mFrameTableWriter;
     309             :   nsDataHashtable<nsGenericHashKey<FrameKey>, uint32_t> mFrameToIndexMap;
     310             : 
     311             :   SpliceableChunkedJSONWriter mStackTableWriter;
     312             : 
     313             :   nsDataHashtable<nsGenericHashKey<StackKey>, uint32_t> mStackToIndexMap;
     314             : };
     315             : 
     316             : //
     317             : // Thread profile JSON Format
     318             : // --------------------------
     319             : //
     320             : // The profile contains much duplicate information. The output JSON of the
     321             : // profile attempts to deduplicate strings, frames, and stack prefixes, to cut
     322             : // down on size and to increase JSON streaming speed. Deduplicated values are
     323             : // streamed as indices into their respective tables.
     324             : //
     325             : // Further, arrays of objects with the same set of properties (e.g., samples,
     326             : // frames) are output as arrays according to a schema instead of an object
     327             : // with property names. A property that is not present is represented in the
     328             : // array as null or undefined.
     329             : //
     330             : // The format of the thread profile JSON is shown by the following example
     331             : // with 1 sample and 1 marker:
     332             : //
     333             : // {
     334             : //   "name": "Foo",
     335             : //   "tid": 42,
     336             : //   "samples":
     337             : //   {
     338             : //     "schema":
     339             : //     {
     340             : //       "stack": 0,           /* index into stackTable */
     341             : //       "time": 1,            /* number */
     342             : //       "responsiveness": 2,  /* number */
     343             : //       "rss": 3,             /* number */
     344             : //       "uss": 4              /* number */
     345             : //     },
     346             : //     "data":
     347             : //     [
     348             : //       [ 1, 0.0, 0.0 ]       /* { stack: 1, time: 0.0, responsiveness: 0.0 } */
     349             : //     ]
     350             : //   },
     351             : //
     352             : //   "markers":
     353             : //   {
     354             : //     "schema":
     355             : //     {
     356             : //       "name": 0,            /* index into stringTable */
     357             : //       "time": 1,            /* number */
     358             : //       "data": 2             /* arbitrary JSON */
     359             : //     },
     360             : //     "data":
     361             : //     [
     362             : //       [ 3, 0.1 ]            /* { name: 'example marker', time: 0.1 } */
     363             : //     ]
     364             : //   },
     365             : //
     366             : //   "stackTable":
     367             : //   {
     368             : //     "schema":
     369             : //     {
     370             : //       "prefix": 0,          /* index into stackTable */
     371             : //       "frame": 1            /* index into frameTable */
     372             : //     },
     373             : //     "data":
     374             : //     [
     375             : //       [ null, 0 ],          /* (root) */
     376             : //       [ 0,    1 ]           /* (root) > foo.js */
     377             : //     ]
     378             : //   },
     379             : //
     380             : //   "frameTable":
     381             : //   {
     382             : //     "schema":
     383             : //     {
     384             : //       "location": 0,        /* index into stringTable */
     385             : //       "implementation": 1,  /* index into stringTable */
     386             : //       "optimizations": 2,   /* arbitrary JSON */
     387             : //       "line": 3,            /* number */
     388             : //       "category": 4         /* number */
     389             : //     },
     390             : //     "data":
     391             : //     [
     392             : //       [ 0 ],                /* { location: '(root)' } */
     393             : //       [ 1, 2 ]              /* { location: 'foo.js', implementation: 'baseline' } */
     394             : //     ]
     395             : //   },
     396             : //
     397             : //   "stringTable":
     398             : //   [
     399             : //     "(root)",
     400             : //     "foo.js",
     401             : //     "baseline",
     402             : //     "example marker"
     403             : //   ]
     404             : // }
     405             : //
     406             : 
     407             : #endif /* ndef ProfileBufferEntry_h */

Generated by: LCOV version 1.13