Строка формата pre-parse (cache) в стиле printf

0

При повторном вызове

Printf/snprintf/fprintf/и т.д..

с той же строкой формата, и на самом деле не имеет смысла переписывать строку формата для каждого вызова для позиций аргументов.

Кто-нибудь знает о библиотеке, которая обеспечивает функцию синтаксического анализа строки формата спереди, а затем передает ее функции printf-стиля, тем самым сокращая время обработки?

  • 5
    Вы сталкивались с ситуацией, когда ваш профилировщик указывал на printf как на самое большое узкое место в вашем коде?
  • 1
    Вы уверены, что это ваша самая большая проблема, или вы оптимизируете преждевременно? Какой сценарий?
Показать ещё 3 комментария
Теги:
c++11
printf

2 ответа

2

Большинство функций printf являются достаточно эффективными, строка формата представляет собой единый, когерентный источник, а не обильные короткие буферы, созданные iostreams и Boot.Format, и в большинстве случаев это (строка формата) является основной частью того, что вы собираются скопировать в буфер назначения. Форматы печатных форматов "Parsing" довольно дешевы, но если вы действительно подтвердили, что ваша функция 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 с ограниченными масками и попытайтесь построить суббуферы согласованно.
  • Используйте вариативные шаблоны С++ 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;
}
0

Boost.Format анализирует строку формата для создания объекта форматирования, один раз, который затем можно повторно использовать. Хотя синтаксический анализ кэшируется, похоже, что вы получаете несколько промежуточных копий строк, поэтому я сомневаюсь, что это будет быстрее.

Вы можете printf реализацию printf для кэширования этапа синтаксического анализа. Единственными ситуациями, когда это, похоже, может привести к значительной экономии, являются:

  • если есть длинные неформатированные литеральные строки, которые вы можете memcpy вместо копирования по каждому символу
  • много явных значений ширины и точности, которые преобразуются в целые числа

По сути, строки printf разработаны, чтобы быть довольно дешевыми для синтаксического анализа, и неясно, что многие промежуточные форматы будут лучше.

  • 0
    Благодарю. Boost.Format работает очень медленно во многих тестах, опубликованных в Интернете. Я попробую, хотя.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню