From 98e2036ef09c8b371f65a913a3c6e86483631eae Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Thu, 23 Nov 2017 16:18:32 +0000 Subject: [PATCH] #999: take bandwidth limit value into account for calculating auto-refresh delay, speed, quality git-svn-id: https://xpra.org/svn/Xpra/trunk@17482 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- .../server/window/batch_delay_calculator.py | 21 +++++++++++++++---- src/xpra/server/window/window_source.py | 12 +++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/xpra/server/window/batch_delay_calculator.py b/src/xpra/server/window/batch_delay_calculator.py index 3285984c46..da99c5e04c 100644 --- a/src/xpra/server/window/batch_delay_calculator.py +++ b/src/xpra/server/window/batch_delay_calculator.py @@ -104,7 +104,7 @@ def update_batch_delay(batch, factors): batch.last_updated = now batch.factors = valid_factors -def get_target_speed(window_dimensions, batch, global_statistics, statistics, min_speed, speed_data): +def get_target_speed(window_dimensions, batch, global_statistics, statistics, bandwidth_limit, min_speed, speed_data): low_limit = get_low_limit(global_statistics.mmap_size>0, window_dimensions) #*********************************************************** # encoding speed: @@ -168,8 +168,13 @@ def get_target_speed(window_dimensions, batch, global_statistics, statistics, mi #(even x264 peaks at tens of MPixels/s) pps = mpixels_per_s/50.0 + max_speed = 1 + if bandwidth_limit>0: + #below 10Mbps, lower the speed ceiling + max_speed = sqrt(bandwidth_limit/(10.0*1000*1000)) + #combine factors: use the highest one: - target = min(1.0, max(dam_lat_abs, dam_lat_rel, dec_lat, pps, 0.0)) + target = min(1.0, max_speed, max(dam_lat_abs, dam_lat_rel, dec_lat, pps, 0.0)) #discount for congestion: target /= (1.0 + global_statistics.congestion_value*5) @@ -179,6 +184,7 @@ def get_target_speed(window_dimensions, batch, global_statistics, statistics, mi #expose data we used: info = { + "max-speed-range" : int(100*max_speed), "low_limit" : int(low_limit), "min_speed" : int(min_speed), "frame_delay" : int(frame_delay), @@ -200,7 +206,7 @@ def get_target_speed(window_dimensions, batch, global_statistics, statistics, mi return info, target_speed -def get_target_quality(window_dimensions, batch, global_statistics, statistics, min_quality, min_speed): +def get_target_quality(window_dimensions, batch, global_statistics, statistics, bandwidth_limit, min_quality, min_speed): info = { "min_quality" : min_quality, "min_speed" : min_speed, @@ -256,7 +262,14 @@ def get_target_quality(window_dimensions, batch, global_statistics, statistics, latency_q = 3.0 * statistics.target_latency / global_statistics.recent_client_latency target = min(target, latency_q) info["latency"] = int(100.0*latency_q) - target = min(1.0, max(0.0, target)) + + max_quality = 1 + if bandwidth_limit>0: + #below 10Mbps, lower the quality ceiling + max_quality = sqrt(bandwidth_limit/(10.0*1000*1000)) + info["max-quality-range"] = int(100*max_quality) + + target = min(max_quality, max(0.0, target)) if min_speed>0: #discount the quality more aggressively if we have speed requirements to satisfy: #ie: for min_speed=50: diff --git a/src/xpra/server/window/window_source.py b/src/xpra/server/window/window_source.py index 9f6f8eb26b..a4e63e60e7 100644 --- a/src/xpra/server/window/window_source.py +++ b/src/xpra/server/window/window_source.py @@ -1004,7 +1004,7 @@ def update_speed(self): if speed<=0: #make a copy to work on (and discard "info") speed_data = [(event_time, speed) for event_time, _, speed in list(self._encoding_speed)] - info, target_speed = get_target_speed(self.window_dimensions, self.batch_config, self.global_statistics, self.statistics, self._fixed_min_speed, speed_data) + info, target_speed = get_target_speed(self.window_dimensions, self.batch_config, self.global_statistics, self.statistics, self.bandwidth_limit, self._fixed_min_speed, speed_data) speed_data.append((monotonic_time(), target_speed)) speed = max(self._fixed_min_speed, time_weighted_average(speed_data, min_offset=1, rpow=1.1)) speed = min(99, speed) @@ -1039,7 +1039,7 @@ def update_quality(self): return quality = self._fixed_quality if quality<=0: - info, quality = get_target_quality(self.window_dimensions, self.batch_config, self.global_statistics, self.statistics, self._fixed_min_quality, self._fixed_min_speed) + info, quality = get_target_quality(self.window_dimensions, self.batch_config, self.global_statistics, self.statistics, self.bandwidth_limit, self._fixed_min_quality, self._fixed_min_speed) #make a copy to work on (and discard "info") ves_copy = [(event_time, speed) for event_time, _, speed in list(self._encoding_quality)] ves_copy.append((monotonic_time(), quality)) @@ -1622,18 +1622,22 @@ def schedule_auto_refresh(self, packet, options): #delay less when speed is high #delay a lot more when we have bandwidth issues qsmult = (200-self._current_quality) * (100+self._current_speed) * (100+self.global_statistics.congestion_value*500) + min_wait = 50 + if self.bandwidth_limit>0: + #1Mbps -> 1s, 10Mbps -> 0.1s + min_wait = min(1000, 1000*1000*1000//self.bandwidth_limit) if not self.refresh_timer: #we must schedule a new refresh timer self.refresh_event_time = monotonic_time() #delay in milliseconds: always at least the settings, #more if we have more than 50% of the window pixels to update: - sched_delay = int(max(50, self.auto_refresh_delay * max(50, pct) / 50, self.batch_config.delay*4) * qsmult / (200*100*100)) + sched_delay = int(max(min_wait, self.auto_refresh_delay * max(50, pct) // 50, self.batch_config.delay*4) * qsmult // (200*100*100)) self.refresh_target_time = now + sched_delay/1000.0 self.refresh_timer = self.timeout_add(int(sched_delay), self.refresh_timer_function, options) msg += ", scheduling refresh in %sms (pct=%s, batch=%s)" % (sched_delay, pct, self.batch_config.delay) else: #add to the target time, but this will not move it forwards for small updates following big ones: - sched_delay = int(max(50, self.auto_refresh_delay * pct / 50, self.batch_config.delay*2) * qsmult / (200*100*100)) + sched_delay = int(max(min_wait, self.auto_refresh_delay * pct // 50, self.batch_config.delay*2) * qsmult // (200*100*100)) target_time = self.refresh_target_time self.refresh_target_time = max(target_time, now + sched_delay/1000.0) msg += ", re-scheduling refresh (due in %ims, %ims added - sched_delay=%s, pct=%s, batch=%s)" % (1000*(self.refresh_target_time-now), 1000*(self.refresh_target_time-target_time), sched_delay, pct, self.batch_config.delay)