0001 function varargout=eidors_cache( command, varargin )
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 if nargin==1 && ischar(command) && strcmp(command,'UNIT_TEST');
0124 do_unit_test; return; end
0125
0126 global eidors_objects;
0127 if nargin<1
0128 fprintf('EIDORS_CACHE: current max memory = %.0f MB\n', ...
0129 eidors_objects.max_cache_size/(1024*1024));
0130 ww= whos('eidors_objects');
0131 fprintf('EIDORS_CACHE: cache memory used = %.0f MB\n', ...
0132 ww.bytes/(1024*1024));
0133 fprintf('EIDORS_CACHE: current priority = %d\n', ...
0134 eidors_objects.cache_priority);
0135 return;
0136 elseif nargin > 1
0137 limit = varargin{1};
0138 end
0139
0140 if isa(command, 'function_handle')
0141 str = func2str(command);
0142 if str(1) == '@'
0143 error('Cannot cache anonymous functions');
0144 end
0145 end
0146
0147 if isa(command, 'function_handle') || (ischar(command) && exist(command) == 2)
0148 output = mk_varargout_str(nargout);
0149 eval(sprintf('%s = %s', output, 'cache_shorthand(command, varargin{:});'));
0150 return
0151 end
0152
0153
0154 switch command
0155 case 'init'
0156 eidors_objects.cache_enable = 1;
0157 eidors_objects.cache_disabled_on = [];
0158 eidors_objects.cache_debug_enable = 0;
0159 eidors_objects.cache_debug_enabled_on = [];
0160 eidors_obj('cache_init');
0161
0162 case 'clear_all'
0163 remove_objids
0164
0165 case 'clear'
0166 switch nargin
0167 case 2
0168 eidors_cache('clear_name',limit);
0169 case 1
0170 eidors_cache('clear_all');
0171 otherwise
0172 error('Wrong number of inputs');
0173 end
0174
0175 case 'cache_size'
0176 if nargin==2
0177 if ischar(limit); limit= str2num(limit); end
0178 eidors_objects.max_cache_size = limit;
0179 else
0180 varargout{1}= eidors_objects.max_cache_size;
0181 end
0182
0183 case 'cache_path'
0184 if nargin == 1
0185 varargout{1}= eidors_objects.cache_path;
0186 else
0187 eidors_objects.cache_path = varargin{1};
0188 end
0189
0190 case 'eidors_path'
0191 if nargin == 1
0192 varargout{1}= eidors_objects.eidors_path;
0193 else
0194 eidors_objects.eidors_path = varargin{1};
0195 end
0196 case {'disable' 'off'}
0197 if nargin == 1
0198 eidors_objects.cache_enable = 0;
0199 eidors_objects.cache_disabled_on = {};
0200 else
0201 eidors_objects.cache_enable = 0.5;
0202 if isfield(eidors_objects,'cache_disabled_on')
0203 if ~any(strcmp(eidors_objects.cache_disabled_on, limit))
0204 eidors_objects.cache_disabled_on = [...
0205 eidors_objects.cache_disabled_on; {limit}];
0206 end
0207 else
0208 eidors_objects.cache_disabled_on = {limit};
0209 end
0210 end
0211 case {'enable' 'on'}
0212 if nargin == 1
0213 eidors_objects.cache_enable = 1;
0214 eidors_objects.cache_disabled_on = {};
0215 else
0216 if isfield(eidors_objects,'cache_disabled_on')
0217 idx = strcmp(eidors_objects.cache_disabled_on, limit);
0218 eidors_objects.cache_disabled_on(idx) = [];
0219 else
0220 eidors_objects.cache_disabled_on = [];
0221 end
0222 if isempty(eidors_objects.cache_disabled_on)
0223 eidors_objects.cache_enable = 1;
0224 end
0225 end
0226 case 'status'
0227 if nargin == 1
0228 try
0229 varargout{1} = eidors_objects.cache_enable;
0230 catch
0231 varargout{1} = 1;
0232 end
0233 else
0234 if isfield(eidors_objects,'cache_disabled_on')
0235 idx = strcmp(eidors_objects.cache_disabled_on, limit);
0236 varargout{1} = double(~any(idx));
0237 end
0238 end
0239 case 'debug_status'
0240 if nargin == 1
0241 varargout{1} = eidors_objects.cache_debug_enable;
0242 else
0243 if isfield(eidors_objects,'cache_debug_enabled_on')
0244 idx = ismember(limit,eidors_objects.cache_debug_enabled_on);
0245 varargout{1} = idx | eidors_objects.cache_debug_enable==1;
0246 end
0247 end
0248 case 'debug_on'
0249 if nargin == 1
0250 eidors_objects.cache_debug_enable = 1;
0251 eidors_objects.cache_debug_enabled_on = {};
0252 else
0253 eidors_objects.cache_debug_enable = 0.5;
0254 if isfield(eidors_objects,'cache_debug_enabled_on')
0255 if ~any(strcmp(eidors_objects.cache_debug_enabled_on, limit))
0256 eidors_objects.cache_debug_enabled_on = [...
0257 eidors_objects.cache_debug_enabled_on; {limit}];
0258 end
0259 else
0260 eidors_objects.cache_debug_enabled_on = {limit};
0261 end
0262 end
0263 case 'debug_off'
0264 if nargin == 1
0265 eidors_objects.cache_debug_enable = 0;
0266 eidors_objects.cache_debug_enabled_on = {};
0267 else
0268 if isfield(eidors_objects,'cache_debug_enabled_on')
0269 idx = strcmp(eidors_objects.cache_debug_enabled_on, limit);
0270 eidors_objects.cache_debug_enabled_on(idx) = [];
0271 else
0272 eidors_objects.cache_debug_enabled_on = [];
0273 end
0274 if isempty(eidors_objects.cache_debug_enabled_on)
0275 eidors_objects.cache_debug_enable = 0;
0276 end
0277 end
0278 case 'boost_priority'
0279 try
0280 varargout{1}= eidors_objects.cache_priority;
0281 catch
0282 varargout{1}= 0;
0283 end
0284 if nargin==2
0285 if ischar(limit); limit= str2double(limit); end
0286 varargout{1} = varargout{1} + limit;
0287 end
0288 eidors_objects.cache_priority = varargout{1};
0289
0290 case {'list', 'show_objs'}
0291 if nargin == 2
0292 cache_list(limit);
0293 else
0294 cache_list;
0295 end
0296
0297
0298 case 'clear_max'
0299 if ischar(limit); limit= str2double(limit); end
0300 try
0301 c = eidors_objects.cache.cols;
0302 catch
0303 return
0304 end
0305
0306 priidx = get_cache_priority;
0307 [jnk, idx] = sort(priidx);
0308 tot= cumsum([eidors_objects.cache.meta{idx,c.size}]);
0309 rmidx = idx(tot > limit);
0310 remove_objids( rmidx );
0311
0312 case 'clear_old'
0313 if ischar(limit); limit= str2num(limit); end
0314 try
0315 c = eidors_objects.cache.cols;
0316 catch
0317 return
0318 end
0319 idx = find([eidors_objects.cache.meta{:,c.time}] < limit);
0320 remove_objids( idx );
0321
0322 case 'clear_new'
0323 if ischar(limit); limit= str2num(limit); end
0324 try
0325 c = eidors_objects.cache.cols;
0326 catch
0327 return
0328 end
0329 idx = find([eidors_objects.cache.meta{:,c.time}] > limit);
0330 remove_objids( idx );
0331
0332 case 'clear_model_library'
0333
0334 delete([eidors_objects.model_cache,'/*.mat']);
0335
0336 case 'clear_name'
0337 idx = clear_names_cache( limit );
0338 remove_objids( idx );
0339
0340 case 'dump'
0341 varargout{1} = eidors_objects;
0342
0343 case 'load'
0344 eidors_objects = limit;
0345
0346 otherwise
0347 error('command %s not understood',command);
0348 end
0349
0350 function cache_list (order)
0351 global eidors_objects;
0352 try
0353 meta = eidors_objects.cache.meta;
0354 catch
0355 return
0356 end
0357 if nargin == 0
0358 order = 'time';
0359 end
0360
0361 c = eidors_objects.cache.cols;
0362 if isempty(meta)
0363 fprintf('No objects in cache\n');
0364 return
0365 end
0366 meta(:,c.time) = cellstr(datestr([meta{:,c.time}],'yyyy-mm-dd HH:MM:SS.FFF'));
0367 N = size(meta,2);
0368
0369
0370 meta(:,N+1) = num2cell(get_cache_priority);
0371 switch order
0372 case 'time'
0373 meta = mysortrows(meta,c.time);
0374 case {'prop','name'}
0375 meta = mysortrows(meta,c.prop);
0376 case 'rank'
0377 meta = mysortrows(meta,N+1);
0378 case 'size'
0379 meta = mysortrows(meta,-c.size);
0380 case 'effort'
0381 meta = mysortrows(meta,-c.effort);
0382 case 'count'
0383 meta = mysortrows(meta,-c.count);
0384 otherwise
0385 error('Unrecognized sort order');
0386 end
0387
0388 meta = meta';
0389 fprintf('%s b=%9.0d [%4d] p=%02d t=%3dx%.2e [%4d] i=%4d: %s { %s }\n', ...
0390 meta{[c.time,c.size,c.score_sz,c.prio,c.count,c.effort,c.score_eff,N+1,c.obj_id, c.prop],:});
0391
0392 function priidx = get_cache_priority
0393 global eidors_objects;
0394 priidx = [];
0395 if isfield(eidors_objects.cache, 'meta') && isfield(eidors_objects.cache, 'cols')
0396 meta = eidors_objects.cache.meta;
0397 c = eidors_objects.cache.cols;
0398 [jnk, priidx] = mysortrows(meta,[-c.score_eff c.score_sz -c.time]);
0399 priidx(priidx) = 1:size(meta,1);
0400 end
0401
0402
0403
0404 function objid = clear_names_cache( name )
0405 objid=[];
0406 global eidors_objects;
0407 try
0408 c = eidors_objects.cache.cols;
0409 objid = find(strcmp(name, eidors_objects.cache.meta(:,c.prop)));
0410 end
0411
0412
0413 function remove_objids(idx, names, sizes)
0414 global eidors_objects;
0415 try
0416 c = eidors_objects.cache.cols;
0417 catch
0418 eidors_obj('cache_init');
0419 return
0420 end
0421 if nargin == 0
0422 idx = 1:size(eidors_objects.cache.meta,1);
0423 end
0424 if isempty(idx)
0425 return
0426 end
0427 switch eidors_cache('debug_status')
0428 case 1
0429 debug_msg( eidors_objects.cache.meta(idx,c.obj_id), ...
0430 eidors_objects.cache.meta(idx,c.prop), 'removed');
0431 case 0.5
0432 db = eidors_cache('debug_status', eidors_objects.cache.meta(idx,c.prop));
0433 debug_msg( eidors_objects.cache.meta(idx(db),c.obj_id), ...
0434 eidors_objects.cache.meta(idx(db),c.prop), 'removed');
0435 end
0436 total_size = sum(cell2mat(eidors_objects.cache.meta(idx,c.size)));
0437 N = numel(idx);
0438 if numel(idx) == size(eidors_objects.cache.meta,1)
0439 eidors_objects = rmfield(eidors_objects,'cache');
0440 eidors_obj('cache_init');
0441 else
0442 eidors_objects.cache = rmfield(eidors_objects.cache, ...
0443 eidors_objects.cache.meta(idx,c.obj_id));
0444 eidors_objects.cache.meta(idx,:) = [];
0445 eidors_objects.cache.size = eidors_objects.cache.size - total_size;
0446 end
0447
0448 eidors_msg('Removed %d objects with %d bytes from cache', ...
0449 N, total_size, 2 );
0450
0451
0452 function varargout = cache_shorthand(fhandle, varargin)
0453
0454 args = varargin{1};
0455 if ~iscell(args)
0456 args = {args};
0457 end
0458
0459 if nargin >2
0460 opt = varargin{2};
0461 else
0462 opt = struct;
0463 end
0464 if ischar(opt)
0465 fstr = opt; clear opt;
0466 opt.fstr = fstr;
0467 end
0468 if isfield(opt, 'cache_obj');
0469 cache_obj = opt.cache_obj;
0470 if ~iscell(cache_obj)
0471 cache_obj = {cache_obj};
0472 end
0473 else
0474 cache_obj = args;
0475 end
0476 try
0477 fstr = opt.fstr;
0478 catch
0479 fstr = func2str(fhandle);
0480 end
0481 if isfield(opt, 'log_level')
0482 level_in = opt.log_level;
0483 level_out = opt.log_level;
0484 else
0485 level_in = 4;
0486 level_out = 3;
0487 end
0488 cache_to_disk = false;
0489 if isfield(opt, 'cache_to_disk')
0490 cache_locn = opt.cache_to_disk;
0491 if cache_locn
0492 cache_to_disk = true;
0493 end
0494 if cache_locn==true
0495 cache_locn = '.';
0496 end
0497 if isfield(opt,'fstr')
0498 cache_str = opt.fstr;
0499 else
0500 cache_str = 'eidors_cache';
0501 end
0502 end
0503
0504 [varargout,obj_id] = eidors_obj('get-cache', cache_obj, fstr );
0505 if length(varargout)==0 && cache_to_disk
0506 savename = [cache_locn,'/',cache_str,'_',obj_id,'.mat'];
0507 if exist(savename,'file')
0508 load(savename)
0509 end
0510 end
0511 if numel(varargout) < nargout
0512 eidors_msg('@@ (Re)calculating %s',fstr, level_in);
0513 output = mk_varargout_str(nargout);
0514 varargout = cell(0);
0515 t0 = tic;
0516 eval(sprintf('%s = %s', output, 'feval(fhandle,args{:});'));
0517 t = toc(t0);
0518 if isfield(opt,'boost_priority');
0519 eidors_cache('boost_priority',opt.boost_priority);
0520 end
0521
0522
0523 if cache_to_disk
0524 eidors_msg('@@ Caching to %s', savename, level_in+1);
0525 save(savename,'varargout','-V7');
0526 else
0527 eidors_obj('set-cache', cache_obj, fstr, varargout, t);
0528 end
0529
0530 if isfield(opt,'boost_priority');
0531 eidors_cache('boost_priority',-opt.boost_priority);
0532 end
0533 return
0534 end
0535 eidors_msg('%s: Using cached value',fstr,level_out);
0536
0537 function output = mk_varargout_str(N)
0538 output = '[';
0539 for i = 1:N
0540 output = [ output sprintf('varargout{%d} ',i)];
0541 end
0542 output = [ output ']' ];
0543
0544 function debug_msg(id,name,action)
0545 global eidors_objects;
0546 if nargin < 3
0547 action = name;
0548 name = fieldnames(eidors_objects.(id));
0549 end
0550 if isempty(id), return, end
0551 if ~iscell(name) name = {name}; end
0552 if ~iscell(id) id = {id}; end
0553
0554 str = sprintf('EIDORS_CACHE: %s %%s { %%s }\\n', action);
0555 arr = [id, name]';
0556
0557 fprintf(str, arr{:});
0558
0559
0560 function do_unit_test
0561 ll= eidors_msg('log_level');
0562 eidors_msg('log_level',5);
0563 eidors_cache
0564 eidors_cache('clear_all');
0565 eidors_cache
0566 eidors_obj('set-cache', rand(1) , 't1', rand(2e3));
0567 eidors_obj('set-cache', rand(1) , 't2', rand(2e3));
0568 eidors_obj('set-cache', rand(1) , 't3', rand(2e3));
0569 eidors_cache
0570 eidors_cache list
0571 eidors_cache('clear_name','t3');
0572 eidors_cache
0573 eidors_cache list
0574 eidors_cache('clear_max', 34e6);
0575 eidors_cache
0576 eidors_cache('boost_priority', 1);
0577 eidors_cache
0578 eidors_cache('boost_priority', -1);
0579 eidors_cache
0580 [v1] = eidors_cache(@test_function,{3,4});
0581 [v2] = eidors_cache(@test_function,{3,4});
0582 unit_test_cmp('shorthand 1 param:',v1,v2);
0583 [v3 v4] = eidors_cache(@test_function,{3,4});
0584 unit_test_cmp('Expect Fail', v3, v4,-inf);
0585 [v5 v6 ] = eidors_cache(@test_function,{3,4});
0586 unit_test_cmp('shorthand 2 params:',v4, v6);
0587 [v5 v6 ] = eidors_cache(@test_function,{3,4, 5});
0588 opt.cache_obj = 5;
0589 [v5 v6 ] = eidors_cache(@test_function,{3,4, 5}, opt);
0590 [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt);
0591 unit_test_cmp('shorthand cache_obj:',v6, v8);
0592 eidors_cache clear_all
0593 opt = struct;
0594 [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt);
0595 opt.boost_priority = 2;
0596 [v7 v8 ] = eidors_cache(@test_function,{3,4, 5}, opt);
0597 eidors_cache show_objs
0598 eidors_cache
0599 eidors_msg('log_level',ll);
0600 try
0601 eidors_cache(@(x) x^2, 3);
0602 catch
0603 eidors_msg('Error on anonymous function: correct',2);
0604 end
0605 test_debug
0606 test_priority
0607 function [v1 v2] = test_function(a,b,c,d)
0608 v1 = rand(1);
0609 v2 = rand(1);
0610
0611 function [meta,idx] = mysortrows(meta, cols)
0612 if ~exist('OCTAVE_VERSION')
0613 [meta,idx] = sortrows(meta, cols);
0614 else
0615 metm = cell2mat(meta(:,3:end));
0616 cols = ( abs(cols) - 2 ) .* sign(cols);
0617 [~,idx] = sortrows(metm, cols);
0618 meta = meta(idx,:);
0619 end
0620
0621
0622 function test_debug
0623 eidors_cache clear
0624 eidors_obj('set-cache',{5}, 'test1',50);
0625 eidors_obj('set-cache',{5}, 'test2',500);
0626 eidors_obj('set-cache',{10}, 'test1',100);
0627 eidors_cache show_objs
0628 eidors_cache debug_off
0629 eidors_cache debug_on test2
0630 eidors_cache clear_name test2
0631 eidors_cache show_objs
0632
0633 eidors_obj('set-cache',{5}, 'test2',500);
0634 eidors_cache debug_off
0635 eidors_cache debug_on test1
0636 eidors_cache clear_name test2
0637 eidors_cache('clear_max',0)
0638 eidors_cache('show_objs')
0639 eidors_cache debug_off
0640
0641
0642 function test_priority
0643 eidors_cache clear
0644 eidors_obj('set-cache',{1}, 'slow_small', zeros(10) ,10); pause(.1)
0645
0646
0647 eidors_obj('set-cache',{1}, 'slow_new', zeros(100),10); pause(.1)
0648
0649
0650 eidors_obj('set-cache',{1}, 'slow_big1', zeros(100),10); pause(.1)
0651
0652
0653 eidors_obj('set-cache',{1}, 'slow_big2', zeros(100),20); pause(.1)
0654
0655
0656 eidors_obj('set-cache',{1}, 'fast_small', zeros(2) , 1); pause(.1)
0657
0658
0659 eidors_obj('set-cache',{1}, 'fast_big', zeros(100), 1); pause(.1)
0660
0661
0662 eidors_obj('get-cache',{1}, 'slow_new');
0663
0664 eidors_cache list
0665
0666
0667