parse.py 4.79 KB
Newer Older
1
import pandas as pd
Andreas Schmidt's avatar
Andreas Schmidt committed
2
import numpy as np
3 4
import ruamel.yaml
import ruamel.yaml as yaml
Andreas Schmidt's avatar
Andreas Schmidt committed
5 6
import logging
import copy
7

8 9
def _stamp_name_by_src_and_type(all_stamps, src, kind=None):
    if kind is None:
10
        kind = ["time", "cycle", "none"]
11
    return [c for c, v in all_stamps.items() if v["Source"] == src and v["Type"] in kind]
12

13 14 15 16
def _stamp_name_by_thread_and_type(all_stamps, thread, kind=None):
    if kind is None:
        kind = ["time", "cycle"]
    return [c for c, v in all_stamps.items() if v["Thread"] == thread and v["Type"] in kind]
17

18
def _extract_stamps_by_src_and_kind(all_stamps, src, kind=None):
19
    columns = _stamp_name_by_src_and_type(all_stamps, src, kind)
20
    return [x + "_T" for x in columns] + [x + "_C" for x in columns]
21

22

23 24
def _evaluate_file(file_name, stamps, kind, measured_column, sender=False):
    df = pd.read_csv(file_name)
25

26
    df = df[df["Kind"] == kind].drop(["Kind"], axis=1).set_index("SeqNo")
27 28

    # Drop columns of opposing side.
29
    if sender:
30
        df.drop(_extract_stamps_by_src_and_kind(stamps, "receiver"), axis=1, inplace=True)
31
    else:
32
        df.drop(_extract_stamps_by_src_and_kind(stamps, "sender"), axis=1, inplace=True)
33

34
    # Drop rows with value 0 (as they have probably not been written out).
35 36 37 38 39
    res = df[df[measured_column + "_T"] != 0]
    total, filtered = df.shape[0], res.shape[0]
    if filtered < total:
        print("{}: ignored {} of {} packets due to missing timestamps.".format(file_name, total-filtered, total))
    return res
40 41


42
def _diff_t_c(df, start, stop):
43 44
    time = df[stop + "_T"] - df[start + "_T"]
    cycles = (df[stop + "_C"] - df[start + "_C"])
45
    return time.astype(float), cycles.astype(float)
46 47


Andreas Schmidt's avatar
Andreas Schmidt committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
def _generate_thread_durations(df, cycle_reference, thread, stamps):
    # Generate Processing Duration
    src_name = "".join(map(str.capitalize, thread.split("_")))
    # Generate Cycle Times
    time, cycles = _diff_t_c(df, cycle_reference[thread]["Start"], cycle_reference[thread]["Stop"])
    # TODO: Introduce check if both are on the same host.
    df[src_name + "_D"] = time
    df[src_name + "_C"] = cycles
    df[src_name + "Cycle_D"] = time / cycles
    # Recreate missing timestamps from cycles
    for stamp_name in _stamp_name_by_thread_and_type(stamps, thread, "cycle"):
        start_stamp = cycle_reference[thread]["Start"]
        diff = df[stamp_name + "_C"] - df[start_stamp + "_C"]
        try:
            df[stamp_name + "_T"] = (diff * df[src_name + "Cycle_D"] + df[start_stamp + "_T"]).astype(int)
        except ValueError as e:
            df[stamp_name + "_T"] = np.nan
Andreas Schmidt's avatar
Andreas Schmidt committed
65
            logging.debug("Stamp '%s' caused a ValueError (Src: %s, Start: %s)", stamp_name, src_name, start_stamp)
Andreas Schmidt's avatar
Andreas Schmidt committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

def evaluate_side(file, config, side="sender", kind=0):
    config = copy.deepcopy(config)
    stamps = config["stamps"]
    df = _evaluate_file(file, stamps, kind, _stamp_name_by_src_and_type(stamps, "sender", kind=["time"])[0], True)

    tr = config["time_reference"]
    cr = config["cycle_reference"]

    for src in config["threads"]:
        _generate_thread_durations(df, cr, src, config["stamps"])

    config["durations"] = dict([(x,y) for (x,y) in config["durations"].items()  if y["Source"] == side])

    _generate_durations(df, config)

    df["Sender_D"] = 0
    df["Receiver_D"] = 0

    df["EndToEnd_D"] = df[tr[side]["Stop"] + "_T"] - df[tr[side]["Start"] + "_T"]

    return df


90
def evaluate(sender_file, receiver_file, config, kind=0):
91
    stamps = config["stamps"]
92 93
    df1 = _evaluate_file(sender_file, stamps, kind, _stamp_name_by_src_and_type(stamps, "sender", kind=["time"])[0], True)
    df2 = _evaluate_file(receiver_file, stamps, kind, _stamp_name_by_src_and_type(stamps, "receiver", kind=["time"])[0])
94 95
    df = df1.join(df2)

96 97
    tr = config["time_reference"]
    cr = config["cycle_reference"]
98

99
    # Determine Channel Duration
100
    df["Transport_D"] = df[tr["receiver"]["Start"] + "_T"] - df[tr["sender"]["Stop"] + "_T"]
101

102 103
    # Correlate Receiver Timestamps with Sender Timestamps (subtracting Channel Duration)
    for s in _stamp_name_by_src_and_type(stamps, "receiver", kind=["time"]):
104
        df[s + "_T"] -= df["Transport_D"]
105

106
    for src in config["threads"]:
Andreas Schmidt's avatar
Andreas Schmidt committed
107
        _generate_thread_durations(df, cr, src, stamps)
108

Andreas Schmidt's avatar
Andreas Schmidt committed
109
    _generate_durations(df, config)
110

111 112 113
    df["Sender_D"] = df[tr["sender"]["Stop"] + "_T"] - df[tr["sender"]["Start"] + "_T"]
    df["Receiver_D"] = df[tr["receiver"]["Stop"] + "_T"] - df[tr["receiver"]["Start"] + "_T"]
    df["EndToEnd_D"] = df[tr["receiver"]["Stop"] + "_T"] - df[tr["sender"]["Start"] + "_T"]
114 115

    return df
116 117


Andreas Schmidt's avatar
Andreas Schmidt committed
118 119 120 121 122
def _generate_durations(df, config):
    for name, duration in config["durations"].items():
        df[name + "_D"] = df[duration["Stop"] + "_T"] - df[duration["Start"] + "_T"]


123 124 125 126
def parse_config(file_name="xlap.yml"):
    with open(file_name) as f:
        contents = f.read()
    return yaml.load(contents, Loader=ruamel.yaml.Loader)