删除不必要的日常呼叫
最近我读了一篇文章关于加速功能实验后的博客。我将使用发布2020A借此机会,使用更新的探查器来调查性能,特别是对于函数函数宏指令。
内容
代码 - 尝试1
我有一个简单的文件来评估一堆点的函数,以便稍后可以使用值,或许是绘图。这是代码。
功能[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,nsteps,lims)%原油辅助函数准备绘图功能值%%的例子:%fh = @(x)sqrt(abs(sin(x。^ 2 + 17)));%[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,50000,[0,pi]);%的阴谋(ptsToPlot vals)%参数跳频(1,1)function_handle;Nsteps (1,1) double = 100000;Lims (1,2) double = [-pi, pi];结尾sm = min (lims);lg = max (lims);%nsteps + 1 =要创建的点数。1 / n有助于确定步骤。%100000远远超过我们需要的点,但我想做一堆%有意义的计算,以便我们获得合理的阅读。得到要绘制的点的x轴。PTSTOPLOL =(SM:((LG-SM)/ NSTEPS):LG)';%compute输出在循环中使用feval。为了IND = 1:长度(PTSTOPLOT)vals(IND,1)= FEVAL(FH,PTSTOPLOL(IND));结尾
我正在使用家庭工具系列的运行和时间功能在此处测量。
我会用同一个输入 - 公平的公平称呼这个函数的所有变体!首先,我将设置参数。
Nsteps = 50000;Lims = [0 pi];
然后,下一步在Profiler右侧的运行和时间窗口左侧的文本框中运行以下代码:
[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,nsteps,lims);
之后我们会看到这个
花了0.034秒。否则,这不是如此有用,所以我点击顶部的火焰图中的函数的名称,看看我的文件中发生了什么。
显示我在打27号线函数宏指令, 多次。进一步滚动,我从代码分析仪结果获取更多信息。
它注意到我没有预先采用输出矢量,虽然看起来我应该知道尺寸。
旁白:注意the的用法参数块用于错误检查。
代码 - 尝试2
接下来,我们会看到当我预配输出的向量时会发生什么。
功能[ptsToPlot,瓦尔斯]=...mycrudeplothelperpreallocloopfeval(fh,nsteps,lims)%原油辅助函数准备绘图功能值%%的例子:%fh = @(x)sqrt(abs(sin(x。^ 2 + 17)));%[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,50000,[0,pi]);%的阴谋(ptsToPlot vals)%参数跳频(1,1)function_handle;Nsteps (1,1) double = 100000;Lims (1,2) double = [-pi, pi];结尾sm = min (lims);lg = max (lims);%nsteps + 1 =要创建的点数。1 / n有助于确定步骤。%100000远远超过我们需要的点,但我想做一堆%有意义的计算,以便我们获得合理的阅读。得到要绘制的点的x轴。PTSTOPLOL =(SM:((LG-SM)/ NSTEPS):LG)';%compute输出在循环中使用feval。瓦尔斯= 0(大小(ptsToPlot));为了IND = 1:长度(PTSTOPLOT)vals(IND,1)= FEVAL(FH,PTSTOPLOL(IND));结尾
时间缩短到0.026秒。
代码 - 尝试3
接下来我想完全失去循环,看看会发生什么。
功能[ptsToPlot, vals] = myCrudePlotHelperFeval(fh,Nsteps,lims) / /上传文件%原油辅助函数准备绘图功能值%%%的例子:%fh = @(x)sqrt(abs(sin(x。^ 2 + 17)));%[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,50000,[0,pi]);%的阴谋(ptsToPlot vals)%参数跳频(1,1)function_handle;Nsteps (1,1) double = 100000;Lims (1,2) double = [-pi, pi];结尾%%检查输入参数-应该是1或2。第二点应该是实值%2元素矢量。如果Nargin < 1错误(“没有足够的输入参数。”)elseifnargin == 1 lims = [-pi,pi];别的如果长度(lims)〜= 2 ||〜Isreal(LIMS)错误("第二个输入必须是2元实向量")结尾结尾sm = min (lims);lg = max (lims);% N+1 =要创建的点数。1 / n有助于确定步骤。%100000远远超过我们需要的点,但我想做一堆%有意义的计算,以便我们获得合理的阅读。N = 100000;得到要绘制的点的x轴。ptsToPlot = (sm ((lg-sm) / N): lg) ';%做一个矢量化的周期,和一个没有周期的矢量化评估。val = feval(fh, ptsToPlot);
时间缩短到0.015秒。调用函数一次而不是Nsteps次数是值得的!
代码 - 尝试4
现在我要删除调用函数宏指令完全没有必要在很长一段时间内调用函数处理。
功能[ptsToPlot, vals] = myCrudePlotHelperNoFeval(fh,Nsteps,lims)%原油辅助函数准备绘图功能值%%的例子:%fh = @(x)sqrt(abs(sin(x。^ 2 + 17)));%[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,50000,[0,pi]);%的阴谋(ptsToPlot vals)%参数跳频(1,1)function_handle;Nsteps (1,1) double = 100000;Lims (1,2) double = [-pi, pi];结尾sm = min (lims);lg = max (lims);%nsteps + 1 =要创建的点数。1 / n有助于确定步骤。%100000远远超过我们需要的点,但我想做一堆%有意义的计算,以便我们获得合理的阅读。得到要绘制的点的x轴。PTSTOPLOL =(SM:((LG-SM)/ NSTEPS):LG)';%计算矢量化的评价没有时间。vals = fh(ptstoplot);
我们现在将时间减少到0.013 - 与具有预先分配的其他版本相比,没有戏剧性。但在早期的那些方面有很大改善。
讨论
我关心开销的原因是函数宏指令有些时候我们在做一些适应性或迭代性的计算。在这种情况下,我们无法在一次调用中完成所有计算。因此,我试图从基本计算中挤出尽可能多的性能,这样多余的不必要的东西就不会占主导地位。
这是我的最终比较,在循环中有一个预曝气变量,没有函数宏指令。
功能[ptsToPlot,瓦尔斯]=...mycrudeplothelperpreallocloopfeval(fh,nsteps,lims)%原油辅助函数准备绘图功能值%%的例子:%fh = @(x)sqrt(abs(sin(x。^ 2 + 17)));%[ptstoplot,vals] = mycrudeplothelperloopfeval(fh,50000,[0,pi]);%的阴谋(ptsToPlot vals)%参数跳频(1,1)function_handle;Nsteps (1,1) double = 100000;Lims (1,2) double = [-pi, pi];结尾sm = min (lims);lg = max (lims);%nsteps + 1 =要创建的点数。1 / n有助于确定步骤。%100000远远超过我们需要的点,但我想做一堆%有意义的计算,以便我们获得合理的阅读。得到要绘制的点的x轴。PTSTOPLOL =(SM:((LG-SM)/ NSTEPS):LG)';%compute输出在循环中使用feval。瓦尔斯= 0(大小(ptsToPlot));为了val (ind,1) = fh(ptsToPlot(ind)); / /输入长度结尾
中间是时间,0.024秒
如此大量的增长,但有些收益,可能有价值,以删除开销函数宏指令。
这可能在您的代码中的某些计算瓶颈中有所不同吗?让我们知道在这里。
评论
要留下评论,请点击在这里登录到您的MathWorks帐户或创建一个新帐户。