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