forked from cjdelisle/cjdns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAverageRoller.c
88 lines (79 loc) · 3.36 KB
/
AverageRoller.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "util/AverageRoller.h"
#include "util/AverageRoller_pvt.h"
#include "util/Bits.h"
#include "util/events/Time.h"
/** @see AverageRoller.h */
struct AverageRoller* AverageRoller_new(const uint32_t windowSeconds,
struct EventBase* eventBase,
struct Allocator* allocator)
{
size_t size = sizeof(struct AverageRoller_pvt)
+ (sizeof(struct AverageRoller_SumAndEntryCount) * (windowSeconds - 1));
struct AverageRoller_pvt* roller = Allocator_calloc(allocator, size, 1);
Bits_memcpy(roller, (&(struct AverageRoller_pvt) {
.windowSeconds = windowSeconds,
.eventBase = eventBase,
.lastUpdateTime = (uint32_t) Time_currentTimeSeconds(eventBase)
}), sizeof(struct AverageRoller_pvt));
Identity_set(roller);
return &roller->pub;
}
/** @see AverageRoller.h */
uint32_t AverageRoller_getAverage(struct AverageRoller* averageRoller)
{
struct AverageRoller_pvt* roller = Identity_check((struct AverageRoller_pvt*) averageRoller);
return roller->average;
}
/**
* Update the roller with a new entry.
*
* @param averageRoller the roller to update.
* @param now the number of seconds since the epoch.
* @param newEntry the a new number to be factored into the average.
* @return the average over the last windowSeconds seconds.
*/
uint32_t AverageRoller_updateAtTime(struct AverageRoller* averageRoller,
const uint64_t now,
const uint32_t newEntry)
{
struct AverageRoller_pvt* roller = Identity_check((struct AverageRoller_pvt*) averageRoller);
uint32_t index =
(now - roller->lastUpdateTime + roller->lastUpdateIndex) % roller->windowSeconds;
if (((uint32_t) now) > roller->lastUpdateTime) {
roller->sum -= roller->seconds[index].sum;
roller->entryCount -= roller->seconds[index].entryCount;
roller->seconds[index].sum = newEntry;
roller->seconds[index].entryCount = 1;
} else {
roller->seconds[index].sum += newEntry;
roller->seconds[index].entryCount++;
}
roller->sum += newEntry;
roller->entryCount++;
roller->average = roller->sum / roller->entryCount;
roller->lastUpdateTime = now;
roller->lastUpdateIndex = index;
return roller->average;
}
/** @see AverageRoller.h */
uint32_t AverageRoller_update(struct AverageRoller* averageRoller, const uint32_t newEntry)
{
struct AverageRoller_pvt* roller = Identity_check((struct AverageRoller_pvt*) averageRoller);
return AverageRoller_updateAtTime(averageRoller,
Time_currentTimeSeconds(roller->eventBase),
newEntry);
}