def collect_ssim(video_acked_results, postgres_cursor): # process InfluxDB data x = {} for pt in video_acked_results['video_acked']: expt_id = int(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) # index x by (abr, cc) abr_cc = (expt_config['abr'], expt_config['cc']) if abr_cc not in x: x[abr_cc] = [] if pt['ssim_index'] is not None: ssim_index = float(pt['ssim_index']) x[abr_cc].append(ssim_index) # calculate average SSIM in dB and record number of chunks ssim = {} num_chunks = {} for abr_cc in x: num_chunks[abr_cc] = len(x[abr_cc]) avg_ssim_index = np.mean(x[abr_cc]) avg_ssim_db = ssim_index_to_db(avg_ssim_index) ssim[abr_cc] = avg_ssim_db return ssim, num_chunks
def process_expired(self): # read and process expired values expired_sessions = self.expiry_list.expired for session in expired_sessions: s = self.smap[session] if not self.valid_expired_session(session): del self.smap[session] continue expt_id = str(session[-1]) expt_config = retrieve_expt_config(expt_id, self.expt, self.postgres_cursor) abr_cc = get_abr_cc(expt_config) if abr_cc not in self.out: self.out[abr_cc] = {} self.out[abr_cc]['total_play'] = 0 self.out[abr_cc]['total_rebuf'] = 0 session_play = ((s['max_play_time'] - s['min_play_time']) / np.timedelta64(1, 's')) session_rebuf = s['max_cum_rebuf'] - s['min_cum_rebuf'] self.out[abr_cc]['total_play'] += session_play self.out[abr_cc]['total_rebuf'] += session_rebuf del self.smap[session] # clean processed expired values self.expiry_list.expired = []
def collect_rebuffer(client_buffer_results, postgres_cursor): # process InfluxDB data x = {} for pt in client_buffer_results['client_buffer']: expt_id = int(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) # index x by (abr, cc) abr_cc = (expt_config['abr'], expt_config['cc']) if abr_cc not in x: x[abr_cc] = {} session = (pt['user'], int(pt['init_id']), pt['channel'], int(pt['expt_id'])) if session not in x[abr_cc]: x[abr_cc][session] = {} x[abr_cc][session]['min_time'] = None x[abr_cc][session]['max_time'] = None x[abr_cc][session]['min_cum_rebuf'] = None x[abr_cc][session]['max_cum_rebuf'] = None # shorthand variable y = x[abr_cc][session] ts = try_parsing_time(pt['time']) cum_rebuf = float(pt['cum_rebuf']) if y['min_time'] is None or ts < y['min_time']: y['min_time'] = ts if y['max_time'] is None or ts > y['max_time']: y['max_time'] = ts if y['min_cum_rebuf'] is None or cum_rebuf < y['min_cum_rebuf']: y['min_cum_rebuf'] = cum_rebuf if y['max_cum_rebuf'] is None or cum_rebuf > y['max_cum_rebuf']: y['max_cum_rebuf'] = cum_rebuf # calculate rebuffer rate rebuffer = {} for abr_cc in x: total_play = 0 total_rebuf = 0 for session in x[abr_cc]: # shorthand variable y = x[abr_cc][session] total_play += (y['max_time'] - y['min_time']).total_seconds() total_rebuf += y['max_cum_rebuf'] - y['min_cum_rebuf'] if total_play == 0: sys.exit('Error: total play time is 0') rebuf_rate = total_rebuf / total_play rebuffer[abr_cc] = rebuf_rate * 100 return rebuffer
def process_rebuffer_session(session, s): # exclude too short sessions if s['play_time'] < 5: return expt_id = str(session[-1]) expt_config = retrieve_expt_config(expt_id, expt, postgres_cursor) abr_cc = get_abr_cc(expt_config) global g_rebuffer if abr_cc not in g_rebuffer: g_rebuffer[abr_cc] = {} g_rebuffer[abr_cc]['total_play'] = 0 g_rebuffer[abr_cc]['total_rebuf'] = 0 g_rebuffer[abr_cc]['total_play'] += s['play_time'] g_rebuffer[abr_cc]['total_rebuf'] += s['cum_rebuf']
def calculate_rebuffer_by_abr_cc(d, expt_id_cache, postgres_cursor): x = {} # indexed by (abr, cc) for session in d: expt_id = int(session[-1]) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) abr_cc = get_abr_cc(expt_config) if abr_cc not in x: x[abr_cc] = {} x[abr_cc]['total_play'] = 0 x[abr_cc]['total_rebuf'] = 0 x[abr_cc]['total_play'] += d[session]['play'] x[abr_cc]['total_rebuf'] += d[session]['rebuf'] return x
def do_collect_ssim(s_str, e_str, d): sys.stderr.write('Processing video_acked data between {} and {}\n' .format(s_str, e_str)) video_acked_results = query_measurement( influx_client, 'video_acked', s_str, e_str)['video_acked'] for pt in video_acked_results: expt_id = str(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt, postgres_cursor) abr_cc = get_abr_cc(expt_config) if abr_cc not in d: d[abr_cc] = [0.0, 0] # sum, count ssim_index = get_ssim_index(pt) if ssim_index is not None and ssim_index != 1: d[abr_cc][0] += ssim_index d[abr_cc][1] += 1
def do_collect_ssim(video_acked_results, expt_id_cache, postgres_cursor): # process InfluxDB data x = {} for pt in video_acked_results['video_acked']: expt_id = get_expt_id(pt) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) abr_cc = get_abr_cc(expt_config) if abr_cc not in x: x[abr_cc] = [] ssim_index = get_ssim_index(pt) if ssim_index is not None: x[abr_cc].append(ssim_index) # calculate average SSIM in dB for abr_cc in x: avg_ssim_index = np.mean(x[abr_cc]) avg_ssim_db = ssim_index_to_db(avg_ssim_index) x[abr_cc] = avg_ssim_db return x
def collect_ssim(video_acked_results, postgres_cursor): # process InfluxDB data x = {} for pt in video_acked_results['video_acked']: expt_id = int(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) # index x by (abr, cc) abr_cc = (expt_config['abr'], expt_config['cc']) if abr_cc not in x: x[abr_cc] = [] ssim_index = get_ssim_index(pt) if ssim_index is not None: x[abr_cc].append(ssim_index) # calculate average SSIM in dB ssim = {} for abr_cc in x: avg_ssim_index = np.mean(x[abr_cc]) avg_ssim_db = ssim_index_to_db(avg_ssim_index) ssim[abr_cc] = avg_ssim_db return ssim
def calculate_trans_times(video_sent_results, video_acked_results, cc, postgres_cursor): d = {} last_video_ts = {} for pt in video_sent_results['video_sent']: expt_id = int(pt['expt_id']) session = (pt['user'], int(pt['init_id']), pt['channel'], expt_id) # filter data points by congestion control expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) if cc is not None and expt_config['cc'] != cc: continue if session not in d: d[session] = {} last_video_ts[session] = None video_ts = int(pt['video_ts']) if last_video_ts[session] is not None: if video_ts != last_video_ts[session] + VIDEO_DURATION: sys.stderr.write('Warning in session {}: video_ts={}\n'.format( session, video_ts)) continue last_video_ts[session] = video_ts d[session][video_ts] = {} dsv = d[session][video_ts] # short name dsv['sent_ts'] = try_parsing_time(pt['time']) dsv['size'] = float(pt['size']) / PKT_BYTES # bytes -> packets # byte/second -> packet/second dsv['delivery_rate'] = float(pt['delivery_rate']) / PKT_BYTES dsv['cwnd'] = float(pt['cwnd']) dsv['in_flight'] = float(pt['in_flight']) dsv['min_rtt'] = float(pt['min_rtt']) / MILLION # us -> s dsv['rtt'] = float(pt['rtt']) / MILLION # us -> s # dsv['ssim_index'] = get_ssim_index(pt) for pt in video_acked_results['video_acked']: expt_id = int(pt['expt_id']) session = (pt['user'], int(pt['init_id']), pt['channel'], expt_id) # filter data points by congestion control expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) if cc is not None and expt_config['cc'] != cc: continue if session not in d: sys.stderr.write('Warning: ignored session {}\n'.format(session)) continue video_ts = int(pt['video_ts']) if video_ts not in d[session]: sys.stderr.write('Warning: ignored acked video_ts {} in the ' 'session {}\n'.format(video_ts, session)) continue dsv = d[session][video_ts] # short name # calculate transmission time sent_ts = dsv['sent_ts'] acked_ts = try_parsing_time(pt['time']) dsv['acked_ts'] = acked_ts dsv['trans_time'] = (acked_ts - sent_ts).total_seconds() return d
def collect_rebuffer(client_buffer_results, postgres_cursor): # process InfluxDB data last_ts = {} last_cum_rebuf = {} outlier_time = {} excluded_sessions = {} x = {} for pt in client_buffer_results['client_buffer']: expt_id = int(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) # index x by (abr, cc) abr_cc = (expt_config['abr'], expt_config['cc']) if abr_cc not in x: x[abr_cc] = {} # index x[abr_cc] by session session = (pt['user'], int(pt['init_id']), pt['channel'], int(pt['expt_id'])) if session not in last_ts: last_ts[session] = None if session not in last_cum_rebuf: last_cum_rebuf[session] = None if session not in outlier_time: outlier_time[session] = None if session not in x[abr_cc]: if session in excluded_sessions: # ignore sessions that were intentionally removed from x[abr_cc] continue x[abr_cc][session] = {} x[abr_cc][session]['min_play_time'] = None x[abr_cc][session]['max_play_time'] = None x[abr_cc][session]['min_cum_rebuf'] = None x[abr_cc][session]['max_cum_rebuf'] = None y = x[abr_cc][session] # short name ts = try_parsing_time(pt['time']) buf = float(pt['buffer']) cum_rebuf = float(pt['cum_rebuf']) # verify that time is basically continuous in the same session if last_ts[session] is not None: diff = (ts - last_ts[session]).total_seconds() if diff > 60: # a new but different session should be ignored continue last_ts[session] = ts # identify outliers: exclude the session if there is one-minute long # duration when buffer is lower than 1 second if buf > 1: outlier_time[session] = None else: if outlier_time[session] is None: outlier_time[session] = ts else: diff = (ts - outlier_time[session]).total_seconds() if diff > 30: print('Outlier session', abr_cc, session) del x[abr_cc][session] excluded_sessions[session] = True continue # identify stalls caused by slow video decoding if last_cum_rebuf[session] is not None: if buf > 5 and cum_rebuf > last_cum_rebuf[session] + 0.25: # should not have stalls print('Decoding stalls', abr_cc, session) del x[abr_cc][session] excluded_sessions[session] = True continue last_cum_rebuf[session] = cum_rebuf if pt['event'] == 'startup': y['min_play_time'] = ts y['min_cum_rebuf'] = cum_rebuf if y['max_play_time'] is None or ts > y['max_play_time']: y['max_play_time'] = ts if y['max_cum_rebuf'] is None or cum_rebuf > y['max_cum_rebuf']: y['max_cum_rebuf'] = cum_rebuf # calculate rebuffer rate rebuffer = {} total_play = {} total_rebuf = {} for abr_cc in x: abr_cc_play = 0 abr_cc_rebuf = 0 for session in x[abr_cc]: y = x[abr_cc][session] # short name if y['min_play_time'] is None or y['min_cum_rebuf'] is None: continue sess_play = (y['max_play_time'] - y['min_play_time']).total_seconds() sess_rebuf = y['max_cum_rebuf'] - y['min_cum_rebuf'] # exclude short sessions if sess_play < 5: continue abr_cc_play += sess_play abr_cc_rebuf += sess_rebuf if abr_cc_play == 0: sys.exit('Error: {}: total play time is 0'.format(abr_cc)) total_play[abr_cc] = abr_cc_play total_rebuf[abr_cc] = abr_cc_rebuf rebuf_rate = abr_cc_rebuf / abr_cc_play rebuffer[abr_cc] = rebuf_rate * 100 return rebuffer, total_play, total_rebuf
def calculate_trans_times(video_sent_results, video_acked_results, cc, postgres_cursor): d = {} last_video_ts = {} for pt in video_sent_results['video_sent']: expt_id = get_expt_id(pt) session = (get_user(pt), int(pt['init_id']), pt['channel'], expt_id) # filter data points by congestion control expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) if cc is not None and expt_config['cc'] != cc: continue if session not in d: d[session] = {} last_video_ts[session] = None video_ts = int(pt['video_ts']) if last_video_ts[session] is not None: if video_ts != last_video_ts[session] + VIDEO_DURATION: continue last_video_ts[session] = video_ts d[session][video_ts] = {} dsv = d[session][video_ts] # short name dsv['sent_ts'] = np.datetime64(pt['time']) dsv['size'] = float(pt['size']) / PKT_BYTES # bytes -> packets # byte/second -> packet/second dsv['delivery_rate'] = float(pt['delivery_rate']) / PKT_BYTES dsv['cwnd'] = float(pt['cwnd']) dsv['in_flight'] = float(pt['in_flight']) dsv['min_rtt'] = float(pt['min_rtt']) / MILLION # us -> s dsv['rtt'] = float(pt['rtt']) / MILLION # us -> s for pt in video_acked_results['video_acked']: expt_id = get_expt_id(pt) session = (get_user(pt), int(pt['init_id']), pt['channel'], expt_id) # filter data points by congestion control expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) if cc is not None and expt_config['cc'] != cc: continue if session not in d: continue video_ts = int(pt['video_ts']) if video_ts not in d[session]: continue dsv = d[session][video_ts] # short name # calculate transmission time sent_ts = dsv['sent_ts'] acked_ts = np.datetime64(pt['time']) dsv['acked_ts'] = acked_ts dsv['trans_time'] = (acked_ts - sent_ts) / np.timedelta64(1, 's') return d
def collect_rebuffer(client_buffer_results, postgres_cursor): # process InfluxDB data x = {} for pt in client_buffer_results['client_buffer']: expt_id = int(pt['expt_id']) expt_config = retrieve_expt_config(expt_id, expt_id_cache, postgres_cursor) # index x by (abr, cc) abr_cc = (expt_config['abr'], expt_config['cc']) if abr_cc not in x: x[abr_cc] = {} # index x[abr_cc] by session session = (pt['user'], int(pt['init_id']), pt['channel'], int(pt['expt_id'])) if session not in x[abr_cc]: x[abr_cc][session] = {} x[abr_cc][session]['min_play_time'] = None x[abr_cc][session]['max_play_time'] = None x[abr_cc][session]['min_cum_rebuf'] = None x[abr_cc][session]['max_cum_rebuf'] = None y = x[abr_cc][session] # short name ts = try_parsing_time(pt['time']) cum_rebuf = float(pt['cum_rebuf']) if pt['event'] == 'startup': y['min_play_time'] = ts y['min_cum_rebuf'] = cum_rebuf if y['max_play_time'] is None or ts > y['max_play_time']: y['max_play_time'] = ts if y['max_cum_rebuf'] is None or cum_rebuf > y['max_cum_rebuf']: y['max_cum_rebuf'] = cum_rebuf # calculate rebuffer rate rebuffer = {} total_play = {} total_rebuf = {} for abr_cc in x: abr_cc_play = 0 abr_cc_rebuf = 0 for session in x[abr_cc]: y = x[abr_cc][session] # short name if y['min_play_time'] is None or y['min_cum_rebuf'] is None: continue sess_play = (y['max_play_time'] - y['min_play_time']).total_seconds() sess_rebuf = y['max_cum_rebuf'] - y['min_cum_rebuf'] # exclude too short sessions if sess_play < 2: continue # TODO: identify and ignore outliers if sess_rebuf / sess_play > 0.5: continue abr_cc_play += sess_play abr_cc_rebuf += sess_rebuf if abr_cc_play == 0: sys.exit('Error: {}: total play time is 0'.format(abr_cc)) total_play[abr_cc] = abr_cc_play total_rebuf[abr_cc] = abr_cc_rebuf rebuf_rate = abr_cc_rebuf / abr_cc_play rebuffer[abr_cc] = rebuf_rate * 100 return rebuffer, total_play, total_rebuf