ipc/chromium/src/base/tracked_objects.cc

changeset 0
6474c204b198
     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

mercurial