gpt4 book ai didi

c++ - 从 {fmt} 中获得最佳性能

转载 作者:太空狗 更新时间:2023-10-29 21:31:49 29 4
gpt4 key购买 nike

我需要将 FILETIME 值信息格式化为宽字符串缓冲区,配置提供了格式字符串。

我实际上在做什么:

  • Config 提供格式字符串:L"{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}.{mmm}"

  • 将 FILETIME 转换为系统时间:

    SYSTEMTIME stUTC;
FileTimeToSystemTime(&fileTime, &stUTC);
  • 格式化字符串
    fmt::format_to(std::back_inserter(buffer), strFormat,        
fmt::arg(L"YYYY", stUTC.wYear),
fmt::arg(L"MM", stUTC.wMonth),
fmt::arg(L"DD", stUTC.wDay),
fmt::arg(L"hh", stUTC.wHour),
fmt::arg(L"mm", stUTC.wMinute),
fmt::arg(L"ss", stUTC.wSecond),
fmt::arg(L"mmm", stUTC.wMilliseconds));

我完全理解服务是有代价的:)但我的代码调用了这个语句数百万次并且明显存在性能损失(超过 6% 的 CPU 使用率)。

我可以为改进此代码做的“任何事情”都会受到欢迎。

我看到 {fmt} 有一个 time API support .不幸的是,它似乎无法格式化时间/日期的毫秒部分,它需要一些从 FILETIMEstd::time_t 的转换工作......

我是否应该忘记“自定义”格式字符串并为 FILETIME(或 SYSTEMTIME)类型提供自定义格式化程序?这会导致显着的性能提升吗?

如果您能提供任何指导,我将不胜感激。

最佳答案

在评论中,我建议将您的自定义时间格式字符串解析为一个简单的状态机。它甚至不必是这样的状态机。它只是一系列线性指令。

目前,fmt 类需要做一些工作来解析格式类型,然后将整数转换为零填充字符串。尽管不太可能,但它有可能像我将要建议的那样进行了大量优化。

基本思想是有一个(大)查找表,当然可以在运行时生成,但为了快速说明的目的:

const wchar_t zeroPad4[10000][5] = { L"0000", L"0001", L"0002", ..., L"9999" };

如果需要,您可以拥有 1 位、2 位和 3 位查找表,或者如果您只是添加一个偏移量,则认识到这些值都包含在 4 位查找表中。

所以要输出一个数字,你只需要知道 SYSTEMTIME 中的偏移量是多少,值是什么类型,以及要应用什么字符串偏移量(0 表示 4 位,1 表示 3 - 数字等)。它使事情变得更简单,因为 SYSTEMTIME 中的所有结构元素都是相同的类型。并且您应该合理地假设没有任何值需要范围检查,但如果不确定您可以添加这一点。

你可以这样配置:

struct Output {
int dataOffset; // offset into SYSTEMTIME struct
int count; // extra adjustment after string lookup
};

文字字符串呢?好吧,您可以复制这些或者只是重新调整 Output 的用途以使用负数 dataOffset 表示格式字符串中的开始位置和 count 来保存如何在该模式下输出许多字符。如果您需要额外的输出模式,请使用 mode 成员扩展此结构。

无论如何,让我们以您的字符串 L"{YYYY}-{MM}-{DD} {hh}:{mm}:{ss}.{mmm}" 为例。解析后,您将得到:

Output outputs[] {
{ offsetof(SYSTEMTIME, wYear), 0 }, // "{YYYY}"
{ -6, 1 }, // "-"
{ offsetof(SYSTEMTIME, wMonth), 2 }, // "{MM}"
{ -11, 1 }, // "-"
{ offsetof(SYSTEMTIME, wDay), 2 }, // "{DD}"
{ -16, 1 }, // " "
// etc... you get the idea
{ offsetof(SYSTEMTIME, wMilliseconds), 1 }, // "{mmm}"
{ -1, 0 }, // terminate
};

不难看出,当您将 SYSTEMTIME 作为输入、指向原始格式字符串的指针、查找表和这个基本的指令数组时,您可以继续并非常快速地将结果输出到预先确定大小的缓冲区中。

我相信您可以想出有效执行这些指令的代码。

这种方法的主要缺点是查找表的大小可能会导致缓存问题。但是,大多数查找将发生在前 100 个元素中。您还可以将表压缩为普通的 char 值,然后在复制时注入(inject) wchar_t 零字节。

一如既往:实验、测量、玩得开心!

关于c++ - 从 {fmt} 中获得最佳性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57103746/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com