1%%%
2%%% Copyright 2011, Boundary
3%%%
4%%% Licensed under the Apache License, Version 2.0 (the "License");
5%%% you may not use this file except in compliance with the License.
6%%% You may obtain a copy of the License at
7%%%
8%%%     http://www.apache.org/licenses/LICENSE-2.0
9%%%
10%%% Unless required by applicable law or agreed to in writing, software
11%%% distributed under the License is distributed on an "AS IS" BASIS,
12%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13%%% See the License for the specific language governing permissions and
14%%% limitations under the License.
15%%%
16
17
18%%%-------------------------------------------------------------------
19%%% File:      folsom_ewma.erl
20%%% @author    joe williams <j@boundary.com>
21%%% @doc
22%%% based on https://github.com/codahale/metrics/blob/development/src/main/java/com/yammer/metrics/stats/EWMA.java
23%%% references:
24%%% http://www.teamquest.com/pdfs/whitepaper/ldavg1.pdf
25%%% http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf
26%%% @end
27%%%-----------------------------------------------------------------
28
29
30-module(folsom_ewma).
31
32-define(M1_ALPHA,   1 - math:exp(-5 / 60.0)).
33-define(M5_ALPHA,   1 - math:exp(-5 / 60.0 / 5)).
34-define(M15_ALPHA,  1 - math:exp(-5 / 60.0 / 15)).
35-define(D1_ALPHA,   1 - math:exp(-5 / 60.0 / 1440)).
36
37-record(ewma, {
38          alpha,
39          interval = 5, % seconds
40          initialized = false,
41          rate = 0,
42          total = 0
43         }).
44
45-export([update/2,
46         new/2,
47         rate/1,
48         tick/1,
49         one_minute_ewma/0,
50         five_minute_ewma/0,
51         fifteen_minute_ewma/0,
52         one_day_ewma/0]).
53
54
55% API
56
57one_minute_ewma() ->
58    new(?M1_ALPHA, 5).
59
60five_minute_ewma() ->
61    new(?M5_ALPHA, 5).
62
63fifteen_minute_ewma() ->
64    new(?M15_ALPHA, 5).
65
66one_day_ewma() ->
67    new(?D1_ALPHA, 5).
68
69new(Alpha, Interval) ->
70    #ewma{alpha = Alpha, interval = Interval}.
71
72update(#ewma{total = Total} = EWMA, Value) ->
73    EWMA#ewma{total = Total + Value}.
74
75tick(#ewma{total = Total, rate = Rate, initialized = Init, interval = Interval, alpha = Alpha} = EWMA) ->
76    InstantRate = Total / Interval,
77    Rate1 = rate_calc(Init, Alpha, Rate, InstantRate),
78    EWMA#ewma{rate = Rate1, initialized = true, total = 0}.
79
80rate(#ewma{rate = Rate}) ->
81    Rate.
82
83% Internal API
84
85rate_calc(true, Alpha, Rate, InstantRate) ->
86    Rate1 = Rate + (Alpha * (InstantRate - Rate)),
87    Rate1;
88rate_calc(false, _, _, InstantRate) ->
89    InstantRate.
90