2KB项目,专业的源码交易网站 帮助 收藏 每日签到

MeTem —— 一个 C++ 度量框架

  • 时间:2019-01-23 18:35 编辑:2KB 来源:2KB.COM 阅读:393
  • 扫一扫,手机访问
  • 分享
摘要: 英文原文:MeT
英文原文:MeTem: A C++ measuring framework

简介

这个框架将帮助你测量代码中不同类型的参数。当你需要实现一个功能,用于测量性能,内存使用等,同时不同的方式来比较这是非常有用的...通过MeTem的方式,您将能够轻松地测量所有这些参数。 

背景

有时你需要测量代码中不同性质的参数,如性能,使用的内存,和其他性质。由于各种各样的这些参数,我已经被迫多次开发测量特设应用。为了试图解决这个问题,我设计了一个框架,比较一个功能的不同实现。该框架将帮助我选择基于特定目标的最佳实现。有时候,我需要选择最快的一个,其他时间我需要选择使用的内存量较少(思考一个高并发的情况)之一。我也考虑到一个简单的方法来参数化测试。

有人可能会指出,分析代码可能是执行这类任务的最佳途径。我这样也认为,但很多时候我们需要测量只有一段代码需要运行的时间,甚至是在不同的计算机上使用不同的处理器架构,使用一个分析器并不总是唯一选项。

使用代码

首先,这个架构的指导方针是颇受好评的,它的主要目的是比较不同的代码,容器,DB server等的性能或效率,因此,当使用MeTem去比较他们的时候,你必须根据每个测试的不同要求在函数的内部进行编码,譬如使用下面的这种形式:

typedef void (* tpTest)(int iSetSize, void *pData, std::vector<int> &results);

我将会在稍后解释形参的含义。

下一步是创建一个测试固定类去把他们组合起来。这个类必须继承MeTem::CTestFixture基类。举个例子:

class CSample1PerformanceFixture : public MeTem::CTestFixture
{
public:
    CSample1PerformanceFixture();
};

为了让库去运行他们,在内部固定的构造函数里,你必须把 每个测试添加到测试集合(collection)中去:

CSample1PerformanceFixture::CSample1PerformanceFixture()
{ 
    // Measurements
    std::list<std::tstring> lstMeasurements;

    lstMeasurements.push_back(_T("Total (s)"));

    setMeasurements(lstMeasurements);

    // Set sizes
    std::list<int> lstSetSizes;

#ifdef _DEBUG
    lstSetSizes.push_back(50000);
#else
    lstSetSizes.push_back(    50000);
    lstSetSizes.push_back(   100000);
    lstSetSizes.push_back(   200000);
#endif

    setSetSizes(lstSetSizes);

    // Tests
    AddTest(_T("Accu_Seq"), Sample1Performance::Test_Accu_Seq, NULL);
    AddTest(_T("Accu_PPL"), Sample1Performance::Test_Accu_PPL, NULL);
}

正如你所看到的,在构造函数中我们不得不进行三个不同的步骤:

1、我们将会从测试中汇集和确定度量。你要做的是赋予这些度量一些意义。这个一定尺寸的度量列表同“结果”向量(vector)是一致的,每一项测试将会作为一个参数接收。在那个整型元素组成的向量(vector)里,测试不得不给每个度量一个正确的顺序。在这种情况下,我们的度量时间测试将会返回一个以毫秒为单位的结果。我们将会需要一个结果去适配毫秒,并将其转换成秒,有序地将结果显示在以秒为单位的屏幕上。

2、建立一定比例的汇总集合(set),并去演示我们的测试。在这种情况下,建立起固定发布版本的时候,我们将会演示每一项测试50000到100000次,并且有200000个“元素”。这些值是作为第一个参数(“iSetSize”)被每一个测试接收。这意味着这个测试必须使用这个值去解析参数化算法以进行测试。

3、添加每一个测试到内部的测试集合,给他们一个名字和一个泛型指针,他们将会把(“pData”)作为参数接收。

为了尽可能地将测试开发与测试执行器隔离,我决定所有的测试夹具必须存在于一个DLL中(你可以在同一个DLL中包含尽可能多的不同夹具),这样我也实现了一个允许执行器以动态方式列举并实例化夹具的对象工厂模式。你要做的只是在你模块的任何地方(一个合适的位置是在类构造之前),通过调用由库(METEM_REGISTER_CLASS)提供的一个注册宏将每个夹具类注册到工厂。实例:

METEM_REGISTER_CLASS(CSample1PerformanceFixture)

并且你也要使用宏METEM_FACTORY_OBJ在你的DLL的任何地方定义这个工厂(仅需一次):

// MeTem fixtures factory
METEM_FACTORY_OBJ

最后,这有一些样本测试:

namespace Sample1Performance
{

void Test_Accu_Seq(int iSetSize, void * /*pData*/, std::vector<int> &results)
{
    std::vector<int> vData(iSetSize, 0);

    TIME_START

    for (int i= 0; i < iSetSize; i++)
    {
        int iAccu= 0;

        for (int j= 0; j <= i; j++)
        {
            iAccu+= j;
        }

        vData[i]= iAccu;
    }

    TIME_STOP(results[0])
}

void Test_Accu_PPL(int iSetSize, void * /*pData*/, std::vector<int> &results)
{
    std::vector<int> vData(iSetSize, 0);

    TIME_START

    Concurrency::parallel_for(0, iSetSize, [&vData](int i)
    {
        int iAccu= 0;

        for (int j= 0; j <= i; j++)
        {
            iAccu+= j;
        }

        vData[i]= iAccu;
    });

    TIME_STOP(results[0])
}

正如你所见,当使用这些类型的框架时,集中注意力在重要的事情上会很容易。你要写的最多的代码行是你要测量的代码,剩下的工作就由框架来完成。库也提供两对宏设置帮助你测量运行时间和消耗的内存:

  1. TIME_START和TIME_STOP。这两个宏将测量它们之间的运行时间并保存到一个整形变量以参数形式传递(以毫秒为单位)。

  2. MEMORY_START和MEMORY_STOP。这对宏计算消耗的内存并保存到一个整形变量以参数形式传出(以字节为单位)。我还没找到比调用Windows的GetProcessMemoryInfo函数更好的方法来测量这个值。你的系统必须处于一个“稳定”状态,以得到可靠的结果。如果系统受压力的状态,你可能实际上得到一个负值,因为这个函数对内存分页事件很敏感。如果谁知道更好的测量消耗的内存的方法的话,请毫不犹豫地在评论区告知。

一旦写完了测试和夹具,你只需要实例化夹具并调用“PerformTest()”方法。我也在使用夹具工厂来提供一个测试执行器图形界面来完成这个任务。

由于使用PPL库,第二个测试(Test_Accu_PPL)不能在VS2010之前的版本上编译(实际上,它会编译一个无返回的空测试)。


图形界面

提供的图形界面是第一次发布的。它允许加载测试DLL(动态链接库),运行选中的夹具测试,甚至可以将结果导出到Excel表。这只是个雏形,所以没有检查Excel是否存在,而且当运行测试时,界面也不响应。我会尽快提供一个更高级的版本。

这是当前版本的样子:

正如你所见,这些样板测试只返回一个时间计量。你可能记得,辅助宏以毫秒为单位返回消耗时间但图形界面以秒为单位显示。这通过重载虚拟夹具方法“FormatMeasure”可以实现。实例如下:

class CSample1PerformanceFixture : public MeTem::CTestFixture
{
public:
    CSample1PerformanceFixture();
    ~CSample1PerformanceFixture();

    std::tstring FormatMeasure(int iMeasure, int iValue) const;
};

实现方式:

std::tstring CSample1PerformanceFixture::FormatMeasure(int /*iMeasure*/, int iValue) const
{
    std::tostringstream ss;

    //ss.imbue(std::locale(""));

    ss << std::fixed << std::setprecision(3) << iValue / 1000.0;

    return ss.str();
}

正如你所见,这个方法接收参数“iMeasure”,因此你可以单独地格式化每个测量值。

我避免使用用户环境来格式化结果,因为如果你想将数据转存到Excel中,它总是期望你的数字是使用美国英语语言环境格式化过的。

由于C++库的兼容性问题(在一个程序里面混合多个VS版本都是不幸的),你不得不使用同样的VS版本编译两个模块(MeTem GUI和夹具测试DLL)。因此我提供了两个MeTem GUI 版本:一个2005版本和一个2013版本。如果你需要使用不同的VS版本,应该不会有任何问题。

下一步

为了改进框架,在我的脑子里有许多提升的想法。以下是这些想法中的一部分:

  1. 响应式的测试运行GUI,允许我们撤销甚至终止运行中的测试。

  2. 并发模拟器为了测量并发场景的测试

  3. 测试运行控制台,允许在自动化的场景中无人化执行测试

  4. 在运行时,允许从GUI指定集合的大小

  5. ...

请别犹豫给出你希望在MeTem中增添的新功能的建议。

兴趣点

写这些代码让我学会了如何实现一个对象工厂模式,以及如何在用户的语言环境中使用C + +标准库格式化数字。

感谢

我要感谢Rafael Cabezas和Joaqu&iacute。感谢他们审核了我的作品,感谢这些家伙!

结束语

除了GUI模块外,我尽量使用标准的C++代码(2005和2013版)和MFC,因此移植这个框架到其他的编译器或者平台应该是不太困难的。我将尽快的推动这个任务,发布一个标准的C++测试运行控制台。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部