Hi Eelco, MFEX v7 will be available shorty EOD today. Some comments are inline.
<Sniped> > > + * for that packet. > > + */ > > + uint32_t mfex_hit = (mf_mask & (1 << i)); > > This was supposed to become a bool? > This cannot be a bool as this is used like a bit-mask and set bits are used to iterate the packets. > > > > + /* Call probe on each impl, and cache the result. */ > > + uint32_t i; > > + for (i = 0; i < ARRAY_SIZE(mfex_impls); i++) { > > Why not use int here? Something like will also make Benn happy: > > for (int i = 0; i < ARRAY_SIZE(mfex_impls); i++)... > Taken into v7. > > + bool avail = true; > > + if (mfex_impls[i].probe) { > > + /* Return zero is success, non-zero means error. */ > > + avail = (mfex_impls[i].probe() == 0); > > + } > > + VLOG_INFO("Miniflow Extract implementation %s (available: %s)\n", > > + mfex_impls[i].name, avail ? "True" : "False"); > > + mfex_impls[i].available = avail; > > + } > > +} > > + > > +miniflow_extract_func > > +dp_mfex_impl_get_default(void) > > +{ > > + /* For the first call, this will be NULL. Compute the compile time > > default. > > + */ > > + if (!default_mfex_func) { > > + > Guess the empty newline can be removed. > Taken into v7. > > + VLOG_INFO("Default MFEX implementation is %s.\n", > > + mfex_impls[MFEX_IMPL_SCALAR].name); > > As the default validator has its function defined as NULL, the vlog will be > called > for each call to dp_mfex_impl_get_default(). > So I think this should become a VLOG_ONCE(). > Yes using VLOG_INFO_ONCE(). > > + default_mfex_func = > > + mfex_impls[MFEX_IMPL_SCALAR].extract_func; > > From the top of my head, setting and getting this value only happens from a > single thread. Can you confirm? If not, this also needs to be atomically > set/get. > Agreed taken into v7. > > + } > > + > > + return default_mfex_func; > > +} > > + > > +int32_t > > This should just be int, don’t see the use case for forcing this to 32-bit > especially > for error values? > Fixed. > > +dp_mfex_impl_set_default_by_name(const char *name) { > > + miniflow_extract_func new_default; > > + > > + > > Guess only one newline is needed. > Fixed. > > + int32_t err = dp_mfex_impl_get_by_name(name, &new_default); > > int? See above. Also it’s only used in this function, so what about making it > static? > > > + > > + if (!err) { > > + default_mfex_func = new_default; > > As we log the default implementation above, should we not also log changing > it? > We can but we would be adding un-necessary log as set command already has logs to indicate it. > > + } > > + > > + return err; > > + > > +} > > + > > +uint32_t > > Maybe the return value should be size_t? > Fixed. > > +dp_mfex_impl_get(struct ds *reply, struct dp_netdev_pmd_thread > **pmd_list, > > + size_t n) > > Can n be more specific? Like pmd_list_size? > Fixed. > > +{ > > + /* Add all mfex functions to reply string. */ > > + ds_put_cstr(reply, "Available MFEX implementations:\n"); > > + > > + for (uint32_t i = 0; i < ARRAY_SIZE(mfex_impls); i++) { > > i can just be int here, so for (int i = 0; ... > Fixed. > > + > > + ds_put_format(reply, " %s (available: %s)(pmds: ", > > + mfex_impls[i].name, mfex_impls[i].available ? > > + "True" : "False"); > > + > > + for (size_t j = 0; j < n; j++) { > > + struct dp_netdev_pmd_thread *pmd = pmd_list[j]; > > + if (pmd->core_id == NON_PMD_CORE_ID) { > > + continue; > > + } > > + > > + if (pmd->miniflow_extract_opt == mfex_impls[i].extract_func) { > > + ds_put_format(reply, "%u,", pmd->core_id); > > + } > > + } > > + > > + ds_chomp(reply, ','); > > + > > + if (ds_last(reply) == ' ') { > > + ds_put_cstr(reply, "none"); > > + } > > + > > + ds_put_cstr(reply, ")\n"); > > + } > > + > > + return ARRAY_SIZE(mfex_impls); > > +} > > + > > +/* This function checks all available MFEX implementations, and > > +selects the > > + * returns the function pointer to the one requested by "name". > > + */ > > +int32_t > > See above, I would define this as int. > Fixed. > > +dp_mfex_impl_get_by_name(const char *name, miniflow_extract_func > > +*out_func) { > > + if ((name == NULL) || (out_func == NULL)) { > > + return -EINVAL; > > + } > > + > > + uint32_t i; > > + > > + for (i = 0; i < ARRAY_SIZE(mfex_impls); i++) { > > Think i, should be int, so: > > for (int i = 0; i < ARRAY_SIZE(mfex_impls); i++) { > Fixed. > > + if (strcmp(mfex_impls[i].name, name) == 0) { > > + /* Probe function is optional - so check it is set before > > exec. */ > > + if (!mfex_impls[i].available) { > > + *out_func = NULL; > > + return -EINVAL; > > Maybe we should return a different error, so we can distingue between the two? > For example ENODEV? > Fixed. > > + } > > + > > + *out_func = mfex_impls[i].extract_func; > > + return 0; > > + } > > + } > > + > > + return -EINVAL; > > Maybe return -ENOENT, so we know the entry was not found? > Fixed. *pmd_handle); > > + > > Thought we would add a BUILD_ASSERT() to make sure the > NETDEV_MAX_BURST does not exceed our uint32_t return code? Or did I miss it > somewhere? > Assert added in v7. > > +/* Probe function is used to detect if this CPU has the ISA required > > + * to run the optimized miniflow implementation. > > + * returns one on successful probe. > > + * returns zero on failure. > > + */ > > +typedef int32_t (*miniflow_extract_probe)(void); > > I think we can make this an int, see no need to cast it to 32-bit? > Agreed and fixed. > > + > > +/* This function returns all available implementations to the caller. > > +The > > + * quantity of implementations is returned by the int return value. > > + */ > > +uint32_t > > +dp_mfex_impl_get(struct ds *reply, struct dp_netdev_pmd_thread > **pmd_list, > > + size_t n); > > Thinks this needs the OVS_REQUIRES(dp_netdev_mutex) addition. > Added in v7. > > + > > +/* This function checks all available MFEX implementations, and > > +selects the > > + * returns the function pointer to the one requested by "name". > > + */ > > +int32_t void *aux OVS_UNUSED) { > > + struct ds reply = DS_EMPTY_INITIALIZER; > > + struct shash_node *node; > > + uint32_t count = 0; > > + > > We should hold the dp_netdev_mutex for the below… > Added a mutex . > > + SHASH_FOR_EACH (node, &dp_netdevs) { > > + struct dp_netdev *dp = node->data; > > + > > + /* Get PMD threads list. */ > > + size_t n; > > + struct dp_netdev_pmd_thread **pmd_list; > > + sorted_poll_thread_list(dp, &pmd_list, &n); > > + count = dp_mfex_impl_get(&reply, pmd_list, n); > > + } > > + > > + if (count == 0) { > > + unixctl_command_reply_error(conn, "Error getting Mfex > > + names."); > > In other log messages you use all capital MFEX, can we make it consistent? > Fixed. > > + } else { > > + unixctl_command_reply(conn, ds_cstr(&reply)); > > > Here log/output should be fixed as selecting a unavailable output shows wrong > error message (see also previous comment): > Fixed the formatting . > $ ovs-appctl dpif-netdev/miniflow-parser-set avx512_dot1q_ipv4_udp > Miniflow implementation not available: Unknown miniflow implementation > avx512_dot1q_ipv4_udp. > > > > + ds_destroy(&reply); > > + ovs_mutex_unlock(&dp_netdev_mutex); > > The unlock could as the first thing after the if(err) to save avoid holding > it when > doing slow logging etc. just like below. > Fixed . > > + return; > > + } > > > Argument handling is not as it should be, see my previous comment. I think the > packets count should only be available for the study option (this might not be > the correct patch, but just want to make sure it’s addressed, and I do not > forget). > > So as an example this looks odd trying to set it for a specific PMD: > > $ ovs-appctl dpif-netdev/miniflow-parser-set autovalidator 15 1 > Miniflow implementation set to autovalidator, on pmd thread 1 > > Why do I have to put in the dummy value 15. Here is a quote from my previous > comment: > > “ > We also might need to re-think the command to make sure > packet_count_to_study is only needed for the study command. > So the help text might become something like: > > dpif-netdev/miniflow-parser-set {miniflow_implementation_name | study > [pkt_cnt]} [dp] [pmd_core] ” > > See Harrys mail . Keeping study_cnt at the end does provide easy use and more visibility combining benefits of your proposal and old implementation. > > > + > > + SHASH_FOR_EACH (node, &dp_netdevs) { > > + struct dp_netdev *dp = node->data; > > + > > + /* Get PMD threads list. */ > > + size_t n; > > + struct dp_netdev_pmd_thread **pmd_list; > > + sorted_poll_thread_list(dp, &pmd_list, &n); > > + > > + for (size_t i = 0; i < n; i++) { > > + struct dp_netdev_pmd_thread *pmd = pmd_list[i]; > > + if (pmd->core_id == NON_PMD_CORE_ID) { > > + continue; > > + } > > + > > + /* Initialize MFEX function pointer to the newly configured > > + * default. */ > > + miniflow_extract_func default_func = > > + dp_mfex_impl_get_default(); > > This can be done outside of the loop, so it only needs to be done once. > Taken outside. > > + atomic_uintptr_t *pmd_func = (void *) > > &pmd->miniflow_extract_opt; > > + atomic_store_relaxed(pmd_func, (uintptr_t) default_func); > > + }; > > + } > > + > > + ovs_mutex_unlock(&dp_netdev_mutex); > > + > > + /* Reply with success to command. */ > > + struct ds reply = DS_EMPTY_INITIALIZER; > > + ds_put_format(&reply, "Miniflow implementation set to %s.\n", > > + mfex_name); > > In other places we use "Miniflow Extract implementation", so I think we should > use the same here, i.e. “Miniflow Extract implementation set to %s.”. Even > with > this we still use MFEX and "Miniflow Extract", maybe we should consolidate to > use either one? I think "Miniflow Extract" might be the best as MFEX might > confuse users? > Using Miniflow extract implementation as standard. > > + const char *reply_str = ds_cstr(&reply); > > + unixctl_command_reply(conn, reply_str); > > + VLOG_INFO("%s", reply_str); > > + ds_destroy(&reply); > > +} > > + > > static void > > dpif_netdev_pmd_rebalance(struct unixctl_conn *conn, int argc, > > const char *argv[], void *aux OVS_UNUSED) > > @@ -1298,6 +1390,13 @@ dpif_netdev_init(void) > > unixctl_command_register("dpif-netdev/dpif-impl-get", "", > > 0, 0, dpif_netdev_impl_get, > > NULL); > > + unixctl_command_register("dpif-netdev/miniflow-parser-set", > > + "miniflow implementation name", > > Not it looks like three individual arguments can be passed, guess it needs to > become miniflow_implementation_name. > Fixed. > > + 1, 1, dpif_miniflow_extract_impl_set, > > + NULL); > > -- > > 2.32.0 Regards Amber _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev