1/*
2 * LICENSE NOTICE.
3 *
4 * Use of the Microsoft Windows Rally Development Kit is covered under
5 * the Microsoft Windows Rally Development Kit License Agreement,
6 * which is provided within the Microsoft Windows Rally Development
7 * Kit or at http://www.microsoft.com/whdc/rally/rallykit.mspx. If you
8 * want a license from Microsoft to use the software in the Microsoft
9 * Windows Rally Development Kit, you must (1) complete the designated
10 * "licensee" information in the Windows Rally Development Kit License
11 * Agreement, and (2) sign and return the Agreement AS IS to Microsoft
12 * at the address provided in the Agreement.
13 */
14
15/*
16 * Copyright (c) Microsoft Corporation 2005.  All rights reserved.
17 * This software is provided with NO WARRANTY.
18 */
19
20#include <stdio.h>
21#include <assert.h>
22
23#include "globals.h"
24
25#include "statemachines.h"
26#include "band.h"
27#include "bandfuncs.h"
28
29void
30band_ResetNi(void)
31{
32    g_band.Ni = BAND_NMAX;
33}
34
35
36void
37band_InitStats(void)
38{
39    band_t *b = &g_band;
40    struct timeval now;
41
42    b->Ni = BAND_NMAX;
43    b->r = BAND_BLOCK_TIME;
44    b->begun = FALSE;
45
46    if (TRACE(TRC_BAND))
47	dbgprintf("InitStats: Ni=%u r=%u\n",
48		b->Ni, b->r);
49
50    gettimeofday(&now, NULL);
51    timeval_add_ms(&now, BAND_BLOCK_TIME);
52
53    assert(g_block_timer == NULL);
54    g_block_timer = event_add(&now, state_block_timeout, /*state:*/NULL);
55}
56
57
58void
59band_UpdateStats(void)
60{
61    band_t *b = &g_band;
62    struct timeval now;
63
64    /* TODO: assumes platform timers are perfect!  Should really measure the time
65     * now and calculate the actual time waited for. */
66    uint32_t Ta = BAND_BLOCK_TIME;
67
68    uint32_t value = BAND_MUL_FRAME(b->r * b->Ni) / (Ta * 1000);
69    uint32_t bound = ((b->Ni * BAND_GAMMA) + (BAND_ALPHA * BAND_BETA -1))
70      / (BAND_ALPHA * BAND_BETA);
71    b->Ni = TOPOMIN(100*BAND_NMAX, TOPOMAX(bound, value));
72
73    if (b->begun) {
74	if (b->Ni < BAND_NMAX/2) {
75	    b->Ni *= 2;
76        } else if (b->Ni < BAND_NMAX) {
77	    b->Ni = BAND_NMAX;
78	}
79    }
80    b->begun = FALSE;
81
82    if (TRACE(TRC_BAND))
83	dbgprintf("UpdateStats: Ni=%u r=%u\n",
84		b->Ni, b->r);
85
86    if (!g_block_timer)
87    {
88	gettimeofday(&now, NULL);
89	timeval_add_ms(&now, BAND_BLOCK_TIME);
90	g_block_timer = event_add(&now, state_block_timeout, /*state:*/NULL);
91    }
92    else
93    {
94	warn("UpdateStats: block timer still running?!?\n");
95    }
96}
97
98void
99band_ChooseHelloTime(void)
100{
101    band_t *b = &g_band;
102
103    uint32_t delay = random_uniform(b->Ni);
104
105    if (TRACE(TRC_BAND))
106	dbgprintf("ChooseHelloTime: delay=%u; ", delay);
107
108    /* if the delay falls within this block, set a timer to send the Hello */
109    if (delay < BAND_ALPHA && !g_hello_timer)
110    {
111	struct timeval now;
112	gettimeofday(&now, NULL);
113	timeval_add_ms(&now, BAND_MUL_FRAME(delay));
114	g_hello_timer = event_add(&now, state_hello_delay_timeout, /*state:*/NULL);
115	if (TRACE(TRC_BAND))
116	    dbgprintf("will hello at %ld.%06ld\n", now.tv_sec, now.tv_usec);
117    }
118    else
119    {
120	if (TRACE(TRC_BAND))
121	    dbgprintf("idle this block, so no Hello\n");
122    }
123}
124
125
126void
127band_IncreaseLoad(bool_t mapbegin)
128{
129    band_t *b = &g_band;
130
131    b->r++;
132    if (mapbegin)
133	b->begun = TRUE;
134
135    if (TRACE(TRC_BAND))
136	dbgprintf("IncreaseLoad: Ni=%u r=%u\n",
137		b->Ni, b->r);
138}
139