예제 #1
0
def graph_num_clients(step_size, output_name, title, data):
    """
    Create a stacked graph per client pool.
    Arguments:
        output_name(Path): where to write the graph
        title(str): title for the graph
        step_size(int): number of milliseconds between samples
        data(DataFrame): data to graph
    """

    max_time = data['end'].max()
    clients = data['client'].unique()
    xs = list()
    ydata = dict()  # client -> data

    time_step = 0
    while time_step < max_time:
        xs.append(map_utils.timestamp_to_minutes(time_step))

        for client in sorted(clients):
            ys = ydata.get(client, list())

            y_value = data.loc[(data['start'] <= time_step)
                               & (time_step < data['end']) &
                               (data['client']
                                == client)]['num clients'].sum()
            ys.append(y_value)

            ydata[client] = ys

        time_step = time_step + step_size

    fig, ax = map_utils.subplots()
    ax.set_title(title)
    ax.set_xlabel("Time (minutes)")
    ax.set_ylabel("Number of clients")

    ax.set_xlim(left=0, right=map_utils.timestamp_to_minutes(max_time))
    stack_labels, stack_ys = zip(*(sorted(ydata.items())))
    ax.stackplot(xs, stack_ys, labels=stack_labels)

    handles, labels = ax.get_legend_handles_labels()
    lgd = ax.legend(handles,
                    labels,
                    bbox_to_anchor=(1.04, 1),
                    loc="upper left")

    fig.savefig(output_name.as_posix(),
                format='png',
                bbox_extra_artists=(lgd, ),
                bbox_inches='tight')
    plt.close(fig)
예제 #2
0
def output_graph(output, data, min_time):
    fig, ax = map_utils.subplots()
    ax.set_title("Resource report generation lag")
    ax.set_xlabel("Time (minutes)")
    ax.set_ylabel("Difference (seconds)")

    max_minutes = 0
    for node_name, plot_data in data.items():
        (xs, ys) = plot_data
        minutes = [map_utils.timestamp_to_minutes(x - min_time) for x in xs]
        max_minutes = max(max_minutes, max(minutes))
        ax.scatter(minutes, ys, label=node_name, s=1)

    ax.set_xlim(left=0, right=max_minutes)
    handles, labels = ax.get_legend_handles_labels()
    lgd = ax.legend(handles,
                    labels,
                    bbox_to_anchor=(1.04, 1),
                    loc="upper left")

    output_name = output / 'resource-report-time-lag.png'
    plt.savefig(output_name.as_posix(),
                format='png',
                bbox_extra_artists=(lgd, ),
                bbox_inches='tight')
    plt.close(fig)
예제 #3
0
def relative_timestamps_service(data, min_timestamp):
    """
    Arguments:
        data (dict): service -> timestamp -> ServiceCounts
        min_timestamp (int): first timestamp as milliseconds since the Epoch

    Returns:
        dict: service -> relative minutes -> ServiceCounts
    """
    relative_data = dict()
    for service, service_data in data.items():
        relative_service_data = dict()

        for timestamp, counts in sorted(service_data.items()):
            minutes = map_utils.timestamp_to_minutes(timestamp - min_timestamp)
            relative_service_data[minutes] = counts

        relative_data[service] = relative_service_data
    return relative_data
예제 #4
0
def output_graph(output, ncp, xs, ys, first_timestamp_ms):
    """
    Arguments:
        output(Path): output directory
        ncp(str): name of the NCP the graph is for
        xs: list of x-values
        ys(dict): neighbor to y-values
        first_timestamp_ms(int): initial timestamp to subtract from values
    """
    fig, ax = map_utils.subplots()
    ax.set_title(f"RLG Resource report lag for node {ncp}")
    ax.set_xlabel("Time (minutes)")
    ax.set_ylabel("Difference (seconds)")

    minutes = [
        map_utils.timestamp_to_minutes(x - first_timestamp_ms) for x in xs
    ]
    max_minutes = max(minutes)
    for node_name, plot_data in ys.items():
        get_logger().debug(
            "Graphing NCP %s with neighbor %s. x.len: %d y.len: %d", ncp,
            node_name, len(minutes), len(plot_data))
        ax.scatter(minutes, plot_data, label=node_name, s=1)

    ax.set_xlim(left=0, right=max_minutes)
    handles, labels = ax.get_legend_handles_labels()
    lgd = ax.legend(handles,
                    labels,
                    bbox_to_anchor=(1.04, 1),
                    loc="upper left")

    output_name = output / f'rlg-node-resource-report-time-lag_{ncp}.png'
    plt.savefig(output_name.as_posix(),
                format='png',
                bbox_extra_artists=(lgd, ),
                bbox_inches='tight')
    plt.close(fig)
예제 #5
0
def output_region_capacity_graph_for_app(first_timestamp, output, capacity, app):
    """
    Create a graph per node attribute for the specified service with a series for each region.
    Creates files with names capacity-<attribute>-<app>.png
    
    Args:
        first_timestamp(datetime.datetime): when the simulation started 
        output (Path): output directory
        capacity (boolean): if true output a graph of capacity only
        app (str): name of the service to generate the graph for
    """

    first_timestamp_ms = first_timestamp.timestamp() * 1000
    max_minutes = 0
    try:
        label='capacity'

        all_regions = set(capacity.keys())
        all_attrs = set()
        for region, region_data in capacity.items():
            all_attrs.update(region_data.keys())

        for attr in all_attrs:
            if 'QueueLength' == attr:
                # graphing queue length capacity doesn't work well because we've hardcoded it to be a big number
                continue

            frames = list()
            fig, ax = map_utils.subplots()
            ax.set_title(f"{attr} {label} for {app}")
            ax.set_xlabel("Time (minutes)")
            
            stack_xs = None
            stack_ys = list()
            stack_labels = list()

            for region in sorted(all_regions):
                region_data = capacity.get(region, dict())
                attr_data = region_data.get(attr, dict())

                app_data = attr_data.get(app, dict())
                if len(app_data) > 0:
                    pairs = sorted(app_data.items())
                    timestamps, values = zip(*pairs)
                    times = [map_utils.timestamp_to_minutes(float(t) - first_timestamp_ms) for t in timestamps]
                    max_minutes = max(max_minutes, max(times))

                    series_label=f"{region} capacity"
                    frames.append(pd.DataFrame(list(values), index=list(times), columns=[series_label]))
                    ax.plot(times, values, label=series_label)

                    if stack_xs is None:
                        stack_xs = times
                    stack_ys.append(values)
                    stack_labels.append(series_label)
                    
            ax.set_xlim(left=0, right=max_minutes)
            handles, labels = ax.get_legend_handles_labels()
            lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

            output_name = output / f"{label}-{attr}-{app}.png"
            fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
            plt.close(fig)
            
            # write out CSV of the plot data
            df = pd.concat(frames, axis=1)
            df.to_csv(output / f"{label}-{attr}-{app}.csv", index_label="relative minutes")

            # create stacked plot
            fig, ax = map_utils.subplots()
            ax.set_title(f"{attr} {label} for {app}")
            ax.set_xlabel("Time (minutes)")
            ax.set_xlim(left=0, right=max_minutes)
            ax.stackplot(stack_xs, stack_ys, labels=stack_labels)

            handles, labels = ax.get_legend_handles_labels()
            lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

            output_name = output / f"{label}-{attr}-{app}_stacked.png"
            fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
            plt.close(fig)
            
    except:
        get_logger().exception("Unexpected error")
예제 #6
0
def output_region_graphs_for_app(first_timestamp, output, capacity, data, label, app):
    """
    Create a graph per node attribute for the specified app with a series for each region.
    Creates files with names <label>-<attribute>-<app>.png
    
    Args:
        first_timestamp(datetime.datetime): when the simulation started 
        output (Path): output directory
        data (dict): region -> attr -> app -> timestamp -> value
        label (str): used to label the graph and generate the filenames
        capacity (dict): region -> attr -> app -> timestamp -> value
        app (str): service to generate the graph for
    """

    first_timestamp_ms = first_timestamp.timestamp() * 1000

    max_minutes = 0
    try:
        all_regions = set(capacity.keys())
        all_attrs = set()
        for region, region_data in data.items():
            all_attrs.update(region_data.keys())

        for attr in all_attrs:
            stack_xs = None
            stack_ys = list()
            stack_labels = list()
            
            frames = list()
            fig, ax = map_utils.subplots()
            ax.set_title(f"{attr} {label} for {app}")
            ax.set_xlabel("Time (minutes)")

            for region in sorted(all_regions):
                region_data = data.get(region, dict())
                attr_data = region_data.get(attr, dict())
                capacity_region = capacity.get(region, dict())

                if attr in capacity_region and 'QueueLength' != attr:
                    app_data = capacity_region[attr].get(app, dict())
                    if len(app_data) > 0:
                        pairs = sorted(app_data.items())
                        timestamps, values = zip(*pairs)
                        times = [map_utils.timestamp_to_minutes(float(t) - first_timestamp_ms) for t in timestamps]
                        max_minutes = max(max_minutes, max(times))

                        series_label=f"{region} capacity"
                        frames.append(pd.DataFrame(list(values), index=list(times), columns=[series_label]))
                        ax.plot(times, values, label=series_label)

                app_data = attr_data.get(app, dict())
                if len(app_data) > 0:
                    pairs = sorted(app_data.items())
                    timestamps, values = zip(*pairs)
                    times = [map_utils.timestamp_to_minutes(float(t) - first_timestamp_ms) for t in timestamps]
                    max_minutes = max(max_minutes, max(times))

                    frames.append(pd.DataFrame(list(values), index=list(times), columns=[region]))
                    ax.plot(times, values, label=region)
                    
                    if stack_xs is None:
                        stack_xs = times
                    stack_ys.append(values)
                    stack_labels.append(region)


            ax.set_xlim(left=0, right=max_minutes)
            handles, labels = ax.get_legend_handles_labels()
            lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

            output_name = output / f"{label}-{attr}-{app}.png"
            fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
            plt.close(fig)
            
            # write out CSV of the plot data
            df = pd.concat(frames, axis=1)
            df.to_csv(output / f"{label}-{attr}-{app}.csv", index_label="relative minutes")

            # create stacked plot
            fig, ax = map_utils.subplots()
            ax.set_title(f"{attr} {label} for {app}")
            ax.set_xlabel("Time (minutes)")
            ax.set_xlim(left=0, right=max_minutes)
            ax.stackplot(stack_xs, stack_ys, labels=stack_labels)

            handles, labels = ax.get_legend_handles_labels()
            lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

            output_name = output / f"{label}-{attr}-{app}_stacked.png"
            fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
            plt.close(fig)
            
    except:
        get_logger().exception("Unexpected error")
예제 #7
0
def output_graphs_per_region(first_timestamp, output, capacity, data, label):
    """
    Create a graph per node attribute.
    Creates files with names <label>-<attribute>-<region>.png
    
    Args:
        first_timestamp(datetime.datetime): when the simulation started 
        output (Path): output directory
        data (dict): region -> attr -> app -> timestamp -> value
        label (str): used to label the graph and generate the filenames
        capacity: region -> attr -> app -> timestamp -> value
    """

    first_timestamp_ms = first_timestamp.timestamp() * 1000

    max_minutes = 0
    try:
        for region, region_data in data.items():
            capacity_region = capacity[region]
            
            for attr, attr_data in region_data.items():
                frames = list()
                fig, ax = map_utils.subplots()
                ax.set_title(f"{attr} {label} in {region}")
                ax.set_xlabel("Time (minutes)")
                
                stack_xs = None
                stack_ys = list()
                stack_labels = list()
                total_capacity = None
                if attr in capacity_region and 'QueueLength' != attr:
                    for app, app_data in sorted(capacity_region[attr].items()):
                        if len(app_data) > 0:
                            pairs = sorted(app_data.items())
                            timestamps, values = zip(*pairs)
                            times = [map_utils.timestamp_to_minutes(float(t) - first_timestamp_ms) for t in timestamps]
                            max_minutes = max(max_minutes, max(times))

                            series_label=f"{app} capacity"
                            frames.append(pd.DataFrame(list(values), index=list(times), columns=[series_label]))
                            ax.plot(times, values, label=series_label)

                            if total_capacity is None:
                                total_capacity = app_data.copy()
                            else:
                                total_capacity = {k: total_capacity.get(k, 0) + app_data.get(k, 0) for k in set(total_capacity) | set(app_data)}

                app_timestamps = None
                for app, app_data in sorted(attr_data.items()):
                    if len(app_data) > 0:
                        pairs = sorted(app_data.items())
                        timestamps, values = zip(*pairs)
                        times = [map_utils.timestamp_to_minutes(float(t) - first_timestamp_ms) for t in timestamps]
                        max_minutes = max(max_minutes, max(times))

                        if app_timestamps is None:
                            app_timestamps = timestamps
                        
                        frames.append(pd.DataFrame(list(values), index=list(times), columns=[app]))
                        ax.plot(times, values, label=app)

                        if stack_xs is None:
                            stack_xs = times
                        stack_ys.append(values)
                        stack_labels.append(app)

                ax.set_xlim(left=0, right=max_minutes)                        
                handles, labels = ax.get_legend_handles_labels()
                lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

                output_name = output / f"{label}-{attr}-{region}.png"
                fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
                plt.close(fig)
                
                # write out CSV of the plot data
                df = pd.concat(frames, axis=1)
                df.to_csv(output / f"{label}-{attr}-{region}.csv", index_label="relative minutes")

                if app_timestamps is not None and total_capacity is not None:
                    # create stacked plot
                    fig, ax = map_utils.subplots()
                    ax.set_title(f"{attr} {label} in {region}")
                    ax.set_xlabel("Time (minutes)")
                    ax.set_xlim(left=0, right=max_minutes)                        
                    ax.stackplot(stack_xs, stack_ys, labels=stack_labels)

                    total_capacity = map_utils.fill_missing_times(app_timestamps, total_capacity)
                    ax.plot(stack_xs, total_capacity, label="Total allocated capacity")

                    handles, labels = ax.get_legend_handles_labels()
                    lgd = ax.legend(handles, labels, bbox_to_anchor=(1.04, 1), loc="upper left")

                    output_name = output / f"{label}-{attr}-{region}_stacked.png"
                    fig.savefig(output_name.as_posix(), format='png', bbox_extra_artists=(lgd,), bbox_inches='tight')
                    plt.close(fig)
                elif 'QueueLength' != attr:
                    get_logger().warning("Missing data to draw stackplot for %s %s in %s", label, attr, region)
                
    except:
        get_logger().exception("Unexpected error")
예제 #8
0
def graph(output, first_timestamp, label, data_type, node_data):
    """
    Graph network data.
    
    Arguments:
        output(Path): output directory
        first_timestamp(int): first timestamp seen in the data
        label(str): "Summary" or "Report"
        label(str): "demand" or "load"
        node_data(dict): service -> NetworkData
    """

    for node_name, network_data in node_data.items():
        rx_frames = list()
        tx_frames = list()
        all_frames = list()

        rx_fig, rx_ax = map_utils.subplots()
        rx_ax.set_title(f"{node_name} {label} {data_type} RX data")
        rx_ax.set_xlabel("Time (minutes)")

        tx_fig, tx_ax = map_utils.subplots()
        tx_ax.set_title(f"{node_name} {label} {data_type} TX data")
        tx_ax.set_xlabel("Time (minutes)")

        all_fig, all_ax = map_utils.subplots()
        all_ax.set_title(f"{node_name} {label} {data_type} ALL data")
        all_ax.set_xlabel("Time (minutes)")

        max_minutes = 0
        rx_empty_plot = True
        tx_empty_plot = True
        all_empty_plot = True
        for service, service_data in network_data.service.items():
            if len(service_data.rx) > 0:
                rx_empty_plot = False
                rx_pairs = sorted(service_data.rx.items())
                rx_timestamps, rx_values = zip(*rx_pairs)
                rx_times = [
                    map_utils.timestamp_to_minutes(float(t) - first_timestamp)
                    for t in rx_timestamps
                ]
                rx_series_label = f"{service} RX"
                rx_ax.plot(rx_times, rx_values, label=rx_series_label)
                rx_frames.append(
                    pd.DataFrame(list(rx_values),
                                 index=rx_times,
                                 columns=[rx_series_label]))
                max_minutes = max(max_minutes, max(rx_times))

            if len(service_data.tx) > 0:
                tx_empty_plot = False
                tx_pairs = sorted(service_data.tx.items())
                tx_timestamps, tx_values = zip(*tx_pairs)
                tx_times = [
                    map_utils.timestamp_to_minutes(float(t) - first_timestamp)
                    for t in tx_timestamps
                ]
                tx_series_label = f"{service} TX"
                tx_ax.plot(tx_times, tx_values, label=tx_series_label)
                tx_frames.append(
                    pd.DataFrame(list(tx_values),
                                 index=tx_times,
                                 columns=[tx_series_label]))
                max_minutes = max(max_minutes, max(tx_times))

            if len(service_data.all_traffic) > 0:
                all_empty_plot = False
                all_pairs = sorted(service_data.all_traffic.items())
                all_timestamps, all_values = zip(*all_pairs)
                all_times = [
                    map_utils.timestamp_to_minutes(float(t) - first_timestamp)
                    for t in all_timestamps
                ]
                all_series_label = f"{service} ALL"
                all_ax.plot(all_times, all_values, label=all_series_label)
                all_frames.append(
                    pd.DataFrame(list(all_values),
                                 index=all_times,
                                 columns=[all_series_label]))
                max_minutes = max(max_minutes, max(all_times))

        if not rx_empty_plot:
            rx_ax.set_xlim(left=0, right=max_minutes)
            rx_handles, rx_labels = rx_ax.get_legend_handles_labels()
            rx_lgd = rx_ax.legend(rx_handles,
                                  rx_labels,
                                  bbox_to_anchor=(1.04, 1),
                                  loc="upper left")
            rx_output_name = output / f"network-{node_name}-{label}-RX-{data_type}.png"
            rx_fig.savefig(rx_output_name.as_posix(),
                           format='png',
                           bbox_extra_artists=(rx_lgd, ),
                           bbox_inches='tight')
            rx_df = pd.concat(rx_frames, axis=1)
            rx_df.to_csv(output /
                         f"network-{node_name}-{label}-RX-{data_type}.csv",
                         index_label="relative minutes")

        if not tx_empty_plot:
            tx_ax.set_xlim(left=0, right=max_minutes)
            tx_handles, tx_labels = tx_ax.get_legend_handles_labels()
            tx_lgd = tx_ax.legend(tx_handles,
                                  tx_labels,
                                  bbox_to_anchor=(1.04, 1),
                                  loc="upper left")
            tx_output_name = output / f"network-{node_name}-{label}-TX-{data_type}.png"
            tx_fig.savefig(tx_output_name.as_posix(),
                           format='png',
                           bbox_extra_artists=(tx_lgd, ),
                           bbox_inches='tight')
            tx_df = pd.concat(tx_frames, axis=1)
            tx_df.to_csv(output /
                         f"network-{node_name}-{label}-TX-{data_type}.csv",
                         index_label="relative minutes")

        if not all_empty_plot:
            all_ax.set_xlim(left=0, right=max_minutes)
            all_handles, all_labels = all_ax.get_legend_handles_labels()
            all_lgd = all_ax.legend(all_handles,
                                    all_labels,
                                    bbox_to_anchor=(1.04, 1),
                                    loc="upper left")
            all_output_name = output / f"network-{node_name}-{label}-ALL-{data_type}.png"
            all_fig.savefig(all_output_name.as_posix(),
                            format='png',
                            bbox_extra_artists=(all_lgd, ),
                            bbox_inches='tight')
            all_df = pd.concat(all_frames, axis=1)
            all_df.to_csv(output /
                          f"network-{node_name}-{label}-ALL-{data_type}.csv",
                          index_label="relative minutes")

        plt.close(rx_fig)
        plt.close(tx_fig)
        plt.close(all_fig)
예제 #9
0
def process_node(output, first_timestamp_ms, all_services, node_dir, show_load_demand_attr):
    minutes = list()
    planned_total = list() # number of planned containers total
    planned_services = dict() # service -> list(value)
    actual_total_allocation = list() # number of containers
    actual_services_allocation = dict() # service -> list(allocation value)
    actual_total_load = list() # load
    actual_services_load = dict() # service -> list(load value)
    actual_total_demand = list() # demand
    actual_services_demand = dict() # service -> list(demand value)

    ncp = node_dir.stem
    get_logger().info("Processing directory for node %s: %s", ncp, node_dir)

    for time_dir in sorted(node_dir.iterdir()):
        if not time_dir.is_dir():
            continue

        get_logger().debug("Working on %s", time_dir)

        directory_time = int(time_dir.stem)
        directory_time_min = map_utils.timestamp_to_minutes(directory_time - first_timestamp_ms)

        rlg_plan_file = time_dir / 'loadBalancerPlan.json'
        if not rlg_plan_file.exists():
            continue
        resource_reports_file = time_dir / 'regionResourceReports-SHORT.json'
        if not resource_reports_file.exists():
            continue

        try:
            with open(rlg_plan_file, 'r') as f:
                rlg_plan = json.load(f)
        except json.decoder.JSONDecodeError:
            get_logger().warning("Problem reading %s, skipping", rlg_plan_file)
            continue

        try:
            with open(resource_reports_file, 'r') as f:
                resource_reports = json.load(f)
        except json.decoder.JSONDecodeError:
            get_logger().warning("Problem reading %s, skipping", resource_reports_file)
            continue

        minutes.append(directory_time_min)

        (p_total, p_per_service) = process_rlg_plan(rlg_plan)
        planned_total.append(p_total)
        for service in all_services:
            service_list = planned_services.get(service, list())
            if service in p_per_service:
                service_list.append(p_per_service[service])
            else:
                service_list.append(0)
            planned_services[service] = service_list

        (a_total_allocation, a_per_service_allocation, a_total_load, a_per_service_load, a_total_demand, a_per_service_demand) = process_reports(resource_reports, show_load_demand_attr)
        actual_total_allocation.append(a_total_allocation)
        actual_total_load.append(a_total_load)
        actual_total_demand.append(a_total_demand)
        for service in all_services:
            service_list_allocation = actual_services_allocation.get(service, list())
            if service in a_per_service_allocation:
                service_list_allocation.append(a_per_service_allocation[service])
            else:
                service_list_allocation.append(0)
            actual_services_allocation[service] = service_list_allocation

            service_list_load = actual_services_load.get(service, list())
            if service in a_per_service_load:
                service_list_load.append(a_per_service_load[service])
            else:
                service_list_load.append(0)
            actual_services_load[service] = service_list_load

            service_list_demand = actual_services_demand.get(service, list())
            if service in a_per_service_demand:
                service_list_demand.append(a_per_service_demand[service])
            else:
                service_list_demand.append(0)
            actual_services_demand[service] = service_list_demand


        graph(output, ncp, 'total', minutes, planned_total, actual_total_allocation, actual_total_load, actual_total_demand, show_load_demand_attr)
        for service in all_services:
            graph(output, ncp, service, minutes, planned_services[service], actual_services_allocation[service], actual_services_load[service], actual_services_demand[service], show_load_demand_attr)