Changeset 7309
- Timestamp:
- Jul 12, 2009, 11:47:15 PM (15 years ago)
- Location:
- anuga_core/source/anuga/caching
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
anuga_core/source/anuga/caching/caching.py
r7276 r7309 30 30 Public functions: 31 31 32 cache( func,args) -- Cache values returned from funcgiven args.32 cache(my_F,args) -- Cache values returned from callable object my_F given args. 33 33 cachestat() -- Reports statistics about cache hits and time saved. 34 34 test() -- Conducts a basic test of the caching functionality. … … 53 53 import numpy as num 54 54 55 #from future 55 56 56 57 cache_dir = '.python_cache' … … 112 113 """ 113 114 114 if options.has_key(key):115 if key in options: 115 116 options[key] = value 116 117 else: … … 120 121 # Function cache - the main routine 121 122 122 def cache( func,123 def cache(my_F, 123 124 args=(), 124 125 kwargs={}, … … 134 135 135 136 USAGE: 136 result = cache( func, args, kwargs, dependencies, cachedir, verbose,137 result = cache(my_F, args, kwargs, dependencies, cachedir, verbose, 137 138 compression, evaluate, test, return_filename) 138 139 139 140 ARGUMENTS: 140 func -- Functionobject (Required)141 args -- Arguments to func(Default: ())142 kwargs -- Keyword arguments to func(Default: {})143 dependencies -- Filenames that funcdepends on (Default: None)141 my_F -- Callable object (Required) 142 args -- Arguments to my_F (Default: ()) 143 kwargs -- Keyword arguments to my_F (Default: {}) 144 dependencies -- Filenames that my_F depends on (Default: None) 144 145 cachedir -- Directory for cache files (Default: options['cachedir']) 145 146 verbose -- Flag verbose output to stdout 146 147 (Default: options['verbose']) 147 148 compression -- Flag zlib compression (Default: options['compression']) 148 evaluate -- Flag forced evaluation of func(Default: False)149 evaluate -- Flag forced evaluation of my_F (Default: False) 149 150 test -- Flag test for cached results (Default: False) 150 151 clear -- Flag delete cached results (Default: False) … … 154 155 A Python function call of the form 155 156 156 result = func(arg1,...,argn)157 result = my_F(arg1,...,argn) 157 158 158 159 can be replaced by 159 160 160 161 from caching import cache 161 result = cache( func,(arg1,...,argn))162 result = cache(my_F,(arg1,...,argn)) 162 163 163 164 The latter form returns the same output as the former but reuses cached … … 165 166 'result' and the arguments can be simple types, tuples, list, dictionaries or 166 167 objects, but not unhashable types such as functions or open file objects. 167 The function ' func' may be a member function of an object or a module.168 The function 'my_F' may be a member function of an object or a module. 168 169 169 170 This type of caching is particularly useful for computationally intensive … … 177 178 178 179 LIMITATIONS: 179 1 Caching uses the apply function and will work with anything that can be 180 pickled, so any limitation in apply or pickle extends to caching. 180 1 Caching uses function(*args, **kwargs) to evaluate and will work 181 with anything that can be pickled, so any limitation in function(,) 182 or pickle extends to caching. 181 183 2 A function to be cached should not depend on global variables 182 184 as wrong results may occur if globals are changed after a result has … … 188 190 Keyword args 189 191 Keyword arguments (kwargs) can be added as a dictionary of keyword: value 190 pairs, following the syntax of the built-in function apply(). 192 pairs, following Python's 'extended call syntax'. 193 191 194 A Python function call of the form 192 195 193 result = func(arg1,...,argn, kwarg1=val1,...,kwargm=valm)196 result = my_F(arg1,...,argn, kwarg1=val1,...,kwargm=valm) 194 197 195 198 is then cached as follows 196 199 197 200 from caching import cache 198 result = cache( func,(arg1,...,argn), {kwarg1:val1,...,kwargm:valm})201 result = cache(my_F,(arg1,...,argn), {kwarg1:val1,...,kwargm:valm}) 199 202 200 203 The default value of kwargs is {} … … 202 205 Explicit dependencies: 203 206 The call 204 cache( func,(arg1,...,argn), dependencies = <list of filenames>)207 cache(my_F,(arg1,...,argn), dependencies = <list of filenames>) 205 208 Checks the size, creation time and modification time of each listed file. 206 209 If any file has changed the function is recomputed and the results stored … … 209 212 Specify caching directory: 210 213 The call 211 cache( func,(arg1,...,argn), cachedir = <cachedir>)214 cache(my_F,(arg1,...,argn), cachedir = <cachedir>) 212 215 designates <cachedir> where cached data are stored. Use ~ to indicate users 213 216 home directory - not $HOME. The default is ~/.python_cache on a UNIX … … 216 219 Silent operation: 217 220 The call 218 cache( func,(arg1,...,argn), verbose=False)221 cache(my_F,(arg1,...,argn), verbose=False) 219 222 suppresses messages to standard output. 220 223 221 224 Compression: 222 225 The call 223 cache( func,(arg1,...,argn), compression=False)226 cache(my_F,(arg1,...,argn), compression=False) 224 227 disables compression. (Default: compression=True). If the requested compressed 225 228 or uncompressed file is not there, it'll try the other version. … … 227 230 Forced evaluation: 228 231 The call 229 cache( func,(arg1,...,argn), evaluate=True)232 cache(my_F,(arg1,...,argn), evaluate=True) 230 233 forces the function to evaluate even though cached data may exist. 231 234 232 235 Testing for presence of cached result: 233 236 The call 234 cache( func,(arg1,...,argn), test=True)237 cache(my_F,(arg1,...,argn), test=True) 235 238 retrieves cached result if it exists, otherwise None. The function will not 236 239 be evaluated. If both evaluate and test are switched on, evaluate takes … … 242 245 Obtain cache filenames: 243 246 The call 244 cache( func,(arg1,...,argn), return_filename=True)247 cache(my_F,(arg1,...,argn), return_filename=True) 245 248 returns the hashed base filename under which this function and its 246 249 arguments would be cached … … 248 251 Clearing cached results: 249 252 The call 250 cache( func,'clear')251 clears all cached data for ' func' and253 cache(my_F,'clear') 254 clears all cached data for 'my_F' and 252 255 cache('clear') 253 256 clears all cached data. 254 257 255 NOTE: The string 'clear' can be passed an *argument* to funcusing256 cache( func,('clear',)) or cache(func,tuple(['clear'])).258 NOTE: The string 'clear' can be passed an *argument* to my_F using 259 cache(my_F,('clear',)) or cache(my_F,tuple(['clear'])). 257 260 258 261 New form of clear: 259 cache( func,(arg1,...,argn), clear=True)260 clears cached data for particular combination funcand args262 cache(my_F,(arg1,...,argn), clear=True) 263 clears cached data for particular combination my_F and args 261 264 262 265 """ … … 280 283 281 284 # Handle the case cache('clear') 282 if type( func) == types.StringType:283 if string.lower( func) == 'clear':285 if type(my_F) == types.StringType: 286 if string.lower(my_F) == 'clear': 284 287 clear_cache(CD,verbose=verbose) 285 288 return 286 289 287 # Handle the case cache( func, 'clear')290 # Handle the case cache(my_F, 'clear') 288 291 if type(args) == types.StringType: 289 292 if string.lower(args) == 'clear': 290 clear_cache(CD, func,verbose=verbose)293 clear_cache(CD,my_F,verbose=verbose) 291 294 return 292 295 … … 309 312 deps = get_depstats(dependencies) 310 313 311 # Extract function name from funcobject312 funcname = get_funcname( func)314 # Extract function name from my_F object 315 funcname = get_funcname(my_F) 313 316 314 317 # Create cache filename … … 339 342 # Check if previous computation has been cached 340 343 if evaluate is True: 341 Retrieved = None # Force evaluation of funcregardless of caching status.344 Retrieved = None # Force evaluation of my_F regardless of caching status. 342 345 reason = 5 343 346 else: 344 347 T, FN, Retrieved, reason, comptime, loadtime, compressed = \ 345 CacheLookup(CD, FN, func,348 CacheLookup(CD, FN, my_F, 346 349 args, kwargs, 347 350 deps, … … 368 371 # Execute and time function with supplied arguments 369 372 t0 = time.time() 370 T = apply(func,args,kwargs) 373 374 T = my_F(*args, **kwargs) # Built-in 'apply' deprecated in Py3K 375 371 376 #comptime = round(time.time()-t0) 372 377 comptime = time.time()-t0 … … 376 381 377 382 # Save results and estimated loading time to cache 378 loadtime = save_results_to_cache(T, CD, FN, func, deps, comptime, \383 loadtime = save_results_to_cache(T, CD, FN, my_F, deps, comptime, \ 379 384 funcname, dependencies, compression) 380 385 if verbose is True: … … 785 790 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 786 791 787 def CacheLookup(CD, FN, func, args, kwargs, deps, verbose, compression,792 def CacheLookup(CD, FN, my_F, args, kwargs, deps, verbose, compression, 788 793 dependencies): 789 794 """Determine whether cached result exists and return info. … … 791 796 USAGE: 792 797 (T, FN, Retrieved, reason, comptime, loadtime, compressed) = \ 793 CacheLookup(CD, FN, func, args, kwargs, deps, verbose, compression, \798 CacheLookup(CD, FN, my_F, args, kwargs, deps, verbose, compression, \ 794 799 dependencies) 795 800 … … 797 802 CD -- Cache Directory 798 803 FN -- Suggested cache file name 799 func -- Functionobject804 my_F -- Callable object 800 805 args -- Tuple of arguments 801 806 kwargs -- Dictionary of keyword arguments … … 891 896 return(None, FN, None, reason, None, None, None) 892 897 893 # Get bytecode from func898 # Get bytecode from my_F 894 899 # 895 bytecode = get_bytecode( func)900 bytecode = get_bytecode(my_F) 896 901 897 902 #print compare(argsref,args), … … 926 931 # 927 932 (T, FN, Retrieved, reason, comptime, loadtime, compressed) = \ 928 CacheLookup(CD, FN+'x', func, args, kwargs, deps,933 CacheLookup(CD, FN+'x', my_F, args, kwargs, deps, 929 934 verbose, compression, dependencies) 930 935 … … 948 953 # ----------------------------------------------------------------------------- 949 954 950 def clear_cache(CD, func=None, verbose=None):951 """Clear cache for func.952 953 USAGE: 954 clear(CD, func, verbose)955 def clear_cache(CD, my_F=None, verbose=None): 956 """Clear cache for my_F. 957 958 USAGE: 959 clear(CD, my_F, verbose) 955 960 956 961 ARGUMENTS: 957 962 CD -- Caching directory (required) 958 func-- Function object (default: None)963 my_F -- Function object (default: None) 959 964 verbose -- Flag verbose output (default: None) 960 965 961 966 DESCRIPTION: 962 967 963 If func== None, clear everything,964 otherwise clear only files pertaining to func.968 If my_F == None, clear everything, 969 otherwise clear only files pertaining to my_F. 965 970 """ 966 971 … … 975 980 # FIXME: Windows version needs to be tested 976 981 977 if func:978 funcname = get_funcname( func)982 if my_F: 983 funcname = get_funcname(my_F) 979 984 if verbose: 980 985 print 'MESSAGE (caching.py): Clearing', CD+funcname+'*' … … 1076 1081 # ----------------------------------------------------------------------------- 1077 1082 1078 def save_results_to_cache(T, CD, FN, func, deps, comptime, funcname,1083 def save_results_to_cache(T, CD, FN, my_F, deps, comptime, funcname, 1079 1084 dependencies, compression): 1080 1085 """Save computed results T and admin info to cache 1081 1086 1082 1087 USAGE: 1083 save_results_to_cache(T, CD, FN, func, deps, comptime, funcname,1088 save_results_to_cache(T, CD, FN, my_F, deps, comptime, funcname, 1084 1089 dependencies, compression) 1085 1090 """ … … 1107 1112 savetime = time.time()-t0 1108 1113 1109 bytecode = get_bytecode( func) # Get bytecode from function object1114 bytecode = get_bytecode(my_F) # Get bytecode from function object 1110 1115 admtup = (deps, comptime, bytecode, funcname) # Gather admin info 1111 1116 … … 1391 1396 elif type(T) == DictType: 1392 1397 # Make dictionary ordering unique 1398 1399 # FIXME(Ole): Need new way of doing this in Python 3.0 1393 1400 I = T.items() 1394 1401 I.sort() … … 1431 1438 iB = id(B) 1432 1439 1433 if ids.has_key((iA, iB)):1440 if (iA, iB) in ids: 1434 1441 # A and B have been compared already 1435 1442 #print 'Found', (iA, iB), A, B … … 1521 1528 # ----------------------------------------------------------------------------- 1522 1529 1523 def get_funcname( func):1530 def get_funcname(my_F): 1524 1531 """Retrieve name of function object func (depending on its type) 1525 1532 1526 1533 USAGE: 1527 get_funcname( func)1534 get_funcname(my_F) 1528 1535 """ 1529 1536 1530 1537 import types, string 1531 1538 1532 if type( func) == types.FunctionType:1533 funcname = func.func_name1534 elif type( func) == types.BuiltinFunctionType:1535 funcname = func.__name__1539 if type(my_F) == types.FunctionType: 1540 funcname = my_F.func_name 1541 elif type(my_F) == types.BuiltinFunctionType: 1542 funcname = my_F.__name__ 1536 1543 else: 1537 1544 tab = string.maketrans("<>'"," ") 1538 tmp = string.translate( `func`,tab)1545 tmp = string.translate(repr(my_F), tab) 1539 1546 tmp = string.split(tmp) 1540 1547 funcname = string.join(tmp) … … 1551 1558 # ----------------------------------------------------------------------------- 1552 1559 1553 def get_bytecode( func):1560 def get_bytecode(my_F): 1554 1561 """ Get bytecode from function object. 1555 1562 1556 1563 USAGE: 1557 get_bytecode( func)1564 get_bytecode(my_F) 1558 1565 """ 1559 1566 1560 1567 import types 1561 1568 1562 if type( func) == types.FunctionType:1563 return get_func_code_details( func)1564 elif type( func) == types.MethodType:1565 return get_func_code_details( func.im_func)1566 elif type( func) == types.InstanceType:1567 if callable(func):1569 if type(my_F) == types.FunctionType: 1570 return get_func_code_details(my_F) 1571 elif type(my_F) == types.MethodType: 1572 return get_func_code_details(my_F.im_func) 1573 elif type(my_F) == types.InstanceType: 1574 if hasattr(my_F, '__call__'): 1568 1575 # Get bytecode from __call__ method 1569 bytecode = get_func_code_details( func.__call__.im_func)1576 bytecode = get_func_code_details(my_F.__call__.im_func) 1570 1577 1571 1578 # Add hash value of object to detect attribute changes 1572 return bytecode + (myhash( func),)1579 return bytecode + (myhash(my_F),) 1573 1580 else: 1574 msg = 'Instance %s was passed into caching in the role of a function ' % str( func)1581 msg = 'Instance %s was passed into caching in the role of a function ' % str(my_F) 1575 1582 msg = ' but it was not callable.' 1576 1583 raise Exception, msg 1577 elif type( func) in [types.BuiltinFunctionType, types.BuiltinMethodType]:1584 elif type(my_F) in [types.BuiltinFunctionType, types.BuiltinMethodType]: 1578 1585 # Built-in functions are assumed not to change 1579 1586 return None, 0, 0, 0 1580 elif type( func) == types.ClassType:1587 elif type(my_F) == types.ClassType: 1581 1588 # Get bytecode from __init__ method 1582 bytecode = get_func_code_details( func.__init__.im_func)1589 bytecode = get_func_code_details(my_F.__init__.im_func) 1583 1590 return bytecode 1584 1591 else: 1585 msg = 'Unknown function type: %s' % type( func)1592 msg = 'Unknown function type: %s' % type(my_F) 1586 1593 raise Exception, msg 1587 1594 … … 1589 1596 1590 1597 1591 def get_func_code_details( func):1598 def get_func_code_details(my_F): 1592 1599 """Extract co_code, co_consts, co_argcount, func_defaults 1593 1600 """ 1594 1601 1595 bytecode = func.func_code.co_code1596 consts = func.func_code.co_consts1597 argcount = func.func_code.co_argcount1598 defaults = func.func_defaults1602 bytecode = my_F.func_code.co_code 1603 consts = my_F.func_code.co_consts 1604 argcount = my_F.func_code.co_argcount 1605 defaults = my_F.func_defaults 1599 1606 1600 1607 return bytecode, consts, argcount, defaults … … 1951 1958 1952 1959 user = record[1] 1953 func= record[2]1960 my_F = record[2] 1954 1961 1955 1962 # Strip hash-stamp off 1956 1963 # 1957 i = find( func,'[')1958 func = func[:i]1964 i = find(my_F,'[') 1965 my_F = my_F[:i] 1959 1966 1960 1967 size = float(record[3]) … … 1990 1997 1991 1998 UpdateDict(UserDict,user,info) 1992 UpdateDict(FuncDict, func,info)1999 UpdateDict(FuncDict,my_F,info) 1993 2000 else: 1994 2001 pass #Stats on recomputations and their reasons could go in here -
anuga_core/source/anuga/caching/test_caching.py
r7276 r7309 884 884 print 885 885 print 'Initial_addr ', initial_addr 886 print 'Redefined addr', `Dummy_memorytest`886 print 'Redefined addr', repr(Dummy_memorytest) 887 887 msg = 'Redefined class ended up at same memory location as ' 888 888 msg += 'original class making this test irrelevant. Try to run ' 889 889 msg += 'it again and see if this error goes away.' 890 890 msg += 'If it persists contact Ole.Nielsen@ga.gov.au' 891 assert initial_addr != `Dummy_memorytest`, msg891 assert initial_addr != repr(Dummy_memorytest), msg 892 892 893 893
Note: See TracChangeset
for help on using the changeset viewer.