import os
from scalesim.scale_config import scale_config as cfg
from scalesim.topology_utils import topologies as topo
from scalesim.single_layer_sim import single_layer_sim as layer_sim
[docs]
class simulator:
"""
Class which runs the simulations and manages generated data across various layers
"""
def __init__(self):
"""
The constructor method for the class
"""
self.conf = cfg()
self.topo = topo()
self.top_path = "./"
self.verbose = True
self.save_trace = True
self.num_layers = 0
self.single_layer_sim_object_list = []
self.params_set_flag = False
self.all_layer_run_done = False
#
[docs]
def set_params(self,
config_obj=cfg(),
topo_obj=topo(),
top_path="./",
verbosity=True,
save_trace=True
):
"""
Method to set the run parameters including inputs and parameters for housekeeping.
:param config_obj: Object of scalesim.scale_config which is used to lookup the architecture and \
run parameters set by the user
:param topo_obj: Object of scalesim.topologies which is used to obtain the workload dimensions
:param top_path: Path where the generated logs and traces will be saved
:param verbosity: Flag to indicate verbosity of runs. If set to False, no output is generated on console
:param save_trace: Flag to indicate if cycle accurate traces needs to be saved
:return: None
"""
self.conf = config_obj
self.topo = topo_obj
self.top_path = top_path
self.verbose = verbosity
self.save_trace = save_trace
# Calculate inferrable parameters here
self.num_layers = self.topo.get_num_layers()
self.params_set_flag = True
#
[docs]
def run(self):
"""
Method to run scalesim simulation for all layers.
This method first runs compute and memory simulations for each layer and gathers the required stats.
Once the simulation runs are done, it gathers the stats from single_layer_sim objects and calls
generate_report() method to create the report files.
If save_trace flag is set, then layer wise traces are saved as well.
:return: None
"""
assert self.params_set_flag, 'Simulator parameters are not set'
# 1. Create the layer runners for each layer
for i in range(self.num_layers):
this_layer_sim = layer_sim()
this_layer_sim.set_params(layer_id=i,
config_obj=self.conf,
topology_obj=self.topo,
verbose=self.verbose)
self.single_layer_sim_object_list.append(this_layer_sim)
if not os.path.isdir(self.top_path):
cmd = 'mkdir ' + self.top_path
os.system(cmd)
report_path = self.top_path + '/' + self.conf.get_run_name()
if not os.path.isdir(report_path):
cmd = 'mkdir ' + report_path
os.system(cmd)
self.top_path = report_path
# 2. Run each layer
# Note: This is parallelizable
for single_layer_obj in self.single_layer_sim_object_list:
if self.verbose:
layer_id = single_layer_obj.get_layer_id()
print('\nRunning Layer ' + str(layer_id))
single_layer_obj.run()
if self.verbose:
comp_items = single_layer_obj.get_compute_report_items()
comp_cycles = comp_items[0]
stall_cycles = comp_items[1]
util = comp_items[2]
mapping_eff = comp_items[3]
print('Compute cycles: ' + str(comp_cycles))
print('Stall cycles: ' + str(stall_cycles))
print('Overall utilization: ' + "{:.2f}".format(util) +'%')
print('Mapping efficiency: ' + "{:.2f}".format(mapping_eff) +'%')
avg_bw_items = single_layer_obj.get_bandwidth_report_items()
avg_ifmap_bw = avg_bw_items[3]
avg_filter_bw = avg_bw_items[4]
avg_ofmap_bw = avg_bw_items[5]
print('Average IFMAP DRAM BW: ' + "{:.3f}".format(avg_ifmap_bw) + ' words/cycle')
print('Average Filter DRAM BW: ' + "{:.3f}".format(avg_filter_bw) + ' words/cycle')
print('Average OFMAP DRAM BW: ' + "{:.3f}".format(avg_ofmap_bw) + ' words/cycle')
if self.save_trace:
if self.verbose:
print('Saving traces: ', end='')
single_layer_obj.save_traces(self.top_path)
if self.verbose:
print('Done!')
self.all_layer_run_done = True
self.generate_reports()
#
[docs]
def generate_reports(self):
"""
Method to generate the report files for scalesim run if the runs are already completed.
For each layer, this method collects the report data from single_layer_sim objects and then prints them out
into COMPUTE_REPORT.csv, BANDWIDTH_REPORT.csv, and DETAILED_ACCESS_REPORT.csv files.
:return: None
"""
assert self.all_layer_run_done, 'Layer runs are not done yet'
compute_report_name = self.top_path + '/COMPUTE_REPORT.csv'
compute_report = open(compute_report_name, 'w')
header = 'LayerID, Total Cycles, Stall Cycles, Overall Util %, Mapping Efficiency %, Compute Util %,\n'
compute_report.write(header)
bandwidth_report_name = self.top_path + '/BANDWIDTH_REPORT.csv'
bandwidth_report = open(bandwidth_report_name, 'w')
header = 'LayerID, Avg IFMAP SRAM BW, Avg FILTER SRAM BW, Avg OFMAP SRAM BW, '
header += 'Avg IFMAP DRAM BW, Avg FILTER DRAM BW, Avg OFMAP DRAM BW,\n'
bandwidth_report.write(header)
detail_report_name = self.top_path + '/DETAILED_ACCESS_REPORT.csv'
detail_report = open(detail_report_name, 'w')
header = 'LayerID, '
header += 'SRAM IFMAP Start Cycle, SRAM IFMAP Stop Cycle, SRAM IFMAP Reads, '
header += 'SRAM Filter Start Cycle, SRAM Filter Stop Cycle, SRAM Filter Reads, '
header += 'SRAM OFMAP Start Cycle, SRAM OFMAP Stop Cycle, SRAM OFMAP Writes, '
header += 'DRAM IFMAP Start Cycle, DRAM IFMAP Stop Cycle, DRAM IFMAP Reads, '
header += 'DRAM Filter Start Cycle, DRAM Filter Stop Cycle, DRAM Filter Reads, '
header += 'DRAM OFMAP Start Cycle, DRAM OFMAP Stop Cycle, DRAM OFMAP Writes,\n'
detail_report.write(header)
for lid in range(len(self.single_layer_sim_object_list)):
single_layer_obj = self.single_layer_sim_object_list[lid]
compute_report_items_this_layer = single_layer_obj.get_compute_report_items()
log = str(lid) +', '
log += ', '.join([str(x) for x in compute_report_items_this_layer])
log += ',\n'
compute_report.write(log)
bandwidth_report_items_this_layer = single_layer_obj.get_bandwidth_report_items()
log = str(lid) + ', '
log += ', '.join([str(x) for x in bandwidth_report_items_this_layer])
log += ',\n'
bandwidth_report.write(log)
detail_report_items_this_layer = single_layer_obj.get_detail_report_items()
log = str(lid) + ', '
log += ', '.join([str(x) for x in detail_report_items_this_layer])
log += ',\n'
detail_report.write(log)
compute_report.close()
bandwidth_report.close()
detail_report.close()
#
[docs]
def get_total_cycles(self):
"""
Method which aggregates the total cycles (both compute and stall) across all the layers for the given
workload.
:return: Total runtime in cycles across all layers
:rtype: int
"""
assert self.all_layer_run_done, 'Layer runs are not done yet'
total_cycles = 0
for layer_obj in self.single_layer_sim_object_list:
cycles_this_layer = int(layer_obj.get_compute_report_items[0])
total_cycles += cycles_this_layer
return total_cycles