acl: rework classify method selection
authorKonstantin Ananyev <konstantin.ananyev@intel.com>
Tue, 6 Oct 2020 15:03:06 +0000 (16:03 +0100)
committerDavid Marchand <david.marchand@redhat.com>
Wed, 14 Oct 2020 12:23:00 +0000 (14:23 +0200)
Right now ACL library determines best possible (default) classify method
on a given platform with special constructor function rte_acl_init().
This patch makes the following changes:
 - Move selection of default classify method into a separate private
   function and call it for each ACL context creation (rte_acl_create()).
 - Remove library constructor function
 - Make rte_acl_set_ctx_classify() to check that requested algorithm
   is supported on given platform.

The purpose of these changes to improve and simplify algorithm selection
process and prepare ACL library to be integrated with the
max SIMD bitwidth series in discussion.

Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
lib/librte_acl/rte_acl.c
lib/librte_acl/rte_acl.h

index aa430a3..d1583c5 100644 (file)
@@ -77,55 +77,150 @@ static const rte_acl_classify_t classify_fns[] = {
        [RTE_ACL_CLASSIFY_ALTIVEC] = rte_acl_classify_altivec,
 };
 
-/* by default, use always available scalar code path. */
-static enum rte_acl_classify_alg rte_acl_default_classify =
-       RTE_ACL_CLASSIFY_SCALAR;
+/*
+ * Helper function for acl_check_alg.
+ * Check support for ARM specific classify methods.
+ */
+static int
+acl_check_alg_arm(enum rte_acl_classify_alg alg)
+{
+       if (alg == RTE_ACL_CLASSIFY_NEON) {
+#if defined(RTE_ARCH_ARM64)
+               return 0;
+#elif defined(RTE_ARCH_ARM)
+               if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON))
+                       return 0;
+               return -ENOTSUP;
+#else
+               return -ENOTSUP;
+#endif
+       }
+
+       return -EINVAL;
+}
 
-static void
-rte_acl_set_default_classify(enum rte_acl_classify_alg alg)
+/*
+ * Helper function for acl_check_alg.
+ * Check support for PPC specific classify methods.
+ */
+static int
+acl_check_alg_ppc(enum rte_acl_classify_alg alg)
 {
-       rte_acl_default_classify = alg;
+       if (alg == RTE_ACL_CLASSIFY_ALTIVEC) {
+#if defined(RTE_ARCH_PPC_64)
+               return 0;
+#else
+               return -ENOTSUP;
+#endif
+       }
+
+       return -EINVAL;
 }
 
-extern int
-rte_acl_set_ctx_classify(struct rte_acl_ctx *ctx, enum rte_acl_classify_alg alg)
+/*
+ * Helper function for acl_check_alg.
+ * Check support for x86 specific classify methods.
+ */
+static int
+acl_check_alg_x86(enum rte_acl_classify_alg alg)
 {
-       if (ctx == NULL || (uint32_t)alg >= RTE_DIM(classify_fns))
-               return -EINVAL;
+       if (alg == RTE_ACL_CLASSIFY_AVX2) {
+#ifdef CC_AVX2_SUPPORT
+               if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+                       return 0;
+#endif
+               return -ENOTSUP;
+       }
 
-       ctx->alg = alg;
-       return 0;
+       if (alg == RTE_ACL_CLASSIFY_SSE) {
+#ifdef RTE_ARCH_X86
+               if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
+                       return 0;
+#endif
+               return -ENOTSUP;
+       }
+
+       return -EINVAL;
 }
 
 /*
- * Select highest available classify method as default one.
- * Note that CLASSIFY_AVX2 should be set as a default only
- * if both conditions are met:
- * at build time compiler supports AVX2 and target cpu supports AVX2.
+ * Check if input alg is supported by given platform/binary.
+ * Note that both conditions should be met:
+ * - at build time compiler supports ISA used by given methods
+ * - at run time target cpu supports necessary ISA.
  */
-RTE_INIT(rte_acl_init)
+static int
+acl_check_alg(enum rte_acl_classify_alg alg)
 {
-       enum rte_acl_classify_alg alg = RTE_ACL_CLASSIFY_DEFAULT;
+       switch (alg) {
+       case RTE_ACL_CLASSIFY_NEON:
+               return acl_check_alg_arm(alg);
+       case RTE_ACL_CLASSIFY_ALTIVEC:
+               return acl_check_alg_ppc(alg);
+       case RTE_ACL_CLASSIFY_AVX2:
+       case RTE_ACL_CLASSIFY_SSE:
+               return acl_check_alg_x86(alg);
+       /* scalar method is supported on all platforms */
+       case RTE_ACL_CLASSIFY_SCALAR:
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
 
-#if defined(RTE_ARCH_ARM64)
-       alg =  RTE_ACL_CLASSIFY_NEON;
-#elif defined(RTE_ARCH_ARM)
-       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON))
-               alg =  RTE_ACL_CLASSIFY_NEON;
+/*
+ * Get preferred alg for given platform.
+ */
+static enum rte_acl_classify_alg
+acl_get_best_alg(void)
+{
+       /*
+        * array of supported methods for each platform.
+        * Note that order is important - from most to less preferable.
+        */
+       static const enum rte_acl_classify_alg alg[] = {
+#if defined(RTE_ARCH_ARM)
+               RTE_ACL_CLASSIFY_NEON,
 #elif defined(RTE_ARCH_PPC_64)
-       alg = RTE_ACL_CLASSIFY_ALTIVEC;
-#else
-#ifdef CC_AVX2_SUPPORT
-       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
-               alg = RTE_ACL_CLASSIFY_AVX2;
-       else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
-#else
-       if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
+               RTE_ACL_CLASSIFY_ALTIVEC,
+#elif defined(RTE_ARCH_X86)
+               RTE_ACL_CLASSIFY_AVX2,
+               RTE_ACL_CLASSIFY_SSE,
 #endif
-               alg = RTE_ACL_CLASSIFY_SSE;
+               RTE_ACL_CLASSIFY_SCALAR,
+       };
 
-#endif
-       rte_acl_set_default_classify(alg);
+       uint32_t i;
+
+       /* find best possible alg */
+       for (i = 0; i != RTE_DIM(alg) && acl_check_alg(alg[i]) != 0; i++)
+               ;
+
+       /* we always have to find something suitable */
+       RTE_VERIFY(i != RTE_DIM(alg));
+       return alg[i];
+}
+
+extern int
+rte_acl_set_ctx_classify(struct rte_acl_ctx *ctx, enum rte_acl_classify_alg alg)
+{
+       int32_t rc;
+
+       /* formal parameters check */
+       if (ctx == NULL || (uint32_t)alg >= RTE_DIM(classify_fns))
+               return -EINVAL;
+
+       /* user asked us to select the *best* one */
+       if (alg == RTE_ACL_CLASSIFY_DEFAULT)
+               alg = acl_get_best_alg();
+
+       /* check that given alg is supported */
+       rc = acl_check_alg(alg);
+       if (rc != 0)
+               return rc;
+
+       ctx->alg = alg;
+       return 0;
 }
 
 int
@@ -260,7 +355,7 @@ rte_acl_create(const struct rte_acl_param *param)
                ctx->max_rules = param->max_rule_num;
                ctx->rule_sz = param->rule_size;
                ctx->socket_id = param->socket_id;
-               ctx->alg = rte_acl_default_classify;
+               ctx->alg = acl_get_best_alg();
                strlcpy(ctx->name, param->name, sizeof(ctx->name));
 
                te->data = (void *) ctx;
index b814423..3999f15 100644 (file)
@@ -329,6 +329,7 @@ rte_acl_classify_alg(const struct rte_acl_ctx *ctx,
  *   existing algorithm, and that it could be run on the given CPU.
  * @return
  *   - -EINVAL if the parameters are invalid.
+ *   - -ENOTSUP requested algorithm is not supported by given platform.
  *   - Zero if operation completed successfully.
  */
 extern int