ipc/chromium/src/base/tracked_objects.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/base/tracked_objects.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,498 @@
     1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#ifndef BASE_TRACKED_OBJECTS_H_
     1.9 +#define BASE_TRACKED_OBJECTS_H_
    1.10 +
    1.11 +//------------------------------------------------------------------------------
    1.12 +#include <map>
    1.13 +#include <string>
    1.14 +#include <vector>
    1.15 +
    1.16 +#include "base/lock.h"
    1.17 +#include "base/message_loop.h"
    1.18 +#include "base/thread_local_storage.h"
    1.19 +#include "base/tracked.h"
    1.20 +
    1.21 +
    1.22 +namespace tracked_objects {
    1.23 +
    1.24 +//------------------------------------------------------------------------------
    1.25 +// For a specific thread, and a specific birth place, the collection of all
    1.26 +// death info (with tallies for each death thread, to prevent access conflicts).
    1.27 +class ThreadData;
    1.28 +class BirthOnThread {
    1.29 + public:
    1.30 +  explicit BirthOnThread(const Location& location);
    1.31 +
    1.32 +  const Location location() const { return location_; }
    1.33 +  const ThreadData* birth_thread() const { return birth_thread_; }
    1.34 +
    1.35 + private:
    1.36 +  // File/lineno of birth.  This defines the essence of the type, as the context
    1.37 +  // of the birth (construction) often tell what the item is for.  This field
    1.38 +  // is const, and hence safe to access from any thread.
    1.39 +  const Location location_;
    1.40 +
    1.41 +  // The thread that records births into this object.  Only this thread is
    1.42 +  // allowed to access birth_count_ (which changes over time).
    1.43 +  const ThreadData* birth_thread_;  // The thread this birth took place on.
    1.44 +
    1.45 +  DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
    1.46 +};
    1.47 +
    1.48 +//------------------------------------------------------------------------------
    1.49 +// A class for accumulating counts of births (without bothering with a map<>).
    1.50 +
    1.51 +class Births: public BirthOnThread {
    1.52 + public:
    1.53 +  explicit Births(const Location& location);
    1.54 +
    1.55 +  int birth_count() const { return birth_count_; }
    1.56 +
    1.57 +  // When we have a birth we update the count for this BirhPLace.
    1.58 +  void RecordBirth() { ++birth_count_; }
    1.59 +
    1.60 +  // When a birthplace is changed (updated), we need to decrement the counter
    1.61 +  // for the old instance.
    1.62 +  void ForgetBirth() { --birth_count_; }  // We corrected a birth place.
    1.63 +
    1.64 + private:
    1.65 +  // The number of births on this thread for our location_.
    1.66 +  int birth_count_;
    1.67 +
    1.68 +  DISALLOW_COPY_AND_ASSIGN(Births);
    1.69 +};
    1.70 +
    1.71 +//------------------------------------------------------------------------------
    1.72 +// Basic info summarizing multiple destructions of an object with a single
    1.73 +// birthplace (fixed Location).  Used both on specific threads, and also used
    1.74 +// in snapshots when integrating assembled data.
    1.75 +
    1.76 +class DeathData {
    1.77 + public:
    1.78 +  // Default initializer.
    1.79 +  DeathData() : count_(0), square_duration_(0) {}
    1.80 +
    1.81 +  // When deaths have not yet taken place, and we gather data from all the
    1.82 +  // threads, we create DeathData stats that tally the number of births without
    1.83 +  // a corrosponding death.
    1.84 +  explicit DeathData(int count) : count_(count), square_duration_(0) {}
    1.85 +
    1.86 +  void RecordDeath(const base::TimeDelta& duration);
    1.87 +
    1.88 +  // Metrics accessors.
    1.89 +  int count() const { return count_; }
    1.90 +  base::TimeDelta life_duration() const { return life_duration_; }
    1.91 +  int64_t square_duration() const { return square_duration_; }
    1.92 +  int AverageMsDuration() const;
    1.93 +  double StandardDeviation() const;
    1.94 +
    1.95 +  // Accumulate metrics from other into this.
    1.96 +  void AddDeathData(const DeathData& other);
    1.97 +
    1.98 +  // Simple print of internal state.
    1.99 +  void Write(std::string* output) const;
   1.100 +
   1.101 +  void Clear();
   1.102 +
   1.103 + private:
   1.104 +  int count_;                // Number of destructions.
   1.105 +  base::TimeDelta life_duration_;    // Sum of all lifetime durations.
   1.106 +  int64_t square_duration_;  // Sum of squares in milliseconds.
   1.107 +};
   1.108 +
   1.109 +//------------------------------------------------------------------------------
   1.110 +// A temporary collection of data that can be sorted and summarized.  It is
   1.111 +// gathered (carefully) from many threads.  Instances are held in arrays and
   1.112 +// processed, filtered, and rendered.
   1.113 +// The source of this data was collected on many threads, and is asynchronously
   1.114 +// changing.  The data in this instance is not asynchronously changing.
   1.115 +
   1.116 +class Snapshot {
   1.117 + public:
   1.118 +  // When snapshotting a full life cycle set (birth-to-death), use this:
   1.119 +  Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread,
   1.120 +           const DeathData& death_data);
   1.121 +
   1.122 +  // When snapshotting a birth, with no death yet, use this:
   1.123 +  Snapshot(const BirthOnThread& birth_on_thread, int count);
   1.124 +
   1.125 +
   1.126 +  const ThreadData* birth_thread() const { return birth_->birth_thread(); }
   1.127 +  const Location location() const { return birth_->location(); }
   1.128 +  const BirthOnThread& birth() const { return *birth_; }
   1.129 +  const ThreadData* death_thread() const {return death_thread_; }
   1.130 +  const DeathData& death_data() const { return death_data_; }
   1.131 +  const std::string DeathThreadName() const;
   1.132 +
   1.133 +  int count() const { return death_data_.count(); }
   1.134 +  base::TimeDelta life_duration() const { return death_data_.life_duration(); }
   1.135 +  int64_t square_duration() const { return death_data_.square_duration(); }
   1.136 +  int AverageMsDuration() const { return death_data_.AverageMsDuration(); }
   1.137 +
   1.138 +  void Write(std::string* output) const;
   1.139 +
   1.140 +  void Add(const Snapshot& other);
   1.141 +
   1.142 + private:
   1.143 +  const BirthOnThread* birth_;  // Includes Location and birth_thread.
   1.144 +  const ThreadData* death_thread_;
   1.145 +  DeathData death_data_;
   1.146 +};
   1.147 +//------------------------------------------------------------------------------
   1.148 +// DataCollector is a container class for Snapshot and BirthOnThread count
   1.149 +// items.  It protects the gathering under locks, so that it could be called via
   1.150 +// Posttask on any threads, such as all the target threads in parallel.
   1.151 +
   1.152 +class DataCollector {
   1.153 + public:
   1.154 +  typedef std::vector<Snapshot> Collection;
   1.155 +
   1.156 +  // Construct with a list of how many threads should contribute.  This helps us
   1.157 +  // determine (in the async case) when we are done with all contributions.
   1.158 +  DataCollector();
   1.159 +
   1.160 +  // Add all stats from the indicated thread into our arrays.  This function is
   1.161 +  // mutex protected, and *could* be called from any threads (although current
   1.162 +  // implementation serialized calls to Append).
   1.163 +  void Append(const ThreadData& thread_data);
   1.164 +
   1.165 +  // After the accumulation phase, the following access is to process data.
   1.166 +  Collection* collection();
   1.167 +
   1.168 +  // After collection of death data is complete, we can add entries for all the
   1.169 +  // remaining living objects.
   1.170 +  void AddListOfLivingObjects();
   1.171 +
   1.172 + private:
   1.173 +  // This instance may be provided to several threads to contribute data.  The
   1.174 +  // following counter tracks how many more threads will contribute.  When it is
   1.175 +  // zero, then all asynchronous contributions are complete, and locked access
   1.176 +  // is no longer needed.
   1.177 +  int count_of_contributing_threads_;
   1.178 +
   1.179 +  // The array that we collect data into.
   1.180 +  Collection collection_;
   1.181 +
   1.182 +  // The total number of births recorded at each location for which we have not
   1.183 +  // seen a death count.
   1.184 +  typedef std::map<const BirthOnThread*, int> BirthCount;
   1.185 +  BirthCount global_birth_count_;
   1.186 +
   1.187 +  Lock accumulation_lock_;  // Protects access during accumulation phase.
   1.188 +
   1.189 +  DISALLOW_COPY_AND_ASSIGN(DataCollector);
   1.190 +};
   1.191 +
   1.192 +//------------------------------------------------------------------------------
   1.193 +// Aggregation contains summaries (totals and subtotals) of groups of Snapshot
   1.194 +// instances to provide printing of these collections on a single line.
   1.195 +
   1.196 +class Aggregation: public DeathData {
   1.197 + public:
   1.198 +  Aggregation() : birth_count_(0) {}
   1.199 +
   1.200 +  void AddDeathSnapshot(const Snapshot& snapshot);
   1.201 +  void AddBirths(const Births& births);
   1.202 +  void AddBirth(const BirthOnThread& birth);
   1.203 +  void AddBirthPlace(const Location& location);
   1.204 +  void Write(std::string* output) const;
   1.205 +  void Clear();
   1.206 +
   1.207 + private:
   1.208 +  int birth_count_;
   1.209 +  std::map<std::string, int> birth_files_;
   1.210 +  std::map<Location, int> locations_;
   1.211 +  std::map<const ThreadData*, int> birth_threads_;
   1.212 +  DeathData death_data_;
   1.213 +  std::map<const ThreadData*, int> death_threads_;
   1.214 +
   1.215 +  DISALLOW_COPY_AND_ASSIGN(Aggregation);
   1.216 +};
   1.217 +
   1.218 +//------------------------------------------------------------------------------
   1.219 +// Comparator does the comparison of Snapshot instances.  It is
   1.220 +// used to order the instances in a vector.  It orders them into groups (for
   1.221 +// aggregation), and can also order instances within the groups (for detailed
   1.222 +// rendering of the instances).
   1.223 +
   1.224 +class Comparator {
   1.225 + public:
   1.226 +  enum Selector {
   1.227 +    NIL = 0,
   1.228 +    BIRTH_THREAD = 1,
   1.229 +    DEATH_THREAD = 2,
   1.230 +    BIRTH_FILE = 4,
   1.231 +    BIRTH_FUNCTION = 8,
   1.232 +    BIRTH_LINE = 16,
   1.233 +    COUNT = 32,
   1.234 +    AVERAGE_DURATION = 64,
   1.235 +    TOTAL_DURATION = 128
   1.236 +  };
   1.237 +
   1.238 +  explicit Comparator();
   1.239 +
   1.240 +  // Reset the comparator to a NIL selector.  Reset() and recursively delete any
   1.241 +  // tiebreaker_ entries.  NOTE: We can't use a standard destructor, because
   1.242 +  // the sort algorithm makes copies of this object, and then deletes them,
   1.243 +  // which would cause problems (either we'd make expensive deep copies, or we'd
   1.244 +  // do more thna one delete on a tiebreaker_.
   1.245 +  void Clear();
   1.246 +
   1.247 +  // The less() operator for sorting the array via std::sort().
   1.248 +  bool operator()(const Snapshot& left, const Snapshot& right) const;
   1.249 +
   1.250 +  void Sort(DataCollector::Collection* collection) const;
   1.251 +
   1.252 +  // Check to see if the items are sort equivalents (should be aggregated).
   1.253 +  bool Equivalent(const Snapshot& left, const Snapshot& right) const;
   1.254 +
   1.255 +  // Check to see if all required fields are present in the given sample.
   1.256 +  bool Acceptable(const Snapshot& sample) const;
   1.257 +
   1.258 +  // A comparator can be refined by specifying what to do if the selected basis
   1.259 +  // for comparison is insufficient to establish an ordering.  This call adds
   1.260 +  // the indicated attribute as the new "least significant" basis of comparison.
   1.261 +  void SetTiebreaker(Selector selector, const std::string required);
   1.262 +
   1.263 +  // Indicate if this instance is set up to sort by the given Selector, thereby
   1.264 +  // putting that information in the SortGrouping, so it is not needed in each
   1.265 +  // printed line.
   1.266 +  bool IsGroupedBy(Selector selector) const;
   1.267 +
   1.268 +  // Using the tiebreakers as set above, we mostly get an ordering, which
   1.269 +  // equivalent groups.  If those groups are displayed (rather than just being
   1.270 +  // aggregated, then the following is used to order them (within the group).
   1.271 +  void SetSubgroupTiebreaker(Selector selector);
   1.272 +
   1.273 +  // Output a header line that can be used to indicated what items will be
   1.274 +  // collected in the group.  It lists all (potentially) tested attributes and
   1.275 +  // their values (in the sample item).
   1.276 +  bool WriteSortGrouping(const Snapshot& sample, std::string* output) const;
   1.277 +
   1.278 +  // Output a sample, with SortGroup details not displayed.
   1.279 +  void WriteSnapshot(const Snapshot& sample, std::string* output) const;
   1.280 +
   1.281 + private:
   1.282 +  // The selector directs this instance to compare based on the specified
   1.283 +  // members of the tested elements.
   1.284 +  enum Selector selector_;
   1.285 +
   1.286 +  // For filtering into acceptable and unacceptable snapshot instance, the
   1.287 +  // following is required to be a substring of the selector_ field.
   1.288 +  std::string required_;
   1.289 +
   1.290 +  // If this instance can't decide on an ordering, we can consult a tie-breaker
   1.291 +  // which may have a different basis of comparison.
   1.292 +  Comparator* tiebreaker_;
   1.293 +
   1.294 +  // We or together all the selectors we sort on (not counting sub-group
   1.295 +  // selectors), so that we can tell if we've decided to group on any given
   1.296 +  // criteria.
   1.297 +  int combined_selectors_;
   1.298 +
   1.299 +  // Some tiebreakrs are for subgroup ordering, and not for basic ordering (in
   1.300 +  // preparation for aggregation).  The subgroup tiebreakers are not consulted
   1.301 +  // when deciding if two items are in equivalent groups.  This flag tells us
   1.302 +  // to ignore the tiebreaker when doing Equivalent() testing.
   1.303 +  bool use_tiebreaker_for_sort_only_;
   1.304 +};
   1.305 +
   1.306 +
   1.307 +//------------------------------------------------------------------------------
   1.308 +// For each thread, we have a ThreadData that stores all tracking info generated
   1.309 +// on this thread.  This prevents the need for locking as data accumulates.
   1.310 +
   1.311 +class ThreadData {
   1.312 + public:
   1.313 +  typedef std::map<Location, Births*> BirthMap;
   1.314 +  typedef std::map<const Births*, DeathData> DeathMap;
   1.315 +
   1.316 +  ThreadData();
   1.317 +
   1.318 +  // Using Thread Local Store, find the current instance for collecting data.
   1.319 +  // If an instance does not exist, construct one (and remember it for use on
   1.320 +  // this thread.
   1.321 +  // If shutdown has already started, and we don't yet have an instance, then
   1.322 +  // return null.
   1.323 +  static ThreadData* current();
   1.324 +
   1.325 +  // In this thread's data, find a place to record a new birth.
   1.326 +  Births* FindLifetime(const Location& location);
   1.327 +
   1.328 +  // Find a place to record a death on this thread.
   1.329 +  void TallyADeath(const Births& lifetimes, const base::TimeDelta& duration);
   1.330 +
   1.331 +  // (Thread safe) Get start of list of instances.
   1.332 +  static ThreadData* first();
   1.333 +  // Iterate through the null terminated list of instances.
   1.334 +  ThreadData* next() const { return next_; }
   1.335 +
   1.336 +  MessageLoop* message_loop() const { return message_loop_; }
   1.337 +  const std::string ThreadName() const;
   1.338 +
   1.339 +  // Using our lock, make a copy of the specified maps.  These calls may arrive
   1.340 +  // from non-local threads.
   1.341 +  void SnapshotBirthMap(BirthMap *output) const;
   1.342 +  void SnapshotDeathMap(DeathMap *output) const;
   1.343 +
   1.344 +  static void RunOnAllThreads(void (*Func)());
   1.345 +
   1.346 +  // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN,
   1.347 +  // based on argument being true or false respectively.
   1.348 +  // IF tracking is not compiled in, this function will return false.
   1.349 +  static bool StartTracking(bool status);
   1.350 +  static bool IsActive();
   1.351 +
   1.352 +#ifdef OS_WIN
   1.353 +  // WARNING: ONLY call this function when all MessageLoops are still intact for
   1.354 +  // all registered threads.  IF you call it later, you will crash.
   1.355 +  // Note: You don't need to call it at all, and you can wait till you are
   1.356 +  // single threaded (again) to do the cleanup via
   1.357 +  // ShutdownSingleThreadedCleanup().
   1.358 +  // Start the teardown (shutdown) process in a multi-thread mode by disabling
   1.359 +  // further additions to thread database on all threads.  First it makes a
   1.360 +  // local (locked) change to prevent any more threads from registering.  Then
   1.361 +  // it Posts a Task to all registered threads to be sure they are aware that no
   1.362 +  // more accumulation can take place.
   1.363 +  static void ShutdownMultiThreadTracking();
   1.364 +#endif
   1.365 +
   1.366 +  // WARNING: ONLY call this function when you are running single threaded
   1.367 +  // (again) and all message loops and threads have terminated.  Until that
   1.368 +  // point some threads may still attempt to write into our data structures.
   1.369 +  // Delete recursively all data structures, starting with the list of
   1.370 +  // ThreadData instances.
   1.371 +  static void ShutdownSingleThreadedCleanup();
   1.372 +
   1.373 + private:
   1.374 +  // Current allowable states of the tracking system.  The states always
   1.375 +  // proceed towards SHUTDOWN, and never go backwards.
   1.376 +  enum Status {
   1.377 +    UNINITIALIZED,
   1.378 +    ACTIVE,
   1.379 +    SHUTDOWN
   1.380 +  };
   1.381 +
   1.382 +  // A class used to count down which is accessed by several threads.  This is
   1.383 +  // used to make sure RunOnAllThreads() actually runs a task on the expected
   1.384 +  // count of threads.
   1.385 +  class ThreadSafeDownCounter {
   1.386 +   public:
   1.387 +    // Constructor sets the count, once and for all.
   1.388 +    explicit ThreadSafeDownCounter(size_t count);
   1.389 +
   1.390 +    // Decrement the count, and return true if we hit zero.  Also delete this
   1.391 +    // instance automatically when we hit zero.
   1.392 +    bool LastCaller();
   1.393 +
   1.394 +   private:
   1.395 +    size_t remaining_count_;
   1.396 +    Lock lock_;  // protect access to remaining_count_.
   1.397 +  };
   1.398 +
   1.399 +#ifdef OS_WIN
   1.400 +  // A Task class that runs a static method supplied, and checks to see if this
   1.401 +  // is the last tasks instance (on last thread) that will run the method.
   1.402 +  // IF this is the last run, then the supplied event is signalled.
   1.403 +  class RunTheStatic : public Task {
   1.404 +   public:
   1.405 +    typedef void (*FunctionPointer)();
   1.406 +    RunTheStatic(FunctionPointer function,
   1.407 +                 HANDLE completion_handle,
   1.408 +                 ThreadSafeDownCounter* counter);
   1.409 +    // Run the supplied static method, and optionally set the event.
   1.410 +    void Run();
   1.411 +
   1.412 +   private:
   1.413 +    FunctionPointer function_;
   1.414 +    HANDLE completion_handle_;
   1.415 +    // Make sure enough tasks are called before completion is signaled.
   1.416 +    ThreadSafeDownCounter* counter_;
   1.417 +
   1.418 +    DISALLOW_COPY_AND_ASSIGN(RunTheStatic);
   1.419 +  };
   1.420 +#endif
   1.421 +
   1.422 +  // Each registered thread is called to set status_ to SHUTDOWN.
   1.423 +  // This is done redundantly on every registered thread because it is not
   1.424 +  // protected by a mutex.  Running on all threads guarantees we get the
   1.425 +  // notification into the memory cache of all possible threads.
   1.426 +  static void ShutdownDisablingFurtherTracking();
   1.427 +
   1.428 +  // We use thread local store to identify which ThreadData to interact with.
   1.429 +  static TLSSlot tls_index_ ;
   1.430 +
   1.431 +  // Link to the most recently created instance (starts a null terminated list).
   1.432 +  static ThreadData* first_;
   1.433 +  // Protection for access to first_.
   1.434 +  static Lock list_lock_;
   1.435 +
   1.436 +
   1.437 +  // We set status_ to SHUTDOWN when we shut down the tracking service. This
   1.438 +  // setting is redundantly established by all participating
   1.439 +  // threads so that we are *guaranteed* (without locking) that all threads
   1.440 +  // can "see" the status and avoid additional calls into the  service.
   1.441 +  static Status status_;
   1.442 +
   1.443 +  // Link to next instance (null terminated list). Used to globally track all
   1.444 +  // registered instances (corresponds to all registered threads where we keep
   1.445 +  // data).
   1.446 +  ThreadData* next_;
   1.447 +
   1.448 +  // The message loop where tasks needing to access this instance's private data
   1.449 +  // should be directed.  Since some threads have no message loop, some
   1.450 +  // instances have data that can't be (safely) modified externally.
   1.451 +  MessageLoop* message_loop_;
   1.452 +
   1.453 +  // A map used on each thread to keep track of Births on this thread.
   1.454 +  // This map should only be accessed on the thread it was constructed on.
   1.455 +  // When a snapshot is needed, this structure can be locked in place for the
   1.456 +  // duration of the snapshotting activity.
   1.457 +  BirthMap birth_map_;
   1.458 +
   1.459 +  // Similar to birth_map_, this records informations about death of tracked
   1.460 +  // instances (i.e., when a tracked instance was destroyed on this thread).
   1.461 +  DeathMap death_map_;
   1.462 +
   1.463 +  // Lock to protect *some* access to BirthMap and DeathMap.  We only use
   1.464 +  // locking protection when we are growing the maps, or using an iterator.  We
   1.465 +  // only do writes to members from this thread, so the updates of values are
   1.466 +  // atomic.  Folks can read from other threads, and get (via races) new or old
   1.467 +  // data, but that is considered acceptable errors (mis-information).
   1.468 +  Lock lock_;
   1.469 +
   1.470 +  DISALLOW_COPY_AND_ASSIGN(ThreadData);
   1.471 +};
   1.472 +
   1.473 +
   1.474 +//------------------------------------------------------------------------------
   1.475 +// Provide simple way to to start global tracking, and to tear down tracking
   1.476 +// when done.  Note that construction and destruction of this object must be
   1.477 +// done when running in single threaded mode (before spawning a lot of threads
   1.478 +// for construction, and after shutting down all the threads for destruction).
   1.479 +
   1.480 +class AutoTracking {
   1.481 + public:
   1.482 +  AutoTracking() { ThreadData::StartTracking(true); }
   1.483 +
   1.484 +  ~AutoTracking() {
   1.485 +#ifndef NDEBUG  // Don't call these in a Release build: they just waste time.
   1.486 +    // The following should ONLY be called when in single threaded mode. It is
   1.487 +    // unsafe to do this cleanup if other threads are still active.
   1.488 +    // It is also very unnecessary, so I'm only doing this in debug to satisfy
   1.489 +    // purify (if we need to!).
   1.490 +    ThreadData::ShutdownSingleThreadedCleanup();
   1.491 +#endif
   1.492 +  }
   1.493 +
   1.494 + private:
   1.495 +  DISALLOW_COPY_AND_ASSIGN(AutoTracking);
   1.496 +};
   1.497 +
   1.498 +
   1.499 +}  // namespace tracked_objects
   1.500 +
   1.501 +#endif  // BASE_TRACKED_OBJECTS_H_

mercurial