tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BaseProfilerCounts.h (11916B)


      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 BaseProfilerCounts_h
      8 #define BaseProfilerCounts_h
      9 
     10 #ifndef MOZ_GECKO_PROFILER
     11 
     12 #  define BASE_PROFILER_DEFINE_COUNT_TOTAL(label, category, description)
     13 #  define BASE_PROFILER_DEFINE_COUNT(label, category, description)
     14 #  define BASE_PROFILER_DEFINE_STATIC_COUNT_TOTAL(label, category, description)
     15 #  define AUTO_BASE_PROFILER_COUNT_TOTAL(label, count)
     16 #  define AUTO_BASE_PROFILER_COUNT(label)
     17 #  define AUTO_BASE_PROFILER_STATIC_COUNT(label, count)
     18 #  define AUTO_BASE_PROFILER_FORCE_ALLOCATION(label)
     19 
     20 #else
     21 
     22 #  include "mozilla/Assertions.h"
     23 #  include "mozilla/Atomics.h"
     24 
     25 namespace mozilla {
     26 namespace baseprofiler {
     27 
     28 class BaseProfilerCount;
     29 MFBT_API void profiler_add_sampled_counter(BaseProfilerCount* aCounter);
     30 MFBT_API void profiler_remove_sampled_counter(BaseProfilerCount* aCounter);
     31 
     32 typedef Atomic<int64_t, MemoryOrdering::Relaxed> ProfilerAtomicSigned;
     33 typedef Atomic<uint64_t, MemoryOrdering::Relaxed> ProfilerAtomicUnsigned;
     34 
     35 // Counter support
     36 // There are two types of counters:
     37 // 1) a simple counter which can be added to or subtracted from.  This could
     38 // track the number of objects of a type, the number of calls to something
     39 // (reflow, JIT, etc).
     40 // 2) a combined counter which has the above, plus a number-of-calls counter
     41 // that is incremented by 1 for each call to modify the count.  This provides
     42 // an optional source for a 'heatmap' of access.  This can be used (for
     43 // example) to track the amount of memory allocated, and provide a heatmap of
     44 // memory operations (allocs/frees).
     45 //
     46 // Counters are sampled by the profiler once per sample-period.  At this time,
     47 // all counters are global to the process.  In the future, there might be more
     48 // versions with per-thread or other discriminators.
     49 //
     50 // Typical usage:
     51 // There are two ways to use counters: With heap-created counter objects,
     52 // or using macros.  Note: the macros use statics, and will be slightly
     53 // faster/smaller, and you need to care about creating them before using
     54 // them.  They're similar to the use-pattern for the other AUTO_PROFILER*
     55 // macros, but they do need the PROFILER_DEFINE* to be use to instantiate
     56 // the statics.
     57 //
     58 // PROFILER_DEFINE_COUNT(mything, "JIT", "Some JIT byte count")
     59 // ...
     60 // void foo() { ... AUTO_PROFILER_COUNT(mything, number_of_bytes_used); ... }
     61 //
     62 // or (to also get a heatmap)
     63 //
     64 // PROFILER_DEFINE_COUNT_TOTAL(mything, "JIT", "Some JIT byte count")
     65 // ...
     66 // void foo() {
     67 //   ...
     68 //   AUTO_PROFILER_COUNT_TOTAL(mything, number_of_bytes_generated);
     69 //   ...
     70 // }
     71 //
     72 // To use without statics/macros:
     73 //
     74 // UniquePtr<ProfilerCounter> myCounter;
     75 // ...
     76 // myCounter =
     77 //   MakeUnique<ProfilerCounter>("mything", "JIT", "Some JIT byte count"));
     78 // ...
     79 // void foo() { ... myCounter->Add(number_of_bytes_generated0; ... }
     80 
     81 class BaseProfilerCount {
     82 public:
     83  BaseProfilerCount(const char* aLabel, ProfilerAtomicSigned* aCounter,
     84                    ProfilerAtomicUnsigned* aNumber, const char* aCategory,
     85                    const char* aDescription)
     86      : mLabel(aLabel),
     87        mCategory(aCategory),
     88        mDescription(aDescription),
     89        mCounter(aCounter),
     90        mNumber(aNumber) {
     91 #  define COUNTER_CANARY 0xDEADBEEF
     92 #  ifdef DEBUG
     93    mCanary = COUNTER_CANARY;
     94    mPrevNumber = 0;
     95 #  endif
     96    // Can't call profiler_* here since this may be non-xul-library
     97  }
     98 #  ifdef DEBUG
     99  ~BaseProfilerCount() { mCanary = 0; }
    100 #  endif
    101 
    102  void Sample(int64_t& aCounter, uint64_t& aNumber) {
    103    MOZ_ASSERT(mCanary == COUNTER_CANARY);
    104 
    105    aCounter = *mCounter;
    106    aNumber = mNumber ? *mNumber : 0;
    107 #  ifdef DEBUG
    108    MOZ_ASSERT(aNumber >= mPrevNumber);
    109    mPrevNumber = aNumber;
    110 #  endif
    111  }
    112 
    113  // We don't define ++ and Add() here, since the static defines directly
    114  // increment the atomic counters, and the subclasses implement ++ and
    115  // Add() directly.
    116 
    117  // These typically are static strings (for example if you use the macros
    118  // below)
    119  const char* mLabel;
    120  const char* mCategory;
    121  const char* mDescription;
    122  // We're ok with these being un-ordered in race conditions.  These are
    123  // pointers because we want to be able to use statics and increment them
    124  // directly.  Otherwise we could just have them inline, and not need the
    125  // constructor args.
    126  // These can be static globals (using the macros below), though they
    127  // don't have to be - their lifetime must be longer than the use of them
    128  // by the profiler (see profiler_add/remove_sampled_counter()).  If you're
    129  // using a lot of these, they probably should be allocated at runtime (see
    130  // class ProfilerCountOnly below).
    131  ProfilerAtomicSigned* mCounter;
    132  ProfilerAtomicUnsigned* mNumber;  // may be null
    133 
    134 #  ifdef DEBUG
    135  uint32_t mCanary;
    136  uint64_t mPrevNumber;  // value of number from the last Sample()
    137 #  endif
    138 };
    139 
    140 // Designed to be allocated dynamically, and simply incremented with obj++
    141 // or obj->Add(n)
    142 class ProfilerCounter final : public BaseProfilerCount {
    143 public:
    144  ProfilerCounter(const char* aLabel, const char* aCategory,
    145                  const char* aDescription)
    146      : BaseProfilerCount(aLabel, &mCounter, nullptr, aCategory, aDescription) {
    147    // Assume we're in libxul
    148    profiler_add_sampled_counter(this);
    149  }
    150 
    151  ~ProfilerCounter() { profiler_remove_sampled_counter(this); }
    152 
    153  BaseProfilerCount& operator++() {
    154    Add(1);
    155    return *this;
    156  }
    157 
    158  void Add(int64_t aNumber) { mCounter += aNumber; }
    159 
    160  ProfilerAtomicSigned mCounter;
    161 };
    162 
    163 // Also keeps a heatmap (number of calls to ++/Add())
    164 class ProfilerCounterTotal final : public BaseProfilerCount {
    165 public:
    166  ProfilerCounterTotal(const char* aLabel, const char* aCategory,
    167                       const char* aDescription)
    168      : BaseProfilerCount(aLabel, &mCounter, &mNumber, aCategory,
    169                          aDescription) {
    170    // Assume we're in libxul
    171    profiler_add_sampled_counter(this);
    172  }
    173 
    174  ~ProfilerCounterTotal() { profiler_remove_sampled_counter(this); }
    175 
    176  BaseProfilerCount& operator++() {
    177    Add(1);
    178    return *this;
    179  }
    180 
    181  void Add(int64_t aNumber) {
    182    mCounter += aNumber;
    183    mNumber++;
    184  }
    185 
    186  ProfilerAtomicSigned mCounter;
    187  ProfilerAtomicUnsigned mNumber;
    188 };
    189 
    190 // Defines a counter that is sampled on each profiler tick, with a running
    191 // count (signed), and number-of-instances. Note that because these are two
    192 // independent Atomics, there is a possiblity that count will not include
    193 // the last call, but number of uses will.  I think this is not worth
    194 // worrying about
    195 #  define BASE_PROFILER_DEFINE_COUNT_TOTAL(label, category, description) \
    196    ProfilerAtomicSigned profiler_count_##label(0);                      \
    197    ProfilerAtomicUnsigned profiler_number_##label(0);                   \
    198    const char profiler_category_##label[] = category;                   \
    199    const char profiler_description_##label[] = description;             \
    200    UniquePtr<::mozilla::baseprofiler::BaseProfilerCount> AutoCount_##label;
    201 
    202 // This counts, but doesn't keep track of the number of calls to
    203 // AUTO_PROFILER_COUNT()
    204 #  define BASE_PROFILER_DEFINE_COUNT(label, category, description) \
    205    ProfilerAtomicSigned profiler_count_##label(0);                \
    206    const char profiler_category_##label[] = category;             \
    207    const char profiler_description_##label[] = description;       \
    208    UniquePtr<::mozilla::baseprofiler::BaseProfilerCount> AutoCount_##label;
    209 
    210 // This will create a static initializer if used, but avoids a possible
    211 // allocation.
    212 #  define BASE_PROFILER_DEFINE_STATIC_COUNT_TOTAL(label, category,           \
    213                                                  description)               \
    214    ProfilerAtomicSigned profiler_count_##label(0);                          \
    215    ProfilerAtomicUnsigned profiler_number_##label(0);                       \
    216    ::mozilla::baseprofiler::BaseProfilerCount AutoCount_##label(            \
    217        #label, &profiler_count_##label, &profiler_number_##label, category, \
    218        description);
    219 
    220 // If we didn't care about static initializers, we could avoid the need for
    221 // a ptr to the BaseProfilerCount object.
    222 
    223 // XXX It would be better to do this without the if() and without the
    224 // theoretical race to set the UniquePtr (i.e. possible leak).
    225 #  define AUTO_BASE_PROFILER_COUNT_TOTAL(label, count)                      \
    226    do {                                                                    \
    227      profiler_number_##label++; /* do this first*/                         \
    228      profiler_count_##label += count;                                      \
    229      if (!AutoCount_##label) {                                             \
    230        /* Ignore that we could call this twice in theory, and that we leak \
    231         * them                                                             \
    232         */                                                                 \
    233        AutoCount_##label.reset(new BaseProfilerCount(                      \
    234            #label, &profiler_count_##label, &profiler_number_##label,      \
    235            profiler_category_##label, profiler_description_##label));      \
    236        ::mozilla::baseprofiler::profiler_add_sampled_counter(              \
    237            AutoCount_##label.get());                                       \
    238      }                                                                     \
    239    } while (0)
    240 
    241 #  define AUTO_BASE_PROFILER_COUNT(label, count)                            \
    242    do {                                                                    \
    243      profiler_count_##label += count; /* do this first*/                   \
    244      if (!AutoCount_##label) {                                             \
    245        /* Ignore that we could call this twice in theory, and that we leak \
    246         * them                                                             \
    247         */                                                                 \
    248        AutoCount_##label.reset(new BaseProfilerCount(                      \
    249            #label, nullptr, &profiler_number_##label,                      \
    250            profiler_category_##label, profiler_description_##label));      \
    251        ::mozilla::baseprofiler::profiler_add_sampled_counter(              \
    252            AutoCount_##label.get());                                       \
    253      }                                                                     \
    254    } while (0)
    255 
    256 #  define AUTO_BASE_PROFILER_STATIC_COUNT(label, count) \
    257    do {                                                \
    258      profiler_number_##label++; /* do this first*/     \
    259      profiler_count_##label += count;                  \
    260    } while (0)
    261 
    262 // if we need to force the allocation
    263 #  define AUTO_BASE_PROFILER_FORCE_ALLOCATION(label)                        \
    264    do {                                                                    \
    265      if (!AutoCount_##label) {                                             \
    266        /* Ignore that we could call this twice in theory, and that we leak \
    267         * them                                                             \
    268         */                                                                 \
    269        AutoCount_##label.reset(                                            \
    270            new ::mozilla::baseprofiler::BaseProfilerCount(                 \
    271                #label, &profiler_count_##label, &profiler_number_##label,  \
    272                profiler_category_##label, profiler_description_##label));  \
    273      }                                                                     \
    274    } while (0)
    275 
    276 }  // namespace baseprofiler
    277 }  // namespace mozilla
    278 
    279 #endif  // !MOZ_GECKO_PROFILER
    280 
    281 #endif  // BaseProfilerCounts_h