summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2019-02-07 06:22:46 -0500
committerDavid S. Miller <davem@davemloft.net>2019-02-08 18:02:49 -0500
commit9069a3817d82b01b3a55da382c774e3575946130 (patch)
tree5b8aca6dbaf69345aec08b325761cdf9162ebc9b
parentbb72e68bd1f2a86c37a990e9d905f34b712ae2b6 (diff)
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: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c37
-rw-r--r--include/linux/objagg.h20
-rw-r--r--lib/objagg.c573
-rw-r--r--lib/test_objagg.c194
4 files changed, 802 insertions, 22 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
index 2941967e1cc5..302070a74f2e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
@@ -1200,6 +1200,32 @@ mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
1200 return 0; 1200 return 0;
1201} 1201}
1202 1202
1203static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
1204 const void *obj)
1205{
1206 const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1207 const struct mlxsw_sp_acl_erp_key *key = obj;
1208 u16 delta_start;
1209 u8 delta_mask;
1210 int err;
1211
1212 err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1213 &delta_start, &delta_mask);
1214 return err ? false : true;
1215}
1216
1217static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2)
1218{
1219 const struct mlxsw_sp_acl_erp_key *key1 = obj1;
1220 const struct mlxsw_sp_acl_erp_key *key2 = obj2;
1221
1222 /* For hints purposes, two objects are considered equal
1223 * in case the masks are the same. Does not matter what
1224 * the "ctcam" value is.
1225 */
1226 return memcmp(key1->mask, key2->mask, sizeof(key1->mask));
1227}
1228
1203static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj, 1229static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1204 void *obj) 1230 void *obj)
1205{ 1231{
@@ -1254,12 +1280,17 @@ static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1254 kfree(delta); 1280 kfree(delta);
1255} 1281}
1256 1282
1257static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj) 1283static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
1284 unsigned int root_id)
1258{ 1285{
1259 struct mlxsw_sp_acl_atcam_region *aregion = priv; 1286 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1260 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table; 1287 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1261 struct mlxsw_sp_acl_erp_key *key = obj; 1288 struct mlxsw_sp_acl_erp_key *key = obj;
1262 1289
1290 if (!key->ctcam &&
1291 root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
1292 root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
1293 return ERR_PTR(-ENOBUFS);
1263 return erp_table->ops->erp_create(erp_table, key); 1294 return erp_table->ops->erp_create(erp_table, key);
1264} 1295}
1265 1296
@@ -1273,6 +1304,8 @@ static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1273 1304
1274static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = { 1305static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
1275 .obj_size = sizeof(struct mlxsw_sp_acl_erp_key), 1306 .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
1307 .delta_check = mlxsw_sp_acl_erp_delta_check,
1308 .hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp,
1276 .delta_create = mlxsw_sp_acl_erp_delta_create, 1309 .delta_create = mlxsw_sp_acl_erp_delta_create,
1277 .delta_destroy = mlxsw_sp_acl_erp_delta_destroy, 1310 .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
1278 .root_create = mlxsw_sp_acl_erp_root_create, 1311 .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 return ERR_PTR(-ENOMEM); 1323 return ERR_PTR(-ENOMEM);
1291 1324
1292 erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops, 1325 erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1293 aregion); 1326 NULL, aregion);
1294 if (IS_ERR(erp_table->objagg)) { 1327 if (IS_ERR(erp_table->objagg)) {
1295 err = PTR_ERR(erp_table->objagg); 1328 err = PTR_ERR(erp_table->objagg);
1296 goto err_objagg_create; 1329 goto err_objagg_create;
diff --git a/include/linux/objagg.h b/include/linux/objagg.h
index 34f38c186ea0..a675286df1af 100644
--- a/include/linux/objagg.h
+++ b/include/linux/objagg.h
@@ -6,14 +6,19 @@
6 6
7struct objagg_ops { 7struct objagg_ops {
8 size_t obj_size; 8 size_t obj_size;
9 bool (*delta_check)(void *priv, const void *parent_obj,
10 const void *obj);
11 int (*hints_obj_cmp)(const void *obj1, const void *obj2);
9 void * (*delta_create)(void *priv, void *parent_obj, void *obj); 12 void * (*delta_create)(void *priv, void *parent_obj, void *obj);
10 void (*delta_destroy)(void *priv, void *delta_priv); 13 void (*delta_destroy)(void *priv, void *delta_priv);
11 void * (*root_create)(void *priv, void *obj); 14 void * (*root_create)(void *priv, void *obj, unsigned int root_id);
15#define OBJAGG_OBJ_ROOT_ID_INVALID UINT_MAX
12 void (*root_destroy)(void *priv, void *root_priv); 16 void (*root_destroy)(void *priv, void *root_priv);
13}; 17};
14 18
15struct objagg; 19struct objagg;
16struct objagg_obj; 20struct objagg_obj;
21struct objagg_hints;
17 22
18const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj); 23const void *objagg_obj_root_priv(const struct objagg_obj *objagg_obj);
19const void *objagg_obj_delta_priv(const struct objagg_obj *objagg_obj); 24const 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 26
22struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj); 27struct objagg_obj *objagg_obj_get(struct objagg *objagg, void *obj);
23void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj); 28void objagg_obj_put(struct objagg *objagg, struct objagg_obj *objagg_obj);
24struct objagg *objagg_create(const struct objagg_ops *ops, void *priv); 29struct objagg *objagg_create(const struct objagg_ops *ops,
30 struct objagg_hints *hints, void *priv);
25void objagg_destroy(struct objagg *objagg); 31void objagg_destroy(struct objagg *objagg);
26 32
27struct objagg_obj_stats { 33struct objagg_obj_stats {
@@ -43,4 +49,14 @@ struct objagg_stats {
43const struct objagg_stats *objagg_stats_get(struct objagg *objagg); 49const struct objagg_stats *objagg_stats_get(struct objagg *objagg);
44void objagg_stats_put(const struct objagg_stats *objagg_stats); 50void objagg_stats_put(const struct objagg_stats *objagg_stats);
45 51
52enum objagg_opt_algo_type {
53 OBJAGG_OPT_ALGO_SIMPLE_GREEDY,
54};
55
56struct objagg_hints *objagg_hints_get(struct objagg *objagg,
57 enum objagg_opt_algo_type opt_algo_type);
58void objagg_hints_put(struct objagg_hints *objagg_hints);
59const struct objagg_stats *
60objagg_hints_stats_get(struct objagg_hints *objagg_hints);
61
46#endif 62#endif
diff --git a/lib/objagg.c b/lib/objagg.c
index dae390bcef1a..befe8a47d080 100644
--- a/lib/objagg.c
+++ b/lib/objagg.c
@@ -4,6 +4,7 @@
4#include <linux/module.h> 4#include <linux/module.h>
5#include <linux/slab.h> 5#include <linux/slab.h>
6#include <linux/rhashtable.h> 6#include <linux/rhashtable.h>
7#include <linux/idr.h>
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/sort.h> 9#include <linux/sort.h>
9#include <linux/objagg.h> 10#include <linux/objagg.h>
@@ -11,6 +12,34 @@
11#define CREATE_TRACE_POINTS 12#define CREATE_TRACE_POINTS
12#include <trace/events/objagg.h> 13#include <trace/events/objagg.h>
13 14
15struct objagg_hints {
16 struct rhashtable node_ht;
17 struct rhashtable_params ht_params;
18 struct list_head node_list;
19 unsigned int node_count;
20 unsigned int root_count;
21 unsigned int refcount;
22 const struct objagg_ops *ops;
23};
24
25struct objagg_hints_node {
26 struct rhash_head ht_node; /* member of objagg_hints->node_ht */
27 struct list_head list; /* member of objagg_hints->node_list */
28 struct objagg_hints_node *parent;
29 unsigned int root_id;
30 struct objagg_obj_stats_info stats_info;
31 unsigned long obj[0];
32};
33
34static struct objagg_hints_node *
35objagg_hints_lookup(struct objagg_hints *objagg_hints, void *obj)
36{
37 if (!objagg_hints)
38 return NULL;
39 return rhashtable_lookup_fast(&objagg_hints->node_ht, obj,
40 objagg_hints->ht_params);
41}
42
14struct objagg { 43struct objagg {
15 const struct objagg_ops *ops; 44 const struct objagg_ops *ops;
16 void *priv; 45 void *priv;
@@ -18,6 +47,8 @@ struct objagg {
18 struct rhashtable_params ht_params; 47 struct rhashtable_params ht_params;
19 struct list_head obj_list; 48 struct list_head obj_list;
20 unsigned int obj_count; 49 unsigned int obj_count;
50 struct ida root_ida;
51 struct objagg_hints *hints;
21}; 52};
22 53
23struct objagg_obj { 54struct objagg_obj {
@@ -30,6 +61,7 @@ struct objagg_obj {
30 void *delta_priv; /* user delta private */ 61 void *delta_priv; /* user delta private */
31 void *root_priv; /* user root private */ 62 void *root_priv; /* user root private */
32 }; 63 };
64 unsigned int root_id;
33 unsigned int refcount; /* counts number of users of this object 65 unsigned int refcount; /* counts number of users of this object
34 * including nested objects 66 * including nested objects
35 */ 67 */
@@ -130,7 +162,8 @@ static struct objagg_obj *objagg_obj_lookup(struct objagg *objagg, void *obj)
130 162
131static int objagg_obj_parent_assign(struct objagg *objagg, 163static int objagg_obj_parent_assign(struct objagg *objagg,
132 struct objagg_obj *objagg_obj, 164 struct objagg_obj *objagg_obj,
133 struct objagg_obj *parent) 165 struct objagg_obj *parent,
166 bool take_parent_ref)
134{ 167{
135 void *delta_priv; 168 void *delta_priv;
136 169
@@ -144,7 +177,8 @@ static int objagg_obj_parent_assign(struct objagg *objagg,
144 */ 177 */
145 objagg_obj->parent = parent; 178 objagg_obj->parent = parent;
146 objagg_obj->delta_priv = delta_priv; 179 objagg_obj->delta_priv = delta_priv;
147 objagg_obj_ref_inc(objagg_obj->parent); 180 if (take_parent_ref)
181 objagg_obj_ref_inc(objagg_obj->parent);
148 trace_objagg_obj_parent_assign(objagg, objagg_obj, 182 trace_objagg_obj_parent_assign(objagg, objagg_obj,
149 parent, 183 parent,
150 parent->refcount); 184 parent->refcount);
@@ -164,7 +198,7 @@ static int objagg_obj_parent_lookup_assign(struct objagg *objagg,
164 if (!objagg_obj_is_root(objagg_obj_cur)) 198 if (!objagg_obj_is_root(objagg_obj_cur))
165 continue; 199 continue;
166 err = objagg_obj_parent_assign(objagg, objagg_obj, 200 err = objagg_obj_parent_assign(objagg, objagg_obj,
167 objagg_obj_cur); 201 objagg_obj_cur, true);
168 if (!err) 202 if (!err)
169 return 0; 203 return 0;
170 } 204 }
@@ -184,16 +218,68 @@ static void objagg_obj_parent_unassign(struct objagg *objagg,
184 __objagg_obj_put(objagg, objagg_obj->parent); 218 __objagg_obj_put(objagg, objagg_obj->parent);
185} 219}
186 220
221static int objagg_obj_root_id_alloc(struct objagg *objagg,
222 struct objagg_obj *objagg_obj,
223 struct objagg_hints_node *hnode)
224{
225 unsigned int min, max;
226 int root_id;
227
228 /* In case there are no hints available, the root id is invalid. */
229 if (!objagg->hints) {
230 objagg_obj->root_id = OBJAGG_OBJ_ROOT_ID_INVALID;
231 return 0;
232 }
233
234 if (hnode) {
235 min = hnode->root_id;
236 max = hnode->root_id;
237 } else {
238 /* For objects with no hint, start after the last
239 * hinted root_id.
240 */
241 min = objagg->hints->root_count;
242 max = ~0;
243 }
244
245 root_id = ida_alloc_range(&objagg->root_ida, min, max, GFP_KERNEL);
246
247 if (root_id < 0)
248 return root_id;
249 objagg_obj->root_id = root_id;
250 return 0;
251}
252
253static void objagg_obj_root_id_free(struct objagg *objagg,
254 struct objagg_obj *objagg_obj)
255{
256 if (!objagg->hints)
257 return;
258 ida_free(&objagg->root_ida, objagg_obj->root_id);
259}
260
187static int objagg_obj_root_create(struct objagg *objagg, 261static int objagg_obj_root_create(struct objagg *objagg,
188 struct objagg_obj *objagg_obj) 262 struct objagg_obj *objagg_obj,
263 struct objagg_hints_node *hnode)
189{ 264{
190 objagg_obj->root_priv = objagg->ops->root_create(objagg->priv, 265 int err;
191 objagg_obj->obj);
192 if (IS_ERR(objagg_obj->root_priv))
193 return PTR_ERR(objagg_obj->root_priv);
194 266
267 err = objagg_obj_root_id_alloc(objagg, objagg_obj, hnode);
268 if (err)
269 return err;
270 objagg_obj->root_priv = objagg->ops->root_create(objagg->priv,
271 objagg_obj->obj,
272 objagg_obj->root_id);
273 if (IS_ERR(objagg_obj->root_priv)) {
274 err = PTR_ERR(objagg_obj->root_priv);
275 goto err_root_create;
276 }
195 trace_objagg_obj_root_create(objagg, objagg_obj); 277 trace_objagg_obj_root_create(objagg, objagg_obj);
196 return 0; 278 return 0;
279
280err_root_create:
281 objagg_obj_root_id_free(objagg, objagg_obj);
282 return err;
197} 283}
198 284
199static void objagg_obj_root_destroy(struct objagg *objagg, 285static void objagg_obj_root_destroy(struct objagg *objagg,
@@ -201,19 +287,69 @@ static void objagg_obj_root_destroy(struct objagg *objagg,
201{ 287{
202 trace_objagg_obj_root_destroy(objagg, objagg_obj); 288 trace_objagg_obj_root_destroy(objagg, objagg_obj);
203 objagg->ops->root_destroy(objagg->priv, objagg_obj->root_priv); 289 objagg->ops->root_destroy(objagg->priv, objagg_obj->root_priv);
290 objagg_obj_root_id_free(objagg, objagg_obj);
291}
292
293static struct objagg_obj *__objagg_obj_get(struct objagg *objagg, void *obj);
294
295static int objagg_obj_init_with_hints(struct objagg *objagg,
296 struct objagg_obj *objagg_obj,
297 bool *hint_found)
298{
299 struct objagg_hints_node *hnode;
300 struct objagg_obj *parent;
301 int err;
302
303 hnode = objagg_hints_lookup(objagg->hints, objagg_obj->obj);
304 if (!hnode) {
305 *hint_found = false;
306 return 0;
307 }
308 *hint_found = true;
309
310 if (!hnode->parent)
311 return objagg_obj_root_create(objagg, objagg_obj, hnode);
312
313 parent = __objagg_obj_get(objagg, hnode->parent->obj);
314 if (IS_ERR(parent))
315 return PTR_ERR(parent);
316
317 err = objagg_obj_parent_assign(objagg, objagg_obj, parent, false);
318 if (err) {
319 *hint_found = false;
320 err = 0;
321 goto err_parent_assign;
322 }
323
324 return 0;
325
326err_parent_assign:
327 objagg_obj_put(objagg, parent);
328 return err;
204} 329}
205 330
206static int objagg_obj_init(struct objagg *objagg, 331static int objagg_obj_init(struct objagg *objagg,
207 struct objagg_obj *objagg_obj) 332 struct objagg_obj *objagg_obj)
208{ 333{
334 bool hint_found;
209 int err; 335 int err;
210 336
337 /* First, try to use hints if they are available and
338 * if they provide result.
339 */
340 err = objagg_obj_init_with_hints(objagg, objagg_obj, &hint_found);
341 if (err)
342 return err;
343
344 if (hint_found)
345 return 0;
346
211 /* Try to find if the object can be aggregated under an existing one. */ 347 /* Try to find if the object can be aggregated under an existing one. */
212 err = objagg_obj_parent_lookup_assign(objagg, objagg_obj); 348 err = objagg_obj_parent_lookup_assign(objagg, objagg_obj);
213 if (!err) 349 if (!err)
214 return 0; 350 return 0;
215 /* If aggregation is not possible, make the object a root. */ 351 /* If aggregation is not possible, make the object a root. */
216 return objagg_obj_root_create(objagg, objagg_obj); 352 return objagg_obj_root_create(objagg, objagg_obj, NULL);
217} 353}
218 354
219static void objagg_obj_fini(struct objagg *objagg, 355static void objagg_obj_fini(struct objagg *objagg,
@@ -349,8 +485,9 @@ EXPORT_SYMBOL(objagg_obj_put);
349 485
350/** 486/**
351 * objagg_create - creates a new objagg instance 487 * objagg_create - creates a new objagg instance
352 * @ops: user-specific callbacks 488 * @ops: user-specific callbacks
353 * @priv: pointer to a private data passed to the ops 489 * @objagg_hints: hints, can be NULL
490 * @priv: pointer to a private data passed to the ops
354 * 491 *
355 * Note: all locking must be provided by the caller. 492 * Note: all locking must be provided by the caller.
356 * 493 *
@@ -374,18 +511,25 @@ EXPORT_SYMBOL(objagg_obj_put);
374 * Returns a pointer to newly created objagg instance in case of success, 511 * Returns a pointer to newly created objagg instance in case of success,
375 * otherwise it returns pointer error using ERR_PTR macro. 512 * otherwise it returns pointer error using ERR_PTR macro.
376 */ 513 */
377struct objagg *objagg_create(const struct objagg_ops *ops, void *priv) 514struct objagg *objagg_create(const struct objagg_ops *ops,
515 struct objagg_hints *objagg_hints, void *priv)
378{ 516{
379 struct objagg *objagg; 517 struct objagg *objagg;
380 int err; 518 int err;
381 519
382 if (WARN_ON(!ops || !ops->root_create || !ops->root_destroy || 520 if (WARN_ON(!ops || !ops->root_create || !ops->root_destroy ||
383 !ops->delta_create || !ops->delta_destroy)) 521 !ops->delta_check || !ops->delta_create ||
522 !ops->delta_destroy))
384 return ERR_PTR(-EINVAL); 523 return ERR_PTR(-EINVAL);
524
385 objagg = kzalloc(sizeof(*objagg), GFP_KERNEL); 525 objagg = kzalloc(sizeof(*objagg), GFP_KERNEL);
386 if (!objagg) 526 if (!objagg)
387 return ERR_PTR(-ENOMEM); 527 return ERR_PTR(-ENOMEM);
388 objagg->ops = ops; 528 objagg->ops = ops;
529 if (objagg_hints) {
530 objagg->hints = objagg_hints;
531 objagg_hints->refcount++;
532 }
389 objagg->priv = priv; 533 objagg->priv = priv;
390 INIT_LIST_HEAD(&objagg->obj_list); 534 INIT_LIST_HEAD(&objagg->obj_list);
391 535
@@ -397,6 +541,8 @@ struct objagg *objagg_create(const struct objagg_ops *ops, void *priv)
397 if (err) 541 if (err)
398 goto err_rhashtable_init; 542 goto err_rhashtable_init;
399 543
544 ida_init(&objagg->root_ida);
545
400 trace_objagg_create(objagg); 546 trace_objagg_create(objagg);
401 return objagg; 547 return objagg;
402 548
@@ -415,8 +561,11 @@ EXPORT_SYMBOL(objagg_create);
415void objagg_destroy(struct objagg *objagg) 561void objagg_destroy(struct objagg *objagg)
416{ 562{
417 trace_objagg_destroy(objagg); 563 trace_objagg_destroy(objagg);
564 ida_destroy(&objagg->root_ida);
418 WARN_ON(!list_empty(&objagg->obj_list)); 565 WARN_ON(!list_empty(&objagg->obj_list));
419 rhashtable_destroy(&objagg->obj_ht); 566 rhashtable_destroy(&objagg->obj_ht);
567 if (objagg->hints)
568 objagg_hints_put(objagg->hints);
420 kfree(objagg); 569 kfree(objagg);
421} 570}
422EXPORT_SYMBOL(objagg_destroy); 571EXPORT_SYMBOL(objagg_destroy);
@@ -496,6 +645,404 @@ void objagg_stats_put(const struct objagg_stats *objagg_stats)
496} 645}
497EXPORT_SYMBOL(objagg_stats_put); 646EXPORT_SYMBOL(objagg_stats_put);
498 647
648static struct objagg_hints_node *
649objagg_hints_node_create(struct objagg_hints *objagg_hints,
650 struct objagg_obj *objagg_obj, size_t obj_size,
651 struct objagg_hints_node *parent_hnode)
652{
653 unsigned int user_count = objagg_obj->stats.user_count;
654 struct objagg_hints_node *hnode;
655 int err;
656
657 hnode = kzalloc(sizeof(*hnode) + obj_size, GFP_KERNEL);
658 if (!hnode)
659 return ERR_PTR(-ENOMEM);
660 memcpy(hnode->obj, &objagg_obj->obj, obj_size);
661 hnode->stats_info.stats.user_count = user_count;
662 hnode->stats_info.stats.delta_user_count = user_count;
663 if (parent_hnode) {
664 parent_hnode->stats_info.stats.delta_user_count += user_count;
665 } else {
666 hnode->root_id = objagg_hints->root_count++;
667 hnode->stats_info.is_root = true;
668 }
669 hnode->stats_info.objagg_obj = objagg_obj;
670
671 err = rhashtable_insert_fast(&objagg_hints->node_ht, &hnode->ht_node,
672 objagg_hints->ht_params);
673 if (err)
674 goto err_ht_insert;
675
676 list_add(&hnode->list, &objagg_hints->node_list);
677 hnode->parent = parent_hnode;
678 objagg_hints->node_count++;
679
680 return hnode;
681
682err_ht_insert:
683 kfree(hnode);
684 return ERR_PTR(err);
685}
686
687static void objagg_hints_flush(struct objagg_hints *objagg_hints)
688{
689 struct objagg_hints_node *hnode, *tmp;
690
691 list_for_each_entry_safe(hnode, tmp, &objagg_hints->node_list, list) {
692 list_del(&hnode->list);
693 rhashtable_remove_fast(&objagg_hints->node_ht, &hnode->ht_node,
694 objagg_hints->ht_params);
695 kfree(hnode);
696 }
697}
698
699struct objagg_tmp_node {
700 struct objagg_obj *objagg_obj;
701 bool crossed_out;
702};
703
704struct objagg_tmp_graph {
705 struct objagg_tmp_node *nodes;
706 unsigned long nodes_count;
707 unsigned long *edges;
708};
709
710static int objagg_tmp_graph_edge_index(struct objagg_tmp_graph *graph,
711 int parent_index, int index)
712{
713 return index * graph->nodes_count + parent_index;
714}
715
716static void objagg_tmp_graph_edge_set(struct objagg_tmp_graph *graph,
717 int parent_index, int index)
718{
719 int edge_index = objagg_tmp_graph_edge_index(graph, index,
720 parent_index);
721
722 __set_bit(edge_index, graph->edges);
723}
724
725static bool objagg_tmp_graph_is_edge(struct objagg_tmp_graph *graph,
726 int parent_index, int index)
727{
728 int edge_index = objagg_tmp_graph_edge_index(graph, index,
729 parent_index);
730
731 return test_bit(edge_index, graph->edges);
732}
733
734static unsigned int objagg_tmp_graph_node_weight(struct objagg_tmp_graph *graph,
735 unsigned int index)
736{
737 struct objagg_tmp_node *node = &graph->nodes[index];
738 unsigned int weight = node->objagg_obj->stats.user_count;
739 int j;
740
741 /* Node weight is sum of node users and all other nodes users
742 * that this node can represent with delta.
743 */
744
745 if (node->crossed_out)
746 return 0;
747 for (j = 0; j < graph->nodes_count; j++) {
748 if (!objagg_tmp_graph_is_edge(graph, index, j))
749 continue;
750 node = &graph->nodes[j];
751 if (node->crossed_out)
752 continue;
753 weight += node->objagg_obj->stats.user_count;
754 }
755 return weight;
756}
757
758static int objagg_tmp_graph_node_max_weight(struct objagg_tmp_graph *graph)
759{
760 unsigned int max_weight = 0;
761 unsigned int weight;
762 int max_index = -1;
763 int i;
764
765 for (i = 0; i < graph->nodes_count; i++) {
766 weight = objagg_tmp_graph_node_weight(graph, i);
767 if (weight > max_weight) {
768 max_weight = weight;
769 max_index = i;
770 }
771 }
772 return max_index;
773}
774
775static struct objagg_tmp_graph *objagg_tmp_graph_create(struct objagg *objagg)
776{
777 unsigned int nodes_count = objagg->obj_count;
778 struct objagg_tmp_graph *graph;
779 struct objagg_tmp_node *node;
780 struct objagg_tmp_node *pnode;
781 struct objagg_obj *objagg_obj;
782 size_t alloc_size;
783 int i, j;
784
785 graph = kzalloc(sizeof(*graph), GFP_KERNEL);
786 if (!graph)
787 return NULL;
788
789 graph->nodes = kcalloc(nodes_count, sizeof(*graph->nodes), GFP_KERNEL);
790 if (!graph->nodes)
791 goto err_nodes_alloc;
792 graph->nodes_count = nodes_count;
793
794 alloc_size = BITS_TO_LONGS(nodes_count * nodes_count) *
795 sizeof(unsigned long);
796 graph->edges = kzalloc(alloc_size, GFP_KERNEL);
797 if (!graph->edges)
798 goto err_edges_alloc;
799
800 i = 0;
801 list_for_each_entry(objagg_obj, &objagg->obj_list, list) {
802 node = &graph->nodes[i++];
803 node->objagg_obj = objagg_obj;
804 }
805
806 /* Assemble a temporary graph. Insert edge X->Y in case Y can be
807 * in delta of X.
808 */
809 for (i = 0; i < nodes_count; i++) {
810 for (j = 0; j < nodes_count; j++) {
811 if (i == j)
812 continue;
813 pnode = &graph->nodes[i];
814 node = &graph->nodes[j];
815 if (objagg->ops->delta_check(objagg->priv,
816 pnode->objagg_obj->obj,
817 node->objagg_obj->obj)) {
818 objagg_tmp_graph_edge_set(graph, i, j);
819
820 }
821 }
822 }
823 return graph;
824
825err_edges_alloc:
826 kfree(graph->nodes);
827err_nodes_alloc:
828 kfree(graph);
829 return NULL;
830}
831
832static void objagg_tmp_graph_destroy(struct objagg_tmp_graph *graph)
833{
834 kfree(graph->edges);
835 kfree(graph->nodes);
836 kfree(graph);
837}
838
839static int
840objagg_opt_simple_greedy_fillup_hints(struct objagg_hints *objagg_hints,
841 struct objagg *objagg)
842{
843 struct objagg_hints_node *hnode, *parent_hnode;
844 struct objagg_tmp_graph *graph;
845 struct objagg_tmp_node *node;
846 int index;
847 int j;
848 int err;
849
850 graph = objagg_tmp_graph_create(objagg);
851 if (!graph)
852 return -ENOMEM;
853
854 /* Find the nodes from the ones that can accommodate most users
855 * and cross them out of the graph. Save them to the hint list.
856 */
857 while ((index = objagg_tmp_graph_node_max_weight(graph)) != -1) {
858 node = &graph->nodes[index];
859 node->crossed_out = true;
860 hnode = objagg_hints_node_create(objagg_hints,
861 node->objagg_obj,
862 objagg->ops->obj_size,
863 NULL);
864 if (IS_ERR(hnode)) {
865 err = PTR_ERR(hnode);
866 goto out;
867 }
868 parent_hnode = hnode;
869 for (j = 0; j < graph->nodes_count; j++) {
870 if (!objagg_tmp_graph_is_edge(graph, index, j))
871 continue;
872 node = &graph->nodes[j];
873 if (node->crossed_out)
874 continue;
875 node->crossed_out = true;
876 hnode = objagg_hints_node_create(objagg_hints,
877 node->objagg_obj,
878 objagg->ops->obj_size,
879 parent_hnode);
880 if (IS_ERR(hnode)) {
881 err = PTR_ERR(hnode);
882 goto out;
883 }
884 }
885 }
886
887 err = 0;
888out:
889 objagg_tmp_graph_destroy(graph);
890 return err;
891}
892
893struct objagg_opt_algo {
894 int (*fillup_hints)(struct objagg_hints *objagg_hints,
895 struct objagg *objagg);
896};
897
898static const struct objagg_opt_algo objagg_opt_simple_greedy = {
899 .fillup_hints = objagg_opt_simple_greedy_fillup_hints,
900};
901
902
903static const struct objagg_opt_algo *objagg_opt_algos[] = {
904 [OBJAGG_OPT_ALGO_SIMPLE_GREEDY] = &objagg_opt_simple_greedy,
905};
906
907static int objagg_hints_obj_cmp(struct rhashtable_compare_arg *arg,
908 const void *obj)
909{
910 struct rhashtable *ht = arg->ht;
911 struct objagg_hints *objagg_hints =
912 container_of(ht, struct objagg_hints, node_ht);
913 const struct objagg_ops *ops = objagg_hints->ops;
914 const char *ptr = obj;
915
916 ptr += ht->p.key_offset;
917 return ops->hints_obj_cmp ? ops->hints_obj_cmp(ptr, arg->key) :
918 memcmp(ptr, arg->key, ht->p.key_len);
919}
920
921/**
922 * objagg_hints_get - obtains hints instance
923 * @objagg: objagg instance
924 * @opt_algo_type: type of hints finding algorithm
925 *
926 * Note: all locking must be provided by the caller.
927 *
928 * According to the algo type, the existing objects of objagg instance
929 * are going to be went-through to assemble an optimal tree. We call this
930 * tree hints. These hints can be later on used for creation of
931 * a new objagg instance. There, the future object creations are going
932 * to be consulted with these hints in order to find out, where exactly
933 * the new object should be put as a root or delta.
934 *
935 * Returns a pointer to hints instance in case of success,
936 * otherwise it returns pointer error using ERR_PTR macro.
937 */
938struct objagg_hints *objagg_hints_get(struct objagg *objagg,
939 enum objagg_opt_algo_type opt_algo_type)
940{
941 const struct objagg_opt_algo *algo = objagg_opt_algos[opt_algo_type];
942 struct objagg_hints *objagg_hints;
943 int err;
944
945 objagg_hints = kzalloc(sizeof(*objagg_hints), GFP_KERNEL);
946 if (!objagg_hints)
947 return ERR_PTR(-ENOMEM);
948
949 objagg_hints->ops = objagg->ops;
950 objagg_hints->refcount = 1;
951
952 INIT_LIST_HEAD(&objagg_hints->node_list);
953
954 objagg_hints->ht_params.key_len = objagg->ops->obj_size;
955 objagg_hints->ht_params.key_offset =
956 offsetof(struct objagg_hints_node, obj);
957 objagg_hints->ht_params.head_offset =
958 offsetof(struct objagg_hints_node, ht_node);
959 objagg_hints->ht_params.obj_cmpfn = objagg_hints_obj_cmp;
960
961 err = rhashtable_init(&objagg_hints->node_ht, &objagg_hints->ht_params);
962 if (err)
963 goto err_rhashtable_init;
964
965 err = algo->fillup_hints(objagg_hints, objagg);
966 if (err)
967 goto err_fillup_hints;
968
969 if (WARN_ON(objagg_hints->node_count != objagg->obj_count))
970 goto err_node_count_check;
971
972 return objagg_hints;
973
974err_node_count_check:
975err_fillup_hints:
976 objagg_hints_flush(objagg_hints);
977 rhashtable_destroy(&objagg_hints->node_ht);
978err_rhashtable_init:
979 kfree(objagg_hints);
980 return ERR_PTR(err);
981}
982EXPORT_SYMBOL(objagg_hints_get);
983
984/**
985 * objagg_hints_put - puts hints instance
986 * @objagg_hints: objagg hints instance
987 *
988 * Note: all locking must be provided by the caller.
989 */
990void objagg_hints_put(struct objagg_hints *objagg_hints)
991{
992 if (--objagg_hints->refcount)
993 return;
994 objagg_hints_flush(objagg_hints);
995 rhashtable_destroy(&objagg_hints->node_ht);
996 kfree(objagg_hints);
997}
998EXPORT_SYMBOL(objagg_hints_put);
999
1000/**
1001 * objagg_hints_stats_get - obtains stats of the hints instance
1002 * @objagg_hints: hints instance
1003 *
1004 * Note: all locking must be provided by the caller.
1005 *
1006 * The returned structure contains statistics of all objects
1007 * currently in use, ordered by following rules:
1008 * 1) Root objects are always on lower indexes than the rest.
1009 * 2) Objects with higher delta user count are always on lower
1010 * indexes.
1011 * 3) In case multiple objects have the same delta user count,
1012 * the objects are ordered by user count.
1013 *
1014 * Returns a pointer to stats instance in case of success,
1015 * otherwise it returns pointer error using ERR_PTR macro.
1016 */
1017const struct objagg_stats *
1018objagg_hints_stats_get(struct objagg_hints *objagg_hints)
1019{
1020 struct objagg_stats *objagg_stats;
1021 struct objagg_hints_node *hnode;
1022 int i;
1023
1024 objagg_stats = kzalloc(struct_size(objagg_stats, stats_info,
1025 objagg_hints->node_count),
1026 GFP_KERNEL);
1027 if (!objagg_stats)
1028 return ERR_PTR(-ENOMEM);
1029
1030 i = 0;
1031 list_for_each_entry(hnode, &objagg_hints->node_list, list) {
1032 memcpy(&objagg_stats->stats_info[i], &hnode->stats_info,
1033 sizeof(objagg_stats->stats_info[0]));
1034 i++;
1035 }
1036 objagg_stats->stats_info_count = i;
1037
1038 sort(objagg_stats->stats_info, objagg_stats->stats_info_count,
1039 sizeof(struct objagg_obj_stats_info),
1040 objagg_stats_info_sort_cmp_func, NULL);
1041
1042 return objagg_stats;
1043}
1044EXPORT_SYMBOL(objagg_hints_stats_get);
1045
499MODULE_LICENSE("Dual BSD/GPL"); 1046MODULE_LICENSE("Dual BSD/GPL");
500MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>"); 1047MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
501MODULE_DESCRIPTION("Object aggregation manager"); 1048MODULE_DESCRIPTION("Object aggregation manager");
diff --git a/lib/test_objagg.c b/lib/test_objagg.c
index ab57144bb0cd..3744573b6365 100644
--- a/lib/test_objagg.c
+++ b/lib/test_objagg.c
@@ -87,6 +87,15 @@ static void world_obj_put(struct world *world, struct objagg *objagg,
87 87
88#define MAX_KEY_ID_DIFF 5 88#define MAX_KEY_ID_DIFF 5
89 89
90static bool delta_check(void *priv, const void *parent_obj, const void *obj)
91{
92 const struct tokey *parent_key = parent_obj;
93 const struct tokey *key = obj;
94 int diff = key->id - parent_key->id;
95
96 return diff >= 0 && diff <= MAX_KEY_ID_DIFF;
97}
98
90static void *delta_create(void *priv, void *parent_obj, void *obj) 99static void *delta_create(void *priv, void *parent_obj, void *obj)
91{ 100{
92 struct tokey *parent_key = parent_obj; 101 struct tokey *parent_key = parent_obj;
@@ -95,7 +104,7 @@ static void *delta_create(void *priv, void *parent_obj, void *obj)
95 int diff = key->id - parent_key->id; 104 int diff = key->id - parent_key->id;
96 struct delta *delta; 105 struct delta *delta;
97 106
98 if (diff < 0 || diff > MAX_KEY_ID_DIFF) 107 if (!delta_check(priv, parent_obj, obj))
99 return ERR_PTR(-EINVAL); 108 return ERR_PTR(-EINVAL);
100 109
101 delta = kzalloc(sizeof(*delta), GFP_KERNEL); 110 delta = kzalloc(sizeof(*delta), GFP_KERNEL);
@@ -115,7 +124,7 @@ static void delta_destroy(void *priv, void *delta_priv)
115 kfree(delta); 124 kfree(delta);
116} 125}
117 126
118static void *root_create(void *priv, void *obj) 127static void *root_create(void *priv, void *obj, unsigned int id)
119{ 128{
120 struct world *world = priv; 129 struct world *world = priv;
121 struct tokey *key = obj; 130 struct tokey *key = obj;
@@ -268,6 +277,12 @@ stats_put:
268 return err; 277 return err;
269} 278}
270 279
280static bool delta_check_dummy(void *priv, const void *parent_obj,
281 const void *obj)
282{
283 return false;
284}
285
271static void *delta_create_dummy(void *priv, void *parent_obj, void *obj) 286static void *delta_create_dummy(void *priv, void *parent_obj, void *obj)
272{ 287{
273 return ERR_PTR(-EOPNOTSUPP); 288 return ERR_PTR(-EOPNOTSUPP);
@@ -279,6 +294,7 @@ static void delta_destroy_dummy(void *priv, void *delta_priv)
279 294
280static const struct objagg_ops nodelta_ops = { 295static const struct objagg_ops nodelta_ops = {
281 .obj_size = sizeof(struct tokey), 296 .obj_size = sizeof(struct tokey),
297 .delta_check = delta_check_dummy,
282 .delta_create = delta_create_dummy, 298 .delta_create = delta_create_dummy,
283 .delta_destroy = delta_destroy_dummy, 299 .delta_destroy = delta_destroy_dummy,
284 .root_create = root_create, 300 .root_create = root_create,
@@ -292,7 +308,7 @@ static int test_nodelta(void)
292 int i; 308 int i;
293 int err; 309 int err;
294 310
295 objagg = objagg_create(&nodelta_ops, &world); 311 objagg = objagg_create(&nodelta_ops, NULL, &world);
296 if (IS_ERR(objagg)) 312 if (IS_ERR(objagg))
297 return PTR_ERR(objagg); 313 return PTR_ERR(objagg);
298 314
@@ -357,6 +373,7 @@ err_stats_second_zero:
357 373
358static const struct objagg_ops delta_ops = { 374static const struct objagg_ops delta_ops = {
359 .obj_size = sizeof(struct tokey), 375 .obj_size = sizeof(struct tokey),
376 .delta_check = delta_check,
360 .delta_create = delta_create, 377 .delta_create = delta_create,
361 .delta_destroy = delta_destroy, 378 .delta_destroy = delta_destroy,
362 .root_create = root_create, 379 .root_create = root_create,
@@ -793,7 +810,7 @@ static int test_delta(void)
793 int i; 810 int i;
794 int err; 811 int err;
795 812
796 objagg = objagg_create(&delta_ops, &world); 813 objagg = objagg_create(&delta_ops, NULL, &world);
797 if (IS_ERR(objagg)) 814 if (IS_ERR(objagg))
798 return PTR_ERR(objagg); 815 return PTR_ERR(objagg);
799 816
@@ -815,6 +832,170 @@ err_do_action_item:
815 return err; 832 return err;
816} 833}
817 834
835struct hints_case {
836 const unsigned int *key_ids;
837 size_t key_ids_count;
838 struct expect_stats expect_stats;
839 struct expect_stats expect_stats_hints;
840};
841
842static const unsigned int hints_case_key_ids[] = {
843 1, 7, 3, 5, 3, 1, 30, 8, 8, 5, 6, 8,
844};
845
846static const struct hints_case hints_case = {
847 .key_ids = hints_case_key_ids,
848 .key_ids_count = ARRAY_SIZE(hints_case_key_ids),
849 .expect_stats =
850 EXPECT_STATS(7, ROOT(1, 2, 7), ROOT(7, 1, 4), ROOT(30, 1, 1),
851 DELTA(8, 3), DELTA(3, 2),
852 DELTA(5, 2), DELTA(6, 1)),
853 .expect_stats_hints =
854 EXPECT_STATS(7, ROOT(3, 2, 9), ROOT(1, 2, 2), ROOT(30, 1, 1),
855 DELTA(8, 3), DELTA(5, 2),
856 DELTA(6, 1), DELTA(7, 1)),
857};
858
859static void __pr_debug_stats(const struct objagg_stats *stats)
860{
861 int i;
862
863 for (i = 0; i < stats->stats_info_count; i++)
864 pr_debug("Stat index %d key %u: u %d, d %d, %s\n", i,
865 obj_to_key_id(stats->stats_info[i].objagg_obj),
866 stats->stats_info[i].stats.user_count,
867 stats->stats_info[i].stats.delta_user_count,
868 stats->stats_info[i].is_root ? "root" : "noroot");
869}
870
871static void pr_debug_stats(struct objagg *objagg)
872{
873 const struct objagg_stats *stats;
874
875 stats = objagg_stats_get(objagg);
876 if (IS_ERR(stats))
877 return;
878 __pr_debug_stats(stats);
879 objagg_stats_put(stats);
880}
881
882static void pr_debug_hints_stats(struct objagg_hints *objagg_hints)
883{
884 const struct objagg_stats *stats;
885
886 stats = objagg_hints_stats_get(objagg_hints);
887 if (IS_ERR(stats))
888 return;
889 __pr_debug_stats(stats);
890 objagg_stats_put(stats);
891}
892
893static int check_expect_hints_stats(struct objagg_hints *objagg_hints,
894 const struct expect_stats *expect_stats,
895 const char **errmsg)
896{
897 const struct objagg_stats *stats;
898 int err;
899
900 stats = objagg_hints_stats_get(objagg_hints);
901 if (IS_ERR(stats))
902 return PTR_ERR(stats);
903 err = __check_expect_stats(stats, expect_stats, errmsg);
904 objagg_stats_put(stats);
905 return err;
906}
907
908static int test_hints_case(const struct hints_case *hints_case)
909{
910 struct objagg_obj *objagg_obj;
911 struct objagg_hints *hints;
912 struct world world2 = {};
913 struct world world = {};
914 struct objagg *objagg2;
915 struct objagg *objagg;
916 const char *errmsg;
917 int i;
918 int err;
919
920 objagg = objagg_create(&delta_ops, NULL, &world);
921 if (IS_ERR(objagg))
922 return PTR_ERR(objagg);
923
924 for (i = 0; i < hints_case->key_ids_count; i++) {
925 objagg_obj = world_obj_get(&world, objagg,
926 hints_case->key_ids[i]);
927 if (IS_ERR(objagg_obj)) {
928 err = PTR_ERR(objagg_obj);
929 goto err_world_obj_get;
930 }
931 }
932
933 pr_debug_stats(objagg);
934 err = check_expect_stats(objagg, &hints_case->expect_stats, &errmsg);
935 if (err) {
936 pr_err("Stats: %s\n", errmsg);
937 goto err_check_expect_stats;
938 }
939
940 hints = objagg_hints_get(objagg, OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
941 if (IS_ERR(hints)) {
942 err = PTR_ERR(hints);
943 goto err_hints_get;
944 }
945
946 pr_debug_hints_stats(hints);
947 err = check_expect_hints_stats(hints, &hints_case->expect_stats_hints,
948 &errmsg);
949 if (err) {
950 pr_err("Hints stats: %s\n", errmsg);
951 goto err_check_expect_hints_stats;
952 }
953
954 objagg2 = objagg_create(&delta_ops, hints, &world2);
955 if (IS_ERR(objagg))
956 return PTR_ERR(objagg);
957
958 for (i = 0; i < hints_case->key_ids_count; i++) {
959 objagg_obj = world_obj_get(&world2, objagg2,
960 hints_case->key_ids[i]);
961 if (IS_ERR(objagg_obj)) {
962 err = PTR_ERR(objagg_obj);
963 goto err_world2_obj_get;
964 }
965 }
966
967 pr_debug_stats(objagg2);
968 err = check_expect_stats(objagg2, &hints_case->expect_stats_hints,
969 &errmsg);
970 if (err) {
971 pr_err("Stats2: %s\n", errmsg);
972 goto err_check_expect_stats2;
973 }
974
975 err = 0;
976
977err_check_expect_stats2:
978err_world2_obj_get:
979 for (i--; i >= 0; i--)
980 world_obj_put(&world2, objagg, hints_case->key_ids[i]);
981 objagg_hints_put(hints);
982 objagg_destroy(objagg2);
983 i = hints_case->key_ids_count;
984err_check_expect_hints_stats:
985err_hints_get:
986err_check_expect_stats:
987err_world_obj_get:
988 for (i--; i >= 0; i--)
989 world_obj_put(&world, objagg, hints_case->key_ids[i]);
990
991 objagg_destroy(objagg);
992 return err;
993}
994static int test_hints(void)
995{
996 return test_hints_case(&hints_case);
997}
998
818static int __init test_objagg_init(void) 999static int __init test_objagg_init(void)
819{ 1000{
820 int err; 1001 int err;
@@ -822,7 +1003,10 @@ static int __init test_objagg_init(void)
822 err = test_nodelta(); 1003 err = test_nodelta();
823 if (err) 1004 if (err)
824 return err; 1005 return err;
825 return test_delta(); 1006 err = test_delta();
1007 if (err)
1008 return err;
1009 return test_hints();
826} 1010}
827 1011
828static void __exit test_objagg_exit(void) 1012static void __exit test_objagg_exit(void)