rbmatlab 0.10.01
general/filecaching/filecache_function.m
Go to the documentation of this file.
00001 function [varargout] = filecache_function(funcptr, varargin)
00002 %function [varargout] = filecache_function(funcptr, varargin)
00003 % function used for file-caching other function calls.
00004 %
00005 % If an expensive function
00006 %
00007 % @code
00008 %     [E, F] = myfunction(A,B,C)
00009 % @endcode
00010 %
00011 % is called frequently during a program run, a filecaching can be
00012 % used, i.e. one calls the function instead as
00013 %
00014 % @code
00015 %     [E, F] = filecache_function(@myfunction,A,B,C);
00016 % @endcode
00017 %
00018 % If the function result exists in the cache, this is loaded, otherwise the
00019 % function is called, the result saved in the cache and the result returned.
00020 %
00021 % Parameters:
00022 %  funcptr:  is the pointer to a function whose calls are to be cached.
00023 %  varargin: is parameter list of the cached function call
00024 %
00025 % Return values:
00026 %  varargout: return values of the cached function call
00027 %
00028 % - The cache-directory is assumed to be in 'RBMATLABTEMP/cache'
00029 % - The cache-directory can be cleared with the function filecache_clear()
00030 
00031 % Bernard Haasdonk 22.5.2007
00032 
00033 if nargout==0
00034   error('filecaching only works for functions with return values!');
00035 end;
00036 
00037 funcname = func2str(funcptr);
00038 
00039 % determining of a 'hash-code' from the function-arguments:
00040 tmpfn = fullfile(filecache_path,'tmparg.mat');
00041 saveargs = varargin;
00042 for i=1:length(saveargs)
00043   if isobject(varargin{i})
00044     warning('off', 'MATLAB:structOnObject');
00045     saveargs{i} = struct(varargin{i});
00046     warning('on', 'MATLAB:structOnObject');
00047   end
00048 end
00049 
00050 save(tmpfn,'saveargs');
00051 fid = fopen(tmpfn,'r');
00052 bin = fread(fid);
00053 % cut of header, which contains date, i.e. first 116 bytes
00054 bin = bin(117:end);
00055 fclose(fid);
00056 uintbin = uint32(bin);
00057 % simple arithmetics for identifying arguments 
00058 key  = mod(sum(uintbin.*uint32(1:length(uintbin))'),1e9);
00059 keystr = num2str(key);
00060 %keyboard;
00061 %key = sum()
00062 
00063 resultfn      = fullfile(filecache_path,...
00064                          [funcname,keystr,'.mat']);
00065 multval_cache = fullfile(filecache_path,...
00066                          [funcname,'mv.mat']);
00067 
00068 is_cached  = 0;
00069 hash_found = 0;
00070 funcstr = strtrim(evalc('disp(funcptr)'));
00071 
00072 if exist(resultfn,'file');
00073   loaded = load(resultfn);
00074   hash_found = 1;
00075 elseif exist(multval_cache,'file')
00076   tmp = load(multval_cache);
00077   tmp_key_pos = find(tmp.keylist==key,1);
00078   if ~isempty(tmp_key_pos)
00079     tmp_key_ind  = tmp.map_key2ind(tmp_key_pos);
00080     tmp_file_ind = tmp.map_key2file(tmp_key_pos);
00081     storefile = fullfile(filecache_path,...
00082                          [funcname,'mv',num2str(tmp_file_ind),'.mat']);
00083     if exist(storefile,'file')
00084       tmp = load(storefile);
00085       loaded = tmp.cache(tmp_key_ind);
00086       hash_found = 1;
00087     else
00088       error(['Could not find file ',storefile,...
00089             ', which is specified in multivalue cache list.']);
00090     end
00091   end
00092 end
00093 
00094 if hash_found
00095   % isequal does not work for handles
00096   %  if isequal(tmp.saveargs,saveargs)
00097   if isequal_ignore_handles(loaded.saveargs,saveargs)
00098     varargout = loaded.varargout;
00099     is_cached = 1;
00100     disp(['call of ',funcstr,', successfully read from cache, key=',keystr]);
00101 %    keyboard;
00102   else
00103     % the key-computation formula must be updated in this case...
00104     disp(['arguments in cached file and current call do not',...
00105           'correspond!!']);
00106     disp('please change key-function in file_cache_function!');
00107     disp('recomputation is started and cache-file replaced.');
00108     %keyboard;
00109   end
00110 end
00111 
00112 
00113 if ~is_cached
00114   % call function
00115   disp('result not found in cache');
00116   [varargout{1:nargout}] = funcptr(varargin{:});
00117   %  save(resultfn,'varargin');
00118 
00119   siz=whos('varargout');
00120   % if size is less than 100kb, store in multi-value cache.
00121   if(siz.bytes < 1024*100)
00122     if exist(multval_cache,'file')
00123       meta=load(multval_cache);
00124       max_file_ind = meta.map_key2file(end);
00125       max_key_ind  = meta.map_key2ind(end)+1;
00126       last_size    = meta.last_size;
00127       % if store file size exceeds 10MB, create a new one
00128       if (last_size + siz.bytes > 1024*10000)
00129         max_file_ind = max_file_ind + 1;
00130         max_key_ind  = 1;
00131       end
00132     else
00133       meta.keylist      = [];
00134       meta.map_key2file = [];
00135       meta.map_key2ind  = [];
00136       max_file_ind      = 1;
00137       max_key_ind       = 1;
00138     end
00139     storefile = fullfile(filecache_path,...
00140                          [funcname,'mv',num2str(max_file_ind),'.mat']);
00141     if exist(storefile, 'file')
00142       load(storefile);
00143     end
00144     cache(max_key_ind).saveargs  = saveargs;
00145     cache(max_key_ind).varargout = varargout;
00146 
00147     tmp_size  = whos('cache');
00148     last_size    = tmp_size.bytes;
00149     keylist      = [meta.keylist, key];
00150     map_key2file = [meta.map_key2file, max_file_ind];
00151     map_key2ind  = [meta.map_key2ind, max_key_ind];
00152 
00153     save(multval_cache, 'last_size', 'keylist', 'map_key2file', 'map_key2ind');
00154     save(storefile, 'cache');
00155 
00156   else
00157     save(resultfn,'saveargs','varargout');
00158   end
00159   disp(['call of ',funcstr,', now computed and cached, key=',keystr]);
00160 end
00161 
 All Classes Namespaces Files Functions Variables