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