Use traverse_serial to short circuit graph evaluation for already visited nodes.

In our previous attempt to optimize this problem, we did not track the type of the
visit to the node, e.g. whether it came from evaluating Requires or Requires.private,
which resulted in some solutions being correctly incalculated due to greedy optimization
of the dependency graph.

We reintroduce this optimization by adding a second traversal serial as well as
re-introducing the PROPF_VISITED node property as well as a new PROPF_VISITED_PRIVATE
node property flag.  This allows a node to be revisted at maximum two times per
traversal level.

Co-authored-by: Yi Chou <yich@google.com>
master
Ariadne Conill 2024-02-04 03:04:52 -08:00
parent 4a3adf3457
commit 80b5011e69
2 changed files with 24 additions and 0 deletions

View File

@ -137,6 +137,8 @@ struct pkgconf_path_ {
#define PKGCONF_PKG_PROPF_CACHED 0x02
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10
#define PKGCONF_PKG_PROPF_VISITED 0x20
#define PKGCONF_PKG_PROPF_VISITED_PRIVATE 0x40
struct pkgconf_pkg_ {
int refcount;
@ -176,6 +178,7 @@ struct pkgconf_pkg_ {
uint64_t serial;
uint64_t identifier;
uint64_t traverse_serial;
};
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data);
@ -212,6 +215,7 @@ struct pkgconf_client_ {
uint64_t serial;
uint64_t identifier;
uint64_t traverse_serial;
pkgconf_pkg_t **cache_table;
size_t cache_count;

View File

@ -1624,10 +1624,28 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
unsigned int skip_flags)
{
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
unsigned int visited_flag = (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) ? PKGCONF_PKG_PROPF_VISITED_PRIVATE : PKGCONF_PKG_PROPF_VISITED;
if (maxdepth == 0)
return eflags;
/* If we have already visited this node, check if we have done so as a Requires or Requires.private
* query as appropriate, and short-circuit if so.
*/
if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) == 0 && root->traverse_serial == client->traverse_serial)
{
if (root->flags & visited_flag)
return eflags;
}
else
{
root->traverse_serial = client->traverse_serial;
root->flags &= ~(PKGCONF_PKG_PROPF_VISITED|PKGCONF_PKG_PROPF_VISITED_PRIVATE);
}
/* Update this node to indicate how we've visited it so far. */
root->flags |= visited_flag;
PKGCONF_TRACE(client, "%s: level %d, serial %"PRIu64, root->id, maxdepth, client->serial);
if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL)
@ -1675,6 +1693,8 @@ pkgconf_pkg_traverse(pkgconf_client_t *client,
if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL)
client->serial++;
client->traverse_serial++;
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags);
}