summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/PerformanceCounter.h
blob: 4181320e1081581c5be99ec11c8d5465534b5366 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_PerformanceCounter_h
#define mozilla_PerformanceCounter_h

#include "mozilla/Array.h"
#include "mozilla/Atomics.h"
#include "mozilla/TaskCategory.h"
#include "nsISupportsImpl.h"
#include "nsString.h"

namespace mozilla {

/*
 * The DispatchCategory class is used to fake the inheritance
 * of the TaskCategory enum so we can extend it to hold
 * one more value corresponding to the category
 * we use when a worker dispatches a call.
 *
 */
class DispatchCategory final {
 public:
  explicit DispatchCategory(uint32_t aValue) : mValue(aValue) {
    // Since DispatchCategory is adding one single value to the
    // TaskCategory enum, we can check here that the value is
    // the next index e.g. TaskCategory::Count
    MOZ_ASSERT(aValue == (uint32_t)TaskCategory::Count);
  }

  constexpr explicit DispatchCategory(TaskCategory aValue)
      : mValue((uint32_t)aValue) {}

  uint32_t GetValue() const { return mValue; }

  static const DispatchCategory Worker;

 private:
  uint32_t mValue;
};

typedef Array<Atomic<uint32_t>, (uint32_t)TaskCategory::Count + 1>
    DispatchCounter;

// PerformanceCounter is a class that can be used to keep track of
// runnable execution times and dispatch counts.
//
// - runnable execution time: time spent in a runnable when called
//   in nsThread::ProcessNextEvent (not counting recursive calls)
// - dispatch counts: number of times a tracked runnable is dispatched
//   in nsThread. Useful to measure the activity of a tab or worker.
//
// The PerformanceCounter class is currently instantiated in DocGroup
// and WorkerPrivate in order to count how many scheduler dispatches
// are done through them, and how long the execution lasts.
//
// The execution time is calculated by the nsThread class (and its
// inherited WorkerThread class) in its ProcessNextEvent method.
//
// For each processed runnable, nsThread will reach out the
// PerformanceCounter attached to the runnable via its DocGroup
// or WorkerPrivate and call IncrementExecutionDuration()
//
// Notice that the execution duration counting takes into account
// recursivity. If an event triggers a recursive call to
// nsThread::ProcessNextEVent, the counter will discard the time
// spent in sub events.
class PerformanceCounter final {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PerformanceCounter)

  explicit PerformanceCounter(const nsACString& aName);

  /**
   * This is called everytime a runnable is dispatched.
   *
   * aCategory can be used to distinguish counts per TaskCategory
   *
   * Note that an overflow will simply reset the counter.
   */
  void IncrementDispatchCounter(DispatchCategory aCategory);

  /**
   * This is called via nsThread::ProcessNextEvent to measure runnable
   * execution duration.
   *
   * Note that an overflow will simply reset the counter.
   */
  void IncrementExecutionDuration(uint32_t aMicroseconds);

  /**
   * Returns a category/counter array of all dispatches.
   */
  const DispatchCounter& GetDispatchCounter() const;

  /**
   * Returns the total execution duration.
   */
  uint64_t GetExecutionDuration() const;

  /**
   * Returns the number of dispatches per TaskCategory.
   */
  uint32_t GetDispatchCount(DispatchCategory aCategory) const;

  /**
   * Returns the total number of dispatches.
   */
  uint64_t GetTotalDispatchCount() const;

  /**
   * Returns the unique id for the instance.
   *
   * Used to distinguish instances since the lifespan of
   * a PerformanceCounter can be shorter than the
   * host it's tracking. That leads to edge cases
   * where a counter appears to have values that go
   * backwards. Having this id let the consumers
   * detect that they are dealing with a new counter
   * when it happens.
   */
  uint64_t GetID() const;

 private:
  ~PerformanceCounter() = default;

  Atomic<uint64_t> mExecutionDuration;
  Atomic<uint64_t> mTotalDispatchCount;
  DispatchCounter mDispatchCounter;
  nsCString mName;
  const uint64_t mID;
};

}  // namespace mozilla

#endif  // mozilla_PerformanceCounter_h