]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sys/pidctrl.h
ping(8): Fix a mandoc related issue
[FreeBSD/FreeBSD.git] / sys / sys / pidctrl.h
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017,  Jeffrey Roberson <jeff@freebsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #ifndef _SYS_PIDCTRL_H_
32 #define _SYS_PIDCTRL_H_
33
34 /*
35  * Proportional Integral Derivative controller.
36  *
37  * This controller is intended to replace a multitude of threshold based
38  * daemon regulation systems.  These systems produce sharp sawtooths of
39  * activity which can cause latency spikes and other undesireable bursty
40  * behavior.  The PID controller adapts to changing load conditions and
41  * adjusts the work done by the daemon to keep a smoother output.
42  *
43  * The setpoint can be thought of as a single watermark that the controller
44  * is always trying to reach.  Compared to a high water/low water type
45  * algorithm the pid controller is dynamically deciding the low water and
46  * regulating to the high water.  The setpoint should be high enough that
47  * the controller and daemon have time to observe the rise in value and
48  * respond to it, else the resource may be exhausted.  More frequent wakeups
49  * permit higher setpoints and less underutilized resources.
50  *
51  * The controller has been optimised for simplicity of math making it quite
52  * inexpensive to execute.  There is no floating point and so the gains must
53  * be the inverse of whole integers.
54  *
55  * Failing to measure and tune the gain parameters can result in wild
56  * oscillations in output.  It is strongly encouraged that controllers are
57  * tested and tuned under a wide variety of workloads before gain values are
58  * picked.  Some reasonable defaults are provided below.
59  */
60
61 struct pidctrl {
62         /* Saved control variables. */
63         int     pc_error;               /* Current error. */
64         int     pc_olderror;            /* Saved error for derivative. */
65         int     pc_integral;            /* Integral accumulator. */
66         int     pc_derivative;          /* Change from last error. */
67         int     pc_input;               /* Last input. */
68         int     pc_output;              /* Last output. */
69         int     pc_ticks;               /* Last sampling time. */
70         /* configuration options, runtime tunable via sysctl */
71         int     pc_setpoint;            /* Desired level */
72         int     pc_interval;            /* Update interval in ticks. */
73         int     pc_bound;               /* Integral wind-up limit. */
74         int     pc_Kpd;                 /* Proportional gain divisor. */
75         int     pc_Kid;                 /* Integral gain divisor. */
76         int     pc_Kdd;                 /* Derivative gain divisor. */
77 };
78
79 /*
80  * Reasonable default divisors.
81  *
82  * Actual gains are 1/divisor.  Gains interact in complex ways with the
83  * setpoint and interval.  Measurement under multiple loads should be
84  * taken to ensure adequate stability and rise time.
85  */
86 #define PIDCTRL_KPD     3               /* Default proportional divisor. */
87 #define PIDCTRL_KID     4               /* Default integral divisor. */
88 #define PIDCTRL_KDD     8               /* Default derivative divisor. */
89 #define PIDCTRL_BOUND   4               /* Bound factor, setpoint multiple. */
90
91 struct sysctl_oid_list;
92
93 void    pidctrl_init(struct pidctrl *pc, int interval, int setpoint,
94             int bound, int Kpd, int Kid, int Kdd);
95 void    pidctrl_init_sysctl(struct pidctrl *pc, struct sysctl_oid_list *parent);
96
97 /*
98  * This is the classic PID controller where the interval is clamped to
99  * [-bound, bound] and the output may be negative.  This should be used
100  * in continuous control loops that can adjust a process variable in
101  * either direction.  This is a descrete time controller and should
102  * only be called once per-interval or the derivative term will be
103  * inaccurate.
104  */
105 int     pidctrl_classic(struct pidctrl *pc, int input);
106
107 /*
108  * This controler is intended for consumer type daemons that can only
109  * regulate in a positive direction, that is to say, they can not exert
110  * positive pressure on the process variable or input.  They can only
111  * reduce it by doing work.  As such the integral is bound between [0, bound]
112  * and the output is similarly a positive value reflecting the units of
113  * work necessary to be completed in the current interval to eliminate error.
114  *
115  * It is a descrete time controller but can be invoked more than once in a
116  * given time interval for ease of client implementation.  This should only
117  * be done in overload situations or the controller may not produce a stable
118  * output.  Calling it less frequently when there is no work to be done will
119  * increase the rise time but should otherwise be harmless.
120  */
121 int     pidctrl_daemon(struct pidctrl *pc, int input);
122
123 #endif  /* !_SYS_PIDCTRL_H_ */