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('CACHE__: Date+Time bytes Score_szPrio CountXEffort Score_eff # obj_id ___\n');
0390 fprintf('%s b=%9.0d [%4d] p=%02d t=%3dx%.2e [%4d] i=%4d: %s { %s }\n', ...
0391 meta{[c.time,c.size,c.score_sz,c.prio,c.count,c.effort,c.score_eff,N+1,c.obj_id, c.prop],:});
0392
0393 function priidx = get_cache_priority
0394 global eidors_objects;
0395 priidx = [];
0396 if isfield(eidors_objects.cache, 'meta') && isfield(eidors_objects.cache, 'cols')
0397 meta = eidors_objects.cache.meta;
0398 c = eidors_objects.cache.cols;
0399 [jnk, priidx] = mysortrows(meta,[-c.score_eff c.score_sz -c.time]);
0400 priidx(priidx) = 1:size(meta,1);
0401 end
0402
0403
0404
0405 function objid = clear_names_cache( name )
0406 objid=[];
0407 global eidors_objects;
0408 try
0409 c = eidors_objects.cache.cols;
0410 objid = find(strcmp(name, eidors_objects.cache.meta(:,c.prop)));
0411 end
0412
0413
0414 function remove_objids(idx, names, sizes)
0415 global eidors_objects;
0416 try
0417 c = eidors_objects.cache.cols;
0418 catch
0419 eidors_obj('cache_init');
0420 return
0421 end
0422 if nargin == 0
0423 idx = 1:size(eidors_objects.cache.meta,1);
0424 end
0425 if isempty(idx)
0426 return
0427 end
0428 switch eidors_cache('debug_status')
0429 case 1
0430 debug_msg( eidors_objects.cache.meta(idx,c.obj_id), ...
0431 eidors_objects.cache.meta(idx,c.prop), 'removed');
0432 case 0.5
0433 db = eidors_cache('debug_status', eidors_objects.cache.meta(idx,c.prop));
0434 debug_msg( eidors_objects.cache.meta(idx(db),c.obj_id), ...
0435 eidors_objects.cache.meta(idx(db),c.prop), 'removed');
0436 end
0437 total_size = sum(cell2mat(eidors_objects.cache.meta(idx,c.size)));
0438 N = numel(idx);
0439 if numel(idx) == size(eidors_objects.cache.meta,1)
0440 eidors_objects = rmfield(eidors_objects,'cache');
0441 eidors_obj('cache_init');
0442 else
0443 eidors_objects.cache = rmfield(eidors_objects.cache, ...
0444 eidors_objects.cache.meta(idx,c.obj_id));
0445 eidors_objects.cache.meta(idx,:) = [];
0446 eidors_objects.cache.size = eidors_objects.cache.size - total_size;
0447 end
0448
0449 eidors_msg('Removed %d objects with %d bytes from cache', ...
0450 N, total_size, 2 );
0451
0452
0453 function varargout = cache_shorthand(fhandle, varargin)
0454
0455 args = varargin{1};
0456 if ~iscell(args)
0457 args = {args};
0458 end
0459
0460 if nargin >2
0461 opt = varargin{2};
0462 else
0463 opt = struct;
0464 end
0465 if ischar(opt)
0466 fstr = opt; clear opt;
0467 opt.fstr = fstr;
0468 end
0469 if isfield(opt, 'cache_obj');
0470 cache_obj = opt.cache_obj;
0471 if ~iscell(cache_obj)
0472 cache_obj = {cache_obj};
0473 end
0474 else
0475 cache_obj = args;
0476 end
0477 try
0478 fstr = opt.fstr;
0479 catch
0480 fstr = func2str(fhandle);
0481 end
0482 if isfield(opt, 'log_level')
0483 level_in = opt.log_level;
0484 level_out = opt.log_level;
0485 else
0486 level_in = 4;
0487 level_out = 3;
0488 end
0489 cache_to_disk = false;
0490 if isfield(opt, 'cache_to_disk')
0491 cache_locn = opt.cache_to_disk;
0492 if cache_locn
0493 cache_to_disk = true;
0494 end
0495 if cache_locn==true
0496 cache_locn = '.';
0497 end
0498 if isfield(opt,'fstr')
0499 cache_str = opt.fstr;
0500 else
0501 cache_str = 'eidors_cache';
0502 end
0503 end
0504
0505 [varargout,obj_id] = eidors_obj('get-cache', cache_obj, fstr );
0506 if length(varargout)==0 && cache_to_disk
0507 savename = [cache_locn,'/',cache_str,'_',obj_id,'.mat'];
0508 if exist(savename,'file')
0509 load(savename)
0510 end
0511 end
0512 if numel(varargout) < nargout
0513 eidors_msg('@@ (Re)calculating %s',fstr, level_in);
0514 output = mk_varargout_str(nargout);
0515 varargout = cell(0);
0516 t0 = tic;
0517 eval(sprintf('%s = %s', output, 'feval(fhandle,args{:});'));
0518 t = toc(t0);
0519 if isfield(opt,'boost_priority');
0520 eidors_cache('boost_priority',opt.boost_priority);
0521 end
0522
0523
0524 if cache_to_disk
0525 eidors_msg('@@ Caching to %s', savename, level_in+1);
0526 save(savename,'varargout','-V7');
0527 else
0528 eidors_obj('set-cache', cache_obj, fstr, varargout, t);
0529 end
0530
0531 if isfield(opt,'boost_priority');
0532 eidors_cache('boost_priority',-opt.boost_priority);
0533 end
0534 return
0535 end
0536 eidors_msg('%s: Using cached value',fstr,level_out);
0537
0538 function output = mk_varargout_str(N)
0539 output = '[';
0540 for i = 1:N
0541 output = [ output sprintf('varargout{%d} ',i)];
0542 end
0543 output = [ output ']' ];
0544
0545 function debug_msg(id,name,action)
0546 global eidors_objects;
0547 if nargin < 3
0548 action = name;
0549 name = fieldnames(eidors_objects.(id));
0550 end
0551 if isempty(id), return, end
0552 if ~iscell(name) name = {name}; end
0553 if ~iscell(id) id = {id}; end
0554
0555 str = sprintf('EIDORS_CACHE: %s %%s { %%s }\\n', action);
0556 arr = [id, name]';
0557
0558 fprintf(str, arr{:});
0559
0560
0561 function do_unit_test
0562 ll= eidors_msg('log_level');
0563 eidors_msg('log_level',5);
0564 eidors_cache
0565 eidors_cache('clear_all');
0566 eidors_cache
0567 eidors_obj('set-cache', rand(1) , 't1', rand(2e3));
0568 eidors_obj('set-cache', rand(1) , 't2', rand(2e3));
0569 eidors_obj('set-cache', rand(1) , 't3', rand(2e3));
0570 eidors_cache
0571 eidors_cache list
0572 eidors_cache('clear_name','t3');
0573 eidors_cache
0574 eidors_cache list
0575 eidors_cache('clear_max', 34e6);
0576 eidors_cache
0577 eidors_cache('boost_priority', 1);
0578 eidors_cache
0579 eidors_cache('boost_priority', -1);
0580 eidors_cache
0581 [v1] = eidors_cache(@test_function,{3,4});
0582 [v2] = eidors_cache(@test_function,{3,4});
0583 unit_test_cmp('shorthand 1 param:',v1,v2);
0584 [v3 v4] = eidors_cache(@test_function,{3,4});
0585 unit_test_cmp('Expect Fail', v3, v4,-inf);
0586 [v5 v6 ] = eidors_cache(@test_function,{3,4});
0587 unit_test_cmp('shorthand 2 params:',v4, v6);
0588 [v5 v6 ] = eidors_cache(@test_function,{3,4, 5});
0589 opt.cache_obj = 5;
0590 [v5 v6 ] = eidors_cache(@test_function,{3,4, 5}, opt);
0591 [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt);
0592 unit_test_cmp('shorthand cache_obj:',v6, v8);
0593 eidors_cache clear_all
0594 opt = struct;
0595 [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt);
0596 opt.boost_priority = 2;
0597 [v7 v8 ] = eidors_cache(@test_function,{3,4, 5}, opt);
0598 eidors_cache show_objs
0599 eidors_cache
0600 eidors_msg('log_level',ll);
0601 try
0602 eidors_cache(@(x) x^2, 3);
0603 catch
0604 eidors_msg('Error on anonymous function: correct',2);
0605 end
0606 test_debug
0607 test_priority
0608 function [v1 v2] = test_function(a,b,c,d)
0609 v1 = rand(1);
0610 v2 = rand(1);
0611
0612 function [meta,idx] = mysortrows(meta, cols)
0613 if ~exist('OCTAVE_VERSION')
0614 [meta,idx] = sortrows(meta, cols);
0615 else
0616 metm = cell2mat(meta(:,3:end));
0617 cols = ( abs(cols) - 2 ) .* sign(cols);
0618 [~,idx] = sortrows(metm, cols);
0619 meta = meta(idx,:);
0620 end
0621
0622
0623 function test_debug
0624 fprintf('\n\n************************\n CACHE DEBUG: VERBOSE OUTPUT\n************************\n');
0625 eidors_cache clear
0626 eidors_obj('set-cache',{5}, 'test1',50);
0627 eidors_obj('set-cache',{5}, 'test2',500);
0628 eidors_obj('set-cache',{10}, 'test1',100);
0629 eidors_cache show_objs
0630 eidors_cache debug_off
0631 eidors_cache debug_on test2
0632 eidors_cache clear_name test2
0633 eidors_cache show_objs
0634
0635 eidors_obj('set-cache',{5}, 'test2',500);
0636 eidors_cache debug_off
0637 eidors_cache debug_on test1
0638 eidors_cache clear_name test2
0639 eidors_cache('clear_max',0)
0640 eidors_cache('show_objs')
0641 eidors_cache debug_off
0642 fprintf('\n\n************************\n CACHE DEBUG: DEBUG FINISHED\n************************\n');
0643
0644
0645 function test_priority
0646 eidors_cache clear
0647 eidors_obj('set-cache',{1}, 'slow_small', zeros(10) ,10); pause(.1)
0648
0649
0650 eidors_obj('set-cache',{1}, 'slow_new', zeros(100),10); pause(.1)
0651
0652
0653 eidors_obj('set-cache',{1}, 'slow_big1', zeros(100),10); pause(.1)
0654
0655
0656 eidors_obj('set-cache',{1}, 'slow_big2', zeros(100),20); pause(.1)
0657
0658
0659 eidors_obj('set-cache',{1}, 'fast_small', zeros(2) , 1); pause(.1)
0660
0661
0662 eidors_obj('set-cache',{1}, 'fast_big', zeros(100), 1); pause(.1)
0663
0664
0665 eidors_obj('get-cache',{1}, 'slow_new');
0666
0667 eidors_cache list
0668
0669
0670