rbmatlab  1.13.10
 All Classes Namespaces Files Functions Variables Groups 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 %keyboard;
61 %key = sum()
62 
63 resultfn = fullfile(filecache_path,...
64  [funcname,keystr,'.mat']);
65 multval_cache = fullfile(filecache_path,...
66  [funcname,'mv.mat']);
67 
68 is_cached = 0;
69 hash_found = 0;
70 funcstr = strtrim(evalc('disp(funcptr)'));
71 
72 if exist(resultfn,'file');
73  loaded = load(resultfn);
74  hash_found = 1;
75 elseif exist(multval_cache,'file')
76  tmp = load(multval_cache);
77  tmp_key_pos = find(tmp.keylist==key,1);
78  if ~isempty(tmp_key_pos)
79  tmp_key_ind = tmp.map_key2ind(tmp_key_pos);
80  tmp_file_ind = tmp.map_key2file(tmp_key_pos);
81  storefile = fullfile(filecache_path,...
82  [funcname,'mv',num2str(tmp_file_ind),'.mat']);
83  if exist(storefile,'file')
84  tmp = load(storefile);
85  loaded = tmp.cache(tmp_key_ind);
86  hash_found = 1;
87  else
88  error(['Could not find file ',storefile,...
89  ', which is specified in multivalue cache list.']);
90  end
91  end
92 end
93 
94 if hash_found
95  % isequal does not work for handles
96  % if isequal(tmp.saveargs,saveargs)
97  if isequal_ignore_handles(loaded.saveargs,saveargs)
98  varargout = loaded.varargout;
99  is_cached = 1;
100  disp(['call of ',funcstr,', successfully read from cache, key=',keystr]);
101 % keyboard;
102  else
103  % the key-computation formula must be updated in this case...
104  disp(['arguments in cached file and current call do not',...
105  'correspond!!']);
106  disp('please change key-function in file_cache_function!');
107  disp('recomputation is started and cache-file replaced.');
108  %keyboard;
109  end
110 end
111 
112 
113 if ~is_cached
114  % call function
115  disp('result not found in cache');
116  [varargout{1:nargout}] = funcptr(varargin{:});
117  % save(resultfn,'varargin');
118 
119  siz=whos('varargout');
120  % if size is less than 100kb, store in multi-value cache.
121  if(siz.bytes < 1024*100)
122  if exist(multval_cache,'file')
123  meta=load(multval_cache);
124  max_file_ind = meta.map_key2file(end);
125  max_key_ind = meta.map_key2ind(end)+1;
126  last_size = meta.last_size;
127  % if store file size exceeds 10MB, create a new one
128  if (last_size + siz.bytes > 1024*10000)
129  max_file_ind = max_file_ind + 1;
130  max_key_ind = 1;
131  end
132  else
133  meta.keylist = [];
134  meta.map_key2file = [];
135  meta.map_key2ind = [];
136  max_file_ind = 1;
137  max_key_ind = 1;
138  end
139  storefile = fullfile(filecache_path,...
140  [funcname,'mv',num2str(max_file_ind),'.mat']);
141  if exist(storefile, 'file')
142  load(storefile);
143  end
144  cache(max_key_ind).saveargs = saveargs;
145  cache(max_key_ind).varargout = varargout;
146 
147  tmp_size = whos('cache');
148  last_size = tmp_size.bytes;
149  keylist = [meta.keylist, key];
150  map_key2file = [meta.map_key2file, max_file_ind];
151  map_key2ind = [meta.map_key2ind, max_key_ind];
152 
153  save(multval_cache, 'last_size', 'keylist', 'map_key2file', 'map_key2ind');
154  save(storefile, 'cache');
155 
156  else
157  save(resultfn,'saveargs','varargout');
158  end
159  disp(['call of ',funcstr,', now computed and cached, key=',keystr]);
160 end
161