1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 #ifndef ABSTRACT_WAIT_OBJECTS_PAGE_H 6 #define ABSTRACT_WAIT_OBJECTS_PAGE_H 7 8 9 #include <stdio.h> 10 11 #include <new> 12 13 #include <CheckBox.h> 14 #include <GroupView.h> 15 16 #include "table/TableColumns.h" 17 #include "table/TreeTable.h" 18 19 20 #define ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE \ 21 template<typename ModelType, typename WaitObjectGroupType, \ 22 typename WaitObjectType> 23 #define ABSTRACT_WAIT_OBJECTS_PAGE_CLASS \ 24 AbstractWaitObjectsPage<ModelType, WaitObjectGroupType, WaitObjectType> 25 26 27 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 28 class AbstractWaitObjectsPage : public BGroupView, protected TreeTableListener { 29 public: 30 AbstractWaitObjectsPage(); 31 virtual ~AbstractWaitObjectsPage(); 32 33 void SetModel(ModelType* model); 34 35 virtual void MessageReceived(BMessage* message); 36 37 virtual void AttachedToWindow(); 38 39 protected: 40 class WaitObjectsTreeModel; 41 42 enum { 43 MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME = 'awog' 44 }; 45 46 protected: 47 void _UpdateTreeModel(); 48 49 protected: 50 TreeTable* fWaitObjectsTree; 51 WaitObjectsTreeModel* fWaitObjectsTreeModel; 52 ModelType* fModel; 53 BCheckBox* fGroupByNameCheckBox; 54 bool fGroupByName; 55 56 57 // #pragma mark - WaitObjectsTreeModel (inner class) 58 59 60 class WaitObjectsTreeModel : public TreeTableModel { 61 public: 62 WaitObjectsTreeModel(ModelType* model, bool groupByName) 63 : 64 fModel(model), 65 fRootNode(NULL) 66 { 67 fRootNode = new RootNode(fModel, groupByName); 68 } 69 70 ~WaitObjectsTreeModel() 71 { 72 delete fRootNode; 73 } 74 75 virtual void* Root() const 76 { 77 return fRootNode; 78 } 79 80 virtual int32 CountChildren(void* parent) const 81 { 82 return ((Node*)parent)->CountChildren(); 83 } 84 85 virtual void* ChildAt(void* parent, int32 index) const 86 { 87 return ((Node*)parent)->ChildAt(index); 88 } 89 90 virtual int32 CountColumns() const 91 { 92 return 6; 93 } 94 95 virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& value) 96 { 97 return ((Node*)object)->GetValueAt(columnIndex, value); 98 } 99 100 private: 101 struct Node { 102 virtual ~Node() {} 103 104 virtual const char* Name() const = 0; 105 virtual uint32 Type() const = 0; 106 virtual addr_t Object() const = 0; 107 virtual addr_t ReferencedObject() const = 0; 108 virtual int64 Waits() const = 0; 109 virtual nanotime_t TotalWaitTime() const = 0; 110 111 virtual int32 CountChildren() const = 0; 112 virtual void* ChildAt(int32 index) const = 0; 113 114 static int CompareByName(const Node* a, const Node* b) 115 { 116 int cmp = (int)a->Type() - (int)b->Type(); 117 return cmp == 0 ? strcmp(a->Name(), b->Name()) : cmp; 118 } 119 120 bool GetValueAt(int32 columnIndex, BVariant& value) 121 { 122 switch (columnIndex) { 123 case 0: 124 value.SetTo(wait_object_type_name(Type()), 125 B_VARIANT_DONT_COPY_DATA); 126 return true; 127 case 1: 128 value.SetTo(Name(), B_VARIANT_DONT_COPY_DATA); 129 return true; 130 case 2: 131 { 132 addr_t object = Object(); 133 if (object == 0) 134 return false; 135 136 char buffer[16]; 137 snprintf(buffer, sizeof(buffer), "%#lx", object); 138 value.SetTo(buffer); 139 return true; 140 } 141 case 3: 142 { 143 addr_t object = ReferencedObject(); 144 if (object == 0) 145 return false; 146 147 char buffer[16]; 148 snprintf(buffer, sizeof(buffer), "%#lx", object); 149 value.SetTo(buffer); 150 return true; 151 } 152 case 4: 153 value.SetTo(Waits()); 154 return true; 155 case 5: 156 value.SetTo(TotalWaitTime()); 157 return true; 158 default: 159 return false; 160 } 161 } 162 }; 163 164 struct ObjectNode : Node { 165 WaitObjectType* object; 166 167 ObjectNode(WaitObjectType* object) 168 : 169 object(object) 170 { 171 } 172 173 virtual const char* Name() const 174 { 175 return object->Name(); 176 } 177 178 virtual uint32 Type() const 179 { 180 return object->Type(); 181 } 182 183 virtual addr_t Object() const 184 { 185 return object->Object(); 186 } 187 188 virtual addr_t ReferencedObject() const 189 { 190 return object->ReferencedObject(); 191 } 192 193 virtual int64 Waits() const 194 { 195 return object->Waits(); 196 } 197 198 virtual nanotime_t TotalWaitTime() const 199 { 200 return object->TotalWaitTime(); 201 } 202 203 virtual int32 CountChildren() const 204 { 205 return 0; 206 } 207 208 virtual void* ChildAt(int32 index) const 209 { 210 return NULL; 211 } 212 }; 213 214 // For GCC 2 215 friend struct ObjectNode; 216 217 struct GroupNode : Node { 218 WaitObjectGroupType* group; 219 BObjectList<ObjectNode> objectNodes; 220 221 GroupNode(WaitObjectGroupType* group) 222 : 223 group(group) 224 { 225 int32 count = group->CountWaitObjects(); 226 for (int32 i = 0; i < count; i++) { 227 WaitObjectType* waitObject = group->WaitObjectAt(i); 228 if (!objectNodes.AddItem(new ObjectNode(waitObject))) 229 throw std::bad_alloc(); 230 } 231 } 232 233 virtual const char* Name() const 234 { 235 return group->Name(); 236 } 237 238 virtual uint32 Type() const 239 { 240 return group->Type(); 241 } 242 243 virtual addr_t Object() const 244 { 245 return group->Object(); 246 } 247 248 virtual addr_t ReferencedObject() const 249 { 250 return 0; 251 } 252 253 virtual int64 Waits() const 254 { 255 return group->Waits(); 256 } 257 258 virtual nanotime_t TotalWaitTime() const 259 { 260 return group->TotalWaitTime(); 261 } 262 263 virtual int32 CountChildren() const 264 { 265 return objectNodes.CountItems(); 266 } 267 268 virtual void* ChildAt(int32 index) const 269 { 270 return objectNodes.ItemAt(index); 271 } 272 }; 273 274 // For GCC 2 275 friend struct GroupNode; 276 277 struct NodeContainerNode : Node { 278 NodeContainerNode() 279 : 280 fChildren(20, true) 281 { 282 } 283 284 NodeContainerNode(BObjectList<Node>& nodes) 285 : 286 fChildren(20, true) 287 { 288 fChildren.AddList(&nodes); 289 290 // compute total waits and total wait time 291 fWaits = 0; 292 fTotalWaitTime = 0; 293 294 for (int32 i = 0; Node* node = fChildren.ItemAt(i); i++) { 295 fWaits += node->Waits(); 296 fTotalWaitTime += node->TotalWaitTime(); 297 } 298 } 299 300 virtual const char* Name() const 301 { 302 Node* child = fChildren.ItemAt(0); 303 return child != NULL ? child->Name() : ""; 304 } 305 306 virtual uint32 Type() const 307 { 308 Node* child = fChildren.ItemAt(0); 309 return child != NULL ? child->Type() : 0; 310 } 311 312 virtual addr_t Object() const 313 { 314 return 0; 315 } 316 317 virtual addr_t ReferencedObject() const 318 { 319 return 0; 320 } 321 322 virtual int64 Waits() const 323 { 324 return fWaits; 325 } 326 327 virtual nanotime_t TotalWaitTime() const 328 { 329 return fTotalWaitTime; 330 } 331 332 virtual int32 CountChildren() const 333 { 334 return fChildren.CountItems(); 335 } 336 337 virtual void* ChildAt(int32 index) const 338 { 339 return fChildren.ItemAt(index); 340 } 341 342 protected: 343 BObjectList<Node> fChildren; 344 int64 fWaits; 345 nanotime_t fTotalWaitTime; 346 }; 347 348 struct RootNode : public NodeContainerNode { 349 ModelType* model; 350 351 RootNode(ModelType* model, bool groupByName) 352 : 353 model(model) 354 { 355 // create nodes for the wait object groups 356 BObjectList<Node> tempChildren; 357 BObjectList<Node>& children 358 = groupByName ? tempChildren : NodeContainerNode::fChildren; 359 int32 count = model->CountWaitObjectGroups(); 360 for (int32 i = 0; i < count; i++) { 361 WaitObjectGroupType* group = model->WaitObjectGroupAt(i); 362 if (!children.AddItem(_CreateGroupNode(group))) 363 throw std::bad_alloc(); 364 } 365 366 // If we shall group the nodes by name, we create grouping nodes. 367 if (groupByName) { 368 if (children.CountItems() < 2) { 369 NodeContainerNode::fChildren.AddList(&children); 370 return; 371 } 372 373 // sort the nodes by name 374 children.SortItems(&Node::CompareByName); 375 376 // create groups 377 int32 nodeCount = children.CountItems(); 378 BObjectList<Node> nameGroup; 379 Node* previousNode = children.ItemAt(0); 380 int32 groupNodeIndex = 0; 381 for (int32 i = 1; i < nodeCount; i++) { 382 Node* node = children.ItemAt(i); 383 if (strcmp(node->Name(), previousNode->Name())) { 384 // create the group -- or just add the node, if it's 385 // the only one 386 if (nameGroup.CountItems() > 1) { 387 NodeContainerNode::fChildren.AddItem( 388 new NodeContainerNode(nameGroup)); 389 } else 390 NodeContainerNode::fChildren.AddItem(previousNode); 391 392 nameGroup.MakeEmpty(); 393 groupNodeIndex = i; 394 } 395 396 // add the node 397 nameGroup.AddItem(node); 398 399 previousNode = node; 400 } 401 } 402 } 403 404 private: 405 static Node* _CreateGroupNode(WaitObjectGroupType* group) 406 { 407 // If the group has only one object, just create an object node. 408 if (group->CountWaitObjects() == 1) 409 return new ObjectNode(group->WaitObjectAt(0)); 410 411 return new GroupNode(group); 412 } 413 }; 414 415 private: 416 ModelType* fModel; 417 RootNode* fRootNode; 418 }; // WaitObjectsTreeModel 419 420 }; // AbstractWaitObjectsPage 421 422 423 // #pragma mark - WaitObjectsPage 424 425 426 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 427 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::AbstractWaitObjectsPage() 428 : 429 BGroupView(B_VERTICAL, 10), 430 fWaitObjectsTree(NULL), 431 fWaitObjectsTreeModel(NULL), 432 fModel(NULL), 433 fGroupByNameCheckBox(NULL), 434 fGroupByName(false) 435 { 436 SetName("Wait objects"); 437 438 fWaitObjectsTree = new TreeTable("wait object list", 0); 439 AddChild(fWaitObjectsTree->ToView()); 440 441 fGroupByNameCheckBox = new BCheckBox("group by name checkbox", 442 "Group by name", new BMessage(MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME)); 443 fGroupByNameCheckBox->SetValue( 444 fGroupByName ? B_CONTROL_ON : B_CONTROL_OFF); 445 AddChild(fGroupByNameCheckBox); 446 447 fWaitObjectsTree->AddColumn(new StringTableColumn(0, "Type", 80, 40, 1000, 448 B_TRUNCATE_END, B_ALIGN_LEFT)); 449 fWaitObjectsTree->AddColumn(new StringTableColumn(1, "Name", 80, 40, 1000, 450 B_TRUNCATE_END, B_ALIGN_LEFT)); 451 fWaitObjectsTree->AddColumn(new StringTableColumn(2, "Object", 80, 40, 1000, 452 B_TRUNCATE_END, B_ALIGN_LEFT)); 453 fWaitObjectsTree->AddColumn(new StringTableColumn(3, "Referenced", 80, 40, 454 1000, B_TRUNCATE_END, B_ALIGN_LEFT)); 455 fWaitObjectsTree->AddColumn(new Int64TableColumn(4, "Waits", 80, 20, 456 1000, B_TRUNCATE_END, B_ALIGN_RIGHT)); 457 fWaitObjectsTree->AddColumn(new NanotimeTableColumn(5, "Wait time", 80, 458 20, 1000, false, B_TRUNCATE_END, B_ALIGN_RIGHT)); 459 460 fWaitObjectsTree->AddTreeTableListener(this); 461 } 462 463 464 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 465 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::~AbstractWaitObjectsPage() 466 { 467 fWaitObjectsTree->SetTreeTableModel(NULL); 468 delete fWaitObjectsTreeModel; 469 } 470 471 472 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 473 void 474 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::SetModel(ModelType* model) 475 { 476 if (model == fModel) 477 return; 478 479 if (fModel != NULL) { 480 fWaitObjectsTree->SetTreeTableModel(NULL); 481 delete fWaitObjectsTreeModel; 482 fWaitObjectsTreeModel = NULL; 483 } 484 485 fModel = model; 486 487 if (fModel != NULL) 488 _UpdateTreeModel(); 489 } 490 491 492 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 493 void 494 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::MessageReceived(BMessage* message) 495 { 496 switch (message->what) { 497 case MSG_ABSTRACT_WAIT_OBJECTS_GROUP_BY_NAME: 498 fGroupByName = fGroupByNameCheckBox->Value() == B_CONTROL_ON; 499 _UpdateTreeModel(); 500 break; 501 default: 502 BGroupView::MessageReceived(message); 503 break; 504 } 505 } 506 507 508 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 509 void 510 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::AttachedToWindow() 511 { 512 fGroupByNameCheckBox->SetTarget(this); 513 } 514 515 516 ABSTRACT_WAIT_OBJECTS_PAGE_TEMPLATE 517 void 518 ABSTRACT_WAIT_OBJECTS_PAGE_CLASS::_UpdateTreeModel() 519 { 520 if (fModel != NULL) { 521 fWaitObjectsTree->SetTreeTableModel(NULL); 522 delete fWaitObjectsTreeModel; 523 fWaitObjectsTreeModel = NULL; 524 } 525 526 if (fModel != NULL) { 527 try { 528 fWaitObjectsTreeModel = new WaitObjectsTreeModel(fModel, 529 fGroupByName); 530 } catch (std::bad_alloc) { 531 // TODO: Report error! 532 } 533 fWaitObjectsTree->SetTreeTableModel(fWaitObjectsTreeModel); 534 fWaitObjectsTree->ResizeAllColumnsToPreferred(); 535 } 536 } 537 538 539 #endif // ABSTRACT_WAIT_OBJECTS_PAGE_H 540