blob: af597df4b8d388ff89c9d5565afff3e283cb09bb [file] [log] [blame]
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +00001/* Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19//
Constantin Kaplinskye47123e2006-02-16 16:44:50 +000020// PollingScheduler class implementation.
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000021//
22
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000023#include <string.h>
24#include <stdlib.h>
25
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000026#include <x0vncserver/PollingScheduler.h>
27
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000028PollingScheduler::PollingScheduler(int interval, int maxload)
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000029{
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000030 setParameters(interval, maxload);
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000031 reset();
32}
33
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000034void PollingScheduler::setParameters(int interval, int maxload)
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000035{
36 m_interval = interval;
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000037 m_maxload = maxload;
38
39 if (m_interval < 0) {
40 m_interval = 0;
41 }
42 if (m_maxload < 1) {
43 m_maxload = 1;
44 } else if (m_maxload > 100) {
45 m_maxload = 100;
46 }
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000047}
48
49void PollingScheduler::reset()
50{
Constantin Kaplinskyd2644442006-02-16 16:49:27 +000051 m_initialState = true;
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000052}
53
54void PollingScheduler::newPass()
55{
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +000056 TimeMillis timeNow;
57
58 if (m_initialState) {
59
60 // First polling pass: initialize statistics.
61 m_initialState = false;
62 m_ratedDuration = 0;
63 m_sleeping = 0;
64 memset(m_errors, 0, sizeof(m_errors));
65 m_errorSum = 0;
66 m_errorAbsSum = 0;
67 memset(m_durations, 0, sizeof(m_durations));
68 m_durationSum = 0;
69 memset(m_slept, 0, sizeof(m_slept));
70 m_sleptSum = 0;
71 m_idx = 0;
72
73 } else {
74
75 // Stop sleeping if not yet.
76 if (m_sleeping)
77 sleepFinished();
78
79 // Update statistics on sleeping time and total pass duration.
80 int duration = timeNow.diffFrom(m_passStarted);
81
82 int oldest = m_durations[m_idx];
83 m_durations[m_idx] = duration;
84 m_durationSum = m_durationSum - oldest + duration;
85
86 oldest = m_slept[m_idx];
87 m_slept[m_idx] = m_sleptThisPass;
88 m_sleptSum = m_sleptSum - oldest + m_sleptThisPass;
89
90 // Compute and save the difference between actual and planned time.
91 int newError = duration - m_interval;
92 oldest = m_errors[m_idx];
93 m_errors[m_idx] = newError;
94 m_errorSum = m_errorSum - oldest + newError;
95 m_errorAbsSum = m_errorAbsSum - abs(oldest) + abs(newError);
96
97 //
98 // Here is the most important part.
99 // Compute desired duration of the upcoming polling pass.
100 //
101 m_ratedDuration = m_interval - m_errorSum;
102
103 int optimalLoadDuration =
104 ((m_durationSum - m_sleptSum) * 900 + m_maxload * 4) / (m_maxload * 8)
105 - m_durationSum;
106
107 if (m_ratedDuration < optimalLoadDuration) {
108 m_ratedDuration = optimalLoadDuration;
109 }
110
111 if (m_ratedDuration < 0) {
112 m_ratedDuration = 0;
113 }
114
115 // Update ring buffer indexer (8 elements in the arrays).
116 m_idx = (m_idx + 1) & 7;
117
118 }
119
120 m_passStarted = timeNow;
121 m_sleptThisPass = 0;
122}
123
124void PollingScheduler::sleepStarted()
125{
126 if (m_initialState || m_sleeping)
127 return;
128
129 m_sleepStarted.update();
130
131 m_sleeping = true;
132}
133
134void PollingScheduler::sleepFinished()
135{
136 if (m_initialState || !m_sleeping)
137 return;
138
139 TimeMillis timeNow;
140 m_sleptThisPass += timeNow.diffFrom(m_sleepStarted);
141
142 m_sleeping = false;
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000143}
144
145int PollingScheduler::millisRemaining() const
146{
Constantin Kaplinskyd2644442006-02-16 16:49:27 +0000147 if (m_initialState)
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000148 return 0;
149
150 TimeMillis timeNow;
151 int elapsed = timeNow.diffFrom(m_passStarted);
152
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000153 if (elapsed > m_ratedDuration)
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000154 return 0;
155
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000156 return (m_ratedDuration - elapsed);
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000157}
158
Constantin Kaplinskye47123e2006-02-16 16:44:50 +0000159bool PollingScheduler::goodTimeToPoll() const
160{
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000161 if (m_initialState)
162 return true;
163
164 // Average error (per 8 elements in the ring buffer).
165 int errorAvg = (m_errorAbsSum + 4) / 8;
166
167 // It's ok to poll earlier if new error is no more than half-average.
168 return (millisRemaining() <= errorAvg / 2);
Constantin Kaplinskye47123e2006-02-16 16:44:50 +0000169}