Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/window/batch_config.py : 100%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2011 Serviware (Arthur Huillet, <ahuillet@serviware.com>)
4# Copyright (C) 2010-2019 Antoine Martin <antoine@xpra.org>
5# Copyright (C) 2008 Nathaniel Smith <njs@pobox.com>
6# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
7# later version. See the file COPYING for details.
9import os
11from collections import deque
12from xpra.simple_stats import get_list_stats
13from xpra.os_util import monotonic_time
14from xpra.log import Logger
16#how many historical records to keep
17#for the various statistics we collect:
18#(cannot be lower than DamageBatchConfig.MAX_EVENTS)
19NRECS = 100
22log = Logger("damage")
24def ival(key, default, minv=0, maxv=None) -> int:
25 try:
26 v = os.environ.get("XPRA_BATCH_%s" % key)
27 if v is None:
28 return default
29 iv = int(v)
30 if minv is not None and iv<minv:
31 log.warn("value for %s is too small: %s (minimum is %s)", key, iv, minv)
32 return minv
33 if maxv is not None and iv>maxv:
34 log.warn("value for %s is too high: %s (maximum is %s)", key, iv, maxv)
35 return maxv
36 return iv
37 except Exception as e:
38 log.warn("failed to parse value '%s' for %s: %s", v, key, e)
39 return default
42class DamageBatchConfig:
43 """
44 Encapsulate all the damage batching configuration into one object.
45 """
46 ALWAYS = ival("ALWAYS", 0, 0, 1)==1
47 MAX_EVENTS = ival("MAX_EVENTS", min(50, NRECS), 10) #maximum number of damage events
48 MAX_PIXELS = ival("MAX_PIXELS", 1024*1024*MAX_EVENTS) #small screen at MAX_EVENTS frames
49 TIME_UNIT = ival("TIME_UNIT", 1, 1, 1000) #per second
50 MIN_DELAY = ival("MIN_DELAY", 5, 0, 1000) #if lower than 5 milliseconds: just don't batch
51 START_DELAY = ival("START_DELAY", 50, 1, 1000)
52 MAX_DELAY = ival("MAX_DELAY", 500, 1, 15000)
53 EXPIRE_DELAY = ival("EXPIRE_DELAY", 50, 10, 1000)
54 TIMEOUT_DELAY = ival("TIMEOUT_DELAY", 15000, 100, 100000)
56 def __init__(self):
57 self.wid = 0
58 self.always = self.ALWAYS
59 self.max_events = self.MAX_EVENTS
60 self.max_pixels = self.MAX_PIXELS
61 self.time_unit = self.TIME_UNIT
62 self.min_delay = self.MIN_DELAY
63 self.max_delay = self.MAX_DELAY
64 self.timeout_delay = self.TIMEOUT_DELAY
65 self.expire_delay = self.EXPIRE_DELAY
66 self.delay = self.START_DELAY
67 self.delay_per_megapixel = -1
68 self.saved = self.START_DELAY
69 self.locked = False #to force a specific delay
70 self.last_event = 0
71 self.last_delays = deque(maxlen=64) #the delays we have tried to use (milliseconds)
72 self.last_delay = None
73 self.last_actual_delays = deque(maxlen=64) #the delays we actually used (milliseconds)
74 self.last_actual_delay = None
75 self.last_updated = 0
76 #the metrics derived from statistics which we use for calculating the new batch delay:
77 #(see batch delay calculator)
78 self.factors = ()
80 def cleanup(self):
81 self.factors = ()
83 def get_info(self) -> dict:
84 info = {
85 "min-delay" : self.min_delay,
86 "max-delay" : self.max_delay,
87 "expire" : self.expire_delay,
88 "timeout-delay" : self.timeout_delay,
89 "locked" : self.locked,
90 }
91 if self.delay_per_megapixel>=0:
92 info["normalized"] = self.delay_per_megapixel
93 if self.last_event>0:
94 info["last-event"] = int(monotonic_time()-self.last_event)
95 if self.locked:
96 info["delay"] = self.delay
97 else:
98 ld = tuple(x[1] for x in self.last_delays)
99 if ld:
100 ls = get_list_stats(ld)
101 ldv = self.last_delay
102 if ldv:
103 ls["last"] = ldv[1]
104 info["delay"] = ls
105 lad = tuple(x[1] for x in self.last_actual_delays)
106 if lad:
107 ls = get_list_stats(lad, show_percentile=(9,))
108 ladv = self.last_actual_delay
109 if ladv:
110 ls["last"] = ladv[1]
111 info["actual_delays"] = ls
112 for name, details, factor, weight in self.factors:
113 fdetails = details.copy()
114 fdetails[""] = int(100.0*factor), int(100.0*weight)
115 info[name] = fdetails
116 return info
119 def clone(self):
120 c = DamageBatchConfig()
121 for x in (
122 "always", "max_events", "max_pixels", "time_unit",
123 "min_delay", "max_delay", "timeout_delay", "delay", "expire_delay",
124 ):
125 setattr(c, x, getattr(self, x))
126 return c
128 def __repr__(self):
129 return "DamageBatchConfig(%i)" % (self.wid)