1# -*- coding: utf-8 -*- 2# This file is part of Xpra. 3# Copyright (C) 2012-2019 Antoine Martin <antoine@xpra.org> 4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any 5# later version. See the file COPYING for details. 6 7# Simple statistical functions 8 9import math 10 11def to_std_unit(v, unit=1000): 12 if v>=unit**3: 13 return "G", v//(unit**3) 14 if v>=unit**2: 15 return "M", v//(unit**2) 16 if v>=unit: 17 return "K", v//unit 18 return "", v 19 20def std_unit(v, unit=1000) -> str: 21 unit, value = to_std_unit(v, unit) 22 return "%s%s" % (int(value), unit) 23 24def std_unit_dec(v): 25 unit, value = to_std_unit(v*10.0) 26 if value>=100: 27 return "%s%s" % (int(value//10), unit) 28 if int(value)%10==0: 29 return "%s%s" % (int(value/10), unit) 30 return "%s%s" % (int(value)/10.0, unit) 31 32 33def absolute_to_diff_values(in_data): 34 """ Given a list of values, return a new list 35 containing the incremental diff between each value 36 ie: [0,2,2,10] -> [2,0,8] 37 """ 38 last_value = None 39 data = [] 40 for x in in_data: 41 if last_value is not None: 42 data.append(x-last_value) 43 last_value = x 44 return data 45 46def values_to_scaled_values(data, scale_unit=10, min_scaled_value=10, num_values=20): 47 #print("values_to_scaled_values(%s, %s, %s)" % (data, scale_unit, num_values)) 48 if not data: 49 return 0, data 50 max_v = max(data) 51 #pad with None values so we have at least num_values: 52 if len(data)<num_values: 53 if isinstance(data, tuple): 54 data = list(data) 55 for _ in range(num_values-len(data)): 56 data.insert(0, None) 57 scale = 1 58 assert scale_unit>1 59 while scale*scale_unit*min_scaled_value<=max_v: 60 scale *= scale_unit 61 if scale==1: 62 return scale, data 63 sdata = [] 64 for x in data: 65 if x is None: 66 sdata.append(None) 67 else: 68 sdata.append(x/scale) 69 return scale, sdata 70 71def values_to_diff_scaled_values(data, scale_unit=10, min_scaled_value=10, num_values=20): 72 return values_to_scaled_values(absolute_to_diff_values(data), scale_unit=scale_unit, min_scaled_value=min_scaled_value, num_values=num_values) 73 74def get_weighted_list_stats(weighted_values, show_percentile=False): 75 values = tuple(x[0] for x in weighted_values) 76 if not values: 77 return {} 78 #weighted mean: 79 tw = 0 80 tv = 0 81 for v, w in weighted_values: 82 tw += w 83 tv += v * w 84 avg = tv/tw 85 stats = { 86 "min" : int(min(values)), 87 "max" : int(max(values)), 88 "avg" : int(avg), 89 } 90 if show_percentile: 91 #percentile 92 svalues = sorted(values) 93 for i in range(1,10): 94 pct = i*10 95 index = len(values)*i//10 96 stats["%ip" % pct] = int(svalues[index]) 97 return stats 98 99 100def find_invpow(x, n): 101 """Finds the integer component of the n'th root of x, 102 an integer such that y ** n <= x < (y + 1) ** n. 103 """ 104 high = 1 105 while high ** n < x: 106 high *= 2 107 low = high/2 108 while low < high: 109 mid = (low + high) // 2 110 if low < mid and mid**n < x: 111 low = mid 112 elif high > mid and mid**n > x: 113 high = mid 114 else: 115 return mid 116 return mid + 1 117 118def get_list_stats(in_values, show_percentile=(5, 8, 9), show_dev=False): 119 #this may be backed by a deque/list whichi is used by other threads 120 #so make a copy before use: 121 values = tuple(in_values) 122 if not values: 123 return {} 124 #arithmetic mean 125 avg = sum(values)/len(values) 126 lstats = { 127 "cur" : int(values[-1]), 128 "min" : int(min(values)), 129 "max" : int(max(values)), 130 "avg" : int(avg), 131 } 132 if show_dev: 133 p = 1 #geometric mean 134 h = 0 #harmonic mean 135 var = 0 #variance 136 counter = 0 137 for x in values: 138 if x!=0: 139 p *= x 140 h += 1.0/x 141 counter += 1 142 var += (x-avg)**2 143 #standard deviation: 144 std = math.sqrt(var/len(values)) 145 lstats["std"] = int(std) 146 if avg!=0: 147 #coefficient of variation 148 lstats["cv_pct"] = int(100.0*std/avg) 149 if counter>0 and p<float('inf'): 150 #geometric mean 151 try: 152 v = int(math.pow(p, 1.0/counter)) 153 except OverflowError: 154 v = find_invpow(p, counter) 155 lstats["gm"] = v 156 if h!=0: 157 #harmonic mean 158 lstats["h"] = int(counter/h) 159 if show_percentile: 160 #percentile 161 svalues = sorted(values) 162 for i in show_percentile: 163 pct = i*10 164 index = len(values)*i//10 165 lstats["%ip" % pct] = int(svalues[index]) 166 return lstats 167