xref: /haiku/src/apps/debuganalyzer/gui/AbstractWaitObjectsPage.h (revision 4f77a907ba4dac8024f6d3d79dcd32c9d9625f6b)
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