1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/tracked_objects.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,754 @@ 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 +#include "base/tracked_objects.h" 1.9 + 1.10 +#include <math.h> 1.11 + 1.12 +#include "base/string_util.h" 1.13 + 1.14 +using base::TimeDelta; 1.15 + 1.16 +namespace tracked_objects { 1.17 + 1.18 +// A TLS slot to the TrackRegistry for the current thread. 1.19 +// static 1.20 +TLSSlot ThreadData::tls_index_(base::LINKER_INITIALIZED); 1.21 + 1.22 +//------------------------------------------------------------------------------ 1.23 +// Death data tallies durations when a death takes place. 1.24 + 1.25 +void DeathData::RecordDeath(const TimeDelta& duration) { 1.26 + ++count_; 1.27 + life_duration_ += duration; 1.28 + int64_t milliseconds = duration.InMilliseconds(); 1.29 + square_duration_ += milliseconds * milliseconds; 1.30 +} 1.31 + 1.32 +int DeathData::AverageMsDuration() const { 1.33 + return static_cast<int>(life_duration_.InMilliseconds() / count_); 1.34 +} 1.35 + 1.36 +double DeathData::StandardDeviation() const { 1.37 + double average = AverageMsDuration(); 1.38 + double variance = static_cast<float>(square_duration_)/count_ 1.39 + - average * average; 1.40 + return sqrt(variance); 1.41 +} 1.42 + 1.43 + 1.44 +void DeathData::AddDeathData(const DeathData& other) { 1.45 + count_ += other.count_; 1.46 + life_duration_ += other.life_duration_; 1.47 + square_duration_ += other.square_duration_; 1.48 +} 1.49 + 1.50 +void DeathData::Write(std::string* output) const { 1.51 + if (!count_) 1.52 + return; 1.53 + if (1 == count_) 1.54 + StringAppendF(output, "(1)Life in %dms ", AverageMsDuration()); 1.55 + else 1.56 + StringAppendF(output, "(%d)Lives %dms/life ", count_, AverageMsDuration()); 1.57 +} 1.58 + 1.59 +void DeathData::Clear() { 1.60 + count_ = 0; 1.61 + life_duration_ = TimeDelta(); 1.62 + square_duration_ = 0; 1.63 +} 1.64 + 1.65 +//------------------------------------------------------------------------------ 1.66 + 1.67 +BirthOnThread::BirthOnThread(const Location& location) 1.68 + : location_(location), 1.69 + birth_thread_(ThreadData::current()) { } 1.70 + 1.71 +//------------------------------------------------------------------------------ 1.72 +Births::Births(const Location& location) 1.73 + : BirthOnThread(location), 1.74 + birth_count_(0) { } 1.75 + 1.76 +//------------------------------------------------------------------------------ 1.77 +// ThreadData maintains the central data for all births and death. 1.78 + 1.79 +// static 1.80 +ThreadData* ThreadData::first_ = NULL; 1.81 +// static 1.82 +Lock ThreadData::list_lock_; 1.83 + 1.84 +// static 1.85 +ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 1.86 + 1.87 +ThreadData::ThreadData() : next_(NULL), message_loop_(MessageLoop::current()) {} 1.88 + 1.89 +// static 1.90 +ThreadData* ThreadData::current() { 1.91 + if (!tls_index_.initialized()) 1.92 + return NULL; 1.93 + 1.94 + ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get()); 1.95 + if (!registry) { 1.96 + // We have to create a new registry for ThreadData. 1.97 + bool too_late_to_create = false; 1.98 + { 1.99 + registry = new ThreadData; 1.100 + AutoLock lock(list_lock_); 1.101 + // Use lock to insure we have most recent status. 1.102 + if (!IsActive()) { 1.103 + too_late_to_create = true; 1.104 + } else { 1.105 + // Use lock to insert into list. 1.106 + registry->next_ = first_; 1.107 + first_ = registry; 1.108 + } 1.109 + } // Release lock. 1.110 + if (too_late_to_create) { 1.111 + delete registry; 1.112 + registry = NULL; 1.113 + } else { 1.114 + tls_index_.Set(registry); 1.115 + } 1.116 + } 1.117 + return registry; 1.118 +} 1.119 + 1.120 +Births* ThreadData::FindLifetime(const Location& location) { 1.121 + if (!message_loop_) // In case message loop wasn't yet around... 1.122 + message_loop_ = MessageLoop::current(); // Find it now. 1.123 + 1.124 + BirthMap::iterator it = birth_map_.find(location); 1.125 + if (it != birth_map_.end()) 1.126 + return it->second; 1.127 + Births* tracker = new Births(location); 1.128 + 1.129 + // Lock since the map may get relocated now, and other threads sometimes 1.130 + // snapshot it (but they lock before copying it). 1.131 + AutoLock lock(lock_); 1.132 + birth_map_[location] = tracker; 1.133 + return tracker; 1.134 +} 1.135 + 1.136 +void ThreadData::TallyADeath(const Births& lifetimes, 1.137 + const TimeDelta& duration) { 1.138 + if (!message_loop_) // In case message loop wasn't yet around... 1.139 + message_loop_ = MessageLoop::current(); // Find it now. 1.140 + 1.141 + DeathMap::iterator it = death_map_.find(&lifetimes); 1.142 + if (it != death_map_.end()) { 1.143 + it->second.RecordDeath(duration); 1.144 + return; 1.145 + } 1.146 + 1.147 + AutoLock lock(lock_); // Lock since the map may get relocated now. 1.148 + death_map_[&lifetimes].RecordDeath(duration); 1.149 +} 1.150 + 1.151 +// static 1.152 +ThreadData* ThreadData::first() { 1.153 + AutoLock lock(list_lock_); 1.154 + return first_; 1.155 +} 1.156 + 1.157 +const std::string ThreadData::ThreadName() const { 1.158 + if (message_loop_) 1.159 + return message_loop_->thread_name(); 1.160 + return "ThreadWithoutMessageLoop"; 1.161 +} 1.162 + 1.163 +// This may be called from another thread. 1.164 +void ThreadData::SnapshotBirthMap(BirthMap *output) const { 1.165 + AutoLock lock(*const_cast<Lock*>(&lock_)); 1.166 + for (BirthMap::const_iterator it = birth_map_.begin(); 1.167 + it != birth_map_.end(); ++it) 1.168 + (*output)[it->first] = it->second; 1.169 +} 1.170 + 1.171 +// This may be called from another thread. 1.172 +void ThreadData::SnapshotDeathMap(DeathMap *output) const { 1.173 + AutoLock lock(*const_cast<Lock*>(&lock_)); 1.174 + for (DeathMap::const_iterator it = death_map_.begin(); 1.175 + it != death_map_.end(); ++it) 1.176 + (*output)[it->first] = it->second; 1.177 +} 1.178 + 1.179 +#ifdef OS_WIN 1.180 +void ThreadData::RunOnAllThreads(void (*function)()) { 1.181 + ThreadData* list = first(); // Get existing list. 1.182 + 1.183 + std::vector<MessageLoop*> message_loops; 1.184 + for (ThreadData* it = list; it; it = it->next()) { 1.185 + if (current() != it && it->message_loop()) 1.186 + message_loops.push_back(it->message_loop()); 1.187 + } 1.188 + 1.189 + ThreadSafeDownCounter* counter = 1.190 + new ThreadSafeDownCounter(message_loops.size() + 1); // Extra one for us! 1.191 + 1.192 + HANDLE completion_handle = CreateEvent(NULL, false, false, NULL); 1.193 + // Tell all other threads to run. 1.194 + for (size_t i = 0; i < message_loops.size(); ++i) 1.195 + message_loops[i]->PostTask(FROM_HERE, 1.196 + new RunTheStatic(function, completion_handle, counter)); 1.197 + 1.198 + // Also run Task on our thread. 1.199 + RunTheStatic local_task(function, completion_handle, counter); 1.200 + local_task.Run(); 1.201 + 1.202 + WaitForSingleObject(completion_handle, INFINITE); 1.203 + int ret_val = CloseHandle(completion_handle); 1.204 + DCHECK(ret_val); 1.205 +} 1.206 +#endif 1.207 + 1.208 +// static 1.209 +bool ThreadData::StartTracking(bool status) { 1.210 +#ifndef TRACK_ALL_TASK_OBJECTS 1.211 + return false; // Not compiled in. 1.212 +#else 1.213 + if (!status) { 1.214 + AutoLock lock(list_lock_); 1.215 + DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); 1.216 + status_ = SHUTDOWN; 1.217 + return true; 1.218 + } 1.219 + AutoLock lock(list_lock_); 1.220 + DCHECK(status_ == UNINITIALIZED); 1.221 + CHECK(tls_index_.Initialize(NULL)); 1.222 + status_ = ACTIVE; 1.223 + return true; 1.224 +#endif 1.225 +} 1.226 + 1.227 +// static 1.228 +bool ThreadData::IsActive() { 1.229 + return status_ == ACTIVE; 1.230 +} 1.231 + 1.232 +#ifdef OS_WIN 1.233 +// static 1.234 +void ThreadData::ShutdownMultiThreadTracking() { 1.235 + // Using lock, guarantee that no new ThreadData instances will be created. 1.236 + if (!StartTracking(false)) 1.237 + return; 1.238 + 1.239 + RunOnAllThreads(ShutdownDisablingFurtherTracking); 1.240 + 1.241 + // Now the *only* threads that might change the database are the threads with 1.242 + // no messages loops. They might still be adding data to their birth records, 1.243 + // but since no objects are deleted on those threads, there will be no further 1.244 + // access to to cross-thread data. 1.245 + // We could do a cleanup on all threads except for the ones without 1.246 + // MessageLoops, but we won't bother doing cleanup (destruction of data) yet. 1.247 + return; 1.248 +} 1.249 +#endif 1.250 + 1.251 +// static 1.252 +void ThreadData::ShutdownSingleThreadedCleanup() { 1.253 + // We must be single threaded... but be careful anyway. 1.254 + if (!StartTracking(false)) 1.255 + return; 1.256 + ThreadData* thread_data_list; 1.257 + { 1.258 + AutoLock lock(list_lock_); 1.259 + thread_data_list = first_; 1.260 + first_ = NULL; 1.261 + } 1.262 + 1.263 + while (thread_data_list) { 1.264 + ThreadData* next_thread_data = thread_data_list; 1.265 + thread_data_list = thread_data_list->next(); 1.266 + 1.267 + for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); 1.268 + next_thread_data->birth_map_.end() != it; ++it) 1.269 + delete it->second; // Delete the Birth Records. 1.270 + next_thread_data->birth_map_.clear(); 1.271 + next_thread_data->death_map_.clear(); 1.272 + delete next_thread_data; // Includes all Death Records. 1.273 + } 1.274 + 1.275 + CHECK(tls_index_.initialized()); 1.276 + tls_index_.Free(); 1.277 + DCHECK(!tls_index_.initialized()); 1.278 + status_ = UNINITIALIZED; 1.279 +} 1.280 + 1.281 +// static 1.282 +void ThreadData::ShutdownDisablingFurtherTracking() { 1.283 + // Redundantly set status SHUTDOWN on this thread. 1.284 + if (!StartTracking(false)) 1.285 + return; 1.286 +} 1.287 + 1.288 + 1.289 +//------------------------------------------------------------------------------ 1.290 + 1.291 +ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count) 1.292 + : remaining_count_(count) { 1.293 + DCHECK(remaining_count_ > 0); 1.294 +} 1.295 + 1.296 +bool ThreadData::ThreadSafeDownCounter::LastCaller() { 1.297 + { 1.298 + AutoLock lock(lock_); 1.299 + if (--remaining_count_) 1.300 + return false; 1.301 + } // Release lock, so we can delete everything in this instance. 1.302 + delete this; 1.303 + return true; 1.304 +} 1.305 + 1.306 +//------------------------------------------------------------------------------ 1.307 +#ifdef OS_WIN 1.308 +ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function, 1.309 + HANDLE completion_handle, 1.310 + ThreadSafeDownCounter* counter) 1.311 + : function_(function), 1.312 + completion_handle_(completion_handle), 1.313 + counter_(counter) { 1.314 +} 1.315 + 1.316 +void ThreadData::RunTheStatic::Run() { 1.317 + function_(); 1.318 + if (counter_->LastCaller()) 1.319 + SetEvent(completion_handle_); 1.320 +} 1.321 +#endif 1.322 + 1.323 +//------------------------------------------------------------------------------ 1.324 +// Individual 3-tuple of birth (place and thread) along with death thread, and 1.325 +// the accumulated stats for instances (DeathData). 1.326 + 1.327 +Snapshot::Snapshot(const BirthOnThread& birth_on_thread, 1.328 + const ThreadData& death_thread, 1.329 + const DeathData& death_data) 1.330 + : birth_(&birth_on_thread), 1.331 + death_thread_(&death_thread), 1.332 + death_data_(death_data) { 1.333 +} 1.334 + 1.335 +Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count) 1.336 + : birth_(&birth_on_thread), 1.337 + death_thread_(NULL), 1.338 + death_data_(DeathData(count)) { 1.339 +} 1.340 + 1.341 +const std::string Snapshot::DeathThreadName() const { 1.342 + if (death_thread_) 1.343 + return death_thread_->ThreadName(); 1.344 + return "Still_Alive"; 1.345 +} 1.346 + 1.347 +void Snapshot::Write(std::string* output) const { 1.348 + death_data_.Write(output); 1.349 + StringAppendF(output, "%s->%s ", 1.350 + birth_->birth_thread()->ThreadName().c_str(), 1.351 + death_thread_->ThreadName().c_str()); 1.352 + birth_->location().Write(true, true, output); 1.353 +} 1.354 + 1.355 +void Snapshot::Add(const Snapshot& other) { 1.356 + death_data_.AddDeathData(other.death_data_); 1.357 +} 1.358 + 1.359 +//------------------------------------------------------------------------------ 1.360 +// DataCollector 1.361 + 1.362 +DataCollector::DataCollector() { 1.363 + DCHECK(ThreadData::IsActive()); 1.364 + 1.365 + ThreadData* my_list = ThreadData::current()->first(); 1.366 + 1.367 + count_of_contributing_threads_ = 0; 1.368 + for (ThreadData* thread_data = my_list; 1.369 + thread_data; 1.370 + thread_data = thread_data->next()) { 1.371 + ++count_of_contributing_threads_; 1.372 + } 1.373 + 1.374 + // Gather data serially. A different constructor could be used to do in 1.375 + // parallel, and then invoke an OnCompletion task. 1.376 + for (ThreadData* thread_data = my_list; 1.377 + thread_data; 1.378 + thread_data = thread_data->next()) { 1.379 + Append(*thread_data); 1.380 + } 1.381 +} 1.382 + 1.383 +void DataCollector::Append(const ThreadData& thread_data) { 1.384 + // Get copy of data (which is done under ThreadData's lock). 1.385 + ThreadData::BirthMap birth_map; 1.386 + thread_data.SnapshotBirthMap(&birth_map); 1.387 + ThreadData::DeathMap death_map; 1.388 + thread_data.SnapshotDeathMap(&death_map); 1.389 + 1.390 + // Use our lock to protect our accumulation activity. 1.391 + AutoLock lock(accumulation_lock_); 1.392 + 1.393 + DCHECK(count_of_contributing_threads_); 1.394 + 1.395 + for (ThreadData::DeathMap::const_iterator it = death_map.begin(); 1.396 + it != death_map.end(); ++it) { 1.397 + collection_.push_back(Snapshot(*it->first, thread_data, it->second)); 1.398 + global_birth_count_[it->first] -= it->first->birth_count(); 1.399 + } 1.400 + 1.401 + for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); 1.402 + it != birth_map.end(); ++it) { 1.403 + global_birth_count_[it->second] += it->second->birth_count(); 1.404 + } 1.405 + 1.406 + --count_of_contributing_threads_; 1.407 +} 1.408 + 1.409 +DataCollector::Collection* DataCollector::collection() { 1.410 + DCHECK(!count_of_contributing_threads_); 1.411 + return &collection_; 1.412 +} 1.413 + 1.414 +void DataCollector::AddListOfLivingObjects() { 1.415 + DCHECK(!count_of_contributing_threads_); 1.416 + for (BirthCount::iterator it = global_birth_count_.begin(); 1.417 + it != global_birth_count_.end(); ++it) { 1.418 + if (it->second > 0) 1.419 + collection_.push_back(Snapshot(*it->first, it->second)); 1.420 + } 1.421 +} 1.422 + 1.423 +//------------------------------------------------------------------------------ 1.424 +// Aggregation 1.425 + 1.426 +void Aggregation::AddDeathSnapshot(const Snapshot& snapshot) { 1.427 + AddBirth(snapshot.birth()); 1.428 + death_threads_[snapshot.death_thread()]++; 1.429 + AddDeathData(snapshot.death_data()); 1.430 +} 1.431 + 1.432 +void Aggregation::AddBirths(const Births& births) { 1.433 + AddBirth(births); 1.434 + birth_count_ += births.birth_count(); 1.435 +} 1.436 +void Aggregation::AddBirth(const BirthOnThread& birth) { 1.437 + AddBirthPlace(birth.location()); 1.438 + birth_threads_[birth.birth_thread()]++; 1.439 +} 1.440 + 1.441 +void Aggregation::AddBirthPlace(const Location& location) { 1.442 + locations_[location]++; 1.443 + birth_files_[location.file_name()]++; 1.444 +} 1.445 + 1.446 +void Aggregation::Write(std::string* output) const { 1.447 + if (locations_.size() == 1) { 1.448 + locations_.begin()->first.Write(true, true, output); 1.449 + } else { 1.450 + StringAppendF(output, "%d Locations. ", locations_.size()); 1.451 + if (birth_files_.size() > 1) 1.452 + StringAppendF(output, "%d Files. ", birth_files_.size()); 1.453 + else 1.454 + StringAppendF(output, "All born in %s. ", 1.455 + birth_files_.begin()->first.c_str()); 1.456 + } 1.457 + 1.458 + if (birth_threads_.size() > 1) 1.459 + StringAppendF(output, "%d BirthingThreads. ", birth_threads_.size()); 1.460 + else 1.461 + StringAppendF(output, "All born on %s. ", 1.462 + birth_threads_.begin()->first->ThreadName().c_str()); 1.463 + 1.464 + if (death_threads_.size() > 1) { 1.465 + StringAppendF(output, "%d DeathThreads. ", death_threads_.size()); 1.466 + } else { 1.467 + if (death_threads_.begin()->first) 1.468 + StringAppendF(output, "All deleted on %s. ", 1.469 + death_threads_.begin()->first->ThreadName().c_str()); 1.470 + else 1.471 + output->append("All these objects are still alive."); 1.472 + } 1.473 + 1.474 + if (birth_count_ > 1) 1.475 + StringAppendF(output, "Births=%d ", birth_count_); 1.476 + 1.477 + DeathData::Write(output); 1.478 +} 1.479 + 1.480 +void Aggregation::Clear() { 1.481 + birth_count_ = 0; 1.482 + birth_files_.clear(); 1.483 + locations_.clear(); 1.484 + birth_threads_.clear(); 1.485 + DeathData::Clear(); 1.486 + death_threads_.clear(); 1.487 +} 1.488 + 1.489 +//------------------------------------------------------------------------------ 1.490 +// Comparison object for sorting. 1.491 + 1.492 +Comparator::Comparator() 1.493 + : selector_(NIL), 1.494 + tiebreaker_(NULL), 1.495 + combined_selectors_(0), 1.496 + use_tiebreaker_for_sort_only_(false) {} 1.497 + 1.498 +void Comparator::Clear() { 1.499 + if (tiebreaker_) { 1.500 + tiebreaker_->Clear(); 1.501 + delete tiebreaker_; 1.502 + tiebreaker_ = NULL; 1.503 + } 1.504 + use_tiebreaker_for_sort_only_ = false; 1.505 + selector_ = NIL; 1.506 +} 1.507 + 1.508 +void Comparator::Sort(DataCollector::Collection* collection) const { 1.509 + std::sort(collection->begin(), collection->end(), *this); 1.510 +} 1.511 + 1.512 + 1.513 +bool Comparator::operator()(const Snapshot& left, 1.514 + const Snapshot& right) const { 1.515 + switch (selector_) { 1.516 + case BIRTH_THREAD: 1.517 + if (left.birth_thread() != right.birth_thread() && 1.518 + left.birth_thread()->ThreadName() != 1.519 + right.birth_thread()->ThreadName()) 1.520 + return left.birth_thread()->ThreadName() < 1.521 + right.birth_thread()->ThreadName(); 1.522 + break; 1.523 + 1.524 + case DEATH_THREAD: 1.525 + if (left.death_thread() != right.death_thread() && 1.526 + left.DeathThreadName() != 1.527 + right.DeathThreadName()) { 1.528 + if (!left.death_thread()) 1.529 + return true; 1.530 + if (!right.death_thread()) 1.531 + return false; 1.532 + return left.DeathThreadName() < 1.533 + right.DeathThreadName(); 1.534 + } 1.535 + break; 1.536 + 1.537 + case BIRTH_FILE: 1.538 + if (left.location().file_name() != right.location().file_name()) { 1.539 + int comp = strcmp(left.location().file_name(), 1.540 + right.location().file_name()); 1.541 + if (comp) 1.542 + return 0 > comp; 1.543 + } 1.544 + break; 1.545 + 1.546 + case BIRTH_FUNCTION: 1.547 + if (left.location().function_name() != right.location().function_name()) { 1.548 + int comp = strcmp(left.location().function_name(), 1.549 + right.location().function_name()); 1.550 + if (comp) 1.551 + return 0 > comp; 1.552 + } 1.553 + break; 1.554 + 1.555 + case BIRTH_LINE: 1.556 + if (left.location().line_number() != right.location().line_number()) 1.557 + return left.location().line_number() < 1.558 + right.location().line_number(); 1.559 + break; 1.560 + 1.561 + case COUNT: 1.562 + if (left.count() != right.count()) 1.563 + return left.count() > right.count(); // Sort large at front of vector. 1.564 + break; 1.565 + 1.566 + case AVERAGE_DURATION: 1.567 + if (left.AverageMsDuration() != right.AverageMsDuration()) 1.568 + return left.AverageMsDuration() > right.AverageMsDuration(); 1.569 + break; 1.570 + 1.571 + default: 1.572 + break; 1.573 + } 1.574 + if (tiebreaker_) 1.575 + return tiebreaker_->operator()(left, right); 1.576 + return false; 1.577 +} 1.578 + 1.579 +bool Comparator::Equivalent(const Snapshot& left, 1.580 + const Snapshot& right) const { 1.581 + switch (selector_) { 1.582 + case BIRTH_THREAD: 1.583 + if (left.birth_thread() != right.birth_thread() && 1.584 + left.birth_thread()->ThreadName() != 1.585 + right.birth_thread()->ThreadName()) 1.586 + return false; 1.587 + break; 1.588 + 1.589 + case DEATH_THREAD: 1.590 + if (left.death_thread() != right.death_thread() && 1.591 + left.DeathThreadName() != right.DeathThreadName()) 1.592 + return false; 1.593 + break; 1.594 + 1.595 + case BIRTH_FILE: 1.596 + if (left.location().file_name() != right.location().file_name()) { 1.597 + int comp = strcmp(left.location().file_name(), 1.598 + right.location().file_name()); 1.599 + if (comp) 1.600 + return false; 1.601 + } 1.602 + break; 1.603 + 1.604 + case BIRTH_FUNCTION: 1.605 + if (left.location().function_name() != right.location().function_name()) { 1.606 + int comp = strcmp(left.location().function_name(), 1.607 + right.location().function_name()); 1.608 + if (comp) 1.609 + return false; 1.610 + } 1.611 + break; 1.612 + 1.613 + case COUNT: 1.614 + if (left.count() != right.count()) 1.615 + return false; 1.616 + break; 1.617 + 1.618 + case AVERAGE_DURATION: 1.619 + if (left.life_duration() != right.life_duration()) 1.620 + return false; 1.621 + break; 1.622 + 1.623 + default: 1.624 + break; 1.625 + } 1.626 + if (tiebreaker_ && !use_tiebreaker_for_sort_only_) 1.627 + return tiebreaker_->Equivalent(left, right); 1.628 + return true; 1.629 +} 1.630 + 1.631 +bool Comparator::Acceptable(const Snapshot& sample) const { 1.632 + if (required_.size()) { 1.633 + switch (selector_) { 1.634 + case BIRTH_THREAD: 1.635 + if (sample.birth_thread()->ThreadName().find(required_) == 1.636 + std::string::npos) 1.637 + return false; 1.638 + break; 1.639 + 1.640 + case DEATH_THREAD: 1.641 + if (sample.DeathThreadName().find(required_) == std::string::npos) 1.642 + return false; 1.643 + break; 1.644 + 1.645 + case BIRTH_FILE: 1.646 + if (!strstr(sample.location().file_name(), required_.c_str())) 1.647 + return false; 1.648 + break; 1.649 + 1.650 + case BIRTH_FUNCTION: 1.651 + if (!strstr(sample.location().function_name(), required_.c_str())) 1.652 + return false; 1.653 + break; 1.654 + 1.655 + default: 1.656 + break; 1.657 + } 1.658 + } 1.659 + if (tiebreaker_ && !use_tiebreaker_for_sort_only_) 1.660 + return tiebreaker_->Acceptable(sample); 1.661 + return true; 1.662 +} 1.663 + 1.664 +void Comparator::SetTiebreaker(Selector selector, const std::string required) { 1.665 + if (selector == selector_ || NIL == selector) 1.666 + return; 1.667 + combined_selectors_ |= selector; 1.668 + if (NIL == selector_) { 1.669 + selector_ = selector; 1.670 + if (required.size()) 1.671 + required_ = required; 1.672 + return; 1.673 + } 1.674 + if (tiebreaker_) { 1.675 + if (use_tiebreaker_for_sort_only_) { 1.676 + Comparator* temp = new Comparator; 1.677 + temp->tiebreaker_ = tiebreaker_; 1.678 + tiebreaker_ = temp; 1.679 + } 1.680 + } else { 1.681 + tiebreaker_ = new Comparator; 1.682 + DCHECK(!use_tiebreaker_for_sort_only_); 1.683 + } 1.684 + tiebreaker_->SetTiebreaker(selector, required); 1.685 +} 1.686 + 1.687 +bool Comparator::IsGroupedBy(Selector selector) const { 1.688 + return 0 != (selector & combined_selectors_); 1.689 +} 1.690 + 1.691 +void Comparator::SetSubgroupTiebreaker(Selector selector) { 1.692 + if (selector == selector_ || NIL == selector) 1.693 + return; 1.694 + if (!tiebreaker_) { 1.695 + use_tiebreaker_for_sort_only_ = true; 1.696 + tiebreaker_ = new Comparator; 1.697 + tiebreaker_->SetTiebreaker(selector, ""); 1.698 + } else { 1.699 + tiebreaker_->SetSubgroupTiebreaker(selector); 1.700 + } 1.701 +} 1.702 + 1.703 +bool Comparator::WriteSortGrouping(const Snapshot& sample, 1.704 + std::string* output) const { 1.705 + bool wrote_data = false; 1.706 + switch (selector_) { 1.707 + case BIRTH_THREAD: 1.708 + StringAppendF(output, "All new on %s ", 1.709 + sample.birth_thread()->ThreadName().c_str()); 1.710 + wrote_data = true; 1.711 + break; 1.712 + 1.713 + case DEATH_THREAD: 1.714 + if (sample.death_thread()) 1.715 + StringAppendF(output, "All deleted on %s ", 1.716 + sample.DeathThreadName().c_str()); 1.717 + else 1.718 + output->append("All still alive "); 1.719 + wrote_data = true; 1.720 + break; 1.721 + 1.722 + case BIRTH_FILE: 1.723 + StringAppendF(output, "All born in %s ", 1.724 + sample.location().file_name()); 1.725 + break; 1.726 + 1.727 + case BIRTH_FUNCTION: 1.728 + output->append("All born in "); 1.729 + sample.location().WriteFunctionName(output); 1.730 + output->push_back(' '); 1.731 + break; 1.732 + 1.733 + default: 1.734 + break; 1.735 + } 1.736 + if (tiebreaker_ && !use_tiebreaker_for_sort_only_) { 1.737 + wrote_data |= tiebreaker_->WriteSortGrouping(sample, output); 1.738 + } 1.739 + return wrote_data; 1.740 +} 1.741 + 1.742 +void Comparator::WriteSnapshot(const Snapshot& sample, 1.743 + std::string* output) const { 1.744 + sample.death_data().Write(output); 1.745 + if (!(combined_selectors_ & BIRTH_THREAD) || 1.746 + !(combined_selectors_ & DEATH_THREAD)) 1.747 + StringAppendF(output, "%s->%s ", 1.748 + (combined_selectors_ & BIRTH_THREAD) ? "*" : 1.749 + sample.birth().birth_thread()->ThreadName().c_str(), 1.750 + (combined_selectors_ & DEATH_THREAD) ? "*" : 1.751 + sample.DeathThreadName().c_str()); 1.752 + sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), 1.753 + !(combined_selectors_ & BIRTH_FUNCTION), 1.754 + output); 1.755 +} 1.756 + 1.757 +} // namespace tracked_objects