ipc/chromium/src/base/tracked_objects.cc

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.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/tracked_objects.h"
michael@0 6
michael@0 7 #include <math.h>
michael@0 8
michael@0 9 #include "base/string_util.h"
michael@0 10
michael@0 11 using base::TimeDelta;
michael@0 12
michael@0 13 namespace tracked_objects {
michael@0 14
michael@0 15 // A TLS slot to the TrackRegistry for the current thread.
michael@0 16 // static
michael@0 17 TLSSlot ThreadData::tls_index_(base::LINKER_INITIALIZED);
michael@0 18
michael@0 19 //------------------------------------------------------------------------------
michael@0 20 // Death data tallies durations when a death takes place.
michael@0 21
michael@0 22 void DeathData::RecordDeath(const TimeDelta& duration) {
michael@0 23 ++count_;
michael@0 24 life_duration_ += duration;
michael@0 25 int64_t milliseconds = duration.InMilliseconds();
michael@0 26 square_duration_ += milliseconds * milliseconds;
michael@0 27 }
michael@0 28
michael@0 29 int DeathData::AverageMsDuration() const {
michael@0 30 return static_cast<int>(life_duration_.InMilliseconds() / count_);
michael@0 31 }
michael@0 32
michael@0 33 double DeathData::StandardDeviation() const {
michael@0 34 double average = AverageMsDuration();
michael@0 35 double variance = static_cast<float>(square_duration_)/count_
michael@0 36 - average * average;
michael@0 37 return sqrt(variance);
michael@0 38 }
michael@0 39
michael@0 40
michael@0 41 void DeathData::AddDeathData(const DeathData& other) {
michael@0 42 count_ += other.count_;
michael@0 43 life_duration_ += other.life_duration_;
michael@0 44 square_duration_ += other.square_duration_;
michael@0 45 }
michael@0 46
michael@0 47 void DeathData::Write(std::string* output) const {
michael@0 48 if (!count_)
michael@0 49 return;
michael@0 50 if (1 == count_)
michael@0 51 StringAppendF(output, "(1)Life in %dms ", AverageMsDuration());
michael@0 52 else
michael@0 53 StringAppendF(output, "(%d)Lives %dms/life ", count_, AverageMsDuration());
michael@0 54 }
michael@0 55
michael@0 56 void DeathData::Clear() {
michael@0 57 count_ = 0;
michael@0 58 life_duration_ = TimeDelta();
michael@0 59 square_duration_ = 0;
michael@0 60 }
michael@0 61
michael@0 62 //------------------------------------------------------------------------------
michael@0 63
michael@0 64 BirthOnThread::BirthOnThread(const Location& location)
michael@0 65 : location_(location),
michael@0 66 birth_thread_(ThreadData::current()) { }
michael@0 67
michael@0 68 //------------------------------------------------------------------------------
michael@0 69 Births::Births(const Location& location)
michael@0 70 : BirthOnThread(location),
michael@0 71 birth_count_(0) { }
michael@0 72
michael@0 73 //------------------------------------------------------------------------------
michael@0 74 // ThreadData maintains the central data for all births and death.
michael@0 75
michael@0 76 // static
michael@0 77 ThreadData* ThreadData::first_ = NULL;
michael@0 78 // static
michael@0 79 Lock ThreadData::list_lock_;
michael@0 80
michael@0 81 // static
michael@0 82 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
michael@0 83
michael@0 84 ThreadData::ThreadData() : next_(NULL), message_loop_(MessageLoop::current()) {}
michael@0 85
michael@0 86 // static
michael@0 87 ThreadData* ThreadData::current() {
michael@0 88 if (!tls_index_.initialized())
michael@0 89 return NULL;
michael@0 90
michael@0 91 ThreadData* registry = static_cast<ThreadData*>(tls_index_.Get());
michael@0 92 if (!registry) {
michael@0 93 // We have to create a new registry for ThreadData.
michael@0 94 bool too_late_to_create = false;
michael@0 95 {
michael@0 96 registry = new ThreadData;
michael@0 97 AutoLock lock(list_lock_);
michael@0 98 // Use lock to insure we have most recent status.
michael@0 99 if (!IsActive()) {
michael@0 100 too_late_to_create = true;
michael@0 101 } else {
michael@0 102 // Use lock to insert into list.
michael@0 103 registry->next_ = first_;
michael@0 104 first_ = registry;
michael@0 105 }
michael@0 106 } // Release lock.
michael@0 107 if (too_late_to_create) {
michael@0 108 delete registry;
michael@0 109 registry = NULL;
michael@0 110 } else {
michael@0 111 tls_index_.Set(registry);
michael@0 112 }
michael@0 113 }
michael@0 114 return registry;
michael@0 115 }
michael@0 116
michael@0 117 Births* ThreadData::FindLifetime(const Location& location) {
michael@0 118 if (!message_loop_) // In case message loop wasn't yet around...
michael@0 119 message_loop_ = MessageLoop::current(); // Find it now.
michael@0 120
michael@0 121 BirthMap::iterator it = birth_map_.find(location);
michael@0 122 if (it != birth_map_.end())
michael@0 123 return it->second;
michael@0 124 Births* tracker = new Births(location);
michael@0 125
michael@0 126 // Lock since the map may get relocated now, and other threads sometimes
michael@0 127 // snapshot it (but they lock before copying it).
michael@0 128 AutoLock lock(lock_);
michael@0 129 birth_map_[location] = tracker;
michael@0 130 return tracker;
michael@0 131 }
michael@0 132
michael@0 133 void ThreadData::TallyADeath(const Births& lifetimes,
michael@0 134 const TimeDelta& duration) {
michael@0 135 if (!message_loop_) // In case message loop wasn't yet around...
michael@0 136 message_loop_ = MessageLoop::current(); // Find it now.
michael@0 137
michael@0 138 DeathMap::iterator it = death_map_.find(&lifetimes);
michael@0 139 if (it != death_map_.end()) {
michael@0 140 it->second.RecordDeath(duration);
michael@0 141 return;
michael@0 142 }
michael@0 143
michael@0 144 AutoLock lock(lock_); // Lock since the map may get relocated now.
michael@0 145 death_map_[&lifetimes].RecordDeath(duration);
michael@0 146 }
michael@0 147
michael@0 148 // static
michael@0 149 ThreadData* ThreadData::first() {
michael@0 150 AutoLock lock(list_lock_);
michael@0 151 return first_;
michael@0 152 }
michael@0 153
michael@0 154 const std::string ThreadData::ThreadName() const {
michael@0 155 if (message_loop_)
michael@0 156 return message_loop_->thread_name();
michael@0 157 return "ThreadWithoutMessageLoop";
michael@0 158 }
michael@0 159
michael@0 160 // This may be called from another thread.
michael@0 161 void ThreadData::SnapshotBirthMap(BirthMap *output) const {
michael@0 162 AutoLock lock(*const_cast<Lock*>(&lock_));
michael@0 163 for (BirthMap::const_iterator it = birth_map_.begin();
michael@0 164 it != birth_map_.end(); ++it)
michael@0 165 (*output)[it->first] = it->second;
michael@0 166 }
michael@0 167
michael@0 168 // This may be called from another thread.
michael@0 169 void ThreadData::SnapshotDeathMap(DeathMap *output) const {
michael@0 170 AutoLock lock(*const_cast<Lock*>(&lock_));
michael@0 171 for (DeathMap::const_iterator it = death_map_.begin();
michael@0 172 it != death_map_.end(); ++it)
michael@0 173 (*output)[it->first] = it->second;
michael@0 174 }
michael@0 175
michael@0 176 #ifdef OS_WIN
michael@0 177 void ThreadData::RunOnAllThreads(void (*function)()) {
michael@0 178 ThreadData* list = first(); // Get existing list.
michael@0 179
michael@0 180 std::vector<MessageLoop*> message_loops;
michael@0 181 for (ThreadData* it = list; it; it = it->next()) {
michael@0 182 if (current() != it && it->message_loop())
michael@0 183 message_loops.push_back(it->message_loop());
michael@0 184 }
michael@0 185
michael@0 186 ThreadSafeDownCounter* counter =
michael@0 187 new ThreadSafeDownCounter(message_loops.size() + 1); // Extra one for us!
michael@0 188
michael@0 189 HANDLE completion_handle = CreateEvent(NULL, false, false, NULL);
michael@0 190 // Tell all other threads to run.
michael@0 191 for (size_t i = 0; i < message_loops.size(); ++i)
michael@0 192 message_loops[i]->PostTask(FROM_HERE,
michael@0 193 new RunTheStatic(function, completion_handle, counter));
michael@0 194
michael@0 195 // Also run Task on our thread.
michael@0 196 RunTheStatic local_task(function, completion_handle, counter);
michael@0 197 local_task.Run();
michael@0 198
michael@0 199 WaitForSingleObject(completion_handle, INFINITE);
michael@0 200 int ret_val = CloseHandle(completion_handle);
michael@0 201 DCHECK(ret_val);
michael@0 202 }
michael@0 203 #endif
michael@0 204
michael@0 205 // static
michael@0 206 bool ThreadData::StartTracking(bool status) {
michael@0 207 #ifndef TRACK_ALL_TASK_OBJECTS
michael@0 208 return false; // Not compiled in.
michael@0 209 #else
michael@0 210 if (!status) {
michael@0 211 AutoLock lock(list_lock_);
michael@0 212 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
michael@0 213 status_ = SHUTDOWN;
michael@0 214 return true;
michael@0 215 }
michael@0 216 AutoLock lock(list_lock_);
michael@0 217 DCHECK(status_ == UNINITIALIZED);
michael@0 218 CHECK(tls_index_.Initialize(NULL));
michael@0 219 status_ = ACTIVE;
michael@0 220 return true;
michael@0 221 #endif
michael@0 222 }
michael@0 223
michael@0 224 // static
michael@0 225 bool ThreadData::IsActive() {
michael@0 226 return status_ == ACTIVE;
michael@0 227 }
michael@0 228
michael@0 229 #ifdef OS_WIN
michael@0 230 // static
michael@0 231 void ThreadData::ShutdownMultiThreadTracking() {
michael@0 232 // Using lock, guarantee that no new ThreadData instances will be created.
michael@0 233 if (!StartTracking(false))
michael@0 234 return;
michael@0 235
michael@0 236 RunOnAllThreads(ShutdownDisablingFurtherTracking);
michael@0 237
michael@0 238 // Now the *only* threads that might change the database are the threads with
michael@0 239 // no messages loops. They might still be adding data to their birth records,
michael@0 240 // but since no objects are deleted on those threads, there will be no further
michael@0 241 // access to to cross-thread data.
michael@0 242 // We could do a cleanup on all threads except for the ones without
michael@0 243 // MessageLoops, but we won't bother doing cleanup (destruction of data) yet.
michael@0 244 return;
michael@0 245 }
michael@0 246 #endif
michael@0 247
michael@0 248 // static
michael@0 249 void ThreadData::ShutdownSingleThreadedCleanup() {
michael@0 250 // We must be single threaded... but be careful anyway.
michael@0 251 if (!StartTracking(false))
michael@0 252 return;
michael@0 253 ThreadData* thread_data_list;
michael@0 254 {
michael@0 255 AutoLock lock(list_lock_);
michael@0 256 thread_data_list = first_;
michael@0 257 first_ = NULL;
michael@0 258 }
michael@0 259
michael@0 260 while (thread_data_list) {
michael@0 261 ThreadData* next_thread_data = thread_data_list;
michael@0 262 thread_data_list = thread_data_list->next();
michael@0 263
michael@0 264 for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
michael@0 265 next_thread_data->birth_map_.end() != it; ++it)
michael@0 266 delete it->second; // Delete the Birth Records.
michael@0 267 next_thread_data->birth_map_.clear();
michael@0 268 next_thread_data->death_map_.clear();
michael@0 269 delete next_thread_data; // Includes all Death Records.
michael@0 270 }
michael@0 271
michael@0 272 CHECK(tls_index_.initialized());
michael@0 273 tls_index_.Free();
michael@0 274 DCHECK(!tls_index_.initialized());
michael@0 275 status_ = UNINITIALIZED;
michael@0 276 }
michael@0 277
michael@0 278 // static
michael@0 279 void ThreadData::ShutdownDisablingFurtherTracking() {
michael@0 280 // Redundantly set status SHUTDOWN on this thread.
michael@0 281 if (!StartTracking(false))
michael@0 282 return;
michael@0 283 }
michael@0 284
michael@0 285
michael@0 286 //------------------------------------------------------------------------------
michael@0 287
michael@0 288 ThreadData::ThreadSafeDownCounter::ThreadSafeDownCounter(size_t count)
michael@0 289 : remaining_count_(count) {
michael@0 290 DCHECK(remaining_count_ > 0);
michael@0 291 }
michael@0 292
michael@0 293 bool ThreadData::ThreadSafeDownCounter::LastCaller() {
michael@0 294 {
michael@0 295 AutoLock lock(lock_);
michael@0 296 if (--remaining_count_)
michael@0 297 return false;
michael@0 298 } // Release lock, so we can delete everything in this instance.
michael@0 299 delete this;
michael@0 300 return true;
michael@0 301 }
michael@0 302
michael@0 303 //------------------------------------------------------------------------------
michael@0 304 #ifdef OS_WIN
michael@0 305 ThreadData::RunTheStatic::RunTheStatic(FunctionPointer function,
michael@0 306 HANDLE completion_handle,
michael@0 307 ThreadSafeDownCounter* counter)
michael@0 308 : function_(function),
michael@0 309 completion_handle_(completion_handle),
michael@0 310 counter_(counter) {
michael@0 311 }
michael@0 312
michael@0 313 void ThreadData::RunTheStatic::Run() {
michael@0 314 function_();
michael@0 315 if (counter_->LastCaller())
michael@0 316 SetEvent(completion_handle_);
michael@0 317 }
michael@0 318 #endif
michael@0 319
michael@0 320 //------------------------------------------------------------------------------
michael@0 321 // Individual 3-tuple of birth (place and thread) along with death thread, and
michael@0 322 // the accumulated stats for instances (DeathData).
michael@0 323
michael@0 324 Snapshot::Snapshot(const BirthOnThread& birth_on_thread,
michael@0 325 const ThreadData& death_thread,
michael@0 326 const DeathData& death_data)
michael@0 327 : birth_(&birth_on_thread),
michael@0 328 death_thread_(&death_thread),
michael@0 329 death_data_(death_data) {
michael@0 330 }
michael@0 331
michael@0 332 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count)
michael@0 333 : birth_(&birth_on_thread),
michael@0 334 death_thread_(NULL),
michael@0 335 death_data_(DeathData(count)) {
michael@0 336 }
michael@0 337
michael@0 338 const std::string Snapshot::DeathThreadName() const {
michael@0 339 if (death_thread_)
michael@0 340 return death_thread_->ThreadName();
michael@0 341 return "Still_Alive";
michael@0 342 }
michael@0 343
michael@0 344 void Snapshot::Write(std::string* output) const {
michael@0 345 death_data_.Write(output);
michael@0 346 StringAppendF(output, "%s->%s ",
michael@0 347 birth_->birth_thread()->ThreadName().c_str(),
michael@0 348 death_thread_->ThreadName().c_str());
michael@0 349 birth_->location().Write(true, true, output);
michael@0 350 }
michael@0 351
michael@0 352 void Snapshot::Add(const Snapshot& other) {
michael@0 353 death_data_.AddDeathData(other.death_data_);
michael@0 354 }
michael@0 355
michael@0 356 //------------------------------------------------------------------------------
michael@0 357 // DataCollector
michael@0 358
michael@0 359 DataCollector::DataCollector() {
michael@0 360 DCHECK(ThreadData::IsActive());
michael@0 361
michael@0 362 ThreadData* my_list = ThreadData::current()->first();
michael@0 363
michael@0 364 count_of_contributing_threads_ = 0;
michael@0 365 for (ThreadData* thread_data = my_list;
michael@0 366 thread_data;
michael@0 367 thread_data = thread_data->next()) {
michael@0 368 ++count_of_contributing_threads_;
michael@0 369 }
michael@0 370
michael@0 371 // Gather data serially. A different constructor could be used to do in
michael@0 372 // parallel, and then invoke an OnCompletion task.
michael@0 373 for (ThreadData* thread_data = my_list;
michael@0 374 thread_data;
michael@0 375 thread_data = thread_data->next()) {
michael@0 376 Append(*thread_data);
michael@0 377 }
michael@0 378 }
michael@0 379
michael@0 380 void DataCollector::Append(const ThreadData& thread_data) {
michael@0 381 // Get copy of data (which is done under ThreadData's lock).
michael@0 382 ThreadData::BirthMap birth_map;
michael@0 383 thread_data.SnapshotBirthMap(&birth_map);
michael@0 384 ThreadData::DeathMap death_map;
michael@0 385 thread_data.SnapshotDeathMap(&death_map);
michael@0 386
michael@0 387 // Use our lock to protect our accumulation activity.
michael@0 388 AutoLock lock(accumulation_lock_);
michael@0 389
michael@0 390 DCHECK(count_of_contributing_threads_);
michael@0 391
michael@0 392 for (ThreadData::DeathMap::const_iterator it = death_map.begin();
michael@0 393 it != death_map.end(); ++it) {
michael@0 394 collection_.push_back(Snapshot(*it->first, thread_data, it->second));
michael@0 395 global_birth_count_[it->first] -= it->first->birth_count();
michael@0 396 }
michael@0 397
michael@0 398 for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
michael@0 399 it != birth_map.end(); ++it) {
michael@0 400 global_birth_count_[it->second] += it->second->birth_count();
michael@0 401 }
michael@0 402
michael@0 403 --count_of_contributing_threads_;
michael@0 404 }
michael@0 405
michael@0 406 DataCollector::Collection* DataCollector::collection() {
michael@0 407 DCHECK(!count_of_contributing_threads_);
michael@0 408 return &collection_;
michael@0 409 }
michael@0 410
michael@0 411 void DataCollector::AddListOfLivingObjects() {
michael@0 412 DCHECK(!count_of_contributing_threads_);
michael@0 413 for (BirthCount::iterator it = global_birth_count_.begin();
michael@0 414 it != global_birth_count_.end(); ++it) {
michael@0 415 if (it->second > 0)
michael@0 416 collection_.push_back(Snapshot(*it->first, it->second));
michael@0 417 }
michael@0 418 }
michael@0 419
michael@0 420 //------------------------------------------------------------------------------
michael@0 421 // Aggregation
michael@0 422
michael@0 423 void Aggregation::AddDeathSnapshot(const Snapshot& snapshot) {
michael@0 424 AddBirth(snapshot.birth());
michael@0 425 death_threads_[snapshot.death_thread()]++;
michael@0 426 AddDeathData(snapshot.death_data());
michael@0 427 }
michael@0 428
michael@0 429 void Aggregation::AddBirths(const Births& births) {
michael@0 430 AddBirth(births);
michael@0 431 birth_count_ += births.birth_count();
michael@0 432 }
michael@0 433 void Aggregation::AddBirth(const BirthOnThread& birth) {
michael@0 434 AddBirthPlace(birth.location());
michael@0 435 birth_threads_[birth.birth_thread()]++;
michael@0 436 }
michael@0 437
michael@0 438 void Aggregation::AddBirthPlace(const Location& location) {
michael@0 439 locations_[location]++;
michael@0 440 birth_files_[location.file_name()]++;
michael@0 441 }
michael@0 442
michael@0 443 void Aggregation::Write(std::string* output) const {
michael@0 444 if (locations_.size() == 1) {
michael@0 445 locations_.begin()->first.Write(true, true, output);
michael@0 446 } else {
michael@0 447 StringAppendF(output, "%d Locations. ", locations_.size());
michael@0 448 if (birth_files_.size() > 1)
michael@0 449 StringAppendF(output, "%d Files. ", birth_files_.size());
michael@0 450 else
michael@0 451 StringAppendF(output, "All born in %s. ",
michael@0 452 birth_files_.begin()->first.c_str());
michael@0 453 }
michael@0 454
michael@0 455 if (birth_threads_.size() > 1)
michael@0 456 StringAppendF(output, "%d BirthingThreads. ", birth_threads_.size());
michael@0 457 else
michael@0 458 StringAppendF(output, "All born on %s. ",
michael@0 459 birth_threads_.begin()->first->ThreadName().c_str());
michael@0 460
michael@0 461 if (death_threads_.size() > 1) {
michael@0 462 StringAppendF(output, "%d DeathThreads. ", death_threads_.size());
michael@0 463 } else {
michael@0 464 if (death_threads_.begin()->first)
michael@0 465 StringAppendF(output, "All deleted on %s. ",
michael@0 466 death_threads_.begin()->first->ThreadName().c_str());
michael@0 467 else
michael@0 468 output->append("All these objects are still alive.");
michael@0 469 }
michael@0 470
michael@0 471 if (birth_count_ > 1)
michael@0 472 StringAppendF(output, "Births=%d ", birth_count_);
michael@0 473
michael@0 474 DeathData::Write(output);
michael@0 475 }
michael@0 476
michael@0 477 void Aggregation::Clear() {
michael@0 478 birth_count_ = 0;
michael@0 479 birth_files_.clear();
michael@0 480 locations_.clear();
michael@0 481 birth_threads_.clear();
michael@0 482 DeathData::Clear();
michael@0 483 death_threads_.clear();
michael@0 484 }
michael@0 485
michael@0 486 //------------------------------------------------------------------------------
michael@0 487 // Comparison object for sorting.
michael@0 488
michael@0 489 Comparator::Comparator()
michael@0 490 : selector_(NIL),
michael@0 491 tiebreaker_(NULL),
michael@0 492 combined_selectors_(0),
michael@0 493 use_tiebreaker_for_sort_only_(false) {}
michael@0 494
michael@0 495 void Comparator::Clear() {
michael@0 496 if (tiebreaker_) {
michael@0 497 tiebreaker_->Clear();
michael@0 498 delete tiebreaker_;
michael@0 499 tiebreaker_ = NULL;
michael@0 500 }
michael@0 501 use_tiebreaker_for_sort_only_ = false;
michael@0 502 selector_ = NIL;
michael@0 503 }
michael@0 504
michael@0 505 void Comparator::Sort(DataCollector::Collection* collection) const {
michael@0 506 std::sort(collection->begin(), collection->end(), *this);
michael@0 507 }
michael@0 508
michael@0 509
michael@0 510 bool Comparator::operator()(const Snapshot& left,
michael@0 511 const Snapshot& right) const {
michael@0 512 switch (selector_) {
michael@0 513 case BIRTH_THREAD:
michael@0 514 if (left.birth_thread() != right.birth_thread() &&
michael@0 515 left.birth_thread()->ThreadName() !=
michael@0 516 right.birth_thread()->ThreadName())
michael@0 517 return left.birth_thread()->ThreadName() <
michael@0 518 right.birth_thread()->ThreadName();
michael@0 519 break;
michael@0 520
michael@0 521 case DEATH_THREAD:
michael@0 522 if (left.death_thread() != right.death_thread() &&
michael@0 523 left.DeathThreadName() !=
michael@0 524 right.DeathThreadName()) {
michael@0 525 if (!left.death_thread())
michael@0 526 return true;
michael@0 527 if (!right.death_thread())
michael@0 528 return false;
michael@0 529 return left.DeathThreadName() <
michael@0 530 right.DeathThreadName();
michael@0 531 }
michael@0 532 break;
michael@0 533
michael@0 534 case BIRTH_FILE:
michael@0 535 if (left.location().file_name() != right.location().file_name()) {
michael@0 536 int comp = strcmp(left.location().file_name(),
michael@0 537 right.location().file_name());
michael@0 538 if (comp)
michael@0 539 return 0 > comp;
michael@0 540 }
michael@0 541 break;
michael@0 542
michael@0 543 case BIRTH_FUNCTION:
michael@0 544 if (left.location().function_name() != right.location().function_name()) {
michael@0 545 int comp = strcmp(left.location().function_name(),
michael@0 546 right.location().function_name());
michael@0 547 if (comp)
michael@0 548 return 0 > comp;
michael@0 549 }
michael@0 550 break;
michael@0 551
michael@0 552 case BIRTH_LINE:
michael@0 553 if (left.location().line_number() != right.location().line_number())
michael@0 554 return left.location().line_number() <
michael@0 555 right.location().line_number();
michael@0 556 break;
michael@0 557
michael@0 558 case COUNT:
michael@0 559 if (left.count() != right.count())
michael@0 560 return left.count() > right.count(); // Sort large at front of vector.
michael@0 561 break;
michael@0 562
michael@0 563 case AVERAGE_DURATION:
michael@0 564 if (left.AverageMsDuration() != right.AverageMsDuration())
michael@0 565 return left.AverageMsDuration() > right.AverageMsDuration();
michael@0 566 break;
michael@0 567
michael@0 568 default:
michael@0 569 break;
michael@0 570 }
michael@0 571 if (tiebreaker_)
michael@0 572 return tiebreaker_->operator()(left, right);
michael@0 573 return false;
michael@0 574 }
michael@0 575
michael@0 576 bool Comparator::Equivalent(const Snapshot& left,
michael@0 577 const Snapshot& right) const {
michael@0 578 switch (selector_) {
michael@0 579 case BIRTH_THREAD:
michael@0 580 if (left.birth_thread() != right.birth_thread() &&
michael@0 581 left.birth_thread()->ThreadName() !=
michael@0 582 right.birth_thread()->ThreadName())
michael@0 583 return false;
michael@0 584 break;
michael@0 585
michael@0 586 case DEATH_THREAD:
michael@0 587 if (left.death_thread() != right.death_thread() &&
michael@0 588 left.DeathThreadName() != right.DeathThreadName())
michael@0 589 return false;
michael@0 590 break;
michael@0 591
michael@0 592 case BIRTH_FILE:
michael@0 593 if (left.location().file_name() != right.location().file_name()) {
michael@0 594 int comp = strcmp(left.location().file_name(),
michael@0 595 right.location().file_name());
michael@0 596 if (comp)
michael@0 597 return false;
michael@0 598 }
michael@0 599 break;
michael@0 600
michael@0 601 case BIRTH_FUNCTION:
michael@0 602 if (left.location().function_name() != right.location().function_name()) {
michael@0 603 int comp = strcmp(left.location().function_name(),
michael@0 604 right.location().function_name());
michael@0 605 if (comp)
michael@0 606 return false;
michael@0 607 }
michael@0 608 break;
michael@0 609
michael@0 610 case COUNT:
michael@0 611 if (left.count() != right.count())
michael@0 612 return false;
michael@0 613 break;
michael@0 614
michael@0 615 case AVERAGE_DURATION:
michael@0 616 if (left.life_duration() != right.life_duration())
michael@0 617 return false;
michael@0 618 break;
michael@0 619
michael@0 620 default:
michael@0 621 break;
michael@0 622 }
michael@0 623 if (tiebreaker_ && !use_tiebreaker_for_sort_only_)
michael@0 624 return tiebreaker_->Equivalent(left, right);
michael@0 625 return true;
michael@0 626 }
michael@0 627
michael@0 628 bool Comparator::Acceptable(const Snapshot& sample) const {
michael@0 629 if (required_.size()) {
michael@0 630 switch (selector_) {
michael@0 631 case BIRTH_THREAD:
michael@0 632 if (sample.birth_thread()->ThreadName().find(required_) ==
michael@0 633 std::string::npos)
michael@0 634 return false;
michael@0 635 break;
michael@0 636
michael@0 637 case DEATH_THREAD:
michael@0 638 if (sample.DeathThreadName().find(required_) == std::string::npos)
michael@0 639 return false;
michael@0 640 break;
michael@0 641
michael@0 642 case BIRTH_FILE:
michael@0 643 if (!strstr(sample.location().file_name(), required_.c_str()))
michael@0 644 return false;
michael@0 645 break;
michael@0 646
michael@0 647 case BIRTH_FUNCTION:
michael@0 648 if (!strstr(sample.location().function_name(), required_.c_str()))
michael@0 649 return false;
michael@0 650 break;
michael@0 651
michael@0 652 default:
michael@0 653 break;
michael@0 654 }
michael@0 655 }
michael@0 656 if (tiebreaker_ && !use_tiebreaker_for_sort_only_)
michael@0 657 return tiebreaker_->Acceptable(sample);
michael@0 658 return true;
michael@0 659 }
michael@0 660
michael@0 661 void Comparator::SetTiebreaker(Selector selector, const std::string required) {
michael@0 662 if (selector == selector_ || NIL == selector)
michael@0 663 return;
michael@0 664 combined_selectors_ |= selector;
michael@0 665 if (NIL == selector_) {
michael@0 666 selector_ = selector;
michael@0 667 if (required.size())
michael@0 668 required_ = required;
michael@0 669 return;
michael@0 670 }
michael@0 671 if (tiebreaker_) {
michael@0 672 if (use_tiebreaker_for_sort_only_) {
michael@0 673 Comparator* temp = new Comparator;
michael@0 674 temp->tiebreaker_ = tiebreaker_;
michael@0 675 tiebreaker_ = temp;
michael@0 676 }
michael@0 677 } else {
michael@0 678 tiebreaker_ = new Comparator;
michael@0 679 DCHECK(!use_tiebreaker_for_sort_only_);
michael@0 680 }
michael@0 681 tiebreaker_->SetTiebreaker(selector, required);
michael@0 682 }
michael@0 683
michael@0 684 bool Comparator::IsGroupedBy(Selector selector) const {
michael@0 685 return 0 != (selector & combined_selectors_);
michael@0 686 }
michael@0 687
michael@0 688 void Comparator::SetSubgroupTiebreaker(Selector selector) {
michael@0 689 if (selector == selector_ || NIL == selector)
michael@0 690 return;
michael@0 691 if (!tiebreaker_) {
michael@0 692 use_tiebreaker_for_sort_only_ = true;
michael@0 693 tiebreaker_ = new Comparator;
michael@0 694 tiebreaker_->SetTiebreaker(selector, "");
michael@0 695 } else {
michael@0 696 tiebreaker_->SetSubgroupTiebreaker(selector);
michael@0 697 }
michael@0 698 }
michael@0 699
michael@0 700 bool Comparator::WriteSortGrouping(const Snapshot& sample,
michael@0 701 std::string* output) const {
michael@0 702 bool wrote_data = false;
michael@0 703 switch (selector_) {
michael@0 704 case BIRTH_THREAD:
michael@0 705 StringAppendF(output, "All new on %s ",
michael@0 706 sample.birth_thread()->ThreadName().c_str());
michael@0 707 wrote_data = true;
michael@0 708 break;
michael@0 709
michael@0 710 case DEATH_THREAD:
michael@0 711 if (sample.death_thread())
michael@0 712 StringAppendF(output, "All deleted on %s ",
michael@0 713 sample.DeathThreadName().c_str());
michael@0 714 else
michael@0 715 output->append("All still alive ");
michael@0 716 wrote_data = true;
michael@0 717 break;
michael@0 718
michael@0 719 case BIRTH_FILE:
michael@0 720 StringAppendF(output, "All born in %s ",
michael@0 721 sample.location().file_name());
michael@0 722 break;
michael@0 723
michael@0 724 case BIRTH_FUNCTION:
michael@0 725 output->append("All born in ");
michael@0 726 sample.location().WriteFunctionName(output);
michael@0 727 output->push_back(' ');
michael@0 728 break;
michael@0 729
michael@0 730 default:
michael@0 731 break;
michael@0 732 }
michael@0 733 if (tiebreaker_ && !use_tiebreaker_for_sort_only_) {
michael@0 734 wrote_data |= tiebreaker_->WriteSortGrouping(sample, output);
michael@0 735 }
michael@0 736 return wrote_data;
michael@0 737 }
michael@0 738
michael@0 739 void Comparator::WriteSnapshot(const Snapshot& sample,
michael@0 740 std::string* output) const {
michael@0 741 sample.death_data().Write(output);
michael@0 742 if (!(combined_selectors_ & BIRTH_THREAD) ||
michael@0 743 !(combined_selectors_ & DEATH_THREAD))
michael@0 744 StringAppendF(output, "%s->%s ",
michael@0 745 (combined_selectors_ & BIRTH_THREAD) ? "*" :
michael@0 746 sample.birth().birth_thread()->ThreadName().c_str(),
michael@0 747 (combined_selectors_ & DEATH_THREAD) ? "*" :
michael@0 748 sample.DeathThreadName().c_str());
michael@0 749 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
michael@0 750 !(combined_selectors_ & BIRTH_FUNCTION),
michael@0 751 output);
michael@0 752 }
michael@0 753
michael@0 754 } // namespace tracked_objects

mercurial