首页 > 解决方案 > 在编译时进行字符串实习以进行分析

问题描述

语境

我正在开发一个仪器分析器,它使您能够按字符串命名不同的测量值。例如:

MEASURE_SCOPE(text_rendering_code);
...
MEASURE_SCOPE(password_hashing);
...
MEASURE_START(system_call);
...
MEASURE_STOP(system_call);

宏的定义如下:

#define MEASURE_START(name) save_start_event(get_timestamp(), #name);
#define MEASURE_STOP(name) save_stop_event(get_timestamp(), #name);
#define MEASURE_SCOPE(name) Profiling_Class object##name (#name);

class Profiling_Class{
    string name;
    Profiling_Class(string name){
        this->name = name; 
        save_start_event(get_timestamp(), name);
    }
    ~Profiling_Class(){save_end_event(get_timestamp(), this->name);}
}

save_start_event并将save_end_event时间戳和名称一起放入某个全局缓冲区以供以后使用(导出测量值等)。

问题在于:将测量的名称与测量本身一起保存是非常低效的。MEASURE_START配对和也需要做很多工作MEASURE_STOP,因为检查它们的名称是否相同需要字符串比较。一个更好的解决方案是实习字符串,即在某个地方有一些数组来保存所有字符串:

std::vector<string> = {"text_rendering_code", "password_hashing", "system_call"};

并将测量宏中的字符串替换为数组中字符串的索引:

MEASURE_SCOPE(0);
...
MEASURE_SCOPE(1);
...
MEASURE_START(2);
...
MEASURE_STOP(2);

这种方式需要更少的存储空间,并且检查名称是否匹配成为一个简单的整数比较。另一方面,它对用户非常不友好,因为他必须提前知道他想要给出他的测量的名称的索引。

问题

有没有办法保持良好的使用MEASURE_SCOPE(text_rendering_code)并用更有效的MEASURE_SCOPE(0)自动替换它?这将需要在编译时构建名称数组,有效地实习字符串。这可能吗?

标签: c++profilingmetaprogrammingcompile-timestring-interning

解决方案


我只能猜测你的意思,因为你没有提供足够的细节,而且它们很重要。

一种可能的方法是使用您自己的生成器生成一些临时 C 或 C++ 代码。请记住,可以生成项目的一些 C 或 C++ 代码(这是一种粗略的形式或元编程;Qt mocRPCGENbisonSWIG是 C++ 或 C 生成器的典型示例,但您可以轻松制作自己的代码,请参见此处; 也许在一些脚本语言的帮助下,如PythonGuileAWK、...,甚至在 C++ 中),您的构建自动化可以处理这个问题(例如,您的Makefile.

然后,您可以编写一个非常简单的生成程序,收集代码中所有出现的和MEASURE_SCOPE宏调用(项目文件)。这对编码非常简单:您可以逐行读取所有文件并查找(etc...) 后跟空格,然后在其中查找。MEASURE_STARTMEASURE_STOP*.cpp.cppMEASURE_SCOPE(

该生成程序 - 处理您的实习字符串 - 可能会发出一个大的头文件measure-generated.h,例如

// in generated header
#define MEASURE_POINT_system_call 1
#define MEASURE_POINT_password_hashing 2

(也许你想生成一些大的enum

它还会发出一个measure-generated-array.cpp

// generated code
const char* measure_array[] = {
  NULL,
  "system_call",
  "password_hashing",
  /// etc....
  NULL,
};

然后你可以在你的一些标题中

#define MEASURE_SCOPE(X) measure_array[MEASURE_POINT_##X]

等,使用预处理器技巧,如字符串化和/或连接

另请参阅

这将需要在编译时构建名称数组,有效地实习字符串。这可能吗?

是的当然。在您自己的 C++ 生成器中执行此操作,该生成器知道您的所有项目*.cpp文件,就像我建议的那样。您可以在构建时生成 C++ 文件。


推荐阅读