eidors_cache

PURPOSE ^

EIDORS_CACHE Control eidors caching

SYNOPSIS ^

function varargout=eidors_cache( command, varargin )

DESCRIPTION ^

 EIDORS_CACHE Control eidors caching
 Usage: eidors_cache( command, limit ) for cache management
 Usage: eidors_cache(@function_handle, {params1, ... }) for shorthand
        chashing in m-files

 USAGE:
   eidors_cache( 'clear_all' ) 
   eidors_cache  clear

   eidors_cache( 'list' )
   eidors_cache( 'show_objs' )
       - list all objects
   eidors_cache(___, order)
       - sort by specific order. Valid values are 
         {time}, size, effort, count, rank

   eidors_cache( 'clear_old'. timestamp );
   eidors_cache( 'clear_new', timestamp );
      - clear all variables older (or newer) than timestamp
      - example:
         time_now= now;
         lots_of_eidors_calcs % don't need to cache this stuff
         eidors_cache('clear_new',time_now);

   eidors_cache( 'clear_max', memory_in_bytes );
      - clear cache so it has less than memory_in_bytes

   eidors_cache( 'cache_size', memory_in_bytes );
      - set max cache size to be memory_in_bytes
      - without 2nd arg will return current cache_size

   eidors_cache( 'clear_name', cache_name )
      - eg. eidors_cache( 'clear_name', 'inv_solve_diff_GN_one_step')
      - clear all variables with name 

   eidors_cache( 'clear_model_library' );
      - clear the eidors model library directory
      - NOTE: this function is experimental. 
      - TODO: add a way to specify what to clear
  
   eidors_cache( 'boost_priority', value)
      - modify the priority of the next cached items
      - low priority variables will be deleted first when memory is tight

   eidors_cache( 'off' )
   eidors_cache( 'disable' )
   eidors_cache( 'off', 'function_name' )
      - new values are not added to cache
      - requests for cached values return []
      - if specified, only applies to a specific function

   eidors_cache( 'on' )
   eidors_cache( 'enable' )
   eidors_cache( 'on', 'function_name' )
      - re-enables caching
      - if specified, only applies to a specific function

   eidors_cache( 'status' )
      - queries the caching status
      - 0  : all off
      - 1  : all on
      - 0.5: off for some functions

   eidors_cache( 'debug_on' )
   eidors_cache( 'debug_on', 'function_name' )
      - enables debug output
      - if specified, only applies to a specific function
      - will print a message everytime an object is removed from cache

   eidors_cache( 'debug_off' )
   eidors_cache( 'debug_off', 'function_name' );
      - disables debug output
      - if specified, only applies to a specific function

   eidors_cache( 'debug_status' )
      - queries debug status
      - output analogous to cache status above

   v1 = eidors_cache( @function_handle, {param1, param2, ...})
   [v1, v2, ...] = eidors_cache( @function_handle, {param1, param2, ...})
   [v1, v2, ...] = eidors_cache( ... , opt)
      Shorthand interface for caching the output of a specific function.
      Specify all arguments to the function as a cell array. They will all
      be used for as a caching object by default. The following options
      are available:
        opt.cache_obj
            - a single value, or a cell array of values to cache on, 
              rather than all the inputs (e.g. not all values of an input
              struct may be used in the function)
        opt.boost_priority
            - priority boost to use for that function
        opt.fstr
            - name to use for the cached result
        opt.log_level
            - message level to use with eidors_msg. By default, it's 4 for
              'setting cache' and 3 for 'using cached value'
        opt.cache_to_disk = true or '.'  
        opt.cache_to_disk = 'path/to/cache/dir'
            - Save the cached file to disk and reload it when called
            - The file is named 'eidors_cache_id????.mat' or opt.fstr,'_id???'
        opt.cache_on_ng_opt = true
            - Cache also on the contents of the 'ng.opt' file in current working dir

   eidors_cache( 'cache_path' )
   eidors_cache( 'cache_path', '/path/to/cache/path' )
       - get and set cache_path, a path to a writable
           directory in which eidors can store files

   eidors_cache( 'eidors_path' )
   eidors_cache( 'eidors_path', '/path/to/eidors/' )
       - /path/to/eidors is the path in which eidors_startup.m is found

 See also EIDORS_OBJ

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function varargout=eidors_cache( command, varargin )
0002 % EIDORS_CACHE Control eidors caching
0003 % Usage: eidors_cache( command, limit ) for cache management
0004 % Usage: eidors_cache(@function_handle, {params1, ... }) for shorthand
0005 %        chashing in m-files
0006 %
0007 % USAGE:
0008 %   eidors_cache( 'clear_all' )
0009 %   eidors_cache  clear
0010 %
0011 %   eidors_cache( 'list' )
0012 %   eidors_cache( 'show_objs' )
0013 %       - list all objects
0014 %   eidors_cache(___, order)
0015 %       - sort by specific order. Valid values are
0016 %         {time}, size, effort, count, rank
0017 %
0018 %   eidors_cache( 'clear_old'. timestamp );
0019 %   eidors_cache( 'clear_new', timestamp );
0020 %      - clear all variables older (or newer) than timestamp
0021 %      - example:
0022 %         time_now= now;
0023 %         lots_of_eidors_calcs % don't need to cache this stuff
0024 %         eidors_cache('clear_new',time_now);
0025 %
0026 %   eidors_cache( 'clear_max', memory_in_bytes );
0027 %      - clear cache so it has less than memory_in_bytes
0028 %
0029 %   eidors_cache( 'cache_size', memory_in_bytes );
0030 %      - set max cache size to be memory_in_bytes
0031 %      - without 2nd arg will return current cache_size
0032 %
0033 %   eidors_cache( 'clear_name', cache_name )
0034 %      - eg. eidors_cache( 'clear_name', 'inv_solve_diff_GN_one_step')
0035 %      - clear all variables with name
0036 %
0037 %   eidors_cache( 'clear_model_library' );
0038 %      - clear the eidors model library directory
0039 %      - NOTE: this function is experimental.
0040 %      - TODO: add a way to specify what to clear
0041 %
0042 %   eidors_cache( 'boost_priority', value)
0043 %      - modify the priority of the next cached items
0044 %      - low priority variables will be deleted first when memory is tight
0045 %
0046 %   eidors_cache( 'off' )
0047 %   eidors_cache( 'disable' )
0048 %   eidors_cache( 'off', 'function_name' )
0049 %      - new values are not added to cache
0050 %      - requests for cached values return []
0051 %      - if specified, only applies to a specific function
0052 %
0053 %   eidors_cache( 'on' )
0054 %   eidors_cache( 'enable' )
0055 %   eidors_cache( 'on', 'function_name' )
0056 %      - re-enables caching
0057 %      - if specified, only applies to a specific function
0058 %
0059 %   eidors_cache( 'status' )
0060 %      - queries the caching status
0061 %      - 0  : all off
0062 %      - 1  : all on
0063 %      - 0.5: off for some functions
0064 %
0065 %   eidors_cache( 'debug_on' )
0066 %   eidors_cache( 'debug_on', 'function_name' )
0067 %      - enables debug output
0068 %      - if specified, only applies to a specific function
0069 %      - will print a message everytime an object is removed from cache
0070 %
0071 %   eidors_cache( 'debug_off' )
0072 %   eidors_cache( 'debug_off', 'function_name' );
0073 %      - disables debug output
0074 %      - if specified, only applies to a specific function
0075 %
0076 %   eidors_cache( 'debug_status' )
0077 %      - queries debug status
0078 %      - output analogous to cache status above
0079 %
0080 %   v1 = eidors_cache( @function_handle, {param1, param2, ...})
0081 %   [v1, v2, ...] = eidors_cache( @function_handle, {param1, param2, ...})
0082 %   [v1, v2, ...] = eidors_cache( ... , opt)
0083 %      Shorthand interface for caching the output of a specific function.
0084 %      Specify all arguments to the function as a cell array. They will all
0085 %      be used for as a caching object by default. The following options
0086 %      are available:
0087 %        opt.cache_obj
0088 %            - a single value, or a cell array of values to cache on,
0089 %              rather than all the inputs (e.g. not all values of an input
0090 %              struct may be used in the function)
0091 %        opt.boost_priority
0092 %            - priority boost to use for that function
0093 %        opt.fstr
0094 %            - name to use for the cached result
0095 %        opt.log_level
0096 %            - message level to use with eidors_msg. By default, it's 4 for
0097 %              'setting cache' and 3 for 'using cached value'
0098 %        opt.cache_to_disk = true or '.'
0099 %        opt.cache_to_disk = 'path/to/cache/dir'
0100 %            - Save the cached file to disk and reload it when called
0101 %            - The file is named 'eidors_cache_id????.mat' or opt.fstr,'_id???'
0102 %        opt.cache_on_ng_opt = true
0103 %            - Cache also on the contents of the 'ng.opt' file in current working dir
0104 %
0105 %   eidors_cache( 'cache_path' )
0106 %   eidors_cache( 'cache_path', '/path/to/cache/path' )
0107 %       - get and set cache_path, a path to a writable
0108 %           directory in which eidors can store files
0109 %
0110 %   eidors_cache( 'eidors_path' )
0111 %   eidors_cache( 'eidors_path', '/path/to/eidors/' )
0112 %       - /path/to/eidors is the path in which eidors_startup.m is found
0113 %
0114 % See also EIDORS_OBJ
0115 
0116 % (C) 2005-2013 Andy Adler and Bartlomiej Grychtol.
0117 % License: GPL version 2
0118 % $Id: eidors_cache.m 6465 2022-12-10 15:39:50Z aadler $
0119 
0120 % Comments
0121 % Want to clear specific structures
0122 %      to clear old variables
0123 %      to clear specific parts of structures
0124 
0125 if nargin==1 && ischar(command) && strcmp(command,'UNIT_TEST');
0126       do_unit_test; return; end
0127 
0128 global eidors_objects;
0129 if nargin<1
0130    fprintf('EIDORS_CACHE: current max memory = %.0f MB\n', ...
0131          eidors_objects.max_cache_size/(1024*1024)); 
0132    ww= whos('eidors_objects');
0133    fprintf('EIDORS_CACHE: cache memory used = %.0f MB\n', ...
0134          ww.bytes/(1024*1024)); 
0135    fprintf('EIDORS_CACHE: current priority = %d\n', ...
0136          eidors_objects.cache_priority); 
0137    return;
0138 elseif nargin > 1 
0139    limit = varargin{1};
0140 end
0141 
0142 
0143 % In order to do caching, we need to have an existing
0144 % function, as a string which exists as a function
0145 % handle.
0146 if isa(command, 'function_handle') || ...
0147   (ischar(command) && ...
0148    any(exist(command) == [2,3])) % m or mex-file
0149    % Test if we're being asked to cache on anonymous function
0150    %   and issue error
0151    if isa(command, 'function_handle')
0152       str = func2str(command);
0153       if str(1) == '@'
0154          error('Cannot cache anonymous functions');
0155       end
0156    end
0157    [varargout{1:nargout}] =  ...
0158            cache_shorthand(command, varargin{:});
0159    return
0160 end
0161 
0162     
0163 switch command
0164    case 'init'
0165       eidors_objects.cache_enable = 1;
0166       eidors_objects.cache_disabled_on = [];
0167       eidors_objects.cache_debug_enable = 0;
0168       eidors_objects.cache_debug_enabled_on = [];
0169       eidors_obj('cache_init');
0170       
0171    case 'clear_all'
0172       remove_objids
0173 
0174    case 'clear'
0175      switch nargin
0176        case 2
0177         eidors_cache('clear_name',limit);
0178        case 1
0179         eidors_cache('clear_all');
0180        otherwise
0181          error('Wrong number of inputs');
0182      end
0183       
0184    case 'cache_size'
0185       if nargin==2
0186       if ischar(limit); limit= str2num(limit); end
0187          eidors_objects.max_cache_size = limit;
0188       else
0189          varargout{1}= eidors_objects.max_cache_size;
0190       end
0191 
0192    case 'cache_path'
0193       if nargin == 1
0194          varargout{1}= eidors_objects.cache_path;
0195       else
0196          eidors_objects.cache_path = varargin{1};
0197       end
0198 
0199    case 'eidors_path'
0200       if nargin == 1
0201          varargout{1}= eidors_objects.eidors_path;
0202       else
0203          eidors_objects.eidors_path = varargin{1};
0204       end
0205    case {'disable' 'off'}
0206        if nargin == 1
0207            eidors_objects.cache_enable = 0;
0208            eidors_objects.cache_disabled_on = {};
0209        else
0210            eidors_objects.cache_enable = 0.5;
0211            if isfield(eidors_objects,'cache_disabled_on')
0212             if ~any(strcmp(eidors_objects.cache_disabled_on, limit))
0213                 eidors_objects.cache_disabled_on = [...
0214                     eidors_objects.cache_disabled_on; {limit}];
0215             end
0216            else
0217                eidors_objects.cache_disabled_on =  {limit};
0218            end
0219        end
0220    case {'enable' 'on'}
0221        if nargin == 1
0222            eidors_objects.cache_enable = 1;
0223            eidors_objects.cache_disabled_on = {};
0224        else
0225            if isfield(eidors_objects,'cache_disabled_on')
0226                idx = strcmp(eidors_objects.cache_disabled_on, limit);
0227                eidors_objects.cache_disabled_on(idx) = [];
0228            else 
0229                eidors_objects.cache_disabled_on = [];
0230            end
0231            if isempty(eidors_objects.cache_disabled_on)
0232                eidors_objects.cache_enable = 1;
0233            end
0234        end
0235    case 'status'
0236       if nargin == 1
0237          try
0238             varargout{1} = eidors_objects.cache_enable;
0239          catch
0240             varargout{1} = 1;
0241          end
0242       else
0243          if isfield(eidors_objects,'cache_disabled_on')
0244             idx = strcmp(eidors_objects.cache_disabled_on, limit);
0245             varargout{1} = double(~any(idx));
0246          end
0247       end
0248    case 'debug_status'
0249       if nargin == 1
0250          varargout{1} = eidors_objects.cache_debug_enable;
0251       else
0252          if isfield(eidors_objects,'cache_debug_enabled_on')
0253             idx = ismember(limit,eidors_objects.cache_debug_enabled_on);
0254             varargout{1} = idx | eidors_objects.cache_debug_enable==1;
0255          end
0256       end
0257    case 'debug_on'
0258        if nargin == 1
0259            eidors_objects.cache_debug_enable = 1;
0260            eidors_objects.cache_debug_enabled_on = {};
0261        else
0262            eidors_objects.cache_debug_enable = 0.5;
0263            if isfield(eidors_objects,'cache_debug_enabled_on')
0264             if ~any(strcmp(eidors_objects.cache_debug_enabled_on, limit))
0265                 eidors_objects.cache_debug_enabled_on = [...
0266                     eidors_objects.cache_debug_enabled_on; {limit}];
0267             end
0268            else
0269                eidors_objects.cache_debug_enabled_on =  {limit};
0270            end
0271        end
0272    case 'debug_off'
0273       if nargin == 1
0274          eidors_objects.cache_debug_enable = 0;
0275          eidors_objects.cache_debug_enabled_on = {};
0276       else
0277          if isfield(eidors_objects,'cache_debug_enabled_on')
0278             idx = strcmp(eidors_objects.cache_debug_enabled_on, limit);
0279             eidors_objects.cache_debug_enabled_on(idx) = [];
0280          else
0281             eidors_objects.cache_debug_enabled_on = [];
0282          end
0283          if isempty(eidors_objects.cache_debug_enabled_on)
0284             eidors_objects.cache_debug_enable = 0;
0285          end
0286       end
0287    case 'boost_priority'
0288       try
0289          varargout{1}= eidors_objects.cache_priority;
0290       catch
0291          varargout{1}= 0; % default priority
0292       end
0293       if nargin==2
0294       if ischar(limit); limit= str2double(limit); end
0295          varargout{1} = varargout{1} + limit;
0296       end
0297       eidors_objects.cache_priority = varargout{1};
0298 
0299    case {'list', 'show_objs'} 
0300       if nargin == 2 
0301          cache_list(limit);
0302       else
0303          cache_list;
0304       end
0305       
0306       
0307    case 'clear_max'
0308       if ischar(limit); limit= str2double(limit); end
0309       try
0310          c = eidors_objects.cache.cols;
0311       catch 
0312          return
0313       end
0314       
0315       priidx = get_cache_priority;
0316       [jnk, idx] = sort(priidx);
0317       tot=     cumsum([eidors_objects.cache.meta{idx,c.size}]); 
0318       rmidx  = idx(tot > limit);
0319       remove_objids( rmidx );
0320 
0321    case 'clear_old'
0322       if ischar(limit); limit= str2num(limit); end
0323       try
0324          c = eidors_objects.cache.cols;
0325       catch
0326          return
0327       end
0328       idx = find([eidors_objects.cache.meta{:,c.time}] < limit);
0329       remove_objids( idx );
0330 
0331    case 'clear_new'
0332       if ischar(limit); limit= str2num(limit); end
0333       try
0334          c = eidors_objects.cache.cols;
0335       catch
0336          return
0337       end
0338       idx = find([eidors_objects.cache.meta{:,c.time}] > limit);
0339       remove_objids( idx );
0340 
0341    case 'clear_model_library'
0342       %TODO: add ways to select what to delete
0343       delete([eidors_objects.model_cache,'/*.mat']);
0344 
0345    case 'clear_name'
0346       idx = clear_names_cache( limit );
0347       remove_objids( idx );
0348       
0349    case 'dump'
0350       varargout{1} = eidors_objects;
0351       
0352    case 'load'
0353       eidors_objects = limit;
0354       
0355    otherwise
0356       error('command %s not understood',command);
0357 end
0358 
0359 function cache_list (order)
0360    global eidors_objects;
0361    try
0362       meta = eidors_objects.cache.meta;
0363    catch
0364       return
0365    end
0366    if nargin == 0
0367        order = 'time';
0368    end
0369    
0370    c = eidors_objects.cache.cols;
0371    if isempty(meta)
0372       fprintf('No objects in cache\n');
0373       return
0374    end
0375    meta(:,c.time) = cellstr(datestr([meta{:,c.time}],'yyyy-mm-dd HH:MM:SS.FFF'));
0376    N = size(meta,2);
0377    %    [jnk, priidx] = sortrows(meta(:,[c.score_eff c.score_sz c.time]),[-1 2 -3]);
0378    
0379    meta(:,N+1) = num2cell(get_cache_priority);
0380    switch order
0381        case 'time'
0382            meta = mysortrows(meta,c.time); % sort by time
0383        case {'prop','name'}
0384            meta = mysortrows(meta,c.prop); % sort by name
0385        case 'rank'
0386            meta = mysortrows(meta,N+1); % sort by rank
0387        case 'size'
0388            meta = mysortrows(meta,-c.size); % sort by rank
0389        case 'effort'
0390            meta = mysortrows(meta,-c.effort);
0391        case 'count'
0392            meta = mysortrows(meta,-c.count);
0393        otherwise
0394            error('Unrecognized sort order');
0395    end
0396    
0397    meta = meta';
0398    fprintf('CACHE__:  Date+Time     bytes       Score_szPrio CountXEffort   Score_eff   #  obj_id ___\n');
0399    fprintf('%s b=%9.0d [%4d]  p=%02d t=%3dx%.2e [%4d] i=%4d: %s { %s }\n', ...
0400       meta{[c.time,c.size,c.score_sz,c.prio,c.count,c.effort,c.score_eff,N+1,c.obj_id, c.prop],:});
0401 
0402 function priidx = get_cache_priority
0403    global eidors_objects;
0404    priidx = [];
0405    if isfield(eidors_objects.cache, 'meta') && isfield(eidors_objects.cache, 'cols')
0406       meta = eidors_objects.cache.meta;
0407       c = eidors_objects.cache.cols;
0408       [jnk, priidx] = mysortrows(meta,[-c.score_eff c.score_sz -c.time]);
0409       priidx(priidx) = 1:size(meta,1);
0410    end
0411 
0412       
0413    
0414 function objid = clear_names_cache( name )
0415    objid=[];
0416    global eidors_objects;
0417    try
0418       c = eidors_objects.cache.cols;
0419       objid = find(strcmp(name, eidors_objects.cache.meta(:,c.prop)));
0420    end
0421    
0422    
0423 function remove_objids(idx, names, sizes)
0424    global eidors_objects;
0425    try
0426    c = eidors_objects.cache.cols;
0427    catch
0428       eidors_obj('cache_init'); 
0429       return % nothing else to do
0430    end
0431    if nargin == 0
0432       idx = 1:size(eidors_objects.cache.meta,1);
0433    end
0434    if isempty(idx)
0435       return
0436    end
0437    switch eidors_cache('debug_status')
0438       case 1
0439          debug_msg(  eidors_objects.cache.meta(idx,c.obj_id), ...
0440                      eidors_objects.cache.meta(idx,c.prop), 'removed');
0441       case 0.5
0442          db = eidors_cache('debug_status', eidors_objects.cache.meta(idx,c.prop));
0443          debug_msg(  eidors_objects.cache.meta(idx(db),c.obj_id), ...
0444                      eidors_objects.cache.meta(idx(db),c.prop), 'removed');
0445    end
0446    total_size = sum(cell2mat(eidors_objects.cache.meta(idx,c.size)));   
0447    N = numel(idx);
0448    if numel(idx) == size(eidors_objects.cache.meta,1)
0449       eidors_objects = rmfield(eidors_objects,'cache');
0450       eidors_obj('cache_init');
0451    else
0452       eidors_objects.cache = rmfield(eidors_objects.cache, ...
0453          eidors_objects.cache.meta(idx,c.obj_id));
0454       eidors_objects.cache.meta(idx,:) = [];
0455       eidors_objects.cache.size = eidors_objects.cache.size - total_size;
0456    end
0457    
0458    eidors_msg('Removed %d objects with %d bytes from cache', ...
0459       N, total_size, 2 );
0460    
0461        
0462 %   v1 = eidors_cache( @function_handle, {param1, param2, ...})
0463 function varargout = cache_shorthand(fhandle, varargin)
0464 % Will cache on all function inputs, unless opt.cache_obj is specified
0465    args = varargin{1};
0466    if ~iscell(args)
0467       args = {args};
0468    end
0469    
0470    if nargin >2
0471       opt = varargin{2};
0472    else
0473       opt = struct;
0474    end
0475    if ischar(opt)
0476       fstr = opt; clear opt;
0477       opt.fstr = fstr;
0478    end
0479    if isfield(opt, 'cache_obj');
0480       cache_obj = opt.cache_obj;
0481       if ~iscell(cache_obj)
0482          cache_obj = {cache_obj};
0483       end
0484    else
0485       cache_obj = args;
0486    end
0487    try
0488       fstr = opt.fstr;
0489    catch
0490       fstr = func2str(fhandle);
0491    end
0492    if isfield(opt, 'log_level')
0493        level_in = opt.log_level;
0494        level_out = opt.log_level;
0495    else
0496        level_in = 4;
0497        level_out = 3;
0498    end
0499    cache_to_disk = false;
0500    if isfield(opt, 'cache_to_disk')
0501        cache_locn    = opt.cache_to_disk;
0502        if cache_locn
0503           cache_to_disk = true;
0504        end
0505        if cache_locn==true
0506           cache_locn = '.';
0507        end
0508        if isfield(opt,'fstr')
0509           cache_str = opt.fstr;
0510        else
0511           cache_str = 'eidors_cache';
0512        end
0513    end
0514    if ~isfield(opt, 'cache_on_ng_opt')
0515        opt.cache_on_ng_opt = false;
0516    end
0517    if opt.cache_on_ng_opt
0518      cache_obj{end+1} = cache_ng_opt_bytes();
0519    end
0520 
0521    [varargout,obj_id] = eidors_obj('get-cache', cache_obj, fstr );
0522    if length(varargout)==0 && cache_to_disk % if not in memory cache
0523        savename = [cache_locn,'/',cache_str,'_',obj_id,'.mat'];
0524        if exist(savename,'file')
0525           load(savename)
0526        end  
0527    end
0528    if numel(varargout) < nargout
0529       eidors_msg('@@ (Re)calculating %s',fstr, level_in);
0530       t0 = tic;
0531       clear varargout; % to ensure it still runs on older MLs (e.g. R2012b)
0532       [varargout{1:nargout}] =  ...
0533                feval(fhandle, args{:});
0534       t = toc(t0);
0535       if isfield(opt,'boost_priority');
0536          eidors_cache('boost_priority',opt.boost_priority);
0537       end
0538       
0539 
0540       if cache_to_disk
0541          eidors_msg('@@ Caching to %s', savename, level_in+1);
0542          save(savename,'varargout','-V7'); % -V7 for octave support
0543       else
0544          eidors_obj('set-cache', cache_obj, fstr, varargout, t);
0545       end
0546       
0547       if isfield(opt,'boost_priority');
0548          eidors_cache('boost_priority',-opt.boost_priority);
0549       end
0550       return
0551    end
0552    eidors_msg('%s: Using cached value',fstr,level_out);
0553 
0554 function bytes = cache_ng_opt_bytes
0555    if ~exist('ng.opt');
0556       bytes = []; return
0557    end
0558    fid = fopen('ng.opt','rb');
0559    bytes = char(fread(fid,[1,inf],'uint8'));
0560    fclose(fid);
0561 
0562 % replace meshsizefilename with contents
0563    mszstr = 'options.meshsizefilename  ';
0564    ff = strfind(bytes,mszstr);
0565    if isempty(ff); return; end
0566    if length(ff)>1 
0567       eidors_msg('Unexpected bug. Check ng.opt writer',1);
0568    end
0569    bytescut(1) = ff(1)+length(mszstr);
0570    ff = strfind(bytes(bytescut(1):end),'.msz');
0571    if length(ff)==0;
0572       return % empty meshsizefilename. That's OK.
0573    end
0574    bytescut(2) = bytescut + ff(1) + 2;
0575    mszfile = bytes(bytescut(1):bytescut(2));
0576    fid = fopen(char(mszfile),'rb');
0577    if fid>0
0578        bytes2= char(fread(fid,[1,inf],'uint8'));
0579        fclose(fid);
0580    else
0581        bytes2 = '';
0582        eidors_msg('Warning. no MSZ file %s',mszfile,1);
0583    end
0584    % Must be int8 ... matlab does some very slow
0585    % lookups in eidors_var_id for char
0586    bytes = int8(...
0587            [bytes(1:bytescut(1)-1), ...
0588             bytes2, ...
0589             bytes(bytescut(2)+3)]);
0590 
0591 function debug_msg(id,name,action)
0592 global eidors_objects;
0593 if nargin < 3 
0594    action = name;
0595    name = fieldnames(eidors_objects.(id));
0596 end
0597 if isempty(id), return, end
0598 if ~iscell(name) name = {name}; end
0599 if ~iscell(id) id = {id}; end
0600 
0601 str = sprintf('EIDORS_CACHE: %s %%s { %%s }\\n', action);
0602 arr = [id, name]'; 
0603 
0604 fprintf(str, arr{:});
0605 % dbstack could be useful too
0606 
0607 function do_unit_test   
0608    ll= eidors_msg('log_level');
0609    eidors_msg('log_level',5);
0610    eidors_cache
0611    eidors_cache('clear_all');
0612    eidors_cache
0613    eidors_obj('set-cache', rand(1) , 't1', rand(2e3));
0614    eidors_obj('set-cache', rand(1) , 't2', rand(2e3));
0615    eidors_obj('set-cache', rand(1) , 't3', rand(2e3));
0616    eidors_cache
0617    eidors_cache list
0618    eidors_cache('clear_name','t3');
0619    eidors_cache
0620    eidors_cache list
0621    eidors_cache('clear_max', 34e6);
0622    eidors_cache
0623    eidors_cache('boost_priority', 1);
0624    eidors_cache
0625    eidors_cache('boost_priority', -1);
0626    eidors_cache
0627    [v1] = eidors_cache(@test_function,{3,4});
0628    [v2] = eidors_cache(@test_function,{3,4});
0629    unit_test_cmp('shorthand 1 param:',v1,v2);
0630    [v3 v4] = eidors_cache(@test_function,{3,4});
0631    unit_test_cmp('Expect Fail', v3, v4,-inf);
0632    [v5 v6 ] = eidors_cache(@test_function,{3,4});
0633    unit_test_cmp('shorthand 2 params:',v4, v6);
0634    [v5 v6 ] = eidors_cache(@test_function,{3,4, 5}); %this should re-calc
0635    opt.cache_obj = 5;
0636    [v5 v6 ] = eidors_cache(@test_function,{3,4, 5}, opt); %this should re-calc
0637    [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt); %this should NOT
0638    unit_test_cmp('shorthand cache_obj:',v6, v8);
0639    eidors_cache clear_all
0640    opt = struct;
0641    [v7 v8 ] = eidors_cache(@test_function,{1,2, 3}, opt); %this should NOT
0642    opt.boost_priority = 2;
0643    [v7 v8 ] = eidors_cache(@test_function,{3,4, 5}, opt); %this should NOT
0644    eidors_cache show_objs
0645    eidors_cache
0646    eidors_msg('log_level',ll);
0647    try
0648       eidors_cache(@(x) x^2, 3);
0649    catch
0650       eidors_msg('Error on anonymous function: correct',2);
0651    end
0652    test_debug
0653    test_priority
0654    test_disk_caching
0655  
0656 function [v1 v2] = test_function(a,b,c,d)
0657    v1 = rand(1);
0658    v2 = rand(1);
0659    
0660 function [meta,idx] = mysortrows(meta, cols)
0661    if ~exist('OCTAVE_VERSION') % octave doesn't sort cells (valid jun 2019)
0662       [meta,idx] = sortrows(meta, cols);
0663    else
0664       metm = cell2mat(meta(:,3:end));
0665       cols = ( abs(cols) - 2 ) .* sign(cols);
0666       [~,idx] = sortrows(metm, cols);
0667       meta = meta(idx,:);
0668    end
0669 
0670 
0671 function test_debug
0672    fprintf('\n\n************************\n        CACHE DEBUG: VERBOSE OUTPUT\n************************\n');
0673    eidors_cache clear
0674    eidors_obj('set-cache',{5}, 'test1',50);
0675    eidors_obj('set-cache',{5}, 'test2',500);
0676    eidors_obj('set-cache',{10}, 'test1',100);
0677    eidors_cache show_objs
0678    eidors_cache debug_off
0679    eidors_cache debug_on test2
0680    eidors_cache clear_name test2
0681    eidors_cache show_objs
0682 %    eidors_obj('set-cache',{5}, 'test1',50);
0683    eidors_obj('set-cache',{5}, 'test2',500);
0684    eidors_cache debug_off
0685    eidors_cache debug_on test1
0686    eidors_cache clear_name test2
0687    eidors_cache('clear_max',0)
0688    eidors_cache('show_objs')
0689    eidors_cache debug_off
0690    fprintf('\n\n************************\n        CACHE DEBUG: DEBUG FINISHED\n************************\n');
0691    
0692 function test_disk_caching
0693    tstdir = 'eidors_cache_test_dir1234321';
0694    [~]=rmdir(tstdir,'s');
0695    [~]=mkdir(tstdir);
0696    disp('============= DISK =============');
0697    opt = struct('cache_to_disk',tstdir);
0698    eidors_cache clear; global eidors_objects
0699    esz = length(fieldnames(eidors_objects.cache));
0700    unit_test_cmp('disk 00',length(dir([tstdir,'/*.mat'])),0)
0701    [v1]= eidors_cache( @sin, {1:100},opt);
0702    unit_test_cmp('disk 01',length(dir([tstdir,'/*.mat'])),1)
0703    unit_test_cmp('disk 02',0, ...
0704       length(fieldnames(eidors_objects.cache))-esz);
0705    obj_id = eidors_var_id({1:100,'sin'});
0706    cfname = [tstdir,'/eidors_cache_',obj_id,'.mat'];
0707    unit_test_cmp('disk 03',length(dir(cfname)),1); 
0708    loader = load(cfname);
0709    unit_test_cmp('disk 04',loader.varargout{1},v1);
0710 
0711    [v1]= eidors_cache( @sin, {1:100},opt);
0712    unit_test_cmp('disk 05',length(dir([tstdir,'/*.mat'])),1)
0713    unit_test_cmp('disk 06',0, ...
0714       length(fieldnames(eidors_objects.cache))-esz);
0715    loader = load(cfname);
0716    unit_test_cmp('disk 07',loader.varargout{1},v1);
0717    [~]=rmdir(tstdir,'s');
0718    disp('============= ~DISK =============');
0719    eidors_cache clear; global eidors_objects
0720    opt = struct('cache_to_disk',false);
0721    esz = length(fieldnames(eidors_objects.cache));
0722    [v1]= eidors_cache( @sin, {1:100},opt);
0723    unit_test_cmp('not disk 01',1, ...
0724       length(fieldnames(eidors_objects.cache))-esz);
0725    obj_id = eidors_var_id({1:100,'sin'});
0726    unit_test_cmp('not disk 02',1, ...
0727       length(fieldnames(eidors_objects.cache))-esz);
0728    unit_test_cmp('not disk 03',isfield(eidors_objects.cache,obj_id),1);
0729    unit_test_cmp('not disk 04',eidors_objects.cache.(obj_id),[v1]);
0730 
0731    [v1]= eidors_cache( @sin, {1:100},opt);
0732    unit_test_cmp('not disk 05',1, ...
0733       length(fieldnames(eidors_objects.cache))-esz);
0734 
0735    
0736 function test_priority
0737    eidors_cache clear
0738    eidors_obj('set-cache',{1}, 'slow_small', zeros(10) ,10); pause(.1)
0739 %    eidors_cache list
0740 %    fprintf('\n');
0741    eidors_obj('set-cache',{1}, 'slow_new',   zeros(100),10); pause(.1)
0742 %    eidors_cache list
0743 %    fprintf('\n');
0744    eidors_obj('set-cache',{1}, 'slow_big1',  zeros(100),10); pause(.1)
0745 %    eidors_cache list
0746 %    fprintf('\n');
0747    eidors_obj('set-cache',{1}, 'slow_big2',  zeros(100),20); pause(.1)
0748 %    eidors_cache list
0749 %    fprintf('\n');
0750    eidors_obj('set-cache',{1}, 'fast_small', zeros(2)  , 1); pause(.1)
0751 %    eidors_cache list
0752 %    fprintf('\n');
0753    eidors_obj('set-cache',{1}, 'fast_big',   zeros(100), 1); pause(.1)
0754 %    eidors_cache list
0755 %    fprintf('\n');
0756    eidors_obj('get-cache',{1}, 'slow_new'); 
0757    
0758    eidors_cache list
0759 
0760    
0761 %    obj= eidors_obj('get-cache',{5}, 'test1');

Generated on Fri 30-Dec-2022 19:44:54 by m2html © 2005