Hi Gaetan, > -----Original Message----- > From: Gaëtan Rivet [mailto:gaetan.ri...@6wind.com] > Sent: Tuesday, September 5, 2017 7:34 PM > To: Matan Azrad <ma...@mellanox.com> > Cc: dev@dpdk.org > Subject: Re: [PATCH] net/failsafe: stat support enhancement > > On Tue, Sep 05, 2017 at 03:12:55PM +0000, Matan Azrad wrote: > > Hi Gaetan, > > > > > -----Original Message----- > > > From: Gaëtan Rivet [mailto:gaetan.ri...@6wind.com] > > > Sent: Tuesday, September 5, 2017 4:23 PM > > > To: Matan Azrad <ma...@mellanox.com> > > > Cc: dev@dpdk.org > > > Subject: Re: [PATCH] net/failsafe: stat support enhancement > > > > > > Hi Matan, > > > > > > On Tue, Sep 05, 2017 at 12:56:34PM +0300, Matan Azrad wrote: > > > > The previous stats code returned only the current TX sub device stats. > > > > > > > > This enhancement extends it to return the sum of all sub devices > > > > stats with history of removed sub-devices. > > > > > > > > Dedicated stats accumulator saves the stat history of all sub > > > > device remove events. > > > > > > > > Each failsafe sub device contains the last stats asked by the user > > > > and updates the accumulator in removal time. > > > > > > > > I would like to implement ultimate snapshot on removal time. > > > > The stats_get API needs to be changed to return error in the case > > > > it is too late to retrieve statistics. > > > > > > You need to have this API evolution first. It is not assured to be > > > accepted by the community. > > > > > > > I already sent suggestion to mailing list, find "stats_get API: return value > suggestion": > > No objections for now. > > > > > > > As it is, this version is incorrect, because the only available > > > stats for a removed slave is the last snapshot. > > > > > > > It is for sure better from the previous version, the accuracy can be > > better if my suggestion will be accepted. > > If it is, I will improve it. > > > > > Thus it complicates the rules while still being incorrect. Even if > > > you were able to push for this API evolution, PMDs with hard > > > counters would be the ones to return an error code on stat read while > removed. > > > You may be lucky at the moment because MLX drivers do not support > > > hard counters, but this won't always be true (and it will be false soon > enough). > > > You will thus be back at square one, with a new useless API and > > > still incorrect stats in the fail-safe. On the other hand, the > > > fail-safe should strive to be as easy to use as possible with most > > > drivers, and not cater specifically to soft- counters ones. > > > > > > So, my take on this: I understand that aggregated stats would be > interesting. > > > Keep it simple & stupid: simple aggregation on stats_get. > > > You will have a rollback at some point on device removal, but this > > > is still easier to detect / deal with than partially / sometimes incorrect > stats. > > > > > > > 100% accuracy is impossible when removal event is in the game, but we > > can do it better as we can. > > > > As I wrote in commit log(if stat gets will return value): > > When some drivers can give the stats after RMV interrupt and before > > dev_close, We just can to improve accuracy and be closer to 100%. > > The stats of the sub devices which return error will be taken from the last > snapshot. > > > > It is just enhancement which is important for customers. > > > > The trade-off is between accuracy and complexity, both at the fail-safe level > and at the application level. > > Your solution | KISS solution > -------------------------+-------------------------------- > Accuracy Closer to reality. | Farther from reality. > Upon device removal, | Upon device removal, > only packets received | all previous accounted received > since the last stats_get | packets are missing, inducing > are missing. | a stats rollback from the app > | PoV. > -------------------------+-------------------------------- > Complexity Medium implementation | Simple implementation. > (fast-path) complexity. | Two hotplug sequences will be > The accumulator induces | identical (from a stats PoV). > a trailing effect | > between device remove / | > plugin, thus incurring | > edge-effects and | > reducing idempotency of | > hotplug sequences. | > -------------------------+-------------------------------- > Complexity Statistical errors | Glaring statistical errors > (application) induced by device | induced by device removal. > removal is hard. | Detecting those (stats rollback) > Device removal is | is trivial and can thus be > pretty much invisible. | mitigated. > | > Plays nice with the | While easier to deal with, > "seamless" feature of | it actually pushes application > fail-safe, but might be | to have custom code-path for > a curse in disguise. | the fail-safe PMD, which goes > | against its design principles. > >
Thanks a lot for the analysis. I agree very much with your complexity analysis, I have version to deliver the accumulator update function from the remove interrupt to the fs_stats_get function with more complexity in fs_stats_get. Is it interesting you? > I consider that your proposed API will only somewhat fix errors with PMDs > having software counters. Thus it being accepted or rejected is irrelevant for > this assessment. And improve the applications (and failsafe) report about optional errors in the current stats_get. > > While I strongly support the simplest solution for any implementation, I > dislike going against the fail-safe core principles. > > This is a very flimsy sheet of ice we are walking upon. Keep in mind that at > the first complication due to your proposal, it will be reverted and the KISS > solution used instead. > But sometimes if the accuracy is just beside us and we can take it easily, why not? > But as it is, I thus accept it. I will do a proper review (there are a few > things to > fix still, now that the `why` is dealt with) soon. > > > > > By this way, failsafe can get stats snapshot in removal interrupt > > > > callback for each PMD which can give stats after removal event. > > > > > > > > Signed-off-by: Matan Azrad <ma...@mellanox.com> > > > > --- > > > > drivers/net/failsafe/failsafe_ether.c | 33 > > > +++++++++++++++++++++++++++++++++ > > > > drivers/net/failsafe/failsafe_ops.c | 16 ++++++++++++---- > > > > drivers/net/failsafe/failsafe_private.h | 5 +++++ > > > > 3 files changed, 50 insertions(+), 4 deletions(-) > > > > > > > > diff --git a/drivers/net/failsafe/failsafe_ether.c > > > > b/drivers/net/failsafe/failsafe_ether.c > > > > index a3a8cce..133080d 100644 > > > > --- a/drivers/net/failsafe/failsafe_ether.c > > > > +++ b/drivers/net/failsafe/failsafe_ether.c > > > > @@ -399,6 +399,37 @@ failsafe_eth_dev_state_sync(struct > > > > rte_eth_dev > > > *dev) > > > > return ret; > > > > } > > > > > > > > +void > > > > +fs_increment_stats(struct rte_eth_stats *from, struct > > > > +rte_eth_stats > > > > +*to) { > > > > + uint8_t i; > > > > + > > > > + RTE_ASSERT(from != NULL && to != NULL); > > > > + to->ipackets += from->ipackets; > > > > + to->opackets += from->opackets; > > > > + to->ibytes += from->ibytes; > > > > + to->obytes += from->obytes; > > > > + to->imissed += from->imissed; > > > > + to->ierrors += from->ierrors; > > > > + to->oerrors += from->oerrors; > > > > + to->rx_nombuf += from->rx_nombuf; > > > > + for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS; i++) { > > > > + to->q_ipackets[i] += from->q_ipackets[i]; > > > > + to->q_opackets[i] += from->q_opackets[i]; > > > > + to->q_ibytes[i] += from->q_ibytes[i]; > > > > + to->q_obytes[i] += from->q_obytes[i]; > > > > + to->q_errors[i] += from->q_errors[i]; > > > > + } > > > > +} > > > > + > > > > +void > > > > +fs_increment_stats_accumulator(struct sub_device *sdev) { > > > > + fs_increment_stats(&sdev->stats_snapshot, > > > > + &PRIV(sdev->fs_dev)->stats_accumulator); > > > > + memset(&sdev->stats_snapshot, 0, sizeof(struct rte_eth_stats)); > > > > +} > > > > + > > > > int > > > > failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused, > > > > enum rte_eth_event_type event > > > __rte_unused, @@ -410,6 +441,8 @@ > > > > failsafe_eth_rmv_event_callback(uint8_t port_id __rte_unused, > > > > fs_switch_dev(sdev->fs_dev, sdev); > > > > /* Use safe bursts in any case. */ > > > > set_burst_fn(sdev->fs_dev, 1); > > > > + /* Increment the stats accumulator by the last stats snapshot. > > > > */ > > > > + fs_increment_stats_accumulator(sdev); > > > > /* > > > > * Async removal, the sub-PMD will try to unregister > > > > * the callback at the source of the current thread context. > > > > diff --git a/drivers/net/failsafe/failsafe_ops.c > > > > b/drivers/net/failsafe/failsafe_ops.c > > > > index ff9ad15..e47cc85 100644 > > > > --- a/drivers/net/failsafe/failsafe_ops.c > > > > +++ b/drivers/net/failsafe/failsafe_ops.c > > > > @@ -586,9 +586,14 @@ static void > > > > fs_stats_get(struct rte_eth_dev *dev, > > > > struct rte_eth_stats *stats) { > > > > - if (TX_SUBDEV(dev) == NULL) > > > > - return; > > > > - rte_eth_stats_get(PORT_ID(TX_SUBDEV(dev)), stats); > > > > + struct sub_device *sdev; > > > > + uint8_t i; > > > > + > > > > + memcpy(stats, &PRIV(dev)->stats_accumulator, sizeof(*stats)); > > > > + FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { > > > > + rte_eth_stats_get(PORT_ID(sdev), &sdev->stats_snapshot); > > > > + fs_increment_stats(&sdev->stats_snapshot, stats); > > > > + } > > > > } > > > > > > > > static void > > > > @@ -597,8 +602,11 @@ fs_stats_reset(struct rte_eth_dev *dev) > > > > struct sub_device *sdev; > > > > uint8_t i; > > > > > > > > - FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) > > > > + FOREACH_SUBDEV_STATE(sdev, i, dev, DEV_ACTIVE) { > > > > rte_eth_stats_reset(PORT_ID(sdev)); > > > > + memset(&sdev->stats_snapshot, 0, sizeof(struct > > > rte_eth_stats)); > > > > + } > > > > + memset(&PRIV(dev)->stats_accumulator, 0, sizeof(struct > > > > +rte_eth_stats)); > > > > } > > > > > > > > /** > > > > diff --git a/drivers/net/failsafe/failsafe_private.h > > > > b/drivers/net/failsafe/failsafe_private.h > > > > index 0361cf4..267c749 100644 > > > > --- a/drivers/net/failsafe/failsafe_private.h > > > > +++ b/drivers/net/failsafe/failsafe_private.h > > > > @@ -102,6 +102,8 @@ struct sub_device { > > > > uint8_t sid; > > > > /* Device state machine */ > > > > enum dev_state state; > > > > + /* Last stats snapshot passed to user */ > > > > + struct rte_eth_stats stats_snapshot; > > > > /* Some device are defined as a command line */ > > > > char *cmdline; > > > > /* fail-safe device backreference */ @@ -140,6 +142,7 @@ struct > > > > fs_priv { > > > > * synchronized state. > > > > */ > > > > enum dev_state state; > > > > + struct rte_eth_stats stats_accumulator; > > > > unsigned int pending_alarm:1; /* An alarm is pending */ > > > > /* flow isolation state */ > > > > int flow_isolated:1; > > > > @@ -180,6 +183,8 @@ int failsafe_eal_uninit(struct rte_eth_dev > > > > *dev); > > > > > > > > int failsafe_eth_dev_state_sync(struct rte_eth_dev *dev); void > > > > failsafe_dev_remove(struct rte_eth_dev *dev); > > > > +void fs_increment_stats(struct rte_eth_stats *from, struct > > > > +rte_eth_stats *to); void fs_increment_stats_accumulator(struct > > > > +sub_device *sdev); > > > > int failsafe_eth_rmv_event_callback(uint8_t port_id, > > > > enum rte_eth_event_type type, > > > > void *arg, void *out); > > > > -- > > > > 2.7.4 > > > > > > > > > > -- > > > Gaëtan Rivet > > > 6WIND > > -- > Gaëtan Rivet > 6WIND Thanks, Matan azrad