kerncraft/models/roofline.py
def calculate_cache_access(self):
        """Apply cache prediction to generate cache access behaviour."""
        self.results = {'misses': self.predictor.get_misses(),
                        'hits': self.predictor.get_hits(),
                        'evicts': self.predictor.get_evicts(),
                        'verbose infos': self.predictor.get_infos(),  # only for verbose outputs
                        'bottleneck level': 0,
                        'mem bottlenecks': []}

        element_size = self.kernel.datatypes_size[self.kernel.datatype]
        cacheline_size = float(self.machine['cacheline size'])
        elements_per_cacheline = int(cacheline_size // element_size)

        total_flops = sum(self.kernel._flops.values())*elements_per_cacheline

        # TODO let user choose threads_per_core:
        threads_per_core = 1

        # Compile relevant information

        # CPU-L1 stats (in bytes!)
        # We compile CPU-L1 stats on our own, because cacheprediction only works on cache lines
        read_offsets, write_offsets = zip(*list(self.kernel.compile_global_offsets(
            iteration=range(0, elements_per_cacheline))))
        read_offsets = set([item for sublist in read_offsets if sublist is not None
                            for item in sublist])
        write_offsets = set([item for sublist in write_offsets if sublist is not None
                             for item in sublist])

        write_streams = len(write_offsets)
        read_streams = len(read_offsets) + write_streams  # write-allocate
        total_loads = read_streams * element_size
        # total_evicts = write_streams * element_size
        bw, measurement_kernel = self.machine.get_bandwidth(
            0,
            read_streams - write_streams,  # no write-allocate in L1
            write_streams,
            threads_per_core,
            cores=self.cores)

        # Calculate performance (arithmetic intensity * bandwidth with
        # arithmetic intensity = flops / bytes loaded )
        if total_loads == 0:
            # This happens in case of full-caching
            arith_intens = None
            performance = None
        else:
            arith_intens = float(total_flops)/total_loads
            performance = PrefixedUnit(arith_intens * float(bw), 'FLOP/s')

        self.results['mem bottlenecks'].append({
            'performance': self.conv_perf(PrefixedUnit(performance, 'FLOP/s')),
            'level': self.machine['memory hierarchy'][0]['level'],
            'arithmetic intensity': arith_intens,
            'bw kernel': measurement_kernel,
            'bandwidth': bw,
            'bytes transfered': total_loads})
        self.results['bottleneck level'] = len(self.results['mem bottlenecks'])-1
        self.results['min performance'] = self.conv_perf(performance)

        # for other cache and memory levels:
        for cache_level, cache_info in list(enumerate(self.machine['memory hierarchy']))[:-1]:
            # Compiling stats (in bytes!)
            total_misses = self.results['misses'][cache_level]*cacheline_size
            total_evicts = self.results['evicts'][cache_level]*cacheline_size

            # choose bw according to cache level and problem
            # first, compile stream counts at current cache level
            # write-allocate is allready resolved above
            read_streams = self.results['misses'][cache_level]
            write_streams = self.results['evicts'][cache_level]
            # second, try to find best fitting kernel (closest to stream seen stream counts):
            bw, measurement_kernel = self.machine.get_bandwidth(
                cache_level+1, read_streams, write_streams, threads_per_core,
                cores=self.cores)

            # Calculate performance (arithmetic intensity * bandwidth with
            # arithmetic intensity = flops / bytes transfered)
            bytes_transfered = total_misses + total_evicts

            if bytes_transfered == 0:
                # This happens in case of full-caching
                arith_intens = float('inf')
                performance = PrefixedUnit(float('inf'), 'FLOP/s')
            else:
                arith_intens = float(total_flops)/bytes_transfered
                performance = PrefixedUnit(arith_intens * float(bw), 'FLOP/s')

            self.results['mem bottlenecks'].append({
                'performance': self.conv_perf(performance),
                'level': (self.machine['memory hierarchy'][cache_level + 1]['level']),
                'arithmetic intensity': arith_intens,
                'bw kernel': measurement_kernel,
                'bandwidth': bw,
                'bytes transfered': bytes_transfered})
            if performance < self.results.get('min performance', {'FLOP/s': performance})['FLOP/s']:
                self.results['bottleneck level'] = len(self.results['mem bottlenecks'])-1
                self.results['min performance'] = self.conv_perf(performance)

        return self.results
def calculate_cache_access(self):
        """Apply cache prediction to generate cache access behaviour."""
        self.results = {'misses': self.predictor.get_misses(),
                        'hits': self.predictor.get_hits(),
                        'evicts': self.predictor.get_evicts(),
                        'verbose infos': self.predictor.get_infos(),  # only for verbose outputs
                        'bottleneck level': 0,
                        'mem bottlenecks': []}

        element_size = self.kernel.datatypes_size[self.kernel.datatype]
        cacheline_size = float(self.machine['cacheline size'])
        elements_per_cacheline = int(cacheline_size // element_size)

        total_flops = sum(self.kernel._flops.values())*elements_per_cacheline

        # TODO let user choose threads_per_core:
        threads_per_core = 1

        # Compile relevant information

        # CPU-L1 stats (in bytes!)
        # We compile CPU-L1 stats on our own, because cacheprediction only works on cache lines
        read_offsets, write_offsets = zip(*list(self.kernel.compile_global_offsets(
            iteration=range(0, elements_per_cacheline))))
        read_offsets = set([item for sublist in read_offsets if sublist is not None
                            for item in sublist])
        write_offsets = set([item for sublist in write_offsets if sublist is not None
                             for item in sublist])

        write_streams = len(write_offsets)
        read_streams = len(read_offsets) + write_streams  # write-allocate
        total_loads = read_streams * element_size
        # total_evicts = write_streams * element_size
        bw, measurement_kernel = self.machine.get_bandwidth(
            0,
            read_streams - write_streams,  # no write-allocate in L1
            write_streams,
            threads_per_core,
            cores=self.cores)

        # Calculate performance (arithmetic intensity * bandwidth with
        # arithmetic intensity = flops / bytes loaded )
        if total_loads == 0:
            # This happens in case of full-caching
            arith_intens = None
            performance = None
        else:
            arith_intens = float(total_flops)/total_loads
            performance = PrefixedUnit(arith_intens * float(bw), 'FLOP/s')

        self.results['mem bottlenecks'].append({
            'performance': self.conv_perf(PrefixedUnit(performance, 'FLOP/s')),
            'level': self.machine['memory hierarchy'][0]['level'],
            'arithmetic intensity': arith_intens,
            'bw kernel': measurement_kernel,
            'bandwidth': bw,
            'bytes transfered': total_loads})
        self.results['bottleneck level'] = len(self.results['mem bottlenecks'])-1
        self.results['min performance'] = self.conv_perf(performance)

        # for other cache and memory levels:
        for cache_level, cache_info in list(enumerate(self.machine['memory hierarchy']))[:-1]:
            # Compiling stats (in bytes!)
            total_misses = self.results['misses'][cache_level]*cacheline_size
            total_evicts = self.results['evicts'][cache_level]*cacheline_size

            # choose bw according to cache level and problem
            # first, compile stream counts at current cache level
            # write-allocate is allready resolved above
            read_streams = self.results['misses'][cache_level]
            write_streams = self.results['evicts'][cache_level]
            # second, try to find best fitting kernel (closest to stream seen stream counts):
            bw, measurement_kernel = self.machine.get_bandwidth(
                cache_level+1, read_streams, write_streams, threads_per_core,
                cores=self.cores)

            # Calculate performance (arithmetic intensity * bandwidth with
            # arithmetic intensity = flops / bytes transfered)
            bytes_transfered = total_misses + total_evicts

            if bytes_transfered == 0:
                # This happens in case of full-caching
                arith_intens = float('inf')
                performance = PrefixedUnit(float('inf'), 'FLOP/s')
            else:
                arith_intens = float(total_flops)/bytes_transfered
                performance = PrefixedUnit(arith_intens * float(bw), 'FLOP/s')

            self.results['mem bottlenecks'].append({
                'performance': self.conv_perf(performance),
                'level': (self.machine['memory hierarchy'][cache_level + 1]['level']),
                'arithmetic intensity': arith_intens,
                'bw kernel': measurement_kernel,
                'bandwidth': bw,
                'bytes transfered': bytes_transfered})
            if performance < self.results.get('min performance', {'FLOP/s': performance})['FLOP/s']:
                self.results['bottleneck level'] = len(self.results['mem bottlenecks'])-1
                self.results['min performance'] = self.conv_perf(performance)

        return self.results
def calculate_cache_access ( self ) : self . results = { 'misses' : self . predictor . get_misses ( ) , 'hits' : self . predictor . get_hits ( ) , 'evicts' : self . predictor . get_evicts ( ) , 'verbose infos' : self . predictor . get_infos ( ) , # only for verbose outputs 'bottleneck level' : 0 , 'mem bottlenecks' : [ ] } element_size = self . kernel . datatypes_size [ self . kernel . datatype ] cacheline_size = float ( self . machine [ 'cacheline size' ] ) elements_per_cacheline = int ( cacheline_size // element_size ) total_flops = sum ( self . kernel . _flops . values ( ) ) * elements_per_cacheline # TODO let user choose threads_per_core: threads_per_core = 1 # Compile relevant information # CPU-L1 stats (in bytes!) # We compile CPU-L1 stats on our own, because cacheprediction only works on cache lines read_offsets , write_offsets = zip ( * list ( self . kernel . compile_global_offsets ( iteration = range ( 0 , elements_per_cacheline ) ) ) ) read_offsets = set ( [ item for sublist in read_offsets if sublist is not None for item in sublist ] ) write_offsets = set ( [ item for sublist in write_offsets if sublist is not None for item in sublist ] ) write_streams = len ( write_offsets ) read_streams = len ( read_offsets ) + write_streams # write-allocate total_loads = read_streams * element_size # total_evicts = write_streams * element_size bw , measurement_kernel = self . machine . get_bandwidth ( 0 , read_streams - write_streams , # no write-allocate in L1 write_streams , threads_per_core , cores = self . cores ) # Calculate performance (arithmetic intensity * bandwidth with # arithmetic intensity = flops / bytes loaded ) if total_loads == 0 : # This happens in case of full-caching arith_intens = None performance = None else : arith_intens = float ( total_flops ) / total_loads performance = PrefixedUnit ( arith_intens * float ( bw ) , 'FLOP/s' ) self . results [ 'mem bottlenecks' ] . append ( { 'performance' : self . conv_perf ( PrefixedUnit ( performance , 'FLOP/s' ) ) , 'level' : self . machine [ 'memory hierarchy' ] [ 0 ] [ 'level' ] , 'arithmetic intensity' : arith_intens , 'bw kernel' : measurement_kernel , 'bandwidth' : bw , 'bytes transfered' : total_loads } ) self . results [ 'bottleneck level' ] = len ( self . results [ 'mem bottlenecks' ] ) - 1 self . results [ 'min performance' ] = self . conv_perf ( performance ) # for other cache and memory levels: for cache_level , cache_info in list ( enumerate ( self . machine [ 'memory hierarchy' ] ) ) [ : - 1 ] : # Compiling stats (in bytes!) total_misses = self . results [ 'misses' ] [ cache_level ] * cacheline_size total_evicts = self . results [ 'evicts' ] [ cache_level ] * cacheline_size # choose bw according to cache level and problem # first, compile stream counts at current cache level # write-allocate is allready resolved above read_streams = self . results [ 'misses' ] [ cache_level ] write_streams = self . results [ 'evicts' ] [ cache_level ] # second, try to find best fitting kernel (closest to stream seen stream counts): bw , measurement_kernel = self . machine . get_bandwidth ( cache_level + 1 , read_streams , write_streams , threads_per_core , cores = self . cores ) # Calculate performance (arithmetic intensity * bandwidth with # arithmetic intensity = flops / bytes transfered) bytes_transfered = total_misses + total_evicts if bytes_transfered == 0 : # This happens in case of full-caching arith_intens = float ( 'inf' ) performance = PrefixedUnit ( float ( 'inf' ) , 'FLOP/s' ) else : arith_intens = float ( total_flops ) / bytes_transfered performance = PrefixedUnit ( arith_intens * float ( bw ) , 'FLOP/s' ) self . results [ 'mem bottlenecks' ] . append ( { 'performance' : self . conv_perf ( performance ) , 'level' : ( self . machine [ 'memory hierarchy' ] [ cache_level + 1 ] [ 'level' ] ) , 'arithmetic intensity' : arith_intens , 'bw kernel' : measurement_kernel , 'bandwidth' : bw , 'bytes transfered' : bytes_transfered } ) if performance < self . results . get ( 'min performance' , { 'FLOP/s' : performance } ) [ 'FLOP/s' ] : self . results [ 'bottleneck level' ] = len ( self . results [ 'mem bottlenecks' ] ) - 1 self . results [ 'min performance' ] = self . conv_perf ( performance ) return self . results
Apply cache prediction to generate cache access behaviour.
Apply cache prediction to generate cache access behaviour .