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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
def collect_buffer_data(client_buffer_results):
    d = {}  # indexed by session

    excluded_sessions = {}
    last_ts = {}
    last_buf = {}
    last_cum_rebuf = {}
    last_low_buf = {}

    for pt in client_buffer_results['client_buffer']:
        session = (pt['user'], int(pt['init_id']), int(pt['expt_id']))
        if session in excluded_sessions:
            continue

        if session not in d:
            d[session] = {}
            d[session]['min_play_time'] = None
            d[session]['max_play_time'] = None
            d[session]['min_cum_rebuf'] = None
            d[session]['max_cum_rebuf'] = None
        ds = d[session]  # short name

        if session not in last_ts:
            last_ts[session] = None
        if session not in last_buf:
            last_buf[session] = None
        if session not in last_cum_rebuf:
            last_cum_rebuf[session] = None
        if session not in last_low_buf:
            last_low_buf[session] = None

        ts = try_parsing_time(pt['time'])
        buf = float(pt['buffer'])
        cum_rebuf = float(pt['cum_rebuf'])

        # update d[session]
        if pt['event'] == 'startup':
            ds['min_play_time'] = ts
            ds['min_cum_rebuf'] = cum_rebuf

        if ds['min_play_time'] is None or ds['min_cum_rebuf'] is None:
            # wait until 'startup' is found
            continue

        if ds['max_play_time'] is None or ts > ds['max_play_time']:
            ds['max_play_time'] = ts

        if ds['max_cum_rebuf'] is None or cum_rebuf > ds['max_cum_rebuf']:
            ds['max_cum_rebuf'] = cum_rebuf

        # verify that time is basically successive in the same session
        if last_ts[session] is not None:
            diff = (ts - last_ts[session]).total_seconds()
            if diff > 60:  # ambiguous / suspicious session
                print('Ambiguous session', session)
                excluded_sessions[session] = True
                continue

        # identify outliers: exclude the sessions if there is a long rebuffer?
        if last_low_buf[session] is not None:
            diff = (ts - last_low_buf[session]).total_seconds()
            if diff > 30:
                print('Outlier session', session)
                excluded_sessions[session] = True
                continue

        # identify stalls caused by slow video decoding
        if last_buf[session] is not None and last_cum_rebuf[
                session] is not None:
            if (buf > 5 and last_buf[session] > 5
                    and cum_rebuf > last_cum_rebuf[session] + 0.25):
                print('Decoding stalls', session)
                excluded_sessions[session] = True
                continue

        # update last_XXX
        last_ts[session] = ts
        last_buf[session] = buf
        last_cum_rebuf[session] = cum_rebuf
        if buf > 0.1:
            last_low_buf[session] = None
        else:
            if last_low_buf[session] is None:
                last_low_buf[session] = ts

    ret = {}  # indexed by session

    # second pass to exclude short sessions
    for session in d:
        if session in excluded_sessions:
            continue

        ds = d[session]
        if ds['min_play_time'] is None or ds['min_cum_rebuf'] is None:
            # no 'startup' is found
            print('No startup found', session)
            continue

        sess_play = (ds['max_play_time'] - ds['min_play_time']).total_seconds()
        # exclude short sessions
        if sess_play < 5:
            continue

        sess_rebuf = ds['max_cum_rebuf'] - ds['min_cum_rebuf']
        if sess_rebuf > 300:
            print('Warning: bad session (rebuffer > 5min)', session)

        if session not in ret:
            ret[session] = {}

        ret[session]['play'] = sess_play
        ret[session]['rebuf'] = sess_rebuf
        ret[session]['startup'] = ds['min_cum_rebuf']

    print('Valid session count', len(ret))
    return ret