• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2  /* Copyright (c) 2019 Mellanox Technologies. */
3  
4  #ifndef DIM_H
5  #define DIM_H
6  
7  #include <linux/module.h>
8  
9  /**
10   * Number of events between DIM iterations.
11   * Causes a moderation of the algorithm run.
12   */
13  #define DIM_NEVENTS 64
14  
15  /**
16   * Is a difference between values justifies taking an action.
17   * We consider 10% difference as significant.
18   */
19  #define IS_SIGNIFICANT_DIFF(val, ref) \
20  	((ref) && (((100UL * abs((val) - (ref))) / (ref)) > 10))
21  
22  /**
23   * Calculate the gap between two values.
24   * Take wrap-around and variable size into consideration.
25   */
26  #define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) \
27  		& (BIT_ULL(bits) - 1))
28  
29  /**
30   * Structure for CQ moderation values.
31   * Used for communications between DIM and its consumer.
32   *
33   * @usec: CQ timer suggestion (by DIM)
34   * @pkts: CQ packet counter suggestion (by DIM)
35   * @cq_period_mode: CQ priod count mode (from CQE/EQE)
36   */
37  struct dim_cq_moder {
38  	u16 usec;
39  	u16 pkts;
40  	u16 comps;
41  	u8 cq_period_mode;
42  };
43  
44  /**
45   * Structure for DIM sample data.
46   * Used for communications between DIM and its consumer.
47   *
48   * @time: Sample timestamp
49   * @pkt_ctr: Number of packets
50   * @byte_ctr: Number of bytes
51   * @event_ctr: Number of events
52   */
53  struct dim_sample {
54  	ktime_t time;
55  	u32 pkt_ctr;
56  	u32 byte_ctr;
57  	u16 event_ctr;
58  	u32 comp_ctr;
59  };
60  
61  /**
62   * Structure for DIM stats.
63   * Used for holding current measured rates.
64   *
65   * @ppms: Packets per msec
66   * @bpms: Bytes per msec
67   * @epms: Events per msec
68   */
69  struct dim_stats {
70  	int ppms; /* packets per msec */
71  	int bpms; /* bytes per msec */
72  	int epms; /* events per msec */
73  	int cpms; /* completions per msec */
74  	int cpe_ratio; /* ratio of completions to events */
75  };
76  
77  /**
78   * Main structure for dynamic interrupt moderation (DIM).
79   * Used for holding all information about a specific DIM instance.
80   *
81   * @state: Algorithm state (see below)
82   * @prev_stats: Measured rates from previous iteration (for comparison)
83   * @start_sample: Sampled data at start of current iteration
84   * @work: Work to perform on action required
85   * @priv: A pointer to the struct that points to dim
86   * @profile_ix: Current moderation profile
87   * @mode: CQ period count mode
88   * @tune_state: Algorithm tuning state (see below)
89   * @steps_right: Number of steps taken towards higher moderation
90   * @steps_left: Number of steps taken towards lower moderation
91   * @tired: Parking depth counter
92   */
93  struct dim {
94  	u8 state;
95  	struct dim_stats prev_stats;
96  	struct dim_sample start_sample;
97  	struct dim_sample measuring_sample;
98  	struct work_struct work;
99  	void *priv;
100  	u8 profile_ix;
101  	u8 mode;
102  	u8 tune_state;
103  	u8 steps_right;
104  	u8 steps_left;
105  	u8 tired;
106  };
107  
108  /**
109   * enum dim_cq_period_mode
110   *
111   * These are the modes for CQ period count.
112   *
113   * @DIM_CQ_PERIOD_MODE_START_FROM_EQE: Start counting from EQE
114   * @DIM_CQ_PERIOD_MODE_START_FROM_CQE: Start counting from CQE (implies timer reset)
115   * @DIM_CQ_PERIOD_NUM_MODES: Number of modes
116   */
117  enum {
118  	DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
119  	DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
120  	DIM_CQ_PERIOD_NUM_MODES
121  };
122  
123  /**
124   * enum dim_state
125   *
126   * These are the DIM algorithm states.
127   * These will determine if the algorithm is in a valid state to start an iteration.
128   *
129   * @DIM_START_MEASURE: This is the first iteration (also after applying a new profile)
130   * @DIM_MEASURE_IN_PROGRESS: Algorithm is already in progress - check if
131   * need to perform an action
132   * @DIM_APPLY_NEW_PROFILE: DIM consumer is currently applying a profile - no need to measure
133   */
134  enum {
135  	DIM_START_MEASURE,
136  	DIM_MEASURE_IN_PROGRESS,
137  	DIM_APPLY_NEW_PROFILE,
138  };
139  
140  /**
141   * enum dim_tune_state
142   *
143   * These are the DIM algorithm tune states.
144   * These will determine which action the algorithm should perform.
145   *
146   * @DIM_PARKING_ON_TOP: Algorithm found a local top point - exit on significant difference
147   * @DIM_PARKING_TIRED: Algorithm found a deep top point - don't exit if tired > 0
148   * @DIM_GOING_RIGHT: Algorithm is currently trying higher moderation levels
149   * @DIM_GOING_LEFT: Algorithm is currently trying lower moderation levels
150   */
151  enum {
152  	DIM_PARKING_ON_TOP,
153  	DIM_PARKING_TIRED,
154  	DIM_GOING_RIGHT,
155  	DIM_GOING_LEFT,
156  };
157  
158  /**
159   * enum dim_stats_state
160   *
161   * These are the DIM algorithm statistics states.
162   * These will determine the verdict of current iteration.
163   *
164   * @DIM_STATS_WORSE: Current iteration shows worse performance than before
165   * @DIM_STATS_WORSE: Current iteration shows same performance than before
166   * @DIM_STATS_WORSE: Current iteration shows better performance than before
167   */
168  enum {
169  	DIM_STATS_WORSE,
170  	DIM_STATS_SAME,
171  	DIM_STATS_BETTER,
172  };
173  
174  /**
175   * enum dim_step_result
176   *
177   * These are the DIM algorithm step results.
178   * These describe the result of a step.
179   *
180   * @DIM_STEPPED: Performed a regular step
181   * @DIM_TOO_TIRED: Same kind of step was done multiple times - should go to
182   * tired parking
183   * @DIM_ON_EDGE: Stepped to the most left/right profile
184   */
185  enum {
186  	DIM_STEPPED,
187  	DIM_TOO_TIRED,
188  	DIM_ON_EDGE,
189  };
190  
191  /**
192   *	dim_on_top - check if current state is a good place to stop (top location)
193   *	@dim: DIM context
194   *
195   * Check if current profile is a good place to park at.
196   * This will result in reducing the DIM checks frequency as we assume we
197   * shouldn't probably change profiles, unless traffic pattern wasn't changed.
198   */
199  bool dim_on_top(struct dim *dim);
200  
201  /**
202   *	dim_turn - change profile alterning direction
203   *	@dim: DIM context
204   *
205   * Go left if we were going right and vice-versa.
206   * Do nothing if currently parking.
207   */
208  void dim_turn(struct dim *dim);
209  
210  /**
211   *	dim_park_on_top - enter a parking state on a top location
212   *	@dim: DIM context
213   *
214   * Enter parking state.
215   * Clear all movement history.
216   */
217  void dim_park_on_top(struct dim *dim);
218  
219  /**
220   *	dim_park_tired - enter a tired parking state
221   *	@dim: DIM context
222   *
223   * Enter parking state.
224   * Clear all movement history and cause DIM checks frequency to reduce.
225   */
226  void dim_park_tired(struct dim *dim);
227  
228  /**
229   *	dim_calc_stats - calculate the difference between two samples
230   *	@start: start sample
231   *	@end: end sample
232   *	@curr_stats: delta between samples
233   *
234   * Calculate the delta between two samples (in data rates).
235   * Takes into consideration counter wrap-around.
236   * Returned boolean indicates whether curr_stats are reliable.
237   */
238  bool dim_calc_stats(struct dim_sample *start, struct dim_sample *end,
239  		    struct dim_stats *curr_stats);
240  
241  /**
242   *	dim_update_sample - set a sample's fields with give values
243   *	@event_ctr: number of events to set
244   *	@packets: number of packets to set
245   *	@bytes: number of bytes to set
246   *	@s: DIM sample
247   */
248  static inline void
dim_update_sample(u16 event_ctr,u64 packets,u64 bytes,struct dim_sample * s)249  dim_update_sample(u16 event_ctr, u64 packets, u64 bytes, struct dim_sample *s)
250  {
251  	s->time	     = ktime_get();
252  	s->pkt_ctr   = packets;
253  	s->byte_ctr  = bytes;
254  	s->event_ctr = event_ctr;
255  }
256  
257  /**
258   *	dim_update_sample_with_comps - set a sample's fields with given
259   *	values including the completion parameter
260   *	@event_ctr: number of events to set
261   *	@packets: number of packets to set
262   *	@bytes: number of bytes to set
263   *	@comps: number of completions to set
264   *	@s: DIM sample
265   */
266  static inline void
dim_update_sample_with_comps(u16 event_ctr,u64 packets,u64 bytes,u64 comps,struct dim_sample * s)267  dim_update_sample_with_comps(u16 event_ctr, u64 packets, u64 bytes, u64 comps,
268  			     struct dim_sample *s)
269  {
270  	dim_update_sample(event_ctr, packets, bytes, s);
271  	s->comp_ctr = comps;
272  }
273  
274  /* Net DIM */
275  
276  /**
277   *	net_dim_get_rx_moderation - provide a CQ moderation object for the given RX profile
278   *	@cq_period_mode: CQ period mode
279   *	@ix: Profile index
280   */
281  struct dim_cq_moder net_dim_get_rx_moderation(u8 cq_period_mode, int ix);
282  
283  /**
284   *	net_dim_get_def_rx_moderation - provide the default RX moderation
285   *	@cq_period_mode: CQ period mode
286   */
287  struct dim_cq_moder net_dim_get_def_rx_moderation(u8 cq_period_mode);
288  
289  /**
290   *	net_dim_get_tx_moderation - provide a CQ moderation object for the given TX profile
291   *	@cq_period_mode: CQ period mode
292   *	@ix: Profile index
293   */
294  struct dim_cq_moder net_dim_get_tx_moderation(u8 cq_period_mode, int ix);
295  
296  /**
297   *	net_dim_get_def_tx_moderation - provide the default TX moderation
298   *	@cq_period_mode: CQ period mode
299   */
300  struct dim_cq_moder net_dim_get_def_tx_moderation(u8 cq_period_mode);
301  
302  /**
303   *	net_dim - main DIM algorithm entry point
304   *	@dim: DIM instance information
305   *	@end_sample: Current data measurement
306   *
307   * Called by the consumer.
308   * This is the main logic of the algorithm, where data is processed in order to decide on next
309   * required action.
310   */
311  void net_dim(struct dim *dim, struct dim_sample end_sample);
312  
313  /* RDMA DIM */
314  
315  /*
316   * RDMA DIM profile:
317   * profile size must be of RDMA_DIM_PARAMS_NUM_PROFILES.
318   */
319  #define RDMA_DIM_PARAMS_NUM_PROFILES 9
320  #define RDMA_DIM_START_PROFILE 0
321  
322  /**
323   * rdma_dim - Runs the adaptive moderation.
324   * @dim: The moderation struct.
325   * @completions: The number of completions collected in this round.
326   *
327   * Each call to rdma_dim takes the latest amount of completions that
328   * have been collected and counts them as a new event.
329   * Once enough events have been collected the algorithm decides a new
330   * moderation level.
331   */
332  void rdma_dim(struct dim *dim, u64 completions);
333  
334  #endif /* DIM_H */
335