预解析(缓存)printf样式的格式字符串

时间:2014-02-25 10:33:58

标签: c++ c++11 printf

反复拨打电话时

  

的printf /的snprintf / fprintf中/等。

使用相同的格式字符串,并且在每次调用参数位置时重新分析格式字符串没有意义。

是否有人知道一个库提供了预先解析格式字符串然后将其传递给printf样式函数的功能,从而减少了处理时间?

2 个答案:

答案 0 :(得分:2)

大多数stockf函数都相当有效,格式字符串是单个连贯的源,而不是由iostreams和Boot.Format生成的大量短缓冲区,在大多数情况下它(格式字符串)是大量的您将要复制到目标缓冲区的内容。 “解析”printf格式相当便宜,但如果您确实已经验证了printf函数是瓶颈而且它不是printf缓冲区管理不善的结果,那么您还应该知道哪些格式很昂贵。

通常,printf / snprintf会显示在采样的配置文件中,因为它不可避免地需要相当多的转移

snprintf(thatBuffer, someSize, "[%u/%u/%u %u:%u:%u.%llu %s:%u] %p %s %f",
    /* a 2-cacheline date object */ date->dy, date->mo, date->yr, date->hr, date->mi, date->sec, date->ms,
    __FUNCTION__, __LINE__, // why didn't you embed those in the format?
    object->ptr,            // another cache line
    message,                // string from somewhere on the heap, page fault,
    floaty                  // floats and doubles are usually expensive
    );

我们甚至没有使用任何花哨的格式。

您可以采取以下措施来优化打印:

  • 使用有限的掩码编写您自己的简化printf,并尝试连贯地构建子缓冲区。
  • 使用C ++ 11可变参数模板来避免“vsnprintf”转发(我发现这可以通过疯狂数量来提高性能)

例如,根据GCC 4.8.2,Clang 3.5和MSVC 2013,以下内容:

template<typename... Args>
int formatText(const char* const fmt, Args&&...)
{
    int len = std::min(snprintf(m_text, m_textSize, fmt, std::forward<Args>(args)...), m_textSize);
    m_text[len] = '\0';
    return len;
}
对我来说,

的基准测试速度比以下快3倍:

int inline formatText(const char* const fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int len = std::min(vsnprintf(m_text, m_textSize, fmt, args), m_textSize);
    va_end(args);
    m_text[len] = '\0'; // assume m_textSize is storage size - sizeof('\0')
    return len;
}

答案 1 :(得分:0)

Boost.Format解析格式字符串以创建格式化程序对象一次,然后可以重复使用。虽然解析是缓存的,但看起来你会得到多个中间字符串副本,所以我怀疑它会更快。

您可以通过printf实现来缓存解析阶段。这似乎可能产生重大节约的唯一情况是:

  • 如果有长的未格式化的文字字符串,你可以记忆而不是逐字符复制
  • 许多明确的宽度和精度,转换为整数

从根本上说,printf字符串的设计解析起来非常便宜,并且不清楚许多中间格式会更好。