开发区域

高级软件开发与MATLAB

继续游泳

还记得海鲂吗?

图片来源:Silvio Tanaka [CC 2.0],通过维基共享

在困境中坚持不懈的榜样,在浩瀚的海洋中欢闹而自由奔放的鱼儿,我们可爱的尼莫的养母,那个多莉?

她走在了时代的前面。谁知道她明智的建议的智慧,就继续游泳。

当我们进行性能测试时,我们有时需要一点这种方法。具体地说,当我们测量代码太快时,我们需要保持“游泳”(这么说吧)。例如,让我们以最后发表(CQ的矩阵库)。我们在这里编写的性能测试如下所示:

classdeftMatrixLibrary < matlab.perftest.TestCase属性TestMatrix = struct(“中型”,魔法(600),...“largeSize”魔法(1000));结束方法(测试)函数testSum (testCase TestMatrix) matrix_sum (TestMatrix);结束函数testMean (testCase TestMatrix) matrix_mean (TestMatrix);结束函数testCase. assertreturnstrue (@() size(TestMatrix,1) == size(TestMatrix,2),...Eig只适用于方阵);testCase.startMeasuring;matrix_eig (TestMatrix);testCase.stopMeasuring;结束结束结束

这里您可以看到,我们针对一个“中型”问题和一个“大型”问题进行了测试。然而,便利的缺失是一个“小尺寸”的问题。这是为什么呢?那我们为什么不加一个…

classdeftMatrixLibrary_v2 < matlab.perftest.TestCase属性TestMatrix = struct(“适用的”,魔法(100),“中型”,魔法(600),...“largeSize”魔法(1000));结束方法(测试)函数testSum (testCase TestMatrix) matrix_sum (TestMatrix);结束函数testMean (testCase TestMatrix) matrix_mean (TestMatrix);结束函数testCase. assertreturnstrue (@() size(TestMatrix,1) == size(TestMatrix,2),...Eig只适用于方阵);testCase.startMeasuring;matrix_eig (TestMatrix);testCase.stopMeasuring;结束结束结束

...随着一个快速函数来检查结果的有效性,我们将发现:

函数checkResults(结果)disp dispFrame(换行符)如果~ ([results.Valid]) disp (“哦,不,多莉,有些尺寸是无效的!”其他的disp (“谢谢你,多莉,你最棒了!”我们的测量结果都不错。”结束dispFrame结束函数dispFrame disp (':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::');结束
结果= runperf (“tMatrixLibrary_v2”);checkResults(结果)
运行tMatrixLibrary_v2……================================================================================ tMatrixLibrary_v2 / testSum (TestMatrix =适用)过滤。测试诊断:测量的时间不应该太接近框架的精度。================================================================================ .. .......... .......... .......... .......================================================================================ tMatrixLibrary_v2 / testMean (TestMatrix =适用)过滤。测试诊断:测量的时间不应该太接近框架的精度。================================================================================ ... .......... .......... .......... .......... . 警告:目标相对误差不满足运行后MaxSamples tMatrixLibrary_v2 / testMean (TestMatrix = largeSize ). ......... .......... .....完成tMatrixLibrary_v2  __________ 失败失败总结:名字不完整的原因(s ) =============================================================================================== tMatrixLibrary_v2 / testSum (TestMatrix =适用)X过滤的假设。----------------------------------------------------------------------------------------------- tMatrixLibrary_v2 / testMean (TestMatrix =适用)X过滤的假设。::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 哦没有平底小渔船,一些测量是无效的! :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

哦,看起来不太理想。看起来我们的一些小尺寸测量是无效的。它们是无效的,因为框架认识到代码执行时间与框架的可测量精度太接近了。框架能够确定这将是一个垃圾度量,因此它不会冒险提供坏数据,而是主动过滤过快的测试,并将结果标记为无效。我还是想测量这个快速的情况,我们该怎么做?通常情况下,我们看到人们用静态代码包装他们的代码循环,就像这样:

classdeftMatrixLibrary_v3 < matlab.perftest.TestCase属性TestMatrix = struct(“适用的”,魔法(100),“中型”,魔法(600),...“largeSize”魔法(1000));结束方法(测试)函数testSum (testCase TestMatrix)idx = 1:1000 matrix_sum(TestMatrix);结束结束函数testMean (testCase TestMatrix)idx = 1:1000 matrix_mean(TestMatrix);结束结束函数testCase. assertreturnstrue (@() size(TestMatrix,1) == size(TestMatrix,2),...Eig只适用于方阵);testCase.startMeasuring;matrix_eig (TestMatrix);testCase.stopMeasuring;结束结束结束
结果= runperf (“tMatrixLibrary_v3”);checkResults(结果)
运行tMatrixLibrary_v3  .......... .......... .......... .......... .......... .......... .......... ..完成tMatrixLibrary_v3  __________ ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 谢谢海鲂,你是最棒的!我们的测量结果都很好。:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

至少结果看起来不错。想象一下,就像你在用厨房秤测量羽毛的重量。测量一根羽毛会给你一个床铺尺寸,所以你要收集1000根或更多的羽毛,把它们放在一个盒子里,然后测量整根羽毛来得到一个好主意的平均重量。

问题解决了吗?这不是真的。这种方法有一些很大的缺点。让我们列举:

  1. 我必须选择一些迭代来进行测试。更重要的是,这个选择是随意的。我怎么知道我在框架精度的边缘上是不对的?如果是这样的话,我可能会偶尔经历一些太快而无法测量的测试!此外,框架精度与机器有关,所以不同的机器会有不同的精度阈值。没有一个准确的数字,所以大家都在猜测。不是安慰。
  2. # ohmygoodness这是慢!为什么会慢?因为我必须为所有内容运行1000次迭代,包括更大的矩阵大小。这些较大的尺寸不需要在循环中运行,但为了保持苹果/桔子比较,如果较小的尺寸是需要的。
  3. 当将其他算法进行比较时,这种方法显得毫无用处。如果一种算法需要1000次迭代,而另一种算法只需要750次,我们很快就会陷入比较苹果和橘子的状态,从而失去对真正性能的洞察。
  4. 假设我们一直努力跟踪代码的性能,而且我们对关键代码进行了出色的优化,并在代码性能方面做出了巨大的改进。这个改进可能需要我们“增加”迭代计数,因为由于我们的代码优化,1000次迭代可能突然变得太快了,我们现在需要度量10,000次迭代。然而,一旦我们这样做了,所有未来的测量将在不同的尺度上与我们的历史数据。站不住脚的。
  5. 最后,也许作为上面讨论的苹果/桔子问题的根源,它并不是对代码执行时间的真正度量。

一旦你的代码达到了测量速度的限制,我们可以添加一个静态但这并不是最好的体验。

输入R2018b

在R2018b中,性能测试框架现在有了一个新的keepMeasuring方法matlab.perftest.TestCase类以支持更快的代码金宝app度量工作流程。这是如何使用的?将它放入while循环中,让框架决定正确的迭代次数:

classdeftMatrixLibrary_final < matlab.perftest.TestCase属性TestMatrix = struct(“适用的”,魔法(100),“中型”,魔法(600),...“largeSize”魔法(1000));结束方法(测试)函数testSum (testCase TestMatrix)testCase。keepMeasuring matrix_sum (TestMatrix);结束结束函数testMean (testCase TestMatrix)testCase。keepMeasuring matrix_mean (TestMatrix);结束结束函数testCase. assertreturnstrue (@() size(TestMatrix,1) == size(TestMatrix,2),...Eig只适用于方阵);testCase。keepMeasuring matrix_eig (TestMatrix);结束结束结束结束
结果= runperf (“tMatrixLibrary_final”);checkResults(结果)
运行tMatrixLibrary_final  .......... .......... .......... .......... .......... .......... .......... ..完成tMatrixLibrary_final  __________ ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 谢谢海鲂,你是最棒的!我们的测量结果都很好。:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

啊!这不是可爱的吗?我不需要硬编码任何静态循环值,我们能够准确地测量明显更快的代码,而返回的测量值实际上是实际花费的时间,而不是由任意比例因子偏移的值。同样,需要更多迭代的代码是快速的代码,所以我甚至没有注意到测试时间的任何差异,而较慢的测试根本不需要更多的迭代来进行精确的测量。太好了。查看示例摘要,你可以看到实时时间:

sampleSummary(结果)
ans = 9×7表名SampleSize意味着StandardDeviation最小中值最大  ___________________________________________________ __________ __________ _________________ __________ __________ __________ tMatrixLibrary_final / testSum (TestMatrix =适用)4 1.5071 1.4833 1.4886 1.4807 1.242 e-05 e-07 e-05 e-05 e-05 tMatrixLibrary_final / testSum (TestMatrix =中型)40.000603.091.4084e-05 0.00058393 0.00060658 0.00061526 tMatrixLibrary_final/testSum(TestMatrix=largeSize) 4 0.003275 6.2535e-05 0.0031897 0.0032854 0.0033395 tMatrixLibrary_final/testMean(TestMatrix=smallSize) 4 1.5534e-05 3.4959e-07 1.5221e-05 1.5535e-05 1.5847e-05 tMatrixLibrary_final/testMean(TestMatrix=midSize) 4 0.00059933 9.2749e-06 0.00058845 0.00060012 0.00060865 tMatrixLibrary_final/testMean(TestMatrix=largeSize) 4 0.0032668 4.8834e-05 0.0031958 0.0032859 0.0032997 tMatrixLibrary_final/testEig(TestMatrix=smallSize) 4 0.003086 6.1447e-05 0.00304 0.0030639 0.0031762 tMatrixLibrary_final/testEig(TestMatrix=midSize) 4 0.16333 0.001356 0.16232 0.16287 0.16527 tMatrixLibrary_final/testEig(TestMatrix=largeSize) 4 0.39709 0.00096197 0.39613 0.39704 0.39813

值得注意的是,这并不是灵丹妙药。在keepmeasurement方法中仍然有一些框架开销,阻止我们度量一些非常快的代码。把它想象成测量一组羽毛,但如果每一根羽毛都被单独包裹在一个小包里,那么我们测量的是这个小包的顶部,而不是实际的羽毛。因此,尽管仍然有一些代码太快而无法度量(请不要期望1+1的有效度量),使用keepMeasuring所示方法在实验允许精度上开拓了2个数量级。

玩得开心,像多莉一样,继续测量!




发布与MATLAB®R2018b

|
  • 打印
  • 发送电子邮件

评论

要留下评论,请点击在这里登录到您的MathWorks帐户或创建一个新帐户。