Новое описание проблемы:
В настоящее время я запускаю наше новое программное обеспечение для сбора данных в тестовой среде. Программное обеспечение имеет два основных потока. Один содержит быстрый цикл, который связывается с аппаратным обеспечением и толкает данные в двойной буфер. Каждые несколько секунд этот цикл замерзает на 200 мс. Я сделал несколько тестов, но никто из них не дал мне понять, что ждет программное обеспечение. Поскольку программное обеспечение довольно сложно, и тестовая среда может помешать работе с программным обеспечением, мне нужен инструмент/методика, чтобы проверить, что ждет поток записывающего устройства, пока он заблокирован на 200 мс. Какой инструмент был бы полезен для достижения этого?
Оригинальный вопрос:
В нашем программном обеспечении для сбора данных у нас есть два потока, которые обеспечивают основные функции. Один поток отвечает за сбор данных от разных датчиков, а второй поток сохраняет данные на диск в больших блоках. Данные собираются в двойном буфере. Он обычно содержит 100000 байт на элемент и собирает до 300 элементов в секунду. Один буфер используется для записи в потоке сбора данных, а один буфер используется для чтения данных и сохранения его на диске во втором потоке. Если все данные были прочитаны, буферы переключаются. Переключение буферов, по-видимому, является серьезной проблемой производительности. Каждый раз, когда буфер переключается, потоки сбора данных блокируются примерно на 200 мс, что слишком велико. Однако время от времени случается, что переключение происходит намного быстрее, и у них почти нет времени. (Тестовый ПК: Windows 7 64 бит, i5-4570 CPU @3,2 ГГц (4 ядра), 16 ГБ DDR3 (800 МГц)).
Я предполагаю, что проблема производительности связана с обменом данными между ядрами. Только если потоки запускаются на одном ядре случайно, обмен будет намного быстрее. Я подумал о настройке маски слияния потоков, чтобы заставить оба потока работать на одном ядре, но это также означает, что я теряю реальный параллелизм. Другая идея заключалась в том, чтобы позволить буферам собирать больше данных перед переключением, но это резко снижает частоту обновления отображения данных, поскольку ему приходится ждать, пока буфер не переключится, прежде чем он сможет получить доступ к новым данным.
Мой вопрос: есть ли способ перемещения данных из одного потока в другой, который не мешает потоку коллекции?
Редактировать: двойной буфер реализуется как два std :: вектора, которые используются как кольцевые буферы. Для определения того, какой буфер является активным буфером записи, используется переменная bool (int). Каждый раз, когда открывается двойной буфер, значение bool проверяется, чтобы узнать, какой вектор следует использовать. Переключение буферов в двойной буфер просто означает переключение этого значения bool. Конечно, во время переключения все чтение и запись блокируются мьютексом. Я не думаю, что этот мьютекс мог блокировать 200 мс. Кстати, 200 мс очень воспроизводимы для каждого события коммутатора.
После обсуждения проблемы в чате выяснилось, что анализатор производительности Windows является подходящим инструментом для использования. Программное обеспечение является частью SDK Windows и может быть открыто с помощью команды wprui в окне команд. (Алоис Краус опубликовал эту полезную ссылку: http://geekswithblogs.net/akraus1/archive/2014/04/30/156156.aspx в чате). Следующие шаги показали, что ожидало программное обеспечение:
Дальнейший анализ показал, что команда получения данных через пару виртуальных последовательных портов иногда теряется. Это может быть связано с очень высокой загрузкой процессора в цикле сохранения и сжатия данных. Если команда fetch потеряна, данные не принимаются, а первая, а также вторая попытка получить данные, рассчитанные с таймаутом 100 мс.
Блокировка и отключение мьютекса только для переключения одной переменной bool не займет 200 мс.
Основная проблема, вероятно, в том, что два потока каким-то образом блокируют друг друга. Такая блокировка называется блокировкой. В основном это происходит, когда один процесс или поток пытается получить блокировку, удерживаемую другим процессом или потоком. Вместо параллелизма у вас есть два потока, ожидающих друг друга, чтобы завершить свою часть работы, имея такой же эффект, как и в однопоточном подходе.
Для дальнейшего чтения я рекомендую эту статью для чтения, в котором описывается конфликт блокировок с более подробным уровнем.
Поскольку вы работаете в 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
Удачи