rbmatlab  1.16.09
 All Classes Namespaces Files Functions Variables Modules Pages
filecache_function.m
Go to the documentation of this file.
1 function [varargout] = filecache_function(funcptr, varargin)
2 %function [varargout] = filecache_function(funcptr, varargin)
3 % function used for file-caching other function calls.
4 %
5 % If an expensive function
6 %
7 % @code
8 % [E, F] = myfunction(A,B,C)
9 % @endcode
10 %
11 % is called frequently during a program run, a filecaching can be
12 % used, i.e. one calls the function instead as
13 %
14 % @code
15 % [E, F] = filecache_function(@myfunction,A,B,C);
16 % @endcode
17 %
18 % If the function result exists in the cache, this is loaded, otherwise the
19 % function is called, the result saved in the cache and the result returned.
20 %
21 % Parameters:
22 % funcptr: is the pointer to a function whose calls are to be cached.
23 % varargin: is parameter list of the cached function call
24 %
25 % Return values:
26 % varargout: return values of the cached function call
27 %
28 % - The cache-directory is assumed to be in 'RBMATLABTEMP/cache'
29 % - The cache-directory can be cleared with the function filecache_clear()
30 
31 % Bernard Haasdonk 22.5.2007
32 
33 if nargout==0
34  error('filecaching only works for functions with return values!');
35 end;
36 
37 funcname = func2str(funcptr);
38 
39 % determining of a 'hash-code' from the function-arguments:
40 tmpfn = fullfile(filecache_path,'tmparg.mat');
41 saveargs = varargin;
42 for i=1:length(saveargs)
43  if isobject(varargin{i})
44  warning('off', 'MATLAB:structOnObject');
45  saveargs{i} = struct(varargin{i});
46  warning('on', 'MATLAB:structOnObject');
47  end
48 end
49 
50 save(tmpfn,'saveargs');
51 fid = fopen(tmpfn,'r');
52 bin = fread(fid);
53 % cut of header, which contains date, i.e. first 116 bytes
54 bin = bin(117:end);
55 fclose(fid);
56 uintbin = uint32(bin);
57 % simple arithmetics for identifying arguments
58 key = mod(sum(uintbin.*uint32(1:length(uintbin))'),1e9);
59 keystr = num2str(key);
60 
61 resultfn = fullfile(filecache_path,...
62  [funcname,keystr,'.mat']);
63 multval_cache = fullfile(filecache_path,...
64  [funcname,'mv.mat']);
65 
66 is_cached = 0;
67 hash_found = 0;
68 funcstr = strtrim(evalc('disp(funcptr)'));
69 
70 if exist(resultfn,'file');
71  loaded = load(resultfn);
72  hash_found = 1;
73 elseif exist(multval_cache,'file')
74  tmp = load(multval_cache);
75  tmp_key_pos = find(tmp.keylist==key,1);
76  if ~isempty(tmp_key_pos)
77  tmp_key_ind = tmp.map_key2ind(tmp_key_pos);
78  tmp_file_ind = tmp.map_key2file(tmp_key_pos);
79  storefile = fullfile(filecache_path,...
80  [funcname,'mv',num2str(tmp_file_ind),'.mat']);
81  if exist(storefile,'file')
82  tmp = load(storefile);
83  loaded = tmp.cache(tmp_key_ind);
84  hash_found = 1;
85  else
86  error(['Could not find file ',storefile,...
87  ', which is specified in multivalue cache list.']);
88  end
89  end
90 end
91 
92 if hash_found
93  % isequal does not work for handles
94  % if isequal(tmp.saveargs,saveargs)
95  if isequal(loaded.saveargs,saveargs)
96  varargout = loaded.varargout;
97  is_cached = 1;
98  debugdisp(['call of ',funcstr,', successfully read from cache, key=',keystr]);
99  else
100  % the key-computation formula must be updated in this case...
101  debugdisp(['arguments in cached file and current call do not',...
102  'correspond!!']);
103  debugdisp('please change key-function in file_cache_function!');
104  debugdisp('recomputation is started and cache-file replaced.');
105  end
106 end
107 
108 
109 if ~is_cached
110  % call function
111  debugdisp('result not found in cache');
112  [varargout{1:nargout(funcptr)}] = funcptr(varargin{:});
113 
114  siz=whos('varargout');
115  % if size is less than 100kb, store in multi-value cache.
116  if(siz.bytes < 1024*100)
117  if exist(multval_cache,'file')
118  meta=load(multval_cache);
119  max_file_ind = meta.map_key2file(end);
120  max_key_ind = meta.map_key2ind(end)+1;
121  last_size = meta.last_size;
122  % if store file size exceeds 10MB, create a new one
123  if (last_size + siz.bytes > 1024*10000)
124  max_file_ind = max_file_ind + 1;
125  max_key_ind = 1;
126  end
127  else
128  meta.keylist = [];
129  meta.map_key2file = [];
130  meta.map_key2ind = [];
131  max_file_ind = 1;
132  max_key_ind = 1;
133  end
134  storefile = fullfile(filecache_path,...
135  [funcname,'mv',num2str(max_file_ind),'.mat']);
136  if exist(storefile, 'file')
137  load(storefile);
138  end
139  cache(max_key_ind).saveargs = saveargs;
140  cache(max_key_ind).varargout = varargout;
141 
142  tmp_size = whos('cache');
143  last_size = tmp_size.bytes;
144  keylist = [meta.keylist, key];
145  map_key2file = [meta.map_key2file, max_file_ind];
146  map_key2ind = [meta.map_key2ind, max_key_ind];
147 
148  save(multval_cache, 'last_size', 'keylist', 'map_key2file', 'map_key2ind');
149  save(storefile, 'cache');
150 
151  else
152  save(resultfn,'saveargs','varargout');
153  end
154  debugdisp(['call of ',funcstr,', now computed and cached, key=',keystr]);
155 end
156 
157 % Append the flag that indicates whether the result was cached or not
158 if nargout == length(varargout)+1
159  varargout{length(varargout)+1} = is_cached;
160 end
161 
function varargout = filecache_function(funcptr, varargin)
function used for file-caching other function calls.