Main Content

使用类测试性能

此示例演示如何为 fprintf 函数创建和运行基于类的性能测试和回归测试。

编写性能测试

考虑以下单元(回归)测试。您可以使用 runperf("fprintfTest") 而非 runtests("fprintfTest") 将此测试作为性能测试运行。

classdef fprintfTest < matlab.unittest.TestCase
    properties
        file
        fid
    end
    methods(TestMethodSetup)
        function openFile(testCase)
            testCase.file = tempname;
            testCase.fid = fopen(testCase.file,'w');
            testCase.assertNotEqual(testCase.fid,-1,'IO Problem')
            
            testCase.addTeardown(@delete,testCase.file);
            testCase.addTeardown(@fclose,testCase.fid);
        end
    end
    
    methods(Test)
        function testPrintingToFile(testCase)
            textToWrite = repmat('abcdef',1,5000000);
            fprintf(testCase.fid,'%s',textToWrite);
            testCase.verifyEqual(fileread(testCase.file),textToWrite)
        end
        
        function testBytesToFile(testCase)
            textToWrite = repmat('tests_',1,5000000);
            nbytes = fprintf(testCase.fid,'%s',textToWrite);
            testCase.verifyEqual(nbytes,length(textToWrite))
        end
    end
end

测量的时间不包括打开和关闭文件的时间或断言,因为这些活动发生在 TestMethodSetup 块(而非 Test 块)内。但是,测量的时间包括执行验证的时间。最佳做法是测量更准确的性能边界。

在当前文件夹中名为 fprintfTest.m 的文件中创建一个性能测试。此测试类似于包含以下修改的回归测试:

  • 该测试继承自 matlab.perftest.TestCase,而不是 matlab.unittest.TestCase

  • 该测试会调用 startMeasuringstopMeasuring 方法来创建一个围绕 fprintf 函数调用过程的范围。

classdef fprintfTest < matlab.perftest.TestCase
    properties
        file
        fid
    end
    methods(TestMethodSetup)
        function openFile(testCase)
            testCase.file = tempname;
            testCase.fid = fopen(testCase.file,'w');
            testCase.assertNotEqual(testCase.fid,-1,'IO Problem')
            
            testCase.addTeardown(@delete,testCase.file);
            testCase.addTeardown(@fclose,testCase.fid);
        end
    end
    
    methods(Test)
        function testPrintingToFile(testCase)
            textToWrite = repmat('abcdef',1,5000000);
            
            testCase.startMeasuring();
            fprintf(testCase.fid,'%s',textToWrite);
            testCase.stopMeasuring();
            
            testCase.verifyEqual(fileread(testCase.file),textToWrite)
        end
        
        function testBytesToFile(testCase)
            textToWrite = repmat('tests_',1,5000000);
            
            testCase.startMeasuring();
            nbytes = fprintf(testCase.fid,'%s',textToWrite);
            testCase.stopMeasuring();
            
            testCase.verifyEqual(nbytes,length(textToWrite))
        end
    end
end

此性能测试的测量时间仅包括对 fprintf 的调用,并且测试框架仍会计算鉴定。

运行性能测试

运行性能测试。根据系统的不同,您可能会看到系统发出警告,提示性能测试框架运行了最大次数的测试,但没有在 0.95 的置信水平内实现 0.05 的相对误差界限目标。

results = runperf("fprintfTest")
Running fprintfTest
.......... .......... ...
Done fprintfTest
__________


results = 

  1×2 TimeResult array with properties:

    Name
    Valid
    Samples
    TestActivity

Totals:
   2 Valid, 0 Invalid.
   3.6789 seconds testing time.

results 变量是一个 1×2 TimeResult 数组。数组中的每个元素都对应于测试文件中定义的一个测试。

显示测试结果

显示第一个测试的测量结果。您的结果可能有所不同。

results(1)
ans = 

  TimeResult with properties:

            Name: 'fprintfTest/testPrintingToFile'
           Valid: 1
         Samples: [4×7 table]
    TestActivity: [9×12 table]

Totals:
   1 Valid, 0 Invalid.
   2.7009 seconds testing time.

TestActivity 属性的大小所示,性能测试框架采集了 9 个测量值。此数字包括五个用于预备代码的测量值。Samples 属性会排除预备测量值。

显示第一个测试的测量值样本。

results(1).Samples
ans =

  4×7 table

                 Name                 MeasuredTime         Timestamp             Host        Platform                 Version                             RunIdentifier            
    ______________________________    ____________    ____________________    ___________    ________    __________________________________    ____________________________________

    fprintfTest/testPrintingToFile       0.04193      14-Oct-2022 14:25:02    MY-HOSTNAME     win64      9.14.0.2081372 (R2023a) Prerelease    b8029663-5fbd-44e8-a5a6-06564ab18df6
    fprintfTest/testPrintingToFile       0.04148      14-Oct-2022 14:25:02    MY-HOSTNAME     win64      9.14.0.2081372 (R2023a) Prerelease    b8029663-5fbd-44e8-a5a6-06564ab18df6
    fprintfTest/testPrintingToFile      0.041849      14-Oct-2022 14:25:03    MY-HOSTNAME     win64      9.14.0.2081372 (R2023a) Prerelease    b8029663-5fbd-44e8-a5a6-06564ab18df6
    fprintfTest/testPrintingToFile      0.041969      14-Oct-2022 14:25:03    MY-HOSTNAME     win64      9.14.0.2081372 (R2023a) Prerelease    b8029663-5fbd-44e8-a5a6-06564ab18df6

计算单个测试元素的统计信息

显示首个测试的测量时间均值。要排除在预备运行中采集的数据,请使用 Samples 属性中的值。

sampleTimes = results(1).Samples.MeasuredTime;
meanTest = mean(sampleTimes)
meanTest =

    0.0418

计算所有测试元素的统计信息

要比较对 fprintf 的不同调用,请基于 results 创建一个摘要统计量表。在此示例中,两种测试方法均会将同量数据写入文件中。因此,统计值间的部分差异归因于带有输出参量调用 fprintf 函数。

T = sampleSummary(results)
T =

  2×7 table

                 Name                 SampleSize      Mean      StandardDeviation      Min       Median       Max   
    ______________________________    __________    ________    _________________    ________    _______    ________

    fprintfTest/testPrintingToFile        4         0.041807       0.00022367         0.04148    0.04189    0.041969
    fprintfTest/testBytesToFile           9         0.044071         0.003268        0.041672    0.04223    0.049611

更改统计目标并重新运行测试

通过构造和运行计时试验来更改 runperf 函数定义的统计目标。构造所采集测量值的样本均值达到 98% 置信水平的 2% 相对误差界限目标的计时试验。采集 4 个预备测量值和最多 16 个样本测量值。

创建一个测试套件。

suite = testsuite("fprintfTest");

根据指定的需求构造一个计时试验,并运行测试。在此示例中,性能测试框架采用指定的最大样本数无法达到更严格的统计目标。您的结果可能有所不同。

import matlab.perftest.TimeExperiment
experiment = TimeExperiment.limitingSamplingError("NumWarmups",4, ...
    "MaxSamples",16,"RelativeMarginOfError",0.02,"ConfidenceLevel",0.98);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... .......... ........Warning: Target Relative Margin of Error not met after running the MaxSamples for fprintfTest/testBytesToFile. 

Done fprintfTest
__________

将最大样本数增加到 32 并重新运行计时试验。

experiment = TimeExperiment.limitingSamplingError("NumWarmups",4, ...
    "MaxSamples",32,"RelativeMarginOfError",0.02,"ConfidenceLevel",0.98);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... .......... .......... .
Done fprintfTest
__________

计算测试元素的摘要统计量。

T1 = sampleSummary(resultsTE)
T1 =

  2×7 table

                 Name                 SampleSize      Mean      StandardDeviation      Min        Median       Max   
    ______________________________    __________    ________    _________________    ________    ________    ________

    fprintfTest/testPrintingToFile         4        0.041632       4.2448e-05        0.041578    0.041638    0.041674
    fprintfTest/testBytesToFile           19        0.042147        0.0016461        0.041428    0.041705    0.048784

测量首次成本

启动一个新 MATLAB® 会话。新会话可确保 MATLAB 尚未运行测试中包含的代码。

创建并运行一个不用预备测量值,仅采用一个样本测量值的定次计时试验,测量代码的首次成本。

创建一个测试套件。由于您是在测量函数的首次成本,所以请运行单独的测试。要运行多个测试,请保存相应结果并在测试间启动一个新 MATLAB 会话。

suite = testsuite("fprintfTest/testPrintingToFile");

构造并运行此计时试验。

import matlab.perftest.TimeExperiment
experiment = TimeExperiment.withFixedSampleSize(1);
results = run(experiment,suite);
Running fprintfTest
.
Done fprintfTest
__________

显示结果。TestActivity 表显示没有预备测量值。

fullTable = results.TestActivity
fullTable =

  1×12 table

                 Name                 Passed    Failed    Incomplete    MeasuredTime    Objective         Timestamp             Host        Platform                 Version                            TestResult                         RunIdentifier            
    ______________________________    ______    ______    __________    ____________    _________    ____________________    ___________    ________    __________________________________    ______________________________    ____________________________________

    fprintfTest/testPrintingToFile    true      false       false         0.044004       sample      14-Oct-2022 14:32:51    MY-HOSTNAME     win64      9.14.0.2078117 (R2023a) Prerelease    1×1 matlab.unittest.TestResult    be5b0bfd-9b87-4498-9ef3-675c6889a85c

另请参阅

| | | |

相关主题