ipc/chromium/src/base/tracked_objects.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #ifndef BASE_TRACKED_OBJECTS_H_
     6 #define BASE_TRACKED_OBJECTS_H_
     8 //------------------------------------------------------------------------------
     9 #include <map>
    10 #include <string>
    11 #include <vector>
    13 #include "base/lock.h"
    14 #include "base/message_loop.h"
    15 #include "base/thread_local_storage.h"
    16 #include "base/tracked.h"
    19 namespace tracked_objects {
    21 //------------------------------------------------------------------------------
    22 // For a specific thread, and a specific birth place, the collection of all
    23 // death info (with tallies for each death thread, to prevent access conflicts).
    24 class ThreadData;
    25 class BirthOnThread {
    26  public:
    27   explicit BirthOnThread(const Location& location);
    29   const Location location() const { return location_; }
    30   const ThreadData* birth_thread() const { return birth_thread_; }
    32  private:
    33   // File/lineno of birth.  This defines the essence of the type, as the context
    34   // of the birth (construction) often tell what the item is for.  This field
    35   // is const, and hence safe to access from any thread.
    36   const Location location_;
    38   // The thread that records births into this object.  Only this thread is
    39   // allowed to access birth_count_ (which changes over time).
    40   const ThreadData* birth_thread_;  // The thread this birth took place on.
    42   DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
    43 };
    45 //------------------------------------------------------------------------------
    46 // A class for accumulating counts of births (without bothering with a map<>).
    48 class Births: public BirthOnThread {
    49  public:
    50   explicit Births(const Location& location);
    52   int birth_count() const { return birth_count_; }
    54   // When we have a birth we update the count for this BirhPLace.
    55   void RecordBirth() { ++birth_count_; }
    57   // When a birthplace is changed (updated), we need to decrement the counter
    58   // for the old instance.
    59   void ForgetBirth() { --birth_count_; }  // We corrected a birth place.
    61  private:
    62   // The number of births on this thread for our location_.
    63   int birth_count_;
    65   DISALLOW_COPY_AND_ASSIGN(Births);
    66 };
    68 //------------------------------------------------------------------------------
    69 // Basic info summarizing multiple destructions of an object with a single
    70 // birthplace (fixed Location).  Used both on specific threads, and also used
    71 // in snapshots when integrating assembled data.
    73 class DeathData {
    74  public:
    75   // Default initializer.
    76   DeathData() : count_(0), square_duration_(0) {}
    78   // When deaths have not yet taken place, and we gather data from all the
    79   // threads, we create DeathData stats that tally the number of births without
    80   // a corrosponding death.
    81   explicit DeathData(int count) : count_(count), square_duration_(0) {}
    83   void RecordDeath(const base::TimeDelta& duration);
    85   // Metrics accessors.
    86   int count() const { return count_; }
    87   base::TimeDelta life_duration() const { return life_duration_; }
    88   int64_t square_duration() const { return square_duration_; }
    89   int AverageMsDuration() const;
    90   double StandardDeviation() const;
    92   // Accumulate metrics from other into this.
    93   void AddDeathData(const DeathData& other);
    95   // Simple print of internal state.
    96   void Write(std::string* output) const;
    98   void Clear();
   100  private:
   101   int count_;                // Number of destructions.
   102   base::TimeDelta life_duration_;    // Sum of all lifetime durations.
   103   int64_t square_duration_;  // Sum of squares in milliseconds.
   104 };
   106 //------------------------------------------------------------------------------
   107 // A temporary collection of data that can be sorted and summarized.  It is
   108 // gathered (carefully) from many threads.  Instances are held in arrays and
   109 // processed, filtered, and rendered.
   110 // The source of this data was collected on many threads, and is asynchronously
   111 // changing.  The data in this instance is not asynchronously changing.
   113 class Snapshot {
   114  public:
   115   // When snapshotting a full life cycle set (birth-to-death), use this:
   116   Snapshot(const BirthOnThread& birth_on_thread, const ThreadData& death_thread,
   117            const DeathData& death_data);
   119   // When snapshotting a birth, with no death yet, use this:
   120   Snapshot(const BirthOnThread& birth_on_thread, int count);
   123   const ThreadData* birth_thread() const { return birth_->birth_thread(); }
   124   const Location location() const { return birth_->location(); }
   125   const BirthOnThread& birth() const { return *birth_; }
   126   const ThreadData* death_thread() const {return death_thread_; }
   127   const DeathData& death_data() const { return death_data_; }
   128   const std::string DeathThreadName() const;
   130   int count() const { return death_data_.count(); }
   131   base::TimeDelta life_duration() const { return death_data_.life_duration(); }
   132   int64_t square_duration() const { return death_data_.square_duration(); }
   133   int AverageMsDuration() const { return death_data_.AverageMsDuration(); }
   135   void Write(std::string* output) const;
   137   void Add(const Snapshot& other);
   139  private:
   140   const BirthOnThread* birth_;  // Includes Location and birth_thread.
   141   const ThreadData* death_thread_;
   142   DeathData death_data_;
   143 };
   144 //------------------------------------------------------------------------------
   145 // DataCollector is a container class for Snapshot and BirthOnThread count
   146 // items.  It protects the gathering under locks, so that it could be called via
   147 // Posttask on any threads, such as all the target threads in parallel.
   149 class DataCollector {
   150  public:
   151   typedef std::vector<Snapshot> Collection;
   153   // Construct with a list of how many threads should contribute.  This helps us
   154   // determine (in the async case) when we are done with all contributions.
   155   DataCollector();
   157   // Add all stats from the indicated thread into our arrays.  This function is
   158   // mutex protected, and *could* be called from any threads (although current
   159   // implementation serialized calls to Append).
   160   void Append(const ThreadData& thread_data);
   162   // After the accumulation phase, the following access is to process data.
   163   Collection* collection();
   165   // After collection of death data is complete, we can add entries for all the
   166   // remaining living objects.
   167   void AddListOfLivingObjects();
   169  private:
   170   // This instance may be provided to several threads to contribute data.  The
   171   // following counter tracks how many more threads will contribute.  When it is
   172   // zero, then all asynchronous contributions are complete, and locked access
   173   // is no longer needed.
   174   int count_of_contributing_threads_;
   176   // The array that we collect data into.
   177   Collection collection_;
   179   // The total number of births recorded at each location for which we have not
   180   // seen a death count.
   181   typedef std::map<const BirthOnThread*, int> BirthCount;
   182   BirthCount global_birth_count_;
   184   Lock accumulation_lock_;  // Protects access during accumulation phase.
   186   DISALLOW_COPY_AND_ASSIGN(DataCollector);
   187 };
   189 //------------------------------------------------------------------------------
   190 // Aggregation contains summaries (totals and subtotals) of groups of Snapshot
   191 // instances to provide printing of these collections on a single line.
   193 class Aggregation: public DeathData {
   194  public:
   195   Aggregation() : birth_count_(0) {}
   197   void AddDeathSnapshot(const Snapshot& snapshot);
   198   void AddBirths(const Births& births);
   199   void AddBirth(const BirthOnThread& birth);
   200   void AddBirthPlace(const Location& location);
   201   void Write(std::string* output) const;
   202   void Clear();
   204  private:
   205   int birth_count_;
   206   std::map<std::string, int> birth_files_;
   207   std::map<Location, int> locations_;
   208   std::map<const ThreadData*, int> birth_threads_;
   209   DeathData death_data_;
   210   std::map<const ThreadData*, int> death_threads_;
   212   DISALLOW_COPY_AND_ASSIGN(Aggregation);
   213 };
   215 //------------------------------------------------------------------------------
   216 // Comparator does the comparison of Snapshot instances.  It is
   217 // used to order the instances in a vector.  It orders them into groups (for
   218 // aggregation), and can also order instances within the groups (for detailed
   219 // rendering of the instances).
   221 class Comparator {
   222  public:
   223   enum Selector {
   224     NIL = 0,
   225     BIRTH_THREAD = 1,
   226     DEATH_THREAD = 2,
   227     BIRTH_FILE = 4,
   228     BIRTH_FUNCTION = 8,
   229     BIRTH_LINE = 16,
   230     COUNT = 32,
   231     AVERAGE_DURATION = 64,
   232     TOTAL_DURATION = 128
   233   };
   235   explicit Comparator();
   237   // Reset the comparator to a NIL selector.  Reset() and recursively delete any
   238   // tiebreaker_ entries.  NOTE: We can't use a standard destructor, because
   239   // the sort algorithm makes copies of this object, and then deletes them,
   240   // which would cause problems (either we'd make expensive deep copies, or we'd
   241   // do more thna one delete on a tiebreaker_.
   242   void Clear();
   244   // The less() operator for sorting the array via std::sort().
   245   bool operator()(const Snapshot& left, const Snapshot& right) const;
   247   void Sort(DataCollector::Collection* collection) const;
   249   // Check to see if the items are sort equivalents (should be aggregated).
   250   bool Equivalent(const Snapshot& left, const Snapshot& right) const;
   252   // Check to see if all required fields are present in the given sample.
   253   bool Acceptable(const Snapshot& sample) const;
   255   // A comparator can be refined by specifying what to do if the selected basis
   256   // for comparison is insufficient to establish an ordering.  This call adds
   257   // the indicated attribute as the new "least significant" basis of comparison.
   258   void SetTiebreaker(Selector selector, const std::string required);
   260   // Indicate if this instance is set up to sort by the given Selector, thereby
   261   // putting that information in the SortGrouping, so it is not needed in each
   262   // printed line.
   263   bool IsGroupedBy(Selector selector) const;
   265   // Using the tiebreakers as set above, we mostly get an ordering, which
   266   // equivalent groups.  If those groups are displayed (rather than just being
   267   // aggregated, then the following is used to order them (within the group).
   268   void SetSubgroupTiebreaker(Selector selector);
   270   // Output a header line that can be used to indicated what items will be
   271   // collected in the group.  It lists all (potentially) tested attributes and
   272   // their values (in the sample item).
   273   bool WriteSortGrouping(const Snapshot& sample, std::string* output) const;
   275   // Output a sample, with SortGroup details not displayed.
   276   void WriteSnapshot(const Snapshot& sample, std::string* output) const;
   278  private:
   279   // The selector directs this instance to compare based on the specified
   280   // members of the tested elements.
   281   enum Selector selector_;
   283   // For filtering into acceptable and unacceptable snapshot instance, the
   284   // following is required to be a substring of the selector_ field.
   285   std::string required_;
   287   // If this instance can't decide on an ordering, we can consult a tie-breaker
   288   // which may have a different basis of comparison.
   289   Comparator* tiebreaker_;
   291   // We or together all the selectors we sort on (not counting sub-group
   292   // selectors), so that we can tell if we've decided to group on any given
   293   // criteria.
   294   int combined_selectors_;
   296   // Some tiebreakrs are for subgroup ordering, and not for basic ordering (in
   297   // preparation for aggregation).  The subgroup tiebreakers are not consulted
   298   // when deciding if two items are in equivalent groups.  This flag tells us
   299   // to ignore the tiebreaker when doing Equivalent() testing.
   300   bool use_tiebreaker_for_sort_only_;
   301 };
   304 //------------------------------------------------------------------------------
   305 // For each thread, we have a ThreadData that stores all tracking info generated
   306 // on this thread.  This prevents the need for locking as data accumulates.
   308 class ThreadData {
   309  public:
   310   typedef std::map<Location, Births*> BirthMap;
   311   typedef std::map<const Births*, DeathData> DeathMap;
   313   ThreadData();
   315   // Using Thread Local Store, find the current instance for collecting data.
   316   // If an instance does not exist, construct one (and remember it for use on
   317   // this thread.
   318   // If shutdown has already started, and we don't yet have an instance, then
   319   // return null.
   320   static ThreadData* current();
   322   // In this thread's data, find a place to record a new birth.
   323   Births* FindLifetime(const Location& location);
   325   // Find a place to record a death on this thread.
   326   void TallyADeath(const Births& lifetimes, const base::TimeDelta& duration);
   328   // (Thread safe) Get start of list of instances.
   329   static ThreadData* first();
   330   // Iterate through the null terminated list of instances.
   331   ThreadData* next() const { return next_; }
   333   MessageLoop* message_loop() const { return message_loop_; }
   334   const std::string ThreadName() const;
   336   // Using our lock, make a copy of the specified maps.  These calls may arrive
   337   // from non-local threads.
   338   void SnapshotBirthMap(BirthMap *output) const;
   339   void SnapshotDeathMap(DeathMap *output) const;
   341   static void RunOnAllThreads(void (*Func)());
   343   // Set internal status_ to either become ACTIVE, or later, to be SHUTDOWN,
   344   // based on argument being true or false respectively.
   345   // IF tracking is not compiled in, this function will return false.
   346   static bool StartTracking(bool status);
   347   static bool IsActive();
   349 #ifdef OS_WIN
   350   // WARNING: ONLY call this function when all MessageLoops are still intact for
   351   // all registered threads.  IF you call it later, you will crash.
   352   // Note: You don't need to call it at all, and you can wait till you are
   353   // single threaded (again) to do the cleanup via
   354   // ShutdownSingleThreadedCleanup().
   355   // Start the teardown (shutdown) process in a multi-thread mode by disabling
   356   // further additions to thread database on all threads.  First it makes a
   357   // local (locked) change to prevent any more threads from registering.  Then
   358   // it Posts a Task to all registered threads to be sure they are aware that no
   359   // more accumulation can take place.
   360   static void ShutdownMultiThreadTracking();
   361 #endif
   363   // WARNING: ONLY call this function when you are running single threaded
   364   // (again) and all message loops and threads have terminated.  Until that
   365   // point some threads may still attempt to write into our data structures.
   366   // Delete recursively all data structures, starting with the list of
   367   // ThreadData instances.
   368   static void ShutdownSingleThreadedCleanup();
   370  private:
   371   // Current allowable states of the tracking system.  The states always
   372   // proceed towards SHUTDOWN, and never go backwards.
   373   enum Status {
   374     UNINITIALIZED,
   375     ACTIVE,
   376     SHUTDOWN
   377   };
   379   // A class used to count down which is accessed by several threads.  This is
   380   // used to make sure RunOnAllThreads() actually runs a task on the expected
   381   // count of threads.
   382   class ThreadSafeDownCounter {
   383    public:
   384     // Constructor sets the count, once and for all.
   385     explicit ThreadSafeDownCounter(size_t count);
   387     // Decrement the count, and return true if we hit zero.  Also delete this
   388     // instance automatically when we hit zero.
   389     bool LastCaller();
   391    private:
   392     size_t remaining_count_;
   393     Lock lock_;  // protect access to remaining_count_.
   394   };
   396 #ifdef OS_WIN
   397   // A Task class that runs a static method supplied, and checks to see if this
   398   // is the last tasks instance (on last thread) that will run the method.
   399   // IF this is the last run, then the supplied event is signalled.
   400   class RunTheStatic : public Task {
   401    public:
   402     typedef void (*FunctionPointer)();
   403     RunTheStatic(FunctionPointer function,
   404                  HANDLE completion_handle,
   405                  ThreadSafeDownCounter* counter);
   406     // Run the supplied static method, and optionally set the event.
   407     void Run();
   409    private:
   410     FunctionPointer function_;
   411     HANDLE completion_handle_;
   412     // Make sure enough tasks are called before completion is signaled.
   413     ThreadSafeDownCounter* counter_;
   415     DISALLOW_COPY_AND_ASSIGN(RunTheStatic);
   416   };
   417 #endif
   419   // Each registered thread is called to set status_ to SHUTDOWN.
   420   // This is done redundantly on every registered thread because it is not
   421   // protected by a mutex.  Running on all threads guarantees we get the
   422   // notification into the memory cache of all possible threads.
   423   static void ShutdownDisablingFurtherTracking();
   425   // We use thread local store to identify which ThreadData to interact with.
   426   static TLSSlot tls_index_ ;
   428   // Link to the most recently created instance (starts a null terminated list).
   429   static ThreadData* first_;
   430   // Protection for access to first_.
   431   static Lock list_lock_;
   434   // We set status_ to SHUTDOWN when we shut down the tracking service. This
   435   // setting is redundantly established by all participating
   436   // threads so that we are *guaranteed* (without locking) that all threads
   437   // can "see" the status and avoid additional calls into the  service.
   438   static Status status_;
   440   // Link to next instance (null terminated list). Used to globally track all
   441   // registered instances (corresponds to all registered threads where we keep
   442   // data).
   443   ThreadData* next_;
   445   // The message loop where tasks needing to access this instance's private data
   446   // should be directed.  Since some threads have no message loop, some
   447   // instances have data that can't be (safely) modified externally.
   448   MessageLoop* message_loop_;
   450   // A map used on each thread to keep track of Births on this thread.
   451   // This map should only be accessed on the thread it was constructed on.
   452   // When a snapshot is needed, this structure can be locked in place for the
   453   // duration of the snapshotting activity.
   454   BirthMap birth_map_;
   456   // Similar to birth_map_, this records informations about death of tracked
   457   // instances (i.e., when a tracked instance was destroyed on this thread).
   458   DeathMap death_map_;
   460   // Lock to protect *some* access to BirthMap and DeathMap.  We only use
   461   // locking protection when we are growing the maps, or using an iterator.  We
   462   // only do writes to members from this thread, so the updates of values are
   463   // atomic.  Folks can read from other threads, and get (via races) new or old
   464   // data, but that is considered acceptable errors (mis-information).
   465   Lock lock_;
   467   DISALLOW_COPY_AND_ASSIGN(ThreadData);
   468 };
   471 //------------------------------------------------------------------------------
   472 // Provide simple way to to start global tracking, and to tear down tracking
   473 // when done.  Note that construction and destruction of this object must be
   474 // done when running in single threaded mode (before spawning a lot of threads
   475 // for construction, and after shutting down all the threads for destruction).
   477 class AutoTracking {
   478  public:
   479   AutoTracking() { ThreadData::StartTracking(true); }
   481   ~AutoTracking() {
   482 #ifndef NDEBUG  // Don't call these in a Release build: they just waste time.
   483     // The following should ONLY be called when in single threaded mode. It is
   484     // unsafe to do this cleanup if other threads are still active.
   485     // It is also very unnecessary, so I'm only doing this in debug to satisfy
   486     // purify (if we need to!).
   487     ThreadData::ShutdownSingleThreadedCleanup();
   488 #endif
   489   }
   491  private:
   492   DISALLOW_COPY_AND_ASSIGN(AutoTracking);
   493 };
   496 }  // namespace tracked_objects
   498 #endif  // BASE_TRACKED_OBJECTS_H_

mercurial