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
parent
4a3adf3457
commit
80b5011e69
|
@ -137,6 +137,8 @@ struct pkgconf_path_ {
|
||||||
#define PKGCONF_PKG_PROPF_CACHED 0x02
|
#define PKGCONF_PKG_PROPF_CACHED 0x02
|
||||||
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
|
#define PKGCONF_PKG_PROPF_UNINSTALLED 0x08
|
||||||
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10
|
#define PKGCONF_PKG_PROPF_VIRTUAL 0x10
|
||||||
|
#define PKGCONF_PKG_PROPF_VISITED 0x20
|
||||||
|
#define PKGCONF_PKG_PROPF_VISITED_PRIVATE 0x40
|
||||||
|
|
||||||
struct pkgconf_pkg_ {
|
struct pkgconf_pkg_ {
|
||||||
int refcount;
|
int refcount;
|
||||||
|
@ -176,6 +178,7 @@ struct pkgconf_pkg_ {
|
||||||
|
|
||||||
uint64_t serial;
|
uint64_t serial;
|
||||||
uint64_t identifier;
|
uint64_t identifier;
|
||||||
|
uint64_t traverse_serial;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data);
|
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 serial;
|
||||||
uint64_t identifier;
|
uint64_t identifier;
|
||||||
|
uint64_t traverse_serial;
|
||||||
|
|
||||||
pkgconf_pkg_t **cache_table;
|
pkgconf_pkg_t **cache_table;
|
||||||
size_t cache_count;
|
size_t cache_count;
|
||||||
|
|
|
@ -1624,10 +1624,28 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client,
|
||||||
unsigned int skip_flags)
|
unsigned int skip_flags)
|
||||||
{
|
{
|
||||||
unsigned int eflags = PKGCONF_PKG_ERRF_OK;
|
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)
|
if (maxdepth == 0)
|
||||||
return eflags;
|
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);
|
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)
|
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)
|
if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL)
|
||||||
client->serial++;
|
client->serial++;
|
||||||
|
|
||||||
|
client->traverse_serial++;
|
||||||
|
|
||||||
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags);
|
return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue