1import config.base 2import os 3import sys 4import collections 5 6class CacheAttribute(object): 7 def __init__(self, name, type_name, help_descr, default=None, min_value=0, max_value=min(sys.maxsize,2**31-1)): 8 self.name = str(name) 9 self.type_name = str(type_name) 10 self.help = str(help_descr) 11 self.default = default 12 self.min = int(min_value) 13 self.max = int(max_value) 14 15 def valid(self,val): 16 return self.min <= val <= self.max 17 18 def enum(self): 19 return self.name.upper().replace('-','_') 20 21class Configure(config.base.Configure): 22 def __init__(self, framework): 23 config.base.Configure.__init__(self, framework) 24 self.headerPrefix = 'PETSC' 25 self.substPrefix = 'PETSC' 26 self.updated = 0 27 self.strmsg = '' 28 self.attrs = collections.OrderedDict( 29 level1_dcache_linesize=CacheAttribute( 30 'level1-dcache-linesize','int','Size in bytes of each line of the Level 1 data cache', 31 default=32,min_value=16 32 ) 33 ) 34# the next two are not currently used 35# CacheAttribute('level1-dcache-size', 'int', 'Size in bytes of Level 1 data cache', 32768, 16), 36# CacheAttribute('level1-dcache-assoc', 'int', 'Associativity of the Level 1 data cache, 0 for full associative', 2, 0)] 37 return 38 39 def __str__(self): 40 return self.strmsg 41 42 def setupHelp(self, help): 43 import nargs 44 for a in self.attrs.values(): 45 help.addArgument('PETSc', '-known-'+a.name+'=<'+a.type_name+'>', nargs.ArgInt(None, None, a.help, min=a.min, max=a.max)) 46 return 47 48 def setupDependencies(self, framework): 49 config.base.Configure.setupDependencies(self, framework) 50 self.compilers = framework.require('config.compilers', self) 51 self.setCompilers = framework.require('config.setCompilers', self) 52 self.headers = framework.require('config.headers', self) 53 return 54 55 def L1CacheLineSizeMethods(self,default_val): 56 var = 'level1_dcache_linesize' 57 func_name = 'getconf_{}'.format(var) 58 if self.setCompilers.isDarwin(self.log): 59 yield ( 60 func_name, 61 '\n'.join([ 62 '#include <sys/sysctl.h>', 63 'int64_t {}(void) {{'.format(func_name), 64 ' int64_t linesize = {};'.format(default_val), 65 ' size_t size = sizeof(linesize);', 66 ' int ret = sysctlbyname("hw.cachelinesize", &linesize, &size, NULL, 0);', 67 ' return ret ? {} : linesize;'.format(default_val), 68 '}' 69 ]) 70 ) 71 # On some systems, maybe just with glibc, sysconf can provide this stuff 72 yield ( 73 func_name, 74 '\n'.join([ 75 '#include <unistd.h>', 76 'long {}(void) {{'.format(func_name), 77 ' long val = sysconf(_SC_{});'.format(var.upper()), 78 ' return val >= 0 ? val : {};'.format(default_val), 79 '}' 80 ]) 81 ) 82 # A total hack since this will compile with any C compiler, but only return useful 83 # results when the getconf program is available 84 yield ( 85 func_name, 86 '\n'.join([ 87 '#include <stdio.h>', 88 'long {}(void) {{'.format(func_name), 89 ' long val = -1;', 90 ' FILE *f = popen("getconf {}", "r");'.format(var.lower()), 91 ' fscanf(f, "%ld", &val);', 92 ' pclose(f);', 93 ' return val >= 0 ? val : {};'.format(default_val), 94 '}' 95 ]) 96 ) 97 return 98 99 def discoverL1CacheLineSize(self,attr): 100 """ 101 Try to determine the L1CacheLineSize dynamically, if not possible returns the default value 102 """ 103 filename = 'conftestval' 104 main_body_base = '\n'.join([ 105 ' FILE *output = fopen("{}", "w");'.format(filename), 106 ' if (!output) return 1;', 107 # note the '{func_name}', this is filled out below 108 ' fprintf(output, "%ld", (long){func_name}());', 109 ' fclose(output);' 110 ]) 111 with self.Language('C'): 112 for func_name,includes in self.L1CacheLineSizeMethods(attr.default): 113 if not self.checkCompile(includes=includes,body=func_name+'();'): 114 continue 115 116 main_includes = '\n'.join(['#include <stdio.h>',includes]) 117 main_body = main_body_base.format(func_name=func_name) 118 if self.checkRun(includes=main_includes,body=main_body) and os.path.exists(filename): 119 with open(filename,"r") as f: 120 val = int(f.read()) 121 os.remove(filename) 122 if attr.valid(val): 123 return val 124 self.log.write('Cannot use value returned for {}: {}, continuing\n'.format(attr.enum(),val)) 125 return attr.default 126 127 def configureL1CacheLineSize(self): 128 """ 129 Try to determine the size (in bytes) of an L1 cacheline. On success defines the 130 variable PETSC_LEVEL1_DCACHE_LINESIZE to the determined value. 131 """ 132 attr = self.attrs['level1_dcache_linesize'] 133 argdb_val = self.argDB.get('known-'+attr.name) 134 if argdb_val is not None: 135 val = int(argdb_val) 136 elif self.argDB['with-batch']: 137 self.log.write('Skipping determination of {} in batch mode, using default {}\n'.format(attr.enum(),attr.default)) 138 val = attr.default 139 else: 140 val = self.discoverL1CacheLineSize(attr) 141 self.addDefine(attr.enum(),val) 142 return 143 144 def configure(self): 145 self.executeTest(self.configureL1CacheLineSize) 146 return 147