Skip to content

Commit

Permalink
#999: take bandwidth limit value into account for calculating auto-re…
Browse files Browse the repository at this point in the history
…fresh delay, speed, quality

git-svn-id: https://xpra.org/svn/Xpra/trunk@17482 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Nov 23, 2017
1 parent f9e3512 commit 98e2036
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
21 changes: 17 additions & 4 deletions src/xpra/server/window/batch_delay_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)

Expand All @@ -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),
Expand All @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
12 changes: 8 additions & 4 deletions src/xpra/server/window/window_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 98e2036

Please sign in to comment.