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_