Относительно низкая производительность spdlog при использовании асинхронных регистраторов с бенчмарками - PullRequest
1 голос
/ 04 февраля 2020

Я неопытный разработчик и заметил, что spdlog позволяет создавать экземпляры многопоточных регистраторов, используя spdlog::async_factory в качестве первого параметра шаблона.

auto basic_async_mt = spdlog::basic_logger_mt<spdlog::async_factory>("basic_mt", "logs/basic_mt.log", true);
// vs
auto basic_mt       = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);

Вопрос

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

Простой сравнительный анализ

**********   Single threaded: 1000000 messages   **********
basic_st                       Elapsed: 0.45 secs          2239158/sec
rotating_st                    Elapsed: 0.44 secs          2293912/sec
daily_st                       Elapsed: 0.45 secs          2210196/sec
**********   Multi threaded: 1 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.41 secs          2458098/sec
rotating_mt                    Elapsed: 0.45 secs          2238492/sec
daily_mt                       Elapsed: 0.48 secs          2074991/sec
**********   Multi threaded: 10 threads, 1000000 messages   **********
basic_mt                       Elapsed: 1.05 secs           950041/sec
rotating_mt                    Elapsed: 1.02 secs           977636/sec
daily_mt                       Elapsed: 1.11 secs           900860/sec
**********   Async threaded: 1 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.79 secs          1259206/sec
rotating_mt                    Elapsed: 1.00 secs          1002389/sec
daily_mt                       Elapsed: 0.84 secs          1197042/sec
**********   Async threaded: 10 threads, 1000000 messages   **********
basic_mt                       Elapsed: 2.56 secs           390791/sec
rotating_mt                    Elapsed: 2.72 secs           367184/sec
daily_mt                       Elapsed: 2.72 secs           368253/sec

Поскольку в репозитории есть несколько простых тестов, я сначала выполнил bench с некоторыми Изменения: Я установил размер очереди пула потоков 32768 с одним рабочим пула потоков со строкой spdlog::init_thread_pool(1 << 15, 1);. Я также добавил добавленную bench_async_logging версию bench_threaded_logging, которая использует параметр шаблона spdlog::async_factory, как показано выше. Результаты показывают, что версия asyn c работает значительно хуже, чем обычная версия с резьбой. Насколько я могу судить, синхронизация происходит в элементе q_type пула потоков , то есть mpmc_blocking_queue. Очередь синхронизирует доступ через один мьютекс, что может ухудшить производительность в этом синтетическом тесте c с 10 производственными потоками и 1 потребительским потоком. Реальные системы могут демонстрировать очень различное поведение, но пропускная способность асинхронной версии составляет только половину пропускной способности многопоточной версии даже при наличии только одного потока производителя. С экспериментальными изменениями, приведенными ниже, асинхронная версия достигает почти одинаковой производительности для 1 потока и значительно лучшей производительности для 10 потоков.

Экспериментальное улучшение с использованием свободной от блокировки ограниченной очереди

**********   Single threaded: 1000000 messages   **********
basic_st                       Elapsed: 0.44 secs          2248376/sec
rotating_st                    Elapsed: 0.45 secs          2217191/sec
daily_st                       Elapsed: 0.48 secs          2092311/sec
**********   Multi threaded: 1 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.42 secs          2395124/sec
rotating_mt                    Elapsed: 0.45 secs          2242889/sec
daily_mt                       Elapsed: 0.51 secs          1960067/sec
**********   Multi threaded: 10 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.98 secs          1019659/sec
rotating_mt                    Elapsed: 1.28 secs           782557/sec
daily_mt                       Elapsed: 1.14 secs           879411/sec
**********   Async threaded: 1 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.50 secs          2004096/sec
rotating_mt                    Elapsed: 0.56 secs          1781594/sec
daily_mt                       Elapsed: 0.49 secs          2053135/sec
**********   Async threaded: 10 threads, 1000000 messages   **********
basic_mt                       Elapsed: 0.62 secs          1604676/sec
rotating_mt                    Elapsed: 0.71 secs          1415312/sec
daily_mt                       Elapsed: 0.73 secs          1378370/sec

Кому подтвердите предположение, что я использовал реализацию ограниченной очереди без блокировки , предоставленную Дмитрием Вьюковым в его блоге, которую я немного изменил. В очереди не реализована блокирующая операция enqueue и синхронная dequeue_for операция. В моем адаптере MPMCQueueAdapter для этой очереди я просто использовал простое вращение с некоторым механизмом отката для реализации требуемого ожидания. Очередь может быть довольно быстрой, но атомы C ++ не предоставляют стандартный механизм ожидания до C ++ 20 . Исходное неблокирующее enqueue_nowait демонстрировало другое поведение в том смысле, что оно заменило самую старую запись в очереди, в то время как мой адаптер просто пытается поставить сообщение в очередь и ничего не делает в случае его заполнения. Из-за этих предостережений, это только для справки по производительности, чтобы определить, насколько конфликт может быть причиной потока.

Использование очереди без блокировки под колпаком значительно повышает производительность, хотя эталонный тест - синтетический c и такая высокая конкуренция может не произойти в реальных системах. Суть реализации по умолчанию может заключаться в том, что потребитель (поток, который пересылает сообщение в реальный приемник) синхронизируется с тем же мьютексом, что и производители, или мои тесты просто каким-то образом глубоко испорчены. Что вы думаете?

Тестовая система

  • ОС: Windows 10 x64 Версия 1903
  • Компилятор: Visual Studio 2019 16.4
  • Ram : 16 ГБ DDR4 3200
  • ЦП: Ryzen 2600 6C / 12T
  • SSD: Samsung 850 EVO 250 ГБ

РЕДАКТИРОВАТЬ: я использовал размер очереди 32768 для теста результаты выше вместо первоначально заявленных 16384.

...