Merge commit 'tuncer/for-jesper'
[etorrent.git] / lib / etorrent-1.0 / src / etorrent_rate.erl
blob12b5fabc77e21d06f254d7e8db36e7c7dd0d66a8
1 %%%-------------------------------------------------------------------
2 %%% File : etorrent_rate.erl
3 %%% Author : Jesper Louis Andersen <>
4 %%% Description : Library of rate calculation code.
5 %%%
6 %%% Created : 10 Jul 2008 by Jesper Louis Andersen <>
7 %%%-------------------------------------------------------------------
8 -module(etorrent_rate).
10 %% API
11 -export([init/0, init/1, update/2, now_secs/0, eta/2]).
13 -include("etorrent_rate.hrl").
15 -define(MAX_RATE_PERIOD, 20).
17 %%====================================================================
18 %% API
19 %%====================================================================
20 %%--------------------------------------------------------------------
21 %% Function: init/1
22 %% Args: Fudge ::= integer() - The fudge skew to start out with
23 %% Description: Return an initialized rate tuple.
24 %%--------------------------------------------------------------------
25 init() -> init(?RATE_FUDGE).
27 init(Fudge) ->
28 T = now_secs(),
29 #peer_rate { next_expected = T + Fudge,
30 last = T - Fudge,
31 rate_since = T - Fudge }.
33 %%--------------------------------------------------------------------
34 %% Function: update/2
35 %% Args: Amount ::= integer() - Number of bytes that arrived
36 %% Rate ::= double() - Current rate
37 %% Total ::= integer() - Total amount of bytes downloaded
38 %% NextExpected ::= time() - When is the next update expected
39 %% Last ::= time() - When was the last update
40 %% RateSince ::= time() - Point in time where the rate has its
41 %% basis
42 %% Description: Update the rate by Amount.
43 %%--------------------------------------------------------------------
44 update(#peer_rate {rate = Rate,
45 total = Total,
46 next_expected = NextExpected,
47 last = Last,
48 rate_since = RateSince} = RT, Amount) when is_integer(Amount) ->
49 T = now_secs(),
50 case T < NextExpected andalso Amount =:= 0 of
51 true ->
52 %% We got 0 bytes, but we did not expect them yet, so just
53 %% return the current tuple (simplification candidate)
54 RT;
55 false ->
56 %% New rate: Timeslot between Last and RateSince contributes
57 %% with the old rate. Then we add the new Amount and calc.
58 %% the rate for the interval [T, RateSince].
59 R = (Rate * (Last - RateSince) + Amount) / (T - RateSince),
60 #peer_rate { rate = R, %% New Rate
61 total = Total + Amount,
62 %% We expect the next data-block at the minimum of 5 secs or
63 %% when Amount bytes has been fetched at the current rate.
64 next_expected =
65 T + lists:min([5, Amount / lists:max([R, 0.0001])]),
66 last = T,
67 %% RateSince is manipulated so it does not go beyond
68 %% ?MAX_RATE_PERIOD
69 rate_since = lists:max([RateSince, T - ?MAX_RATE_PERIOD])}
70 end.
73 %%--------------------------------------------------------------------
74 %% Function: eta/2
75 %% Args: Left ::= integer() - Number of bytes left to download
76 %% DownloadRate ::= double() - Download rate
77 %% Description: Calculate estimated time of arrival.
78 %% Returns: {Days, {Hours, Minutes, Seconds}}
79 %%--------------------------------------------------------------------
80 eta(Left, DownloadRate) ->
81 calendar:seconds_to_daystime(round(Left / DownloadRate)).
83 %%====================================================================
84 %% Internal functions
85 %%====================================================================
86 now_secs() ->
87 calendar:datetime_to_gregorian_seconds(
88 calendar:local_time()).