Укажите причину замерзания 200 мс в цикле, критичном ко времени

0

Новое описание проблемы:

В настоящее время я запускаю наше новое программное обеспечение для сбора данных в тестовой среде. Программное обеспечение имеет два основных потока. Один содержит быстрый цикл, который связывается с аппаратным обеспечением и толкает данные в двойной буфер. Каждые несколько секунд этот цикл замерзает на 200 мс. Я сделал несколько тестов, но никто из них не дал мне понять, что ждет программное обеспечение. Поскольку программное обеспечение довольно сложно, и тестовая среда может помешать работе с программным обеспечением, мне нужен инструмент/методика, чтобы проверить, что ждет поток записывающего устройства, пока он заблокирован на 200 мс. Какой инструмент был бы полезен для достижения этого?

Оригинальный вопрос:

В нашем программном обеспечении для сбора данных у нас есть два потока, которые обеспечивают основные функции. Один поток отвечает за сбор данных от разных датчиков, а второй поток сохраняет данные на диск в больших блоках. Данные собираются в двойном буфере. Он обычно содержит 100000 байт на элемент и собирает до 300 элементов в секунду. Один буфер используется для записи в потоке сбора данных, а один буфер используется для чтения данных и сохранения его на диске во втором потоке. Если все данные были прочитаны, буферы переключаются. Переключение буферов, по-видимому, является серьезной проблемой производительности. Каждый раз, когда буфер переключается, потоки сбора данных блокируются примерно на 200 мс, что слишком велико. Однако время от времени случается, что переключение происходит намного быстрее, и у них почти нет времени. (Тестовый ПК: Windows 7 64 бит, i5-4570 CPU @3,2 ГГц (4 ядра), 16 ГБ DDR3 (800 МГц)).

Я предполагаю, что проблема производительности связана с обменом данными между ядрами. Только если потоки запускаются на одном ядре случайно, обмен будет намного быстрее. Я подумал о настройке маски слияния потоков, чтобы заставить оба потока работать на одном ядре, но это также означает, что я теряю реальный параллелизм. Другая идея заключалась в том, чтобы позволить буферам собирать больше данных перед переключением, но это резко снижает частоту обновления отображения данных, поскольку ему приходится ждать, пока буфер не переключится, прежде чем он сможет получить доступ к новым данным.

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

Редактировать: двойной буфер реализуется как два std :: вектора, которые используются как кольцевые буферы. Для определения того, какой буфер является активным буфером записи, используется переменная bool (int). Каждый раз, когда открывается двойной буфер, значение bool проверяется, чтобы узнать, какой вектор следует использовать. Переключение буферов в двойной буфер просто означает переключение этого значения bool. Конечно, во время переключения все чтение и запись блокируются мьютексом. Я не думаю, что этот мьютекс мог блокировать 200 мс. Кстати, 200 мс очень воспроизводимы для каждого события коммутатора.

  • 1
    Как вы переключаете буферы? Кроме того, вы говорите о догадке, что это проблема, вы ее профилировали?
  • 1
    Почему бы вам не использовать один огромный кольцевой буфер? А почему нет асинхронной записи?
Показать ещё 16 комментариев
Теги:
multithreading
virtual-serial-port

3 ответа

0
Лучший ответ

После обсуждения проблемы в чате выяснилось, что анализатор производительности Windows является подходящим инструментом для использования. Программное обеспечение является частью SDK Windows и может быть открыто с помощью команды wprui в окне команд. (Алоис Краус опубликовал эту полезную ссылку: http://geekswithblogs.net/akraus1/archive/2014/04/30/156156.aspx в чате). Следующие шаги показали, что ожидало программное обеспечение:

  • Записывайте информацию в WPR с использованием настроек по умолчанию и загружайте сохраненный файл в WPA.
  • Определите соответствующий поток. В этом случае поток записи и сохраняющий поток, очевидно, имели самую высокую загрузку процессора. Сохраняемая нить может быть легко идентифицирована. Так как он сохраняет данные на диск, это тот, который имеет доступ к файлу. (Посмотрите на Memory-> Жесткие ошибки)
  • Проверьте Computation-> Использование ЦП (Точный) и выберите "Использование по процессу, поток". Выберите процесс, который вы анализируете. Лучше всего отображать столбцы в порядке: NewProcess, ReadyingProcess, ReadyingThreadId, NewThreadID, [yellow bar], Ready (μs) sum, Wait (μs) sum, Count...
  • В разделе ReadyingProcess я искал процесс с наибольшим Wait (μs), так как я ожидал, что это будет отвечать за задержки.
  • В ReadingThreadID я проверил каждую строку, ссылаясь на поток с задержками в столбце NewThreadId. После короткого поиска я нашел поток, который показывал частые ожидания около 100 мс, которые всегда отображались как пара. В столбце ReadyingThreadID я смог прочитать идентификатор потока, который ожидает цикл записи.
  • Согласно его использованию ЦП, этот поток практически ничего не делал. В нашем специальном случае это привело меня к предположению, что команда последовательного порта io может вызвать это ожидание. После дезактивации их задержка исчезла. Важным открытием было то, что задержка в 200 мс фактически состояла из двух задержек 100 мс.

Дальнейший анализ показал, что команда получения данных через пару виртуальных последовательных портов иногда теряется. Это может быть связано с очень высокой загрузкой процессора в цикле сохранения и сжатия данных. Если команда fetch потеряна, данные не принимаются, а первая, а также вторая попытка получить данные, рассчитанные с таймаутом 100 мс.

2

Блокировка и отключение мьютекса только для переключения одной переменной bool не займет 200 мс.

Основная проблема, вероятно, в том, что два потока каким-то образом блокируют друг друга. Такая блокировка называется блокировкой. В основном это происходит, когда один процесс или поток пытается получить блокировку, удерживаемую другим процессом или потоком. Вместо параллелизма у вас есть два потока, ожидающих друг друга, чтобы завершить свою часть работы, имея такой же эффект, как и в однопоточном подходе.

Для дальнейшего чтения я рекомендую эту статью для чтения, в котором описывается конфликт блокировок с более подробным уровнем.

  • 0
    Хотя это может теоретически ответить на вопрос, было бы предпочтительным включить здесь основные части ответа и предоставить ссылку для справки.
1

Поскольку вы работаете в Windows, возможно, вы используете визуальную студию? если да, я бы прибегнул к профилировщику VS, который неплох (IMHO) в таких случаях, как только вам не нужно проверять кеши данных/инструкций (тогда Intel vTune - естественный выбор). По моему опыту, VS достаточно хорош, чтобы уловить конфликтные проблемы, а также узкие места в процессорах. вы можете запустить его непосредственно из VS или как автономный инструмент. вам не нужен VS, установленный на вашем тестовом компьютере, вы можете просто скопировать инструмент и запустить его локально.

VSPerfCmd.exe/start: SAMPLE/attach: 12345/output: samples - присоединяется к процессу 12345 и собирает информацию о выборке процессора
VSPerfCmd.exe/detach: 12345 - отсоединить от процесса
VSPerfCmd.exe/shutdown - завершает работу профилировщика, записывается sample.vsp (см. Первую строку)

то вы можете открыть файл и проверить его в визуальной студии. если вы не видите ничего, что делает ваш процессор занят переключением на профилирование конкуренции - просто измените аргумент "start" от "SAMPLE" до "CONCURRENCY"

Инструмент находится в папке% YourVSInstallDir%\Team Tools\Performance Tools \, AFAIR доступен из VS2010
Удачи

Ещё вопросы

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