Commit 9069a381 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

lib: objagg: implement optimization hints assembly and use hints for object creation

Implement simple greedy algo to find more optimized root-delta tree for
a given objagg instance. This "hints" can be used by a driver to:
1) check if the hints are better (driver's choice) than the original
   objagg tree. Driver does comparison of objagg stats and hints stats.
2) use the hints to create a new objagg instance which will construct
   the root-delta tree according to the passed hints. Currently, only a
   simple greedy algorithm is implemented. Basically it finds the roots
   according to the maximal possible user count including deltas.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bb72e68b
...@@ -1200,6 +1200,32 @@ mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key, ...@@ -1200,6 +1200,32 @@ mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
return 0; return 0;
} }
static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
const void *obj)
{
const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
const struct mlxsw_sp_acl_erp_key *key = obj;
u16 delta_start;
u8 delta_mask;
int err;
err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
&delta_start, &delta_mask);
return err ? false : true;
}
static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2)
{
const struct mlxsw_sp_acl_erp_key *key1 = obj1;
const struct mlxsw_sp_acl_erp_key *key2 = obj2;
/* For hints purposes, two objects are considered equal
* in case the masks are the same. Does not matter what
* the "ctcam" value is.
*/
return memcmp(key1->mask, key2->mask, sizeof(key1->mask));
}
static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj, static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
void *obj) void *obj)
{ {
...@@ -1254,12 +1280,17 @@ static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv) ...@@ -1254,12 +1280,17 @@ static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
kfree(delta); kfree(delta);
} }
static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj) static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
unsigned int root_id)
{ {
struct mlxsw_sp_acl_atcam_region *aregion = priv; struct mlxsw_sp_acl_atcam_region *aregion = priv;
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
struct mlxsw_sp_acl_erp_key *key = obj; struct mlxsw_sp_acl_erp_key *key = obj;
if (!key->ctcam &&
root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
return ERR_PTR(-ENOBUFS);
return erp_table->ops->erp_create(erp_table, key); return erp_table->ops->erp_create(erp_table, key);
} }
...@@ -1273,6 +1304,8 @@ static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv) ...@@ -1273,6 +1304,8 @@ static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = { static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
.obj_size = sizeof(struct mlxsw_sp_acl_erp_key), .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
.delta_check = mlxsw_sp_acl_erp_delta_check,
.hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp,
.delta_create = mlxsw_sp_acl_erp_delta_create, .delta_create = mlxsw_sp_acl_erp_delta_create,
.delta_destroy = mlxsw_sp_acl_erp_delta_destroy, .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
.root_create = mlxsw_sp_acl_erp_root_create, .root_create = mlxsw_sp_acl_erp_root_create,
...@@ -1290,7 +1323,7 @@ mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion) ...@@ -1290,7 +1323,7 @@ mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops, erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
aregion); NULL, aregion);
if (IS_ERR(erp_table->objagg)) { if (IS_ERR(erp_table->objagg)) {
err = PTR_ERR(erp_table->objagg); err = PTR_ERR(erp_table->objagg);
goto err_objagg_create; goto err_objagg_create;
......
...@@ -6,14 +6,19 @@ ...@@ -6,14 +6,19 @@
struct objagg_ops { struct objagg_ops {
size_t obj_size; size_t obj_size;
bool (*delta_check)(void *priv, const void *parent_obj,
const void *obj);
int (*hints_obj_cmp)(const void *obj1, const void *obj2);
void * (*delta_create)(void *priv, void *parent_obj, void *obj); void * (*delta_create)(void *priv, void *parent_obj, void *obj);
void (*delta_destroy)(void *priv, void *delta_priv); void (*delta_destroy)(void *priv, void *delta_priv);
void * (*root_create)(void *priv, void *obj); void * (*root_create)(void *priv, void *obj, unsigned int root_id);
#define OBJAGG_OBJ_ROOT_ID_INVALID UINT_MAX
void (*root_destroy)(void *priv, void *root_priv); void (*root_destroy)(void *priv, void *root_priv);
}; };
struct objagg; struct objagg;
struct objagg_obj; struct objagg_obj;
struct objagg_hints;
const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj); const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj);
const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj); const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj);
...@@ -21,7 +26,8 @@ const void *objagg_obj_raw(const struct objagg_obj *objagg_obj); ...@@ -21,7 +26,8 @@ const void *objagg_obj_raw(const struct objagg_obj *objagg_obj);
struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj); struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj);
void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj); void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj);
struct objagg *objagg_create(const struct objagg_ops *ops, void *priv); struct objagg *objagg_create(const struct objagg_ops *ops,
struct objagg_hints *hints, void *priv);
void objagg_destroy(struct objagg *objagg); void objagg_destroy(struct objagg *objagg);
struct objagg_obj_stats { struct objagg_obj_stats {
...@@ -43,4 +49,14 @@ struct objagg_stats { ...@@ -43,4 +49,14 @@ struct objagg_stats {
const struct objagg_stats *objagg_stats_get(struct objagg *objagg); const struct objagg_stats *objagg_stats_get(struct objagg *objagg);
void objagg_stats_put(const struct objagg_stats *objagg_stats); void objagg_stats_put(const struct objagg_stats *objagg_stats);
enum objagg_opt_algo_type {
OBJAGG_OPT_ALGO_SIMPLE_GREEDY,
};
struct objagg_hints *objagg_hints_get(struct objagg *objagg,
enum objagg_opt_algo_type opt_algo_type);
void objagg_hints_put(struct objagg_hints *objagg_hints);
const struct objagg_stats *
objagg_hints_stats_get(struct objagg_hints *objagg_hints);
#endif #endif
This diff is collapsed.
...@@ -87,6 +87,15 @@ static void world_obj_put(struct world *world, struct objagg *objagg, ...@@ -87,6 +87,15 @@ static void world_obj_put(struct world *world, struct objagg *objagg,
#define MAX_KEY_ID_DIFF 5 #define MAX_KEY_ID_DIFF 5
static bool delta_check(void *priv, const void *parent_obj, const void *obj)
{
const struct tokey *parent_key = parent_obj;
const struct tokey *key = obj;
int diff = key->id - parent_key->id;
return diff >= 0 && diff <= MAX_KEY_ID_DIFF;
}
static void *delta_create(void *priv, void *parent_obj, void *obj) static void *delta_create(void *priv, void *parent_obj, void *obj)
{ {
struct tokey *parent_key = parent_obj; struct tokey *parent_key = parent_obj;
...@@ -95,7 +104,7 @@ static void *delta_create(void *priv, void *parent_obj, void *obj) ...@@ -95,7 +104,7 @@ static void *delta_create(void *priv, void *parent_obj, void *obj)
int diff = key->id - parent_key->id; int diff = key->id - parent_key->id;
struct delta *delta; struct delta *delta;
if (diff < 0 || diff > MAX_KEY_ID_DIFF) if (!delta_check(priv, parent_obj, obj))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
delta = kzalloc(sizeof(*delta), GFP_KERNEL); delta = kzalloc(sizeof(*delta), GFP_KERNEL);
...@@ -115,7 +124,7 @@ static void delta_destroy(void *priv, void *delta_priv) ...@@ -115,7 +124,7 @@ static void delta_destroy(void *priv, void *delta_priv)
kfree(delta); kfree(delta);
} }
static void *root_create(void *priv, void *obj) static void *root_create(void *priv, void *obj, unsigned int id)
{ {
struct world *world = priv; struct world *world = priv;
struct tokey *key = obj; struct tokey *key = obj;
...@@ -268,6 +277,12 @@ static int check_stats_nodelta(struct objagg *objagg) ...@@ -268,6 +277,12 @@ static int check_stats_nodelta(struct objagg *objagg)
return err; return err;
} }
static bool delta_check_dummy(void *priv, const void *parent_obj,
const void *obj)
{
return false;
}
static void *delta_create_dummy(void *priv, void *parent_obj, void *obj) static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
{ {
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
...@@ -279,6 +294,7 @@ static void delta_destroy_dummy(void *priv, void *delta_priv) ...@@ -279,6 +294,7 @@ static void delta_destroy_dummy(void *priv, void *delta_priv)
static const struct objagg_ops nodelta_ops = { static const struct objagg_ops nodelta_ops = {
.obj_size = sizeof(struct tokey), .obj_size = sizeof(struct tokey),
.delta_check = delta_check_dummy,
.delta_create = delta_create_dummy, .delta_create = delta_create_dummy,
.delta_destroy = delta_destroy_dummy, .delta_destroy = delta_destroy_dummy,
.root_create = root_create, .root_create = root_create,
...@@ -292,7 +308,7 @@ static int test_nodelta(void) ...@@ -292,7 +308,7 @@ static int test_nodelta(void)
int i; int i;
int err; int err;
objagg = objagg_create(&nodelta_ops, &world); objagg = objagg_create(&nodelta_ops, NULL, &world);
if (IS_ERR(objagg)) if (IS_ERR(objagg))
return PTR_ERR(objagg); return PTR_ERR(objagg);
...@@ -357,6 +373,7 @@ static int test_nodelta(void) ...@@ -357,6 +373,7 @@ static int test_nodelta(void)
static const struct objagg_ops delta_ops = { static const struct objagg_ops delta_ops = {
.obj_size = sizeof(struct tokey), .obj_size = sizeof(struct tokey),
.delta_check = delta_check,
.delta_create = delta_create, .delta_create = delta_create,
.delta_destroy = delta_destroy, .delta_destroy = delta_destroy,
.root_create = root_create, .root_create = root_create,
...@@ -793,7 +810,7 @@ static int test_delta(void) ...@@ -793,7 +810,7 @@ static int test_delta(void)
int i; int i;
int err; int err;
objagg = objagg_create(&delta_ops, &world); objagg = objagg_create(&delta_ops, NULL, &world);
if (IS_ERR(objagg)) if (IS_ERR(objagg))
return PTR_ERR(objagg); return PTR_ERR(objagg);
...@@ -815,6 +832,170 @@ static int test_delta(void) ...@@ -815,6 +832,170 @@ static int test_delta(void)
return err; return err;
} }
struct hints_case {
const unsigned int *key_ids;
size_t key_ids_count;
struct expect_stats expect_stats;
struct expect_stats expect_stats_hints;
};
static const unsigned int hints_case_key_ids[] = {
1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
};
static const struct hints_case hints_case = {
.key_ids = hints_case_key_ids,
.key_ids_count = ARRAY_SIZE(hints_case_key_ids),
.expect_stats =
EXPECT_STATS(7, ROOT(1, 2, 7), ROOT(7, 1, 4), ROOT(30, 1, 1),
DELTA(8, 3), DELTA(3, 2),
DELTA(5, 2), DELTA(6, 1)),
.expect_stats_hints =
EXPECT_STATS(7, ROOT(3, 2, 9), ROOT(1, 2, 2), ROOT(30, 1, 1),
DELTA(8, 3), DELTA(5, 2),
DELTA(6, 1), DELTA(7, 1)),
};
static void __pr_debug_stats(const struct objagg_stats *stats)
{
int i;
for (i = 0; i < stats->stats_info_count; i++)
pr_debug("Stat index %d key %u: u %d, d %d, %s\n", i,
obj_to_key_id(stats->stats_info[i].objagg_obj),
stats->stats_info[i].stats.user_count,
stats->stats_info[i].stats.delta_user_count,
stats->stats_info[i].is_root ? "root" : "noroot");
}
static void pr_debug_stats(struct objagg *objagg)
{
const struct objagg_stats *stats;
stats = objagg_stats_get(objagg);
if (IS_ERR(stats))
return;
__pr_debug_stats(stats);
objagg_stats_put(stats);
}
static void pr_debug_hints_stats(struct objagg_hints *objagg_hints)
{
const struct objagg_stats *stats;
stats = objagg_hints_stats_get(objagg_hints);
if (IS_ERR(stats))
return;
__pr_debug_stats(stats);
objagg_stats_put(stats);
}
static int check_expect_hints_stats(struct objagg_hints *objagg_hints,
const struct expect_stats *expect_stats,
const char **errmsg)
{
const struct objagg_stats *stats;
int err;
stats = objagg_hints_stats_get(objagg_hints);
if (IS_ERR(stats))
return PTR_ERR(stats);
err = __check_expect_stats(stats, expect_stats, errmsg);
objagg_stats_put(stats);
return err;
}
static int test_hints_case(const struct hints_case *hints_case)
{
struct objagg_obj *objagg_obj;
struct objagg_hints *hints;
struct world world2 = {};
struct world world = {};
struct objagg *objagg2;
struct objagg *objagg;
const char *errmsg;
int i;
int err;
objagg = objagg_create(&delta_ops, NULL, &world);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
for (i = 0; i < hints_case->key_ids_count; i++) {
objagg_obj = world_obj_get(&world, objagg,
hints_case->key_ids[i]);
if (IS_ERR(objagg_obj)) {
err = PTR_ERR(objagg_obj);
goto err_world_obj_get;
}
}
pr_debug_stats(objagg);
err = check_expect_stats(objagg, &hints_case->expect_stats, &errmsg);
if (err) {
pr_err("Stats: %s\n", errmsg);
goto err_check_expect_stats;
}
hints = objagg_hints_get(objagg, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
if (IS_ERR(hints)) {
err = PTR_ERR(hints);
goto err_hints_get;
}
pr_debug_hints_stats(hints);
err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
&errmsg);
if (err) {
pr_err("Hints stats: %s\n", errmsg);
goto err_check_expect_hints_stats;
}
objagg2 = objagg_create(&delta_ops, hints, &world2);
if (IS_ERR(objagg))
return PTR_ERR(objagg);
for (i = 0; i < hints_case->key_ids_count; i++) {
objagg_obj = world_obj_get(&world2, objagg2,
hints_case->key_ids[i]);
if (IS_ERR(objagg_obj)) {
err = PTR_ERR(objagg_obj);
goto err_world2_obj_get;
}
}
pr_debug_stats(objagg2);
err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
&errmsg);
if (err) {
pr_err("Stats2: %s\n", errmsg);
goto err_check_expect_stats2;
}
err = 0;
err_check_expect_stats2:
err_world2_obj_get:
for (i--; i >= 0; i--)
world_obj_put(&world2, objagg, hints_case->key_ids[i]);
objagg_hints_put(hints);
objagg_destroy(objagg2);
i = hints_case->key_ids_count;
err_check_expect_hints_stats:
err_hints_get:
err_check_expect_stats:
err_world_obj_get:
for (i--; i >= 0; i--)
world_obj_put(&world, objagg, hints_case->key_ids[i]);
objagg_destroy(objagg);
return err;
}
static int test_hints(void)
{
return test_hints_case(&hints_case);
}
static int __init test_objagg_init(void) static int __init test_objagg_init(void)
{ {
int err; int err;
...@@ -822,7 +1003,10 @@ static int __init test_objagg_init(void) ...@@ -822,7 +1003,10 @@ static int __init test_objagg_init(void)
err = test_nodelta(); err = test_nodelta();
if (err) if (err)
return err; return err;
return test_delta(); err = test_delta();
if (err)
return err;
return test_hints();
} }
static void __exit test_objagg_exit(void) static void __exit test_objagg_exit(void)
......
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