with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Systems; use Systems; with CFG_Nodes; use CFG_Nodes; with Basic_Blocks; use Basic_Blocks; with CFG_Nodes; use CFG_Nodes.CFG_Nodes_Table_Package; with CFG_Nodes.Extended; use CFG_Nodes.Extended; with CFG_Node_Set; use CFG_Node_Set; with CFG_Node_Set.Basic_Block_Set; use CFG_Node_Set.Basic_Block_Set; with Integer_Arrays; use Integer_Arrays; with Tasks; use Tasks; with Scheduling_Analysis; use Scheduling_Analysis; with CFG_Edge_Set; use CFG_Edge_Set; with CFGs; use CFGs; with CFG_Edges; use CFG_Edges.CFG_Edges_Table_Package; with Caches; use Caches; with Caches; use Caches.Cache_Blocks_Table_Package; with Cache_Block_Set; use Cache_Block_Set; with Cache_Access_Profile_Set; use Cache_Access_Profile_Set; with Ada.Exceptions; use Ada.Exceptions; with Translate; use Translate; with Framework_Config; use Framework_Config; with Core_Units; use Core_Units; with Processors; use Processors; with Task_Set; use Task_Set; with CFG_Set; use CFG_Set; with Processor_Set; use Processor_Set; with processor_interface; use processor_interface; with Cache_Set; use Cache_Set; with unbounded_strings; use unbounded_strings; with Call_Framework_Interface; use Call_Framework_Interface; with Tables; with sets; Package body Basic_Block_Analysis is ------------------------------------------------------ -- Procedure for analysis based on the algorithm in: -- Lee, Chang-Gun, et al. -- "Analysis of cache-related preemption delay in fixed-priority preemptive scheduling." -- Computers, IEEE Transactions on 47.6 (1998): 700-713. ------------------------------------------------------ procedure Calculate_GEN (my_basic_blocks : in out Basic_Blocks_Set; number_cache_block : in Integer) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; ucb_basic_block : Basic_Block_UCB_Ptr; cache_position : Integer; begin reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); ucb_basic_block := Basic_Block_UCB_Ptr (a_basic_block); for i in 0 .. number_cache_block-1 loop ucb_basic_block.GenCBR.Elements(i) := -1; ucb_basic_block.GenCBL.Elements(i) := -1; end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0 .. ucb_basic_block.instruction_capacity-1 loop cache_position := (ucb_basic_block.instruction_offset+i) mod number_cache_block; ucb_basic_block.GenCBR.Elements(cache_position) := ucb_basic_block.instruction_offset+i; if(ucb_basic_block.GenCBL.Elements(cache_position) = -1) then ucb_basic_block.GenCBL.Elements(cache_position) := ucb_basic_block.instruction_offset+i; end if; end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; end Calculate_GEN; procedure Calculate_GEN (my_basic_blocks : in out Basic_Blocks_Set; cache_size : in Integer; cache_block_size : in Integer) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; ucb_basic_block : Basic_Block_UCB_Ptr; memory_address : Integer; memory_block_number : Integer; memory_block_number_used : Integer; number_cache_block : Integer := cache_size / cache_block_size; first_cache_block : Integer; last_cache_block : Integer; function Get_Cache_Address (memory_address : in Integer; number_cache_block : in Integer; cache_block_size : in Integer) return Integer is begin return (memory_address / cache_block_size) mod number_cache_block; end Get_Cache_Address; function Get_Memory_Block_Number (memory_address : in Integer; cache_block_size : in Integer) return Integer is begin return (memory_address / cache_block_size); end Get_Memory_Block_Number; begin --Initilization reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); ucb_basic_block := Basic_Block_UCB_Ptr(a_basic_block); for i in 0 .. number_cache_block-1 loop ucb_basic_block.GenCBR.Elements(i) := -1; ucb_basic_block.GenCBL.Elements(i) := -1; end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; --Calculation reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); ucb_basic_block := Basic_Block_UCB_Ptr(a_basic_block); first_cache_block := Get_Cache_Address(ucb_basic_block.instruction_offset, number_cache_block, cache_block_size); last_cache_block := Get_Cache_Address(ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity-1, number_cache_block, cache_block_size); memory_block_number_used := Get_Memory_Block_Number(ucb_basic_block.instruction_offset+ucb_basic_block.instruction_capacity,cache_block_size) - Get_Memory_Block_Number(ucb_basic_block.instruction_offset,cache_block_size); --Gen CBL - First Gen for cache_block in 0 .. number_cache_block-1 loop --1 if (cache_block >= first_cache_block AND cache_block <= last_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block - first_cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBL.Elements(cache_block) := memory_block_number; end if; --2 if (last_cache_block >= first_cache_block AND cache_block > last_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block - first_cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(cache_block) := memory_block_number; end if; --3 if(last_cache_block >= first_cache_block AND cache_block < first_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block + number_cache_block + first_cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(cache_block) := memory_block_number; end if; --4 if(first_cache_block > last_cache_block AND cache_block <= last_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block + (number_cache_block - first_cache_block)) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(cache_block) := memory_block_number; end if; --5 if(first_cache_block > last_cache_block AND cache_block >= first_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block - first_cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(cache_block) := memory_block_number; end if; --6 if(first_cache_block > last_cache_block AND cache_block < first_cache_block AND cache_block > last_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + (cache_block + number_cache_block - first_cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(cache_block) := memory_block_number; end if; end loop; --Gen CBR - Last Gen for cache_block in 0 .. number_cache_block-1 loop --1 if (cache_block >= first_cache_block AND cache_block <= last_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; --2 if (last_cache_block >= first_cache_block AND cache_block > last_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block + number_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; --3 if(last_cache_block >= first_cache_block AND cache_block < first_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; --4 if(first_cache_block > last_cache_block AND cache_block <= last_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; --5 if(first_cache_block > last_cache_block AND cache_block >= first_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block + number_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; --6 if(first_cache_block > last_cache_block AND cache_block < first_cache_block AND cache_block > last_cache_block AND memory_block_number_used >= number_cache_block) then memory_address := ucb_basic_block.instruction_offset + ucb_basic_block.instruction_capacity -1 - (last_cache_block + number_cache_block - cache_block) * cache_block_size; memory_block_number := Get_Memory_Block_Number(memory_address,cache_block_size); ucb_basic_block.GenCBR.Elements(cache_block) := memory_block_number; end if; end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; end Calculate_GEN; procedure Calculate_RMB (my_basic_blocks : in out Basic_Blocks_Set; number_cache_block : in Integer) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; oldout : Integer_Array; change : Boolean := true; begin reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0 .. number_cache_block-1 loop Integer_Arrays.Add(arr => Basic_Block_UCB_Ptr (a_basic_block).RMBOut(i), element => Basic_Block_UCB_Ptr (a_basic_block).GenCBR.Elements (i)); end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; --Calculation change := true; while change loop change := false; reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0 .. number_cache_block-1 loop for j in 0 .. Basic_Block_UCB_Ptr (a_basic_block).previous_nodes.Nb_Entries-1 loop Integer_Arrays.Union(arr_a => Basic_Block_UCB_Ptr (a_basic_block).RMBIn(i), arr_b => Basic_Block_UCB_Ptr (Basic_Block_UCB_Ptr(a_basic_block).previous_nodes.Entries(j)).RMBOut(i)); end loop; oldout := Basic_Block_UCB_Ptr (a_basic_block).RMBOut(i); if(Basic_Block_UCB_Ptr (a_basic_block).GenCBR.Elements(i) = -1) then Basic_Block_UCB_Ptr (a_basic_block).RMBOut(i) := Basic_Block_UCB_Ptr (a_basic_block).RMBIn(i); end if; if (Basic_Block_UCB_Ptr (a_basic_block).RMBOut(i) /= oldout) then change := true; end if; end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; end loop; end Calculate_RMB; procedure Calculate_LMB (my_basic_blocks : in out Basic_Blocks_Set; number_cache_block : in Integer) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; oldin : Integer_Array; change : Boolean := true; begin --LMB --Initilization reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0 .. number_cache_block-1 loop Integer_Arrays.Add(arr => Basic_Block_UCB_Ptr (a_basic_block).LMBIn(i), element => Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements (i)); end loop; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; --Calculation change := true; while change loop change := false; reset_tail_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0 .. number_cache_block-1 loop for j in 0 .. Basic_Block_UCB_Ptr(a_basic_block).next_nodes.Nb_Entries-1 loop Integer_Arrays.Union(arr_a => Basic_Block_UCB_Ptr (a_basic_block).LMBOut(i), arr_b => Basic_Block_UCB_Ptr (Basic_Block_UCB_Ptr(a_basic_block).next_nodes.Entries(j)).LMBIn(i)); end loop; oldin := Basic_Block_UCB_Ptr (a_basic_block).LMBIn(i); if(Basic_Block_UCB_Ptr (a_basic_block).GenCBL.Elements(i) = -1) then Basic_Block_UCB_Ptr (a_basic_block).LMBIn(i) := Basic_Block_UCB_Ptr (a_basic_block).LMBOut(i); end if; if (Basic_Block_UCB_Ptr (a_basic_block).LMBIn(i) /= oldin) then change := true; end if; end loop; exit when is_first_element (my_basic_blocks,my_iterator); previous_element (my_basic_blocks,my_iterator); end loop; end loop; end Calculate_LMB; procedure Intersect_UsefulBlocks (my_basic_blocks : in out Basic_Blocks_Set; number_cache_block : in Integer) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; arr_c : Integer_Array; arr_mem : Integer_Array; n : Integer; begin reset_iterator(my_basic_blocks,my_iterator); loop arr_mem.Size := 0; arr_mem.Elements := new Integer_Arr(0..0); current_element (my_basic_blocks, a_basic_block, my_iterator); for j in 0 .. Basic_Block_UCB_Ptr (a_basic_block).next_nodes.Nb_Entries-1 loop for i in 0 .. number_cache_block-1 loop Integer_Arrays.Intersect(arr_a => Basic_Block_UCB_Ptr (a_basic_block).RMBOut(i), arr_b => Basic_Block_UCB_Ptr (Basic_Block_UCB_Ptr(a_basic_block).next_nodes.Entries(j)).LMBIn(i), arr_c => arr_c, n => n); if(arr_c.Size > 0) then Add(Basic_Block_UCB_Ptr (a_basic_block).UCBs, True, i); end if; end loop; end loop; Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock := Basic_Block_UCB_Ptr (a_basic_block).UCBs.Size; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; end Intersect_UsefulBlocks; procedure Calculate_UsefulBlocks (my_basic_blocks : in out Basic_Blocks_Set; cache_size : in Integer; line_size : in Integer) is number_cache_block : Integer := cache_size / line_size; begin Calculate_GEN(my_basic_blocks => my_basic_blocks, cache_size => cache_size, cache_block_size => line_size); Calculate_RMB(my_basic_blocks => my_basic_blocks, number_cache_block => number_cache_block); Calculate_LMB(my_basic_blocks => my_basic_blocks, number_cache_block => number_cache_block); Intersect_UsefulBlocks(my_basic_blocks => my_basic_blocks, number_cache_block => number_cache_block); end Calculate_UsefulBlocks; procedure Calculate_Cost_Table (my_cfg_nodes : in out CFG_Nodes_Set; my_cfg_edges : in out CFG_Edges_Set; cache_blocks : in Cache_Blocks_Table; cache_size : in Integer; line_size : in Integer; block_reload_time : in Integer; a_cache_access_profile : in out Cache_Access_Profile_Ptr; cost_arr : out Integer_Array) is my_iterator : Basic_Blocks_Iterator; a_basic_block : Basic_Block_Ptr; my_basic_blocks : Basic_Blocks_Set; max_n_ucb : Integer := 0; a_cfg_node : CFG_Node_Ptr; my_iterator_cfg : CFG_Nodes_Iterator; UCBs : Integer_Array; ECBs : Integer_Array; begin cost_arr.Size := 0; cost_arr.Elements := new Integer_Arr(0..0); --CONVERT CFG_Nodes_Set to Basic_Blocks_Set reset_iterator(my_cfg_nodes,my_iterator_cfg); loop current_element (my_cfg_nodes, a_cfg_node, my_iterator_cfg); Add(my_basic_blocks,Basic_Block_Ptr(a_cfg_node)); exit when is_last_element (my_cfg_nodes,my_iterator_cfg); next_element (my_cfg_nodes,my_iterator_cfg); end loop; --CONVERT Basic_Blocks_Set to set of Basic_Blocks_UCB with information of previous_nodes, next_nodes. Convert_To_Basic_Block_UCB_Set(my_basic_blocks => my_basic_blocks, my_cfg_edges => my_cfg_edges, size => cache_size/line_size); Calculate_UsefulBlocks(my_basic_blocks,cache_size,line_size); --COMPUTE Cost Table reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); if (Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock > 0) then Integer_Arrays.Add(arr => cost_arr, element => (Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock)*block_reload_time); end if; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; --COMPUTE Cache Access Profile initialize(UCBs); initialize(ECBs); reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); for i in 0..Basic_Block_UCB_Ptr(a_basic_block).GenCBR.Size-1 loop if(Basic_Block_UCB_Ptr(a_basic_block).GenCBR.Elements(i) >= 0) then Add(ECBs, TRUE, i); end if; end loop; if (Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock > max_n_ucb) then max_n_ucb := Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock; UCBs := Basic_Block_UCB_Ptr (a_basic_block).UCBs; end if; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; for i in 0..UCBs.Size-1 loop Add(a_cache_access_profile.UCBs, cache_blocks.Entries(Caches.Cache_Blocks_Range(UCBs.Elements(i)))); end loop; for i in 0..ECBs.Size-1 loop Add(a_cache_access_profile.ECBs, cache_blocks.Entries(Caches.Cache_Blocks_Range(ECBs.Elements(i)))); end loop; Sort_DESC(arr_a => cost_arr); reset_iterator(my_basic_blocks,my_iterator); loop current_element (my_basic_blocks, a_basic_block, my_iterator); if (Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock > 0) then Basic_Block_UCB_Ptr (a_basic_block).NumberOfUsefulBlock := 0; end if; exit when is_last_element (my_basic_blocks,my_iterator); next_element (my_basic_blocks,my_iterator); end loop; end Calculate_Cost_Table; procedure Calculate_Task_Cache_Utilization (my_basic_blocks : in out Basic_Blocks_Table; cache_size : in Integer; cache_block_size : in Integer; cache_utilization_array : in out Integer_Array) is function Get_Cache_Address (memory_address : in Integer; number_cache_block : in Integer; cache_block_size : in Integer) return Integer is begin return (memory_address / cache_block_size) mod number_cache_block; end Get_Cache_Address; task_instruction_capacity : Integer :=0; task_instruction_offset : Integer :=0; start_addr : Integer; end_addr : Integer; number_cache_block : Integer; begin for i in 0 .. my_basic_blocks.Nb_Entries-1 loop task_instruction_capacity := task_instruction_capacity+ my_basic_blocks.Entries(i).instruction_capacity; end loop; task_instruction_offset := my_basic_blocks.Entries(0).instruction_offset; number_cache_block := cache_size/cache_block_size; start_addr := Get_Cache_Address(task_instruction_offset,number_cache_block,cache_block_size); end_addr := Get_Cache_Address(task_instruction_offset+task_instruction_capacity, number_cache_block,cache_block_size); if(task_instruction_capacity>cache_size)then for i in 0..number_cache_block loop add(cache_utilization_array,i); end loop; end if; if(start_addrend_addr AND task_instruction_capacity my_cfg_nodes, my_cfg_edges => my_cfg_edges, cache_blocks => a_cache.cache_blocks, cache_size => a_cache.cache_size, line_size => a_cache.line_size, block_reload_time => Integer(a_cache.block_reload_time), a_cache_access_profile => a_cache_access_profile, cost_arr => cost_arr); ----------------------------------------------------- Add(Sys.Cache_Access_Profiles,a_cache_access_profile); a_task.cache_access_profile_name := a_cache_access_profile.name; ----------------------------------------------------- end Compute_Cache_Access_Profile; End Basic_Block_Analysis;