1/*******************************************************************************
2 *
3 * Module Name: dbstats - Generation and display of ACPI table statistics
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45#include "accommon.h"
46#include "acdebug.h"
47#include "acnamesp.h"
48
49#define _COMPONENT          ACPI_CA_DEBUGGER
50ACPI_MODULE_NAME("dbstats")
51
52/* Local prototypes */
53static void acpi_db_count_namespace_objects(void);
54
55static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc);
56
57static acpi_status
58acpi_db_classify_one_object(acpi_handle obj_handle,
59			    u32 nesting_level,
60			    void *context, void **return_value);
61
62#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
63static void acpi_db_list_info(struct acpi_memory_list *list);
64#endif
65
66/*
67 * Statistics subcommands
68 */
69static struct acpi_db_argument_info acpi_db_stat_types[] = {
70	{"ALLOCATIONS"},
71	{"OBJECTS"},
72	{"MEMORY"},
73	{"MISC"},
74	{"TABLES"},
75	{"SIZES"},
76	{"STACK"},
77	{NULL}			/* Must be null terminated */
78};
79
80#define CMD_STAT_ALLOCATIONS     0
81#define CMD_STAT_OBJECTS         1
82#define CMD_STAT_MEMORY          2
83#define CMD_STAT_MISC            3
84#define CMD_STAT_TABLES          4
85#define CMD_STAT_SIZES           5
86#define CMD_STAT_STACK           6
87
88#if defined ACPI_DBG_TRACK_ALLOCATIONS || defined ACPI_USE_LOCAL_CACHE
89/*******************************************************************************
90 *
91 * FUNCTION:    acpi_db_list_info
92 *
93 * PARAMETERS:  list            - Memory list/cache to be displayed
94 *
95 * RETURN:      None
96 *
97 * DESCRIPTION: Display information about the input memory list or cache.
98 *
99 ******************************************************************************/
100
101static void acpi_db_list_info(struct acpi_memory_list *list)
102{
103#ifdef ACPI_DBG_TRACK_ALLOCATIONS
104	u32 outstanding;
105#endif
106
107	acpi_os_printf("\n%s\n", list->list_name);
108
109	/* max_depth > 0 indicates a cache object */
110
111	if (list->max_depth > 0) {
112		acpi_os_printf
113		    ("    Cache: [Depth    MaxD Avail  Size]                "
114		     "%8.2X %8.2X %8.2X %8.2X\n", list->current_depth,
115		     list->max_depth, list->max_depth - list->current_depth,
116		     (list->current_depth * list->object_size));
117	}
118#ifdef ACPI_DBG_TRACK_ALLOCATIONS
119	if (list->max_depth > 0) {
120		acpi_os_printf
121		    ("    Cache: [Requests Hits Misses ObjSize]             "
122		     "%8.2X %8.2X %8.2X %8.2X\n", list->requests, list->hits,
123		     list->requests - list->hits, list->object_size);
124	}
125
126	outstanding = acpi_db_get_cache_info(list);
127
128	if (list->object_size) {
129		acpi_os_printf
130		    ("    Mem:   [Alloc    Free Max    CurSize Outstanding] "
131		     "%8.2X %8.2X %8.2X %8.2X %8.2X\n", list->total_allocated,
132		     list->total_freed, list->max_occupied,
133		     outstanding * list->object_size, outstanding);
134	} else {
135		acpi_os_printf
136		    ("    Mem:   [Alloc Free Max CurSize Outstanding Total] "
137		     "%8.2X %8.2X %8.2X %8.2X %8.2X %8.2X\n",
138		     list->total_allocated, list->total_freed,
139		     list->max_occupied, list->current_total_size, outstanding,
140		     list->total_size);
141	}
142#endif
143}
144#endif
145
146/*******************************************************************************
147 *
148 * FUNCTION:    acpi_db_enumerate_object
149 *
150 * PARAMETERS:  obj_desc            - Object to be counted
151 *
152 * RETURN:      None
153 *
154 * DESCRIPTION: Add this object to the global counts, by object type.
155 *              Limited recursion handles subobjects and packages, and this
156 *              is probably acceptable within the AML debugger only.
157 *
158 ******************************************************************************/
159
160static void acpi_db_enumerate_object(union acpi_operand_object *obj_desc)
161{
162	u32 i;
163
164	if (!obj_desc) {
165		return;
166	}
167
168	/* Enumerate this object first */
169
170	acpi_gbl_num_objects++;
171
172	if (obj_desc->common.type > ACPI_TYPE_NS_NODE_MAX) {
173		acpi_gbl_obj_type_count_misc++;
174	} else {
175		acpi_gbl_obj_type_count[obj_desc->common.type]++;
176	}
177
178	/* Count the sub-objects */
179
180	switch (obj_desc->common.type) {
181	case ACPI_TYPE_PACKAGE:
182
183		for (i = 0; i < obj_desc->package.count; i++) {
184			acpi_db_enumerate_object(obj_desc->package.elements[i]);
185		}
186		break;
187
188	case ACPI_TYPE_DEVICE:
189
190		acpi_db_enumerate_object(obj_desc->device.notify_list[0]);
191		acpi_db_enumerate_object(obj_desc->device.notify_list[1]);
192		acpi_db_enumerate_object(obj_desc->device.handler);
193		break;
194
195	case ACPI_TYPE_BUFFER_FIELD:
196
197		if (acpi_ns_get_secondary_object(obj_desc)) {
198			acpi_gbl_obj_type_count[ACPI_TYPE_BUFFER_FIELD]++;
199		}
200		break;
201
202	case ACPI_TYPE_REGION:
203
204		acpi_gbl_obj_type_count[ACPI_TYPE_LOCAL_REGION_FIELD]++;
205		acpi_db_enumerate_object(obj_desc->region.handler);
206		break;
207
208	case ACPI_TYPE_POWER:
209
210		acpi_db_enumerate_object(obj_desc->power_resource.
211					 notify_list[0]);
212		acpi_db_enumerate_object(obj_desc->power_resource.
213					 notify_list[1]);
214		break;
215
216	case ACPI_TYPE_PROCESSOR:
217
218		acpi_db_enumerate_object(obj_desc->processor.notify_list[0]);
219		acpi_db_enumerate_object(obj_desc->processor.notify_list[1]);
220		acpi_db_enumerate_object(obj_desc->processor.handler);
221		break;
222
223	case ACPI_TYPE_THERMAL:
224
225		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[0]);
226		acpi_db_enumerate_object(obj_desc->thermal_zone.notify_list[1]);
227		acpi_db_enumerate_object(obj_desc->thermal_zone.handler);
228		break;
229
230	default:
231
232		break;
233	}
234}
235
236/*******************************************************************************
237 *
238 * FUNCTION:    acpi_db_classify_one_object
239 *
240 * PARAMETERS:  Callback for walk_namespace
241 *
242 * RETURN:      Status
243 *
244 * DESCRIPTION: Enumerate both the object descriptor (including subobjects) and
245 *              the parent namespace node.
246 *
247 ******************************************************************************/
248
249static acpi_status
250acpi_db_classify_one_object(acpi_handle obj_handle,
251			    u32 nesting_level,
252			    void *context, void **return_value)
253{
254	struct acpi_namespace_node *node;
255	union acpi_operand_object *obj_desc;
256	u32 type;
257
258	acpi_gbl_num_nodes++;
259
260	node = (struct acpi_namespace_node *)obj_handle;
261	obj_desc = acpi_ns_get_attached_object(node);
262
263	acpi_db_enumerate_object(obj_desc);
264
265	type = node->type;
266	if (type > ACPI_TYPE_NS_NODE_MAX) {
267		acpi_gbl_node_type_count_misc++;
268	} else {
269		acpi_gbl_node_type_count[type]++;
270	}
271
272	return (AE_OK);
273
274#ifdef ACPI_FUTURE_IMPLEMENTATION
275
276	/* TBD: These need to be counted during the initial parsing phase */
277
278	if (acpi_ps_is_named_op(op->opcode)) {
279		num_nodes++;
280	}
281
282	if (is_method) {
283		num_method_elements++;
284	}
285
286	num_grammar_elements++;
287	op = acpi_ps_get_depth_next(root, op);
288
289	size_of_parse_tree = (num_grammar_elements - num_method_elements) *
290	    (u32)sizeof(union acpi_parse_object);
291	size_of_method_trees =
292	    num_method_elements * (u32)sizeof(union acpi_parse_object);
293	size_of_node_entries =
294	    num_nodes * (u32)sizeof(struct acpi_namespace_node);
295	size_of_acpi_objects =
296	    num_nodes * (u32)sizeof(union acpi_operand_object);
297#endif
298}
299
300/*******************************************************************************
301 *
302 * FUNCTION:    acpi_db_count_namespace_objects
303 *
304 * PARAMETERS:  None
305 *
306 * RETURN:      None
307 *
308 * DESCRIPTION: Count and classify the entire namespace, including all
309 *              namespace nodes and attached objects.
310 *
311 ******************************************************************************/
312
313static void acpi_db_count_namespace_objects(void)
314{
315	u32 i;
316
317	acpi_gbl_num_nodes = 0;
318	acpi_gbl_num_objects = 0;
319
320	acpi_gbl_obj_type_count_misc = 0;
321	for (i = 0; i < (ACPI_TYPE_NS_NODE_MAX - 1); i++) {
322		acpi_gbl_obj_type_count[i] = 0;
323		acpi_gbl_node_type_count[i] = 0;
324	}
325
326	(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
327				     ACPI_UINT32_MAX, FALSE,
328				     acpi_db_classify_one_object, NULL, NULL,
329				     NULL);
330}
331
332/*******************************************************************************
333 *
334 * FUNCTION:    acpi_db_display_statistics
335 *
336 * PARAMETERS:  type_arg        - Subcommand
337 *
338 * RETURN:      Status
339 *
340 * DESCRIPTION: Display various statistics
341 *
342 ******************************************************************************/
343
344acpi_status acpi_db_display_statistics(char *type_arg)
345{
346	u32 i;
347	u32 temp;
348
349	acpi_ut_strupr(type_arg);
350	temp = acpi_db_match_argument(type_arg, acpi_db_stat_types);
351	if (temp == ACPI_TYPE_NOT_FOUND) {
352		acpi_os_printf("Invalid or unsupported argument\n");
353		return (AE_OK);
354	}
355
356	switch (temp) {
357	case CMD_STAT_ALLOCATIONS:
358
359#ifdef ACPI_DBG_TRACK_ALLOCATIONS
360		acpi_ut_dump_allocation_info();
361#endif
362		break;
363
364	case CMD_STAT_TABLES:
365
366		acpi_os_printf("ACPI Table Information (not implemented):\n\n");
367		break;
368
369	case CMD_STAT_OBJECTS:
370
371		acpi_db_count_namespace_objects();
372
373		acpi_os_printf
374		    ("\nObjects defined in the current namespace:\n\n");
375
376		acpi_os_printf("%16.16s %10.10s %10.10s\n",
377			       "ACPI_TYPE", "NODES", "OBJECTS");
378
379		for (i = 0; i < ACPI_TYPE_NS_NODE_MAX; i++) {
380			acpi_os_printf("%16.16s % 10ld% 10ld\n",
381				       acpi_ut_get_type_name(i),
382				       acpi_gbl_node_type_count[i],
383				       acpi_gbl_obj_type_count[i]);
384		}
385		acpi_os_printf("%16.16s % 10ld% 10ld\n", "Misc/Unknown",
386			       acpi_gbl_node_type_count_misc,
387			       acpi_gbl_obj_type_count_misc);
388
389		acpi_os_printf("%16.16s % 10ld% 10ld\n", "TOTALS:",
390			       acpi_gbl_num_nodes, acpi_gbl_num_objects);
391		break;
392
393	case CMD_STAT_MEMORY:
394
395#ifdef ACPI_DBG_TRACK_ALLOCATIONS
396		acpi_os_printf
397		    ("\n----Object Statistics (all in hex)---------\n");
398
399		acpi_db_list_info(acpi_gbl_global_list);
400		acpi_db_list_info(acpi_gbl_ns_node_list);
401#endif
402
403#ifdef ACPI_USE_LOCAL_CACHE
404		acpi_os_printf
405		    ("\n----Cache Statistics (all in hex)---------\n");
406		acpi_db_list_info(acpi_gbl_operand_cache);
407		acpi_db_list_info(acpi_gbl_ps_node_cache);
408		acpi_db_list_info(acpi_gbl_ps_node_ext_cache);
409		acpi_db_list_info(acpi_gbl_state_cache);
410#endif
411
412		break;
413
414	case CMD_STAT_MISC:
415
416		acpi_os_printf("\nMiscellaneous Statistics:\n\n");
417		acpi_os_printf("Calls to AcpiPsFind:.. ........% 7ld\n",
418			       acpi_gbl_ps_find_count);
419		acpi_os_printf("Calls to AcpiNsLookup:..........% 7ld\n",
420			       acpi_gbl_ns_lookup_count);
421
422		acpi_os_printf("\n");
423
424		acpi_os_printf("Mutex usage:\n\n");
425		for (i = 0; i < ACPI_NUM_MUTEX; i++) {
426			acpi_os_printf("%-28s:     % 7ld\n",
427				       acpi_ut_get_mutex_name(i),
428				       acpi_gbl_mutex_info[i].use_count);
429		}
430		break;
431
432	case CMD_STAT_SIZES:
433
434		acpi_os_printf("\nInternal object sizes:\n\n");
435
436		acpi_os_printf("Common         %3d\n",
437			       sizeof(struct acpi_object_common));
438		acpi_os_printf("Number         %3d\n",
439			       sizeof(struct acpi_object_integer));
440		acpi_os_printf("String         %3d\n",
441			       sizeof(struct acpi_object_string));
442		acpi_os_printf("Buffer         %3d\n",
443			       sizeof(struct acpi_object_buffer));
444		acpi_os_printf("Package        %3d\n",
445			       sizeof(struct acpi_object_package));
446		acpi_os_printf("BufferField    %3d\n",
447			       sizeof(struct acpi_object_buffer_field));
448		acpi_os_printf("Device         %3d\n",
449			       sizeof(struct acpi_object_device));
450		acpi_os_printf("Event          %3d\n",
451			       sizeof(struct acpi_object_event));
452		acpi_os_printf("Method         %3d\n",
453			       sizeof(struct acpi_object_method));
454		acpi_os_printf("Mutex          %3d\n",
455			       sizeof(struct acpi_object_mutex));
456		acpi_os_printf("Region         %3d\n",
457			       sizeof(struct acpi_object_region));
458		acpi_os_printf("PowerResource  %3d\n",
459			       sizeof(struct acpi_object_power_resource));
460		acpi_os_printf("Processor      %3d\n",
461			       sizeof(struct acpi_object_processor));
462		acpi_os_printf("ThermalZone    %3d\n",
463			       sizeof(struct acpi_object_thermal_zone));
464		acpi_os_printf("RegionField    %3d\n",
465			       sizeof(struct acpi_object_region_field));
466		acpi_os_printf("BankField      %3d\n",
467			       sizeof(struct acpi_object_bank_field));
468		acpi_os_printf("IndexField     %3d\n",
469			       sizeof(struct acpi_object_index_field));
470		acpi_os_printf("Reference      %3d\n",
471			       sizeof(struct acpi_object_reference));
472		acpi_os_printf("Notify         %3d\n",
473			       sizeof(struct acpi_object_notify_handler));
474		acpi_os_printf("AddressSpace   %3d\n",
475			       sizeof(struct acpi_object_addr_handler));
476		acpi_os_printf("Extra          %3d\n",
477			       sizeof(struct acpi_object_extra));
478		acpi_os_printf("Data           %3d\n",
479			       sizeof(struct acpi_object_data));
480
481		acpi_os_printf("\n");
482
483		acpi_os_printf("ParseObject    %3d\n",
484			       sizeof(struct acpi_parse_obj_common));
485		acpi_os_printf("ParseObjectNamed %3d\n",
486			       sizeof(struct acpi_parse_obj_named));
487		acpi_os_printf("ParseObjectAsl %3d\n",
488			       sizeof(struct acpi_parse_obj_asl));
489		acpi_os_printf("OperandObject  %3d\n",
490			       sizeof(union acpi_operand_object));
491		acpi_os_printf("NamespaceNode  %3d\n",
492			       sizeof(struct acpi_namespace_node));
493		acpi_os_printf("AcpiObject     %3d\n",
494			       sizeof(union acpi_object));
495
496		acpi_os_printf("\n");
497
498		acpi_os_printf("Generic State  %3d\n",
499			       sizeof(union acpi_generic_state));
500		acpi_os_printf("Common State   %3d\n",
501			       sizeof(struct acpi_common_state));
502		acpi_os_printf("Control State  %3d\n",
503			       sizeof(struct acpi_control_state));
504		acpi_os_printf("Update State   %3d\n",
505			       sizeof(struct acpi_update_state));
506		acpi_os_printf("Scope State    %3d\n",
507			       sizeof(struct acpi_scope_state));
508		acpi_os_printf("Parse Scope    %3d\n",
509			       sizeof(struct acpi_pscope_state));
510		acpi_os_printf("Package State  %3d\n",
511			       sizeof(struct acpi_pkg_state));
512		acpi_os_printf("Thread State   %3d\n",
513			       sizeof(struct acpi_thread_state));
514		acpi_os_printf("Result Values  %3d\n",
515			       sizeof(struct acpi_result_values));
516		acpi_os_printf("Notify Info    %3d\n",
517			       sizeof(struct acpi_notify_info));
518		break;
519
520	case CMD_STAT_STACK:
521#if defined(ACPI_DEBUG_OUTPUT)
522
523		temp =
524		    (u32)ACPI_PTR_DIFF(acpi_gbl_entry_stack_pointer,
525				       acpi_gbl_lowest_stack_pointer);
526
527		acpi_os_printf("\nSubsystem Stack Usage:\n\n");
528		acpi_os_printf("Entry Stack Pointer        %p\n",
529			       acpi_gbl_entry_stack_pointer);
530		acpi_os_printf("Lowest Stack Pointer       %p\n",
531			       acpi_gbl_lowest_stack_pointer);
532		acpi_os_printf("Stack Use                  %X (%u)\n", temp,
533			       temp);
534		acpi_os_printf("Deepest Procedure Nesting  %u\n",
535			       acpi_gbl_deepest_nesting);
536#endif
537		break;
538
539	default:
540
541		break;
542	}
543
544	acpi_os_printf("\n");
545	return (AE_OK);
546}
547