Matlab获取属性函数导致性能问题

时间:2011-08-01 23:40:28

标签: performance oop matlab profiling getter

我在我创建的一个类中有一个属性,它当前有一个与之关联的不必要的get函数。我最初在返回值之前做了有用的事情,但现在我只需要属性值,所以get函数已经减少到了这个:

    function value =  get.error(obj)
        value = obj.error;
    end

现在,看到这段代码完全是多余的,我决定一起删除get函数,但这导致我的代码的一部分中出现令人难以置信的减速,其中'error'属性是反复访问。

在这部分代码中,探查器明确地说缺少的get函数是导致问题的原因(它表示所有的时间都浪费在a'的'end'处。 'for'loop),但当我重新添加功能无用的代码时,性能问题就消失了。

为什么删除这个无用的get函数会减慢我的代码?

编辑:我已经将问题隔离到足以发布一些代码示例。

这是方法调用的虚拟版本,它有以下问题: enter image description here

这是没有无用getter的代码配置文件: enter image description here

和魔法无用的吸气剂: enter image description here

请注意,性能要求如下:

  1. 将计算集中我的'pool'对象的某些属性用于任何变量。 'error'属性引起了我的注意,但是在相同情况下所有属性都会出现bug。

  2. 计算涉及任何事情,甚至'。* 0'导致这种减速,但设置的单个术语是免费减速的(例如obj.pools(i).delta = obj.pools(i).error)

  3. 编辑2:

    这是完整的池类;也许它会有所帮助:

    classdef pool < handle
    
    properties
        name;
        unit_count;
        activation;
        net_input = 0;
        %all projections now incoming
        projections = [];
        error; % same is dEd net for rbp
        target;
        clamped_error = false;
        delta;
        clamped_activation = 0; %0 no clamp, 1 soft clamp, 2 hard clamp
        copyback = false;
        copy_from;
        type = 'hidden';
    
        activation_history;
        error_history;
    
    end
    
    methods
        function obj = pool(name,count,type,copy_from)
            obj.name = name;
            assignin('caller', name, obj);
            obj.unit_count = count;
            obj.error = zeros(1,count);
            obj.target = zeros(1,count);
            obj.delta = zeros(1,count);
            obj.activation = zeros(1,count);
            obj.net_input = zeros(1,count);
            obj.activation_history(:,1) = zeros(1,count);
            obj.error_history(:,1) = zeros(1,count);
            if nargin > 2
                obj.type = type;
                if nargin == 4
                    obj.clamped_activation = 2;
                    obj.activation = ones(1,count)/2;
                    obj.copy_from = copy_from;
                    obj.copyback = true;
                end
            else
                obj.type = 'hidden';
            end
            switch obj.type
                case 'input'
                    obj.clamped_activation = 2;
                case 'output'
                    obj.clamped_error = true;
                case 'bias'
                    obj.clamped_activation = 2;
                    obj.activation = 1;
                case 'hidden'
            end
    
        end
    
        function proj = connect(obj,send_pool,proj_var)
            %see if you need a new projection or if the user provided one
    
            if nargin == 2
                proj = projection(obj, send_pool);
            else
                proj = proj_var;
            end
            obj.projections = [obj.projections struct('from',send_pool,'using',proj)];
        end
    
    
        function value =  get.error(obj)
            value = obj.error;
        end
    
    end
    
    end
    

1 个答案:

答案 0 :(得分:1)

这听起来像Matlab JIT或解释器怪异。

您可能正在查看与MCOS内存管理相关的Matlab错误,如Dataset array indexing is very slow with Statistics Toolbox中所述。在某些情况下,在引用其字段时,该错误看起来会导致虚假的深层复制对象。如果池对象中有单元数组或其他复杂结构,则可能会导致类似行为 - 它们会被复制到新变量中,并且可能会在“结束”处显示释放成本。

我能够在几个Matlab版本中重现类似的令人惊讶的缓慢结果。但是我无法表现出与吸气剂的存在有任何区别。

档案fooclass.m。

classdef fooclass
    properties
        error = 42;
        whatever = 42;
        delta = 1;
        bigjunk = num2cell(rand(1000,40));
        %bigjunk = rand(1000,10000);  % non-cell does not cause slowdown
    end

    methods        
%         function out = get.error(obj)
%             out = obj.error;
%         end
    end

end

文件looper.m。

classdef looper
    properties
        pools
    end

    methods
        function obj = looper()
            obj.pools = repmat(fooclass(), [1 5]);;
        end

        function weird(obj)
        p = obj.pools;
        n = numel(p);
        for i = 1:n
            dummy = obj.pools(i).error .* 0;
        end
        end
    end
end

重现:

>> lp = looper;
>> tic; for i = 1:100; weird(lp); end; toc
Elapsed time is 0.600428 seconds.

这是我在64位Windows 7上的R2011a(预发行版)。这很慢。时间与bigjunk的大小成正比,而探查者说它几乎都发生在p = obj.pools行。这表明对象引用导致副本而不是像它应该的那样使用写时复制优化。或者它正在走对象图或其他东西。您的代码可能会发生类似情况。

最好只是将它用于解释怪异,如果它能使你的代码更快,那么将getter留在那里,并在下一个版本中等待修复。听起来值得提交给MathWorks作为错误报告。