Commit c45b5c09 authored by Alexey Starikovskiy's avatar Alexey Starikovskiy Committed by Len Brown

ACPICA: Performance enhancement for namespace search and access

This change enhances the performance of namespace searches and
walks by adding a backpointer to the parent in each namespace
node. On large namespaces, this change can improve overall ACPI
performance by up to 9X.  Adding a pointer to each namespace node
increases the overall size of the internal namespace by about 5%,
since each namespace entry usually consists of both a namespace
node and an ACPI operand object.
Signed-off-by: default avatarAlexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5821f754
......@@ -184,8 +184,9 @@ struct acpi_namespace_node {
u8 flags; /* Miscellaneous flags */
acpi_owner_id owner_id; /* Node creator */
union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */
struct acpi_namespace_node *parent; /* Parent node */
struct acpi_namespace_node *child; /* First child */
struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */
struct acpi_namespace_node *peer; /* First peer */
/*
* The following fields are used by the ASL compiler and disassembler only
......@@ -199,7 +200,7 @@ struct acpi_namespace_node {
/* Namespace Node flags */
#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
#define ANOBJ_RESERVED 0x01 /* Available for use */
#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */
#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
......
......@@ -369,11 +369,4 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle);
void acpi_ns_terminate(void);
struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
*node);
struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
acpi_namespace_node
*node);
#endif /* __ACNAMESP_H__ */
......@@ -102,8 +102,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->arguments[i].name.integer |= (i << 24);
walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
walk_state->arguments[i].type = ACPI_TYPE_ANY;
walk_state->arguments[i].flags =
ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;
}
/* Init the method locals */
......@@ -116,8 +115,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->local_variables[i].descriptor_type =
ACPI_DESC_TYPE_NAMED;
walk_state->local_variables[i].type = ACPI_TYPE_ANY;
walk_state->local_variables[i].flags =
ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;
}
return_VOID;
......
......@@ -213,7 +213,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
......@@ -257,7 +257,7 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
......@@ -394,7 +394,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
/* Execute the argument AML */
status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
if (ACPI_FAILURE(status)) {
......
......@@ -199,7 +199,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
return_ACPI_STATUS(status);
}
parent_node = acpi_ns_get_parent_node(region_obj->region.node);
parent_node = region_obj->region.node->parent;
/*
* Get the _SEG and _BBN values from the device upon which the handler
......@@ -248,7 +248,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
break;
}
pci_root_node = acpi_ns_get_parent_node(pci_root_node);
pci_root_node = pci_root_node->parent;
}
/* PCI root bridge not found, use namespace root node */
......@@ -280,7 +280,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
*/
pci_device_node = region_obj->region.node;
while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
pci_device_node = acpi_ns_get_parent_node(pci_device_node);
pci_device_node = pci_device_node->parent;
}
if (!pci_device_node) {
......@@ -521,7 +521,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
return_ACPI_STATUS(AE_NOT_EXIST);
}
node = acpi_ns_get_parent_node(region_obj->region.node);
node = region_obj->region.node->parent;
space_id = region_obj->region.space_id;
/* Setup defaults */
......@@ -654,7 +654,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
/* This node does not have the handler we need; Pop up one level */
node = acpi_ns_get_parent_node(node);
node = node->parent;
}
/* If we get here, there is no handler for this region */
......
......@@ -812,7 +812,7 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
acpi_ex_out_pointer("Attached Object",
acpi_ns_get_attached_object(node));
acpi_ex_out_pointer("Parent", acpi_ns_get_parent_node(node));
acpi_ex_out_pointer("Parent", node->parent);
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
acpi_ex_dump_node);
......
......@@ -338,8 +338,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
*/
while (!acpi_ns_opens_scope(prefix_node->type) &&
prefix_node->type != ACPI_TYPE_ANY) {
prefix_node =
acpi_ns_get_parent_node(prefix_node);
prefix_node = prefix_node->parent;
}
}
}
......@@ -419,7 +418,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
/* Backup to the parent node */
num_carats++;
this_node = acpi_ns_get_parent_node(this_node);
this_node = this_node->parent;
if (!this_node) {
/* Current scope has no parent scope */
......
......@@ -159,7 +159,7 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
parent_node = acpi_ns_get_parent_node(node);
parent_node = node->parent;
prev_node = NULL;
next_node = parent_node->child;
......@@ -168,29 +168,20 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
while (next_node != node) {
prev_node = next_node;
next_node = prev_node->peer;
next_node = next_node->peer;
}
if (prev_node) {
/* Node is not first child, unlink it */
prev_node->peer = next_node->peer;
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
}
prev_node->peer = node->peer;
} else {
/* Node is first child (has no previous peer) */
if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
/* No peers at all */
parent_node->child = NULL;
} else { /* Link peer list to parent */
parent_node->child = next_node->peer;
}
/*
* Node is first child (has no previous peer).
* Link peer list to parent
*/
parent_node->child = node->peer;
}
/* Delete the node and any attached objects */
......@@ -238,23 +229,20 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
/* Link the new entry into the parent and existing children */
node->peer = NULL;
node->parent = parent_node;
child_node = parent_node->child;
if (!child_node) {
parent_node->child = node;
node->flags |= ANOBJ_END_OF_PEER_LIST;
node->peer = parent_node;
} else {
while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
/* Add node to the end of the peer list */
while (child_node->peer) {
child_node = child_node->peer;
}
child_node->peer = node;
/* Clear end-of-list flag */
child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
node->flags |= ANOBJ_END_OF_PEER_LIST;
node->peer = parent_node;
}
/* Init the new entry */
......@@ -288,9 +276,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *next_node;
u8 flags;
struct acpi_namespace_node *node_to_delete;
ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
......@@ -298,37 +285,26 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
return_VOID;
}
/* If no children, all done! */
child_node = parent_node->child;
if (!child_node) {
return_VOID;
}
/* Deallocate all children at this level */
do {
/* Get the things we need */
next_node = child_node->peer;
flags = child_node->flags;
next_node = parent_node->child;
while (next_node) {
/* Grandchildren should have all been deleted already */
if (child_node->child) {
if (next_node->child) {
ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
parent_node, child_node));
parent_node, next_node));
}
/*
* Delete this child node and move on to the next child in the list.
* No need to unlink the node since we are deleting the entire branch.
*/
acpi_ns_delete_node(child_node);
child_node = next_node;
} while (!(flags & ANOBJ_END_OF_PEER_LIST));
node_to_delete = next_node;
next_node = next_node->peer;
acpi_ns_delete_node(node_to_delete);
};
/* Clear the parent's child pointer */
......@@ -405,7 +381,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
/* Move up the tree to the grandparent */
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
}
}
......@@ -510,7 +486,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
/* Move up the tree to the grandparent */
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
}
}
......
......@@ -410,7 +410,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
* The only _INI methods that we care about are those that are
* present under Device, Processor, and Thermal objects.
*/
parent_node = acpi_ns_get_parent_node(node);
parent_node = node->parent;
switch (parent_node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
......@@ -420,7 +420,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
while (parent_node) {
parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
}
break;
......
......@@ -93,7 +93,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
/* Put the name into the buffer */
ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name);
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
/* Prefix name with the path separator */
......@@ -198,7 +198,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
return 0;
}
size += ACPI_PATH_SEGMENT_LENGTH;
next_node = acpi_ns_get_parent_node(next_node);
next_node = next_node->parent;
}
if (!size) {
......
......@@ -152,17 +152,6 @@ acpi_ns_search_one_scope(u32 target_name,
return_ACPI_STATUS(AE_OK);
}
/*
* The last entry in the list points back to the parent,
* so a flag is used to indicate the end-of-list
*/
if (node->flags & ANOBJ_END_OF_PEER_LIST) {
/* Searched entire list, we are done */
break;
}
/* Didn't match name, move on to the next peer object */
node = node->peer;
......@@ -217,7 +206,7 @@ acpi_ns_search_parent_tree(u32 target_name,
ACPI_FUNCTION_TRACE(ns_search_parent_tree);
parent_node = acpi_ns_get_parent_node(node);
parent_node = node->parent;
/*
* If there is no parent (i.e., we are at the root) or type is "local",
......@@ -261,7 +250,7 @@ acpi_ns_search_parent_tree(u32 target_name,
/* Not found here, go up another level (until we reach the root) */
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
}
/* Not found in parent tree */
......
......@@ -847,116 +847,3 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
ACPI_FREE(internal_path);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_parent_node
*
* PARAMETERS: Node - Current table entry
*
* RETURN: Parent entry of the given entry
*
* DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
*
******************************************************************************/
struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
*node)
{
ACPI_FUNCTION_ENTRY();
if (!node) {
return (NULL);
}
/*
* Walk to the end of this peer list. The last entry is marked with a flag
* and the peer pointer is really a pointer back to the parent. This saves
* putting a parent back pointer in each and every named object!
*/
while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
node = node->peer;
}
return (node->peer);
}
/*******************************************************************************
*
* FUNCTION: acpi_ns_get_next_valid_node
*
* PARAMETERS: Node - Current table entry
*
* RETURN: Next valid Node in the linked node list. NULL if no more valid
* nodes.
*
* DESCRIPTION: Find the next valid node within a name table.
* Useful for implementing NULL-end-of-list loops.
*
******************************************************************************/
struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
acpi_namespace_node
*node)
{
/* If we are at the end of this peer list, return NULL */
if (node->flags & ANOBJ_END_OF_PEER_LIST) {
return NULL;
}
/* Otherwise just return the next peer */
return (node->peer);
}
#ifdef ACPI_OBSOLETE_FUNCTIONS
/*******************************************************************************
*
* FUNCTION: acpi_ns_find_parent_name
*
* PARAMETERS: *child_node - Named Obj whose name is to be found
*
* RETURN: The ACPI name
*
* DESCRIPTION: Search for the given obj in its parent scope and return the
* name segment, or "????" if the parent name can't be found
* (which "should not happen").
*
******************************************************************************/
acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node)
{
struct acpi_namespace_node *parent_node;
ACPI_FUNCTION_TRACE(ns_find_parent_name);
if (child_node) {
/* Valid entry. Get the parent Node */
parent_node = acpi_ns_get_parent_node(child_node);
if (parent_node) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Parent of %p [%4.4s] is %p [%4.4s]\n",
child_node,
acpi_ut_get_node_name(child_node),
parent_node,
acpi_ut_get_node_name(parent_node)));
if (parent_node->name.integer) {
return_VALUE((acpi_name) parent_node->name.
integer);
}
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Unable to find parent of %p (%4.4s)\n",
child_node,
acpi_ut_get_node_name(child_node)));
}
return_VALUE(ACPI_UNKNOWN_NAME);
}
#endif
......@@ -79,15 +79,6 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
return parent_node->child;
}
/*
* Get the next node.
*
* If we are at the end of this peer list, return NULL
*/
if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
return NULL;
}
/* Otherwise just return the next peer */
return child_node->peer;
......@@ -146,9 +137,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
return (next_node);
}
/* Otherwise, move on to the next node */
/* Otherwise, move on to the next peer node */
next_node = acpi_ns_get_next_valid_node(next_node);
next_node = next_node->peer;
}
/* Not found */
......@@ -355,7 +346,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
*/
level--;
child_node = parent_node;
parent_node = acpi_ns_get_parent_node(parent_node);
parent_node = parent_node->parent;
node_previously_visited = TRUE;
}
......
......@@ -190,7 +190,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
/* Get the parent entry */
parent_node = acpi_ns_get_parent_node(node);
parent_node = node->parent;
*ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node);
/* Return exception if parent is null */
......
......@@ -813,10 +813,10 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE;
acpi_gbl_root_node_struct.parent = NULL;
acpi_gbl_root_node_struct.child = NULL;
acpi_gbl_root_node_struct.peer = NULL;
acpi_gbl_root_node_struct.object = NULL;
acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment