162306a36Sopenharmony_ci======================================================
262306a36Sopenharmony_ciNet DIM - Generic Network Dynamic Interrupt Moderation
362306a36Sopenharmony_ci======================================================
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci:Author: Tal Gilboa <talgi@mellanox.com>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci.. contents:: :depth: 2
862306a36Sopenharmony_ci
962306a36Sopenharmony_ciAssumptions
1062306a36Sopenharmony_ci===========
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciThis document assumes the reader has basic knowledge in network drivers
1362306a36Sopenharmony_ciand in general interrupt moderation.
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciIntroduction
1762306a36Sopenharmony_ci============
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciDynamic Interrupt Moderation (DIM) (in networking) refers to changing the
2062306a36Sopenharmony_ciinterrupt moderation configuration of a channel in order to optimize packet
2162306a36Sopenharmony_ciprocessing. The mechanism includes an algorithm which decides if and how to
2262306a36Sopenharmony_cichange moderation parameters for a channel, usually by performing an analysis on
2362306a36Sopenharmony_ciruntime data sampled from the system. Net DIM is such a mechanism. In each
2462306a36Sopenharmony_ciiteration of the algorithm, it analyses a given sample of the data, compares it
2562306a36Sopenharmony_cito the previous sample and if required, it can decide to change some of the
2662306a36Sopenharmony_ciinterrupt moderation configuration fields. The data sample is composed of data
2762306a36Sopenharmony_cibandwidth, the number of packets and the number of events. The time between
2862306a36Sopenharmony_cisamples is also measured. Net DIM compares the current and the previous data and
2962306a36Sopenharmony_cireturns an adjusted interrupt moderation configuration object. In some cases,
3062306a36Sopenharmony_cithe algorithm might decide not to change anything. The configuration fields are
3162306a36Sopenharmony_cithe minimum duration (microseconds) allowed between events and the maximum
3262306a36Sopenharmony_cinumber of wanted packets per event. The Net DIM algorithm ascribes importance to
3362306a36Sopenharmony_ciincrease bandwidth over reducing interrupt rate.
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciNet DIM Algorithm
3762306a36Sopenharmony_ci=================
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciEach iteration of the Net DIM algorithm follows these steps:
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#. Calculates new data sample.
4262306a36Sopenharmony_ci#. Compares it to previous sample.
4362306a36Sopenharmony_ci#. Makes a decision - suggests interrupt moderation configuration fields.
4462306a36Sopenharmony_ci#. Applies a schedule work function, which applies suggested configuration.
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciThe first two steps are straightforward, both the new and the previous data are
4762306a36Sopenharmony_cisupplied by the driver registered to Net DIM. The previous data is the new data
4862306a36Sopenharmony_cisupplied to the previous iteration. The comparison step checks the difference
4962306a36Sopenharmony_cibetween the new and previous data and decides on the result of the last step.
5062306a36Sopenharmony_ciA step would result as "better" if bandwidth increases and as "worse" if
5162306a36Sopenharmony_cibandwidth reduces. If there is no change in bandwidth, the packet rate is
5262306a36Sopenharmony_cicompared in a similar fashion - increase == "better" and decrease == "worse".
5362306a36Sopenharmony_ciIn case there is no change in the packet rate as well, the interrupt rate is
5462306a36Sopenharmony_cicompared. Here the algorithm tries to optimize for lower interrupt rate so an
5562306a36Sopenharmony_ciincrease in the interrupt rate is considered "worse" and a decrease is
5662306a36Sopenharmony_ciconsidered "better". Step #2 has an optimization for avoiding false results: it
5762306a36Sopenharmony_cionly considers a difference between samples as valid if it is greater than a
5862306a36Sopenharmony_cicertain percentage. Also, since Net DIM does not measure anything by itself, it
5962306a36Sopenharmony_ciassumes the data provided by the driver is valid.
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciStep #3 decides on the suggested configuration based on the result from step #2
6262306a36Sopenharmony_ciand the internal state of the algorithm. The states reflect the "direction" of
6362306a36Sopenharmony_cithe algorithm: is it going left (reducing moderation), right (increasing
6462306a36Sopenharmony_cimoderation) or standing still. Another optimization is that if a decision
6562306a36Sopenharmony_cito stay still is made multiple times, the interval between iterations of the
6662306a36Sopenharmony_cialgorithm would increase in order to reduce calculation overhead. Also, after
6762306a36Sopenharmony_ci"parking" on one of the most left or most right decisions, the algorithm may
6862306a36Sopenharmony_cidecide to verify this decision by taking a step in the other direction. This is
6962306a36Sopenharmony_cidone in order to avoid getting stuck in a "deep sleep" scenario. Once a
7062306a36Sopenharmony_cidecision is made, an interrupt moderation configuration is selected from
7162306a36Sopenharmony_cithe predefined profiles.
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciThe last step is to notify the registered driver that it should apply the
7462306a36Sopenharmony_cisuggested configuration. This is done by scheduling a work function, defined by
7562306a36Sopenharmony_cithe Net DIM API and provided by the registered driver.
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciAs you can see, Net DIM itself does not actively interact with the system. It
7862306a36Sopenharmony_ciwould have trouble making the correct decisions if the wrong data is supplied to
7962306a36Sopenharmony_ciit and it would be useless if the work function would not apply the suggested
8062306a36Sopenharmony_ciconfiguration. This does, however, allow the registered driver some room for
8162306a36Sopenharmony_cimanoeuvre as it may provide partial data or ignore the algorithm suggestion
8262306a36Sopenharmony_ciunder some conditions.
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciRegistering a Network Device to DIM
8662306a36Sopenharmony_ci===================================
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ciNet DIM API exposes the main function net_dim().
8962306a36Sopenharmony_ciThis function is the entry point to the Net
9062306a36Sopenharmony_ciDIM algorithm and has to be called every time the driver would like to check if
9162306a36Sopenharmony_ciit should change interrupt moderation parameters. The driver should provide two
9262306a36Sopenharmony_cidata structures: :c:type:`struct dim <dim>` and
9362306a36Sopenharmony_ci:c:type:`struct dim_sample <dim_sample>`. :c:type:`struct dim <dim>`
9462306a36Sopenharmony_cidescribes the state of DIM for a specific object (RX queue, TX queue,
9562306a36Sopenharmony_ciother queues, etc.). This includes the current selected profile, previous data
9662306a36Sopenharmony_cisamples, the callback function provided by the driver and more.
9762306a36Sopenharmony_ci:c:type:`struct dim_sample <dim_sample>` describes a data sample,
9862306a36Sopenharmony_ciwhich will be compared to the data sample stored in :c:type:`struct dim <dim>`
9962306a36Sopenharmony_ciin order to decide on the algorithm's next
10062306a36Sopenharmony_cistep. The sample should include bytes, packets and interrupts, measured by
10162306a36Sopenharmony_cithe driver.
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciIn order to use Net DIM from a networking driver, the driver needs to call the
10462306a36Sopenharmony_cimain net_dim() function. The recommended method is to call net_dim() on each
10562306a36Sopenharmony_ciinterrupt. Since Net DIM has a built-in moderation and it might decide to skip
10662306a36Sopenharmony_ciiterations under certain conditions, there is no need to moderate the net_dim()
10762306a36Sopenharmony_cicalls as well. As mentioned above, the driver needs to provide an object of type
10862306a36Sopenharmony_ci:c:type:`struct dim <dim>` to the net_dim() function call. It is advised for
10962306a36Sopenharmony_cieach entity using Net DIM to hold a :c:type:`struct dim <dim>` as part of its
11062306a36Sopenharmony_cidata structure and use it as the main Net DIM API object.
11162306a36Sopenharmony_ciThe :c:type:`struct dim_sample <dim_sample>` should hold the latest
11262306a36Sopenharmony_cibytes, packets and interrupts count. No need to perform any calculations, just
11362306a36Sopenharmony_ciinclude the raw data.
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciThe net_dim() call itself does not return anything. Instead Net DIM relies on
11662306a36Sopenharmony_cithe driver to provide a callback function, which is called when the algorithm
11762306a36Sopenharmony_cidecides to make a change in the interrupt moderation parameters. This callback
11862306a36Sopenharmony_ciwill be scheduled and run in a separate thread in order not to add overhead to
11962306a36Sopenharmony_cithe data flow. After the work is done, Net DIM algorithm needs to be set to
12062306a36Sopenharmony_cithe proper state in order to move to the next iteration.
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciExample
12462306a36Sopenharmony_ci=======
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciThe following code demonstrates how to register a driver to Net DIM. The actual
12762306a36Sopenharmony_ciusage is not complete but it should make the outline of the usage clear.
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci.. code-block:: c
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci  #include <linux/dim.h>
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci  /* Callback for net DIM to schedule on a decision to change moderation */
13462306a36Sopenharmony_ci  void my_driver_do_dim_work(struct work_struct *work)
13562306a36Sopenharmony_ci  {
13662306a36Sopenharmony_ci	/* Get struct dim from struct work_struct */
13762306a36Sopenharmony_ci	struct dim *dim = container_of(work, struct dim,
13862306a36Sopenharmony_ci				       work);
13962306a36Sopenharmony_ci	/* Do interrupt moderation related stuff */
14062306a36Sopenharmony_ci	...
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* Signal net DIM work is done and it should move to next iteration */
14362306a36Sopenharmony_ci	dim->state = DIM_START_MEASURE;
14462306a36Sopenharmony_ci  }
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci  /* My driver's interrupt handler */
14762306a36Sopenharmony_ci  int my_driver_handle_interrupt(struct my_driver_entity *my_entity, ...)
14862306a36Sopenharmony_ci  {
14962306a36Sopenharmony_ci	...
15062306a36Sopenharmony_ci	/* A struct to hold current measured data */
15162306a36Sopenharmony_ci	struct dim_sample dim_sample;
15262306a36Sopenharmony_ci	...
15362306a36Sopenharmony_ci	/* Initiate data sample struct with current data */
15462306a36Sopenharmony_ci	dim_update_sample(my_entity->events,
15562306a36Sopenharmony_ci		          my_entity->packets,
15662306a36Sopenharmony_ci		          my_entity->bytes,
15762306a36Sopenharmony_ci		          &dim_sample);
15862306a36Sopenharmony_ci	/* Call net DIM */
15962306a36Sopenharmony_ci	net_dim(&my_entity->dim, dim_sample);
16062306a36Sopenharmony_ci	...
16162306a36Sopenharmony_ci  }
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci  /* My entity's initialization function (my_entity was already allocated) */
16462306a36Sopenharmony_ci  int my_driver_init_my_entity(struct my_driver_entity *my_entity, ...)
16562306a36Sopenharmony_ci  {
16662306a36Sopenharmony_ci	...
16762306a36Sopenharmony_ci	/* Initiate struct work_struct with my driver's callback function */
16862306a36Sopenharmony_ci	INIT_WORK(&my_entity->dim.work, my_driver_do_dim_work);
16962306a36Sopenharmony_ci	...
17062306a36Sopenharmony_ci  }
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciDynamic Interrupt Moderation (DIM) library API
17362306a36Sopenharmony_ci==============================================
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci.. kernel-doc:: include/linux/dim.h
17662306a36Sopenharmony_ci    :internal:
177