xpcom/threads/PerformanceCounter.h
author Henri Sivonen <hsivonen@hsivonen.fi>
Fri, 06 Jul 2018 10:44:43 +0300
changeset 489140 4ef0f163fdeb9afeddd87b37bfd987298c038542
parent 486892 b4bef97f6573ba4d34886b92d0b8e17281b990b8
child 508163 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1402247 - Use encoding_rs for XPCOM string encoding conversions. r=Nika,erahm,froydnj. Correctness improvements: * UTF errors are handled safely per spec instead of dangerously truncating strings. * There are fewer converter implementations. Performance improvements: * The old code did exact buffer length math, which meant doing UTF math twice on each input string (once for length calculation and another time for conversion). Exact length math is more complicated when handling errors properly, which the old code didn't do. The new code does UTF math on the string content only once (when converting) but risks allocating more than once. There are heuristics in place to lower the probability of reallocation in cases where the double math avoidance isn't enough of a saving to absorb an allocation and memcpy. * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized but a single non-ASCII code point pessimized the rest of the string. The new code tries to get back on the fast ASCII path. * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range input to eliminate an operation from the inner loop on x86/x86_64. * When assigning to a pre-existing string, the new code tries to reuse the old buffer instead of first releasing the old buffer and then allocating a new one. * When reallocating from the new code, the memcpy covers only the data that is part of the logical length of the old string instead of memcpying the whole capacity. (For old callers old excess memcpy behavior is preserved due to bogus callers. See bug 1472113.) * UTF-8 strings in XPConnect that are in the Latin1 range are passed to SpiderMonkey as Latin1. New features: * Conversion between UTF-8 and Latin1 is added in order to enable faster future interop between Rust code (or otherwise UTF-8-using code) and text node and SpiderMonkey code that uses Latin1. MozReview-Commit-ID: JaJuExfILM9

/* -*- 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

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();

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

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

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

  /**
   * 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() {}

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

} // namespace mozilla

#endif // mozilla_PerformanceCounter_h