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