Source code for scalesim.single_layer_sim

import os

from scalesim.scale_config import scale_config as cfg
from scalesim.topology_utils import topologies as topo
from scalesim.compute.operand_matrix import operand_matrix as opmat
from scalesim.compute.systolic_compute_os import systolic_compute_os
from scalesim.compute.systolic_compute_ws import systolic_compute_ws
from scalesim.compute.systolic_compute_is import systolic_compute_is
from scalesim.memory.double_buffered_scratchpad_mem import double_buffered_scratchpad as mem_dbsp


[docs] class single_layer_sim: """ Class which runs the simulation for a single layer and generates report data """ def __init__(self): """ The constructor method for the class """ self.layer_id = 0 self.topo = topo() self.config = cfg() self.op_mat_obj = opmat() self.compute_system = systolic_compute_os() self.memory_system = mem_dbsp() self.verbose = True # Report items : Compute report self.total_cycles = 0 self.stall_cycles = 0 self.num_compute = 0 self.num_mac_unit = 0 self.overall_util = 0 self.mapping_eff = 0 self.compute_util = 0 # Report items : BW report self.avg_ifmap_sram_bw = 0 self.avg_filter_sram_bw = 0 self.avg_ofmap_sram_bw = 0 self.avg_ifmap_dram_bw = 0 self.avg_filter_dram_bw = 0 self.avg_ofmap_dram_bw = 0 # Report items : Detailed Access report self.ifmap_sram_start_cycle = 0 self.ifmap_sram_stop_cycle = 0 self.ifmap_sram_reads = 0 self.filter_sram_start_cycle = 0 self.filter_sram_stop_cycle = 0 self.filter_sram_reads = 0 self.ofmap_sram_start_cycle = 0 self.ofmap_sram_stop_cycle = 0 self.ofmap_sram_writes = 0 self.ifmap_dram_start_cycle = 0 self.ifmap_dram_stop_cycle = 0 self.ifmap_dram_reads = 0 self.filter_dram_start_cycle = 0 self.filter_dram_stop_cycle = 0 self.filter_dram_reads = 0 self.ofmap_dram_start_cycle = 0 self.ofmap_dram_stop_cycle = 0 self.ofmap_dram_writes = 0 self.params_set_flag = False self.memory_system_ready_flag = False self.runs_ready = False self.report_items_ready = False
[docs] def set_params(self, layer_id=0, config_obj=cfg(), topology_obj=topo(), verbose=True): """ Method to set the run parameters for housekeeping. :param layer_id: Layer number of the workload :param config_obj: Object of scalesim.scale_config which is used to lookup the architecture and \ run parameters set by the user :param topology_obj: Object of scalesim.topologies which is used to obtain the workload dimensions :param verbose: Flag to indicate verbosity of runs. If set to False, no output is generated on console :return: None """ self.layer_id = layer_id self.config = config_obj self.topo = topology_obj self.op_mat_obj.set_params(layer_id=self.layer_id, config_obj=self.config, topoutil_obj=self.topo, ) self.dataflow = self.config.get_dataflow() if self.dataflow == 'os': self.compute_system = systolic_compute_os() elif self.dataflow == 'ws': self.compute_system = systolic_compute_ws() elif self.dataflow == 'is': self.compute_system = systolic_compute_is() arr_dims =self.config.get_array_dims() self.num_mac_unit = arr_dims[0] * arr_dims[1] self.verbose=verbose self.params_set_flag = True
# This communicates that the memory is being managed externally # And the class will not interfere with setting it up
[docs] def set_memory_system(self, mem_sys_obj=mem_dbsp()): self.memory_system = mem_sys_obj self.memory_system_ready_flag = True
[docs] def run(self): """ Method to run scalesim simulation for a single layer. This method first runs the compute part to generate operand, prefetch and demand matrices in order. After that, it runs the memory simulation using the demand matrices. :return: None """ assert self.params_set_flag, 'Parameters are not set. Run set_params()' # 1. Setup and the get the demand from compute system # 1.1 Get the operand matrices _, ifmap_op_mat = self.op_mat_obj.get_ifmap_matrix() _, filter_op_mat = self.op_mat_obj.get_filter_matrix() _, ofmap_op_mat = self.op_mat_obj.get_ofmap_matrix() self.num_compute = self.topo.get_layer_num_ofmap_px(self.layer_id) \ * self.topo.get_layer_window_size(self.layer_id) # 1.2 Get the prefetch matrices for both operands self.compute_system.set_params(config_obj=self.config, ifmap_op_mat=ifmap_op_mat, filter_op_mat=filter_op_mat, ofmap_op_mat=ofmap_op_mat) # 1.3 Get the no compute demand matrices from for 2 operands and the output ifmap_prefetch_mat, filter_prefetch_mat = self.compute_system.get_prefetch_matrices() ifmap_demand_mat, filter_demand_mat, ofmap_demand_mat = self.compute_system.get_demand_matrices() #print('DEBUG: Compute operations done') # 2. Setup the memory system and run the demands through it to find any memory bottleneck and generate traces # 2.1 Setup the memory system if it was not setup externally if not self.memory_system_ready_flag: word_size = 1 # bytes, this can be incorporated in the config file active_buf_frac = 0.5 # This can be incorporated in the config as well ifmap_buf_size_kb, filter_buf_size_kb, ofmap_buf_size_kb = self.config.get_mem_sizes() ifmap_buf_size_bytes = 1024 * ifmap_buf_size_kb filter_buf_size_bytes = 1024 * filter_buf_size_kb ofmap_buf_size_bytes = 1024 * ofmap_buf_size_kb ifmap_backing_bw = 1 filter_backing_bw = 1 ofmap_backing_bw = 1 estimate_bandwidth_mode = False if self.config.use_user_dram_bandwidth(): bws = self.config.get_bandwidths_as_list() ifmap_backing_bw = bws[0] filter_backing_bw = bws[0] ofmap_backing_bw = bws[0] else: dataflow = self.config.get_dataflow() arr_row, arr_col = self.config.get_array_dims() estimate_bandwidth_mode = True # The number 10 elems per cycle is arbitrary ifmap_backing_bw = 10 filter_backing_bw = 10 ofmap_backing_bw = arr_col self.memory_system.set_params( word_size=word_size, ifmap_buf_size_bytes=ifmap_buf_size_bytes, filter_buf_size_bytes=filter_buf_size_bytes, ofmap_buf_size_bytes=ofmap_buf_size_bytes, rd_buf_active_frac=active_buf_frac, wr_buf_active_frac=active_buf_frac, ifmap_backing_buf_bw=ifmap_backing_bw, filter_backing_buf_bw=filter_backing_bw, ofmap_backing_buf_bw=ofmap_backing_bw, verbose=self.verbose, estimate_bandwidth_mode=estimate_bandwidth_mode ) # 2.2 Install the prefetch matrices to the read buffers to finish setup if self.config.use_user_dram_bandwidth() : self.memory_system.set_read_buf_prefetch_matrices(ifmap_prefetch_mat=ifmap_prefetch_mat, filter_prefetch_mat=filter_prefetch_mat) # 2.3 Start sending the requests through the memory system until # all the OFMAP memory requests have been serviced self.memory_system.service_memory_requests(ifmap_demand_mat, filter_demand_mat, ofmap_demand_mat) self.runs_ready = True
# This will write the traces
[docs] def save_traces(self, top_path): """ Method to save SRAM and DRAM traces for ifmap, filter and ofmap matrices. :param top_path: Path where the generated traces will be saved :return: None """ assert self.params_set_flag, 'Parameters are not set' dir_name = top_path + '/layer' + str(self.layer_id) if not os.path.isdir(dir_name): cmd = 'mkdir ' + dir_name os.system(cmd) ifmap_sram_filename = dir_name + '/IFMAP_SRAM_TRACE.csv' filter_sram_filename = dir_name + '/FILTER_SRAM_TRACE.csv' ofmap_sram_filename = dir_name + '/OFMAP_SRAM_TRACE.csv' ifmap_dram_filename = dir_name + '/IFMAP_DRAM_TRACE.csv' filter_dram_filename = dir_name + '/FILTER_DRAM_TRACE.csv' ofmap_dram_filename = dir_name + '/OFMAP_DRAM_TRACE.csv' self.memory_system.print_ifmap_sram_trace(ifmap_sram_filename) self.memory_system.print_ifmap_dram_trace(ifmap_dram_filename) self.memory_system.print_filter_sram_trace(filter_sram_filename) self.memory_system.print_filter_dram_trace(filter_dram_filename) self.memory_system.print_ofmap_sram_trace(ofmap_sram_filename) self.memory_system.print_ofmap_dram_trace(ofmap_dram_filename)
#
[docs] def calc_report_data(self): """ Method to generate the report data for a single layer if the run is already completed. This method collects and calculates the data for compute, bandwidth and detail reports. :return: None """ assert self.runs_ready, 'Runs are not done yet' # Compute report self.total_cycles = self.memory_system.get_total_compute_cycles() self.stall_cycles = self.memory_system.get_stall_cycles() self.overall_util = (self.num_compute * 100) / (self.total_cycles * self.num_mac_unit) self.mapping_eff = self.compute_system.get_avg_mapping_efficiency() * 100 self.compute_util = self.compute_system.get_avg_compute_utilization() * 100 # BW report self.ifmap_sram_reads = self.compute_system.get_ifmap_requests() self.filter_sram_reads = self.compute_system.get_filter_requests() self.ofmap_sram_writes = self.compute_system.get_ofmap_requests() self.avg_ifmap_sram_bw = self.ifmap_sram_reads / self.total_cycles self.avg_filter_sram_bw = self.filter_sram_reads / self.total_cycles self.avg_ofmap_sram_bw = self.ofmap_sram_writes / self.total_cycles # Detail report self.ifmap_sram_start_cycle, self.ifmap_sram_stop_cycle \ = self.memory_system.get_ifmap_sram_start_stop_cycles() self.filter_sram_start_cycle, self.filter_sram_stop_cycle \ = self.memory_system.get_filter_sram_start_stop_cycles() self.ofmap_sram_start_cycle, self.ofmap_sram_stop_cycle \ = self.memory_system.get_ofmap_sram_start_stop_cycles() self.ifmap_dram_start_cycle, self.ifmap_dram_stop_cycle, self.ifmap_dram_reads \ = self.memory_system.get_ifmap_dram_details() self.filter_dram_start_cycle, self.filter_dram_stop_cycle, self.filter_dram_reads \ = self.memory_system.get_filter_dram_details() self.ofmap_dram_start_cycle, self.ofmap_dram_stop_cycle, self.ofmap_dram_writes \ = self.memory_system.get_ofmap_dram_details() # BW calc for DRAM access self.avg_ifmap_dram_bw = self.ifmap_dram_reads / (self.ifmap_dram_stop_cycle - self.ifmap_dram_start_cycle + 1) self.avg_filter_dram_bw = self.filter_dram_reads / (self.filter_dram_stop_cycle - self.filter_dram_start_cycle + 1) self.avg_ofmap_dram_bw = self.ofmap_dram_writes / (self.ofmap_dram_stop_cycle - self.ofmap_dram_start_cycle + 1) self.report_items_ready = True
#
[docs] def get_layer_id(self): """ Method to return layer id. :return: Layer number of the workload """ assert self.params_set_flag, 'Parameters are not set yet' return self.layer_id
#
[docs] def get_compute_report_items(self): """ Method to calculate data for the compute report if not already done. :return: List of data items for the compute report """ if not self.report_items_ready: self.calc_report_data() items = [self.total_cycles, self.stall_cycles, self.overall_util, self.mapping_eff, self.compute_util] return items
#
[docs] def get_bandwidth_report_items(self): """ Method to calculate data for the bandwidth report if not already done. :return: List of SRAM and DRAM bandwidths for the bandwidth report """ if not self.report_items_ready: self.calc_report_data() items = [self.avg_ifmap_sram_bw, self.avg_filter_sram_bw, self.avg_ofmap_sram_bw] items += [self.avg_ifmap_dram_bw, self.avg_filter_dram_bw, self.avg_ofmap_dram_bw] return items
#
[docs] def get_detail_report_items(self): """ Method to calculate data for the detailed report if not already done. :return: List of data items for the detailed report """ if not self.report_items_ready: self.calc_report_data() items = [self.ifmap_sram_start_cycle, self.ifmap_sram_stop_cycle, self.ifmap_sram_reads] items += [self.filter_sram_start_cycle, self.filter_sram_stop_cycle, self.filter_sram_reads] items += [self.ofmap_sram_start_cycle, self.ofmap_sram_stop_cycle, self.ofmap_sram_writes] items += [self.ifmap_dram_start_cycle, self.ifmap_dram_stop_cycle, self.ifmap_dram_reads] items += [self.filter_dram_start_cycle, self.filter_dram_stop_cycle, self.filter_dram_reads] items += [self.ofmap_dram_start_cycle, self.ofmap_dram_stop_cycle, self.ofmap_dram_writes] return items