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.
   4.1417 seconds testing time.

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

显示测试结果

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

results(1)
ans = 

  TimeResult with properties:

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

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

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

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

results(1).Samples
ans =

  4×7 table

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

    fprintfTest/testPrintingToFile      0.067729      24-Jun-2019 16:22:09    MY-HOSTNAME     win64      9.7.0.1141441 (R2019b) Prerelease Update 2    62991eef-5570-47b0-ade5-b8a805245e8f
    fprintfTest/testPrintingToFile      0.067513      24-Jun-2019 16:22:09    MY-HOSTNAME     win64      9.7.0.1141441 (R2019b) Prerelease Update 2    62991eef-5570-47b0-ade5-b8a805245e8f
    fprintfTest/testPrintingToFile      0.068737      24-Jun-2019 16:22:09    MY-HOSTNAME     win64      9.7.0.1141441 (R2019b) Prerelease Update 2    62991eef-5570-47b0-ade5-b8a805245e8f
    fprintfTest/testPrintingToFile      0.068576      24-Jun-2019 16:22:10    MY-HOSTNAME     win64      9.7.0.1141441 (R2019b) Prerelease Update 2    62991eef-5570-47b0-ade5-b8a805245e8f

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

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

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

    0.0681

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

确定所有测试元素的平均时间。fprintfTest 测试包括两个不同的方法。比较每个方法(测试元素)的时间。

因为性能测试框架为每个测试元素返回一个 Samples 表,并将所有这些表串联成一个表。然后按测试元素 Name 对行分组,并计算每个组的平均 MeasuredTime

fullTable = vertcat(results.Samples);
summaryStats = varfun(@mean,fullTable,...
    'InputVariables','MeasuredTime','GroupingVariables','Name')
summaryStats =

  2×3 table

                 Name                 GroupCount    mean_MeasuredTime
    ______________________________    __________    _________________

    fprintfTest/testPrintingToFile        4             0.068139     
    fprintfTest/testBytesToFile           9             0.071595     

两种测试方法均会将同量数据写入文件中。因此,均值间的部分差异归因于带有输出参数调用 fprintf 函数。

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

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

构造一个显式测试套件。

suite = testsuite('fprintfTest');

构造一个采集不定测量值样本数的计时试验,并运行这些测试。

import matlab.perftest.TimeExperiment
experiment = TimeExperiment.limitingSamplingError('NumWarmups',4,...
    'MaxSamples',16,'RelativeMarginOfError',0.03,'ConfidenceLevel',0.97);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... ..........Warning: Target Relative Margin of Error not met after running the MaxSamples for fprintfTest/testPrintingToFile. 
 ........
Done fprintfTest
__________

在此示例输出中,性能测试框架采用指定的最大样本数无法达到更严格的统计目标。您的结果可能有所不同。

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

fullTableTE = vertcat(resultsTE.Samples);
summaryStatsTE = varfun(@mean,fullTableTE,...
    'InputVariables','MeasuredTime','GroupingVariables','Name')
summaryStatsTE =

  2×3 table

                 Name                 GroupCount    mean_MeasuredTime
    ______________________________    __________    _________________

    fprintfTest/testPrintingToFile        16            0.069482     
    fprintfTest/testBytesToFile            4            0.067902     

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

experiment = TimeExperiment.limitingSamplingError('NumWarmups',4,...
    'MaxSamples',32,'RelativeMarginOfError',0.03,'ConfidenceLevel',0.97);
resultsTE = run(experiment,suite);
Running fprintfTest
.......... ......
Done fprintfTest
__________

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

fullTableTE = vertcat(resultsTE.Samples);
summaryStatsTE = varfun(@mean,fullTableTE,...
    'InputVariables','MeasuredTime','GroupingVariables','Name')
summaryStatsTE =

  2×3 table

                 Name                 GroupCount    mean_MeasuredTime
    ______________________________    __________    _________________

    fprintfTest/testPrintingToFile        4             0.067228     
    fprintfTest/testBytesToFile           4             0.067766     

测试框架使用 4 个样本达到两个测试的统计目标。

测量首次成本

启动一个新 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.071754       sample      24-Jun-2019 16:31:27    MY-HOSTNAME     win64      9.7.0.1141441 (R2019b) Prerelease Update 2    [1×1 matlab.unittest.TestResult]    045394eb-e722-4241-8da2-1d17a97ac90a

性能测试框架为每个测试采集一个样本。

另请参阅

| | | | |