diff --git a/lib/analysis/ecb.rb b/lib/analysis/ecb.rb index 1933a2c2e4c5cc05cda7b26c01e96c9f9795e15e..453e12254867df84db3c1c08689d64bd67786c4f 100644 --- a/lib/analysis/ecb.rb +++ b/lib/analysis/ecb.rb @@ -38,6 +38,7 @@ class ECBAnalysis # Calculates set of accessed cache blocks locally for this stream of # instructions. Modifications of the cache by calls are ignored. def ecb(instructions, cache_config) + cache_config.analysis_strategy = :must # Only used for address calculation cache = Cache.new(cache_config) # Only used for address calculation ecb = Set.new instructions.each do |instr| diff --git a/lib/analysis/meg.rb b/lib/analysis/meg.rb index 6a73a415f7c570f2cfb132daba266f9d5ac2fc7a..dff8793e047d6a1d0960d770910dfa3666906065 100644 --- a/lib/analysis/meg.rb +++ b/lib/analysis/meg.rb @@ -331,6 +331,9 @@ class MAAnalysis cache = ilist.first.block.classification.cache_at_entry[:must] end + #quickfix for analysis: we just need to model the cache state durng execution + cache.strategy = :must + graph = MEG.new(lst.dup, cache, @pipeline) graph.construct_uninterrupted_graph graph.minimize diff --git a/lib/core/cache.rb b/lib/core/cache.rb index 1ea462f3289e3d25d5b628b1e5c3fa367adddde1..778c025abefced5fb415e4ec82a7144bd3440b9e 100644 --- a/lib/core/cache.rb +++ b/lib/core/cache.rb @@ -6,6 +6,23 @@ class LRUMustAnalysisOperator # combination after H. Theiling, C. Ferdinand: Combining Abstract # Interpretation and ILP for Microarchitecture Modelling and Program Path # Analysis. + + def update(set, elem) + cache_hit = set.include?(elem) + if cache_hit + # cache hit: move datum to way0, age the rest + set.ways[1].merge(set.ways[0]) + set.ways[1].delete(elem) + set.ways[0] = Set[elem] + else + # cache miss: discard way1, move way0 to way1, move datum to way0 + set.ways[1] = set.ways[0].dup + set.ways[0] = Set[elem] + end + + return cache_hit + end + def combine(a, b) elems_a = a.elements elems_b = b.elements @@ -52,7 +69,30 @@ class LRUMustAnalysisOperator end class LRUMayAnalysisOperator - def combine(a, b) + def update(m, x) + m_dup = m.dup + way_x = m_dup.ways.index(x) + + if !!way_x && way_x < m.ways.size - 1 + m.ways[0] = Set[x] + for i in 1..way_x do + m.ways[i] = m_dup.ways[i-1].dup + end + m.ways[way_x+1] = m_dup.ways[way_x+1].dup + m.ways[way_x+1].merge(m_dup.ways[way_x]) + m.ways[way_x+1].delete(x) + for i in (way_x + 2)...m.ways.size do + m.ways[i] = m_dup.ways[i].dup + end + else + m.ways[0] = Set[x] + for i in 1...m.ways.size do + m.ways[i] = m_dup.ways[i-1].dup + end + end + end + + def combine(a, b) elems_a = a.elements elems_b = b.elements elems = Hash.new @@ -60,7 +100,7 @@ class LRUMayAnalysisOperator elems_a.each { |e| elems[e[:elem]] = {way: e[:way], occs: 1}} elems_b.each { |e| if elems[e[:elem]].nil? - + elems[e[:elem]] = {way: e[:way], occs: 1} else old = elems[e[:elem]] @@ -81,31 +121,101 @@ class LRUMayAnalysisOperator } end - # All ways of the callee up to the oldest non-empty way are taken over. - # The remaining ways are then filled up with the youngest ways of the caller. def interprocedural_combine(caller_state, callee_state) # no conflict, keep existing ways return if callee_state.ways.all? { |w| w.empty? } if callee_state.ways[-1].empty? - if (caller_state.ways[0] & (callee_state.ways[0])).empty? - caller_state.ways[1] = caller_state.ways[0].dup - caller_state.ways[1].subtract(callee_state.ways[0]) - caller_state.ways[0] = callee_state.ways[0].dup - else - caller_state.ways[1] = caller_state.ways[0].dup - caller_state.ways[1].merge(caller_state.ways[0]).subtract(callee_state.ways[0]) - caller_state.ways[0] = callee_state.ways[0].dup - end + if (caller_state.ways[0] & (callee_state.ways[0])).empty? + caller_state.ways[1] = caller_state.ways[0].dup + caller_state.ways[1].subtract(callee_state.ways[0]) + caller_state.ways[0] = callee_state.ways[0].dup + else + caller_state.ways[1] = caller_state.ways[0].dup + caller_state.ways[1].merge(caller_state.ways[0]).subtract(callee_state.ways[0]) + caller_state.ways[0] = callee_state.ways[0].dup + end else - # callee overwrote both ways - caller_state.ways.each_with_index { |e, i| - caller_state.ways[i] = callee_state.ways[i].dup - } + # callee overwrote both ways + caller_state.ways.each_with_index { |e, i| + caller_state.ways[i] = callee_state.ways[i].dup + } end end end +class LRUMayMaxAnalysisOperator + def update(m, m_pers, x) + m_pers_dup = m_pers.dup + mayevict = m.ways.inject(0) { |acc, elem| if (elem.include?(x)) then acc + elem.size - 1 else acc + elem.size end } >= m.ways.size + associativity = m_pers.ways.size + + if mayevict + m_pers.ways[0] = Set[x] + for i in 1...associativity do + m_pers.ways[i] = m_pers_dup.ways[i-1].dup + m_pers.ways[i].delete(x) + end + m_pers.removed = m_pers_dup.removed.dup + m_pers.removed.merge(m_pers_dup.ways[-1]) + m_pers.removed.delete(x) + else + m_pers.ways[0] = Set[x] + for i in 1...associativity - 1 do + m_pers.ways[i] = m_pers_dup.ways[i-1].dup + m_pers.ways[i].delete(x) + end + m_pers.ways[associativity-1] = m_pers_dup.ways[associativity-1].dup + m_pers.ways[associativity-1].merge(m_pers_dup.ways[associativity-2]) + m_pers.ways[associativity-1].delete(x) + + m_pers.removed = m_pers_dup.removed.dup + m_pers.removed.delete(x) + end + end + + def combine(a, b) + elems_a = a.elements + elems_b = b.elements + elems = Hash.new + + elems_a.each { |e| elems[e[:elem]] = {way: e[:way], occs: 1}} + elems_b.each { |e| + if elems[e[:elem]].nil? + + elems[e[:elem]] = {way: e[:way], occs: 1} + else + old = elems[e[:elem]] + old_way = old[:way] + new_way = old_way > e[:way] ? old_way : e[:way] + elems[e[:elem]] = {way: new_way, occs: old[:occs] + 1 } + end + } + + a.removed.merge(b.removed) + + a.ways[0] = Set.new + a.ways[1] = Set.new + elems.each { |k,v| + next if a.removed.include?(k) + if v[:way] == 0 + a.ways[0].add(k) + else + a.ways[1].add(k) + end + } + + end + + # All ways of the callee up to the oldest non-empty way are taken over. + # The remaining ways are then filled up with the youngest ways of the caller. + def interprocedural_combine(caller_state, callee_state) + combine(caller_state, callee_state) + caller_state.removed.merge(callee_state.removed) + end +end + +# deprecated class LRUPersAnalysisOperator def combine(a, b) elems_a = a.elements @@ -159,23 +269,20 @@ end class LRUCacheSet attr_accessor :ways - attr_accessor :removed #set of removed blocks (only for persistence analysis) attr_reader :associativity, :operator - def initialize(associativity, strategy=:must) + def initialize(associativity, strategy) die("Only 2-way cache supported currently.") if associativity != 2 @associativity = associativity @ways = Array.new(associativity) { Set.new } - @removed = Set.new if strategy == :must @operator = LRUMustAnalysisOperator.new elsif strategy == :may @operator = LRUMayAnalysisOperator.new elsif strategy == :pers - @operator = LRUPersAnalysisOperator.new + @operator = LRUMayMaxAnalysisOperator.new else - #throw "no such strategy as #{strategy}" - @operator = LRUMustAnalysisOperator.new + throw "no such strategy as #{strategy}" end end @@ -188,22 +295,7 @@ class LRUCacheSet end def access(tag) - cache_hit = include?(tag) - if cache_hit - # cache hit: move datum to way0, age the rest - @ways[1].merge(@ways[0]) - @ways[1].delete(tag) - @ways[0] = Set[tag] - else - # cache miss: discard way1, move way0 to way1, move datum to way0 - if @operator.is_a?(LRUPersAnalysisOperator) - @removed.merge(ways[1]) - end - @ways[1] = @ways[0].dup - @ways[0] = Set[tag] - end - - return cache_hit + @operator.update(self, tag) end def elements @@ -228,7 +320,6 @@ class LRUCacheSet @associativity = source.associativity @ways = source.ways.map {|w| w.dup} @operator = source.operator - @removed = source.removed.dup end def ==(other) @@ -238,6 +329,47 @@ class LRUCacheSet alias_method :eql?, :== end +# Cullmann Cache Persistence Analysis +# combined may and may_pers +class LRUPersCacheSet < LRUCacheSet + attr_accessor :removed #set of removed blocks (only for persistence analysis) + attr_accessor :shadow_may + def initialize(associativity, strategy) + die("PERS without :pers.") if strategy != :pers + super(associativity, strategy) + @removed = Set.new + @shadow_may = LRUCacheSet.new(associativity, :may) + end + + # i.e. is shadow may update after the first call? + def access(tag) + @operator.update(@shadow_may, self, tag) + @shadow_may.access(tag) + end + + def combine(other) + @operator.combine(self,other) + @shadow_may.combine(other) + end + + def interprocedural_combine(callee) + @operator.interprocedural_combine(self,callee) + @shadow_may.interprocedural_combine(callee) + end + + def initialize_copy(source) + super(source) + @removed = source.removed.dup + @shadow_may = source.shadow_may.dup + end + + def ==(other) + super(other) && @shadow_may == other.shadow_may + end + + alias_method :eql?, :== +end + class Cache attr_accessor :sets, :number_of_sets, :set_bits, :addr_bits, :associativity, :hit_time, :miss_time, :strategy def initialize(cache_config) @@ -252,11 +384,16 @@ class Cache def init_sets(replacement_policy) case replacement_policy when 'LRU', 'lru' - @settype = LRUCacheSet - @sets = Array.new(@number_of_sets) {|i| LRUCacheSet.new(@associativity, @strategy)} + case @strategy + when :pers + @settype = LRUPersCacheSet + else + @settype = LRUCacheSet + end else die("Only LRU caches are supported right now.") end + @sets = Array.new(@number_of_sets) {|i| @settype.new(@associativity, @strategy)} end def access(address) @@ -282,17 +419,6 @@ class Cache self end - #def interprocedural_combine(callee) - # @sets.each_index do |i| - # if callee.nil? - # reset(i) - # else - # @sets[i].interprocedural_combine(callee.sets[i]) - # end - # end - # self - #end - def interprocedural_combine(call_instr) if @strategy == :must ecb = Set.new @@ -302,8 +428,6 @@ class Cache @sets.each_index do |i| if ecb.include?(i) reset(i) - #else - #@sets[i].interprocedural_combine(callee.sets[i]) end end else @@ -319,7 +443,7 @@ class Cache end def reset(set) - @sets[set] = @settype.new(@associativity) + @sets[set] = @settype.new(@associativity, @strategy) end def reset_all @@ -331,6 +455,7 @@ class Cache @number_of_sets = source.number_of_sets @set_bits = source.set_bits @addr_bits = source.addr_bits + @strategy = source.strategy end def ==(other) @@ -364,7 +489,8 @@ class Cache end s += "\t#{way.to_s}" end - if set.operator.is_a?(LRUPersAnalysisOperator) + #if set.operator.is_a?(LRUPersAnalysisOperator) + if set.is_a?(LRUPersCacheSet) def (set.removed).to_s removed = "{ " for x in self