Source code for perfsim.helpers.logger

#  Copyright (C) 2020 Michel Gokan Khan
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#  This file is a part of the PerfSim project, which is now open source and available under the GPLv2.
#  Written by Michel Gokan Khan, February 2020

#
from __future__ import annotations

import os
import sys
from typing import TYPE_CHECKING

import numpy as np
import pandas as pd
from prettytable import PrettyTable
from tabulate import tabulate

if TYPE_CHECKING:
    from perfsim import Simulation, ServiceChainManager


[docs] class Logger: """ This class represents a logger that logs the simulation events. """ lb_timer = [] tick_timer = [] core_sorting_timer = [] sim: Simulation def __init__(self, simulation: Simulation = None): # self.latencies = [] # self.arrivals = [] self.sim = simulation # self.average_compute_times = np.zeros(len(self.sim.load_generator.sim.cluster.microservices_dict)) # self.average_transmission_times = np.zeros(self.sim.load_generator.sim.cluster.count_total_service_edges()) if self.sim.debug_file_location is not None and self.sim.debug_file_location is not False: os.remove(self.sim.debug_file_location) def _print_log(self, log_str: str, end: str = None): if self.sim.debug_file_location is None or self.sim.debug_file_location is False: if end is not None: print(log_str, end=end) else: print(log_str) else: original_stdout = sys.stdout # Save a reference to the original standard output with open(self.sim.debug_file_location, 'a') as f: sys.stdout = f # Change the standard output to the file we created. if end is not None: print(log_str, end=end) else: print(log_str) sys.stdout = original_stdout # Reset the standard output to its original value
[docs] def print_traffic_details(self): table = PrettyTable( ["Traffic Generator Name/SCM ID", "Duration", "Arrival Delta T", "Start at", "Batch size", "Total requests"]) self._print_log("\nTraffic Prototypes\n") for traffic_prototype in self.sim.traffic_prototypes_dict.values(): row = [str(traffic_prototype.name), str(traffic_prototype.duration), str(traffic_prototype.arrival_interval_ns), str(traffic_prototype.start_at), str(traffic_prototype.parallel_user), str(traffic_prototype.requests_count)] table.add_row(row) self._print_log(log_str=str(table))
[docs] def print_hosts_info(self): hosts_table = PrettyTable(["Host Name", "Clock Rate", "Cores"]) self._print_log("\nHosts\n") for h in self.sim.cluster.cluster_scheduler.hosts_dict.values(): hosts_table.add_row([str(h.name), str(h.cpu.clock_rate), str(len(h.cpu.cores))]) self._print_log(str(hosts_table))
[docs] def print_microservices_info(self): self._print_log("\nMicroservices\n") table = PrettyTable(["MS Name", "CPU Requests", "CPU Limits", "Replica Name", "Host", "Endpoint Function ID", "Thread ID", "Instructions", "CPI", "Misses", "Refs", "Penalty"]) for scm in self.sim.cluster.scm_dict.values(): row = [] for ms in scm.service_chain.microservices_dict.values(): row.append(ms.name) row.append(ms.cpu_requests) row.append(ms.cpu_limits) for replica in ms.replicas: row.append(replica.name) row.append(replica.host.name) if replica.host is not None else row.append("None") for f in ms.endpoint_functions: _f_data = ms.endpoint_functions[f] row.append(_f_data.name) for t in np.arange(ms.endpoint_functions[f].threads_count): row.append(str(t)) row.append(_f_data.threads_instructions[t]) row.append(str(_f_data.threads_avg_cpi[t])) row.append(str(_f_data.threads_single_core_isolated_cache_misses[t])) row.append(str(_f_data.threads_single_core_isolated_cache_refs[t])) row.append(str(_f_data.threads_avg_cache_miss_penalty[t])) table.add_row(row) row = ['', '', '', '', '', ''] row = ['', '', '', '', ''] row = ['', '', ''] row = [] self._print_log(str(table))
[docs] def print_cluster_info(self): self._print_log(log_str=self.sim.cluster.cluster_scheduler.placement_matrix.to_string()) self.print_hosts_info() self.print_microservices_info()
[docs] def print_subchains(self, scm: ServiceChainManager): self._print_log(log_str="----------------------") self._print_log(log_str="Subchains of scm #" + str(scm.name)) for subchain_id, subchain in enumerate(scm.subchains): self._print_log(log_str="Subchain #" + str(subchain_id) + ": ", end='') for node in subchain: self._print_log(log_str="(" + str(node[0]) + "," + str(node[1]) + ") ", end="") self._print_log(log_str="") self._print_log(log_str="----------------------") self._print_log(log_str="")
[docs] def print_all(self): self.print_cluster_info() self.print_traffic_details() for scm_name, scm in enumerate(self.sim.cluster.scm_dict.values()): self.print_subchains(scm=scm)
[docs] def log(self, msg: str, level: int = 1): if self.sim.debug and self.sim.debug_level >= level: self._print_log(log_str=str(self.sim.time) + ": " + msg)
[docs] def print_latencies(self, summary=False, detailed=True): if detailed: self._print_log(log_str=tabulate(self.sim.load_generator.latencies, headers="keys", tablefmt="psql")) if summary: self._print_log(log_str=tabulate(self.get_latencies_summary(), headers="keys", tablefmt="psql"))
[docs] def get_latencies_summary(self): summary = pd.DataFrame(columns=["avg. latency", "max latency", "min latency"]) summary.loc[0] = {"avg. latency": int(self.sim.load_generator.latencies["latency"].mean()), "max latency": int(self.sim.load_generator.latencies["latency"].max()), "min latency": int(self.sim.load_generator.latencies["latency"].min())} return summary
# def calculate_average_computation_times(self) -> None: # if self.total_batch_requests_count != 0: # for request in self.requests: # for ms_id in np.arange(self.cluster.service_chain.chain_count): # self.average_compute_times[ms_id] += request.compute_times[ms_id] # # if ms_id < self.cluster.service_chain.chain_count - 1: # self.average_transmission_times[ms_id] += request.transmission_times[ms_id] # # self.average_compute_times = self.average_compute_times / len(self.requests) # self.average_transmission_times = self.average_transmission_times / len(self.requests)