]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_callout.c
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * Kernel callout related functions, including moving average calculation
31 * to permit the kernel to know about insufficiently responsive user space
35 #include <string.h> /* memove, memset */
36 #include <stdint.h> /* uint64_t */
37 #include <sys/kern_callout.h>
42 * Initialize a moving average structure for use
44 * Parameters: map Pointer to the moving average state
45 * threshold Threshold % at which to trigger (>100)
46 * kind Kind of trigger(s) to set
50 * Notes: The number of samples in a simple moving average is not
51 * controllable; this might be a future direction.
53 * The simple and weighted thresholds are not separately
54 * controllable; this might be a future direction, but
55 * will likely be unnecessary due to one type being in use
56 * at a time in the most likely scenarios.
59 kco_ma_init(struct kco_moving_average
*map
, int32_t threshold
, int kind
)
61 memset(map
, 0, sizeof(*map
));
63 /* per algorithm init required */
64 map
->ma_flags
|= KCO_MA_F_NEEDS_INIT
;
66 /* set algorithm selector flags */
67 map
->ma_flags
|= kind
;
70 map
->ma_sma_threshold
= threshold
;
71 map
->ma_wma_threshold
= threshold
;
78 * Report on the current moving average information; this is typically only
79 * called after a trigger event.
81 * Parameters: map Pointer to the moving average state
82 * kind Kind of trigger to report on
83 * averagep Pointer to area to receive current
84 * old_averagep Pointer to area to receive previous
85 * thresholdp Pointer to area to receive threshold
87 * Returns: 0 Information not available
88 * 1 Information retrieved
90 * Notes: You can only retrieve one kind of average information at a
91 * time; if you are collecting multiple types, then you must
92 * call this function one time for each type you are interested
96 kco_ma_info(struct kco_moving_average
*map
, int kind
, uint64_t *averagep
, uint64_t *old_averagep
, int32_t *thresholdp
, int *countp
)
103 /* Not collecting this type of data or no data yet*/
104 if (!(map
->ma_flags
& kind
) || (map
->ma_flags
& KCO_MA_F_NEEDS_INIT
))
109 average
= map
->ma_sma
;
110 old_average
= map
->ma_old_sma
;
111 threshold
= map
->ma_sma_threshold
;
112 count
= map
->ma_sma_trigger_count
;
116 average
= map
->ma_wma
;
117 old_average
= map
->ma_old_wma
;
118 threshold
= map
->ma_wma_threshold
;
119 count
= map
->ma_wma_trigger_count
;
124 * Asking for data we don't have or more than one kind of
125 * data at the same time.
130 if (averagep
!= NULL
)
132 if (old_averagep
!= NULL
)
133 *old_averagep
= old_average
;
134 if (thresholdp
!= NULL
)
135 *thresholdp
= threshold
;
146 * Accumulate a sample into a moving average
148 * Parameters: map Pointer to the moving average state
149 * sample_time latency delta time
151 * Returns: 0 Nothing triggered
152 * !0 Bitmap of KCO_MA_F_* flags for the
153 * algorithms which triggered
155 * Notes: Add a delta time sample to the moving average; this function
156 * will return bits for each algorithm which went over its
157 * trigger threshold as a result of receiving the sample.
158 * Callers can then log/complain/panic over the unresponsive
159 * process to which they are calling out.
162 kco_ma_addsample(struct kco_moving_average
*map
, uint64_t sample_time
)
165 int do_init
= (map
->ma_flags
& KCO_MA_F_NEEDS_INIT
);
168 * SIMPLE MOVING AVERAGE
170 * Compute simple moving average over MA_SMA_SAMPLES; incremental is
171 * cheaper than re-sum.
173 if (map
->ma_flags
& KCO_MA_F_SMA
) {
174 map
->ma_old_sma
= map
->ma_sma
;
176 map
->ma_sma
= ((map
->ma_sma
* MA_SMA_SAMPLES
) - map
->ma_sma_samples
[0] + sample_time
) / MA_SMA_SAMPLES
;
177 memmove(&map
->ma_sma_samples
[1], &map
->ma_sma_samples
[0], sizeof(map
->ma_sma_samples
[0]) *(MA_SMA_SAMPLES
- 1));
178 map
->ma_sma_samples
[0] = sample_time
;
180 * Check if percentage change exceeds the allowed trigger
181 * threshold; this will only happen if the sample time
182 * increases more than an acceptable amount; decreases will
183 * not cause a trigger (but will decrease the overall average,
184 * which can cause a trigger the next time).
186 * Note: We don't start triggering on the simple moving
187 * average until after we have enough samples for
188 * the delta to be statistically valid; this is
189 * defined to be MA_SMA_SAMPLES.
191 if (map
->ma_sma_samples
[MA_SMA_SAMPLES
-1] && ((int)((map
->ma_sma
* 100) / map
->ma_old_sma
)) > map
->ma_sma_threshold
) {
192 triggered
|= KCO_MA_F_SMA
;
193 map
->ma_sma_trigger_count
++;
198 * WEIGHTED MOVING AVERAGE
200 * Compute the weighted moving average. Do this by averaging over
201 * two values, one with a lesser weighting than the other; the lesser
202 * weighted value is the persistent historical value, whose sample
203 * weight decreases over time, the older the samples get. Be careful
204 * here to permit strict integer artimatic.
206 if (map
->ma_flags
& KCO_MA_F_WMA
) {
207 map
->ma_old_wma
= map
->ma_wma
;
209 /* Prime the pump, if necessary */
211 map
->ma_old_wma
= sample_time
;
213 map
->ma_wma
= ((((map
->ma_wma
* 90) + sample_time
* ((100*2) - 90))/100) / 2);
216 * Check if percentage change exceeds the allowed trigger
217 * threshold; this will only happen if the sample time
218 * increases more than an acceptable amount; decreases will
219 * not cause a trigger (but will decrease the overall average,
220 * which can cause a trigger the next time).
222 if (((int)(((map
->ma_wma
* 100) / map
->ma_old_wma
))) > map
->ma_wma_threshold
) {
223 triggered
|= KCO_MA_F_WMA
;
224 map
->ma_wma_trigger_count
++;
229 map
->ma_flags
&= ~KCO_MA_F_NEEDS_INIT
;