Новое описание проблемы:
В настоящее время я запускаю наше новое программное обеспечение для сбора данных в тестовой среде. Программное обеспечение имеет два основных потока. Один содержит быстрый цикл, который обменивается данными с оборудованием и помещает данные в двойной буфер. Каждые несколько секунд этот цикл останавливается на 200 мс. Я провел несколько тестов, но ни один из них не позволил мне выяснить, что ждет программное обеспечение. Поскольку программное обеспечение является довольно сложным, и среда тестирования может также мешать работе программного обеспечения, мне нужен инструмент / методика для проверки того, что ожидает поток рекордера, пока он заблокирован в течение 200 мс. Какой инструмент будет полезен для достижения этой цели?
Оригинальный вопрос:
В нашем программном обеспечении для сбора данных у нас есть два потока, которые обеспечивают основную функциональность. Один поток отвечает за сбор данных с разных датчиков, а второй поток сохраняет данные на диск большими блоками. Данные собираются в двойной буфер. Обычно он содержит 100000 байт на элемент и собирает до 300 элементов в секунду. Один буфер используется для записи в поток сбора данных, а один буфер используется для чтения данных и сохранения их на диск во втором потоке. Если все данные были прочитаны, буферы переключаются. Переключение буферов, похоже, является серьезной проблемой производительности. Каждый раз, когда буфер переключается, поток сбора данных блокируется примерно на 200 мс, что слишком долго. Однако время от времени случается так, что переключение происходит намного быстрее, почти не занимая время. (Тестовый ПК: 64-битная Windows 7, процессор i5-4570 @ 3,2 ГГц (4 ядра), 16 ГБ DDR3 (800 МГц)).
Я предполагаю, что проблема с производительностью связана с обменом данными между ядрами. Только если потоки работают на одном и том же ядре случайно, обмен будет намного быстрее. Я подумал о том, чтобы настроить маску привязки потоков так, чтобы оба потока работали на одном и том же ядре, но это также означает, что я теряю реальный параллелизм. Другая идея состояла в том, чтобы позволить буферам собирать больше данных перед переключением, но это резко снижает частоту обновления отображения данных, поскольку ему приходится ждать переключения буфера, прежде чем он сможет получить доступ к новым данным.
У меня вопрос: есть ли метод перемещения данных из одного потока в другой, который не мешает потоку сбора?
редактировать: Двойной буфер реализован как два std :: векторы, которые используются в качестве кольцевых буферов. Переменная bool (int) используется, чтобы указать, какой буфер является активным буфером записи. При каждом обращении к двойному буферу проверяется значение bool, чтобы узнать, какой вектор следует использовать. Переключение буферов в двойной буфер означает переключение этого значения bool. Конечно, во время переключения все чтение и запись блокируются мьютексом. Я не думаю, что этот мьютекс может блокироваться в течение 200 мс. Кстати, 200 мс очень воспроизводимы для каждого события переключения.
Блокировка и освобождение мьютекса только для переключения одной переменной bool не займет 200 мс.
Основная проблема, вероятно, в том, что два потока каким-то образом блокируют друг друга.
Этот вид блокировки называется блокировать раздор. В основном это происходит всякий раз, когда один процесс или поток пытается получить блокировку, удерживаемую другим процессом или потоком. Вместо параллелизма у вас есть два потока, ожидающие друг друга, чтобы завершить свою часть работы, с эффектом, подобным однопоточному.
Для дальнейшего чтения я рекомендую этот статья для чтения, которая описывает конфликт блокировки с более детальным уровнем.
Поскольку вы работаете на Windows, может быть, вы используете Visual Studio? если да, я бы прибегнул к профилировщику VS, который в таких случаях неплох (IMHO), если вам не нужно проверять кэши данных / инструкций (тогда Intel vTune является естественным выбором). По моему опыту VS достаточно хорош, чтобы улавливать проблемы с конкуренцией, а также узкие места процессора. Вы можете запустить его непосредственно из VS или как отдельный инструмент. вам не нужна установленная VS на вашем тестовом компьютере, вы можете просто скопировать инструмент и запустить его локально.
VSPerfCmd.exe / start: SAMPLE / attach: 12345 / output: samples — подключиться к процессу 12345 и собрать данные выборки ЦП
VSPerfCmd.exe / detach: 12345 — отсоединиться от процесса
VSPerfCmd.exe / shutdown — отключить профилировщик, в файле samples.vsp записано (см. Первую строку)
Затем вы можете открыть файл и проверить его в Visual Studio. если вы не видите, что ваш процессор занят работой, переключитесь на профилирование конкуренции — просто измените аргумент «start» с «SAMPLE» на «CONCURRENCY»
Инструмент находится в папке% YourVSInstallDir% \ Team Tools \ Performance Tools \, AFAIR доступен с VS2010.
Удачи
После обсуждения проблемы в чате выяснилось, что анализатор производительности Windows является подходящим инструментом для использования. Программное обеспечение является частью Windows SDK и может быть открыто с помощью команды wprui в командном окне. (Алоис Краус разместил эту полезную ссылку: http://geekswithblogs.net/akraus1/archive/2014/04/30/156156.aspx в чате). Следующие шаги показали, что ожидает программное обеспечение:
Дальнейший анализ показал, что команда fetch data через пару виртуальных последовательных портов иногда теряется. Это может быть связано с очень высокой загрузкой ЦП в цикле сохранения и сжатия данных. Если команда извлечения теряется, данные не принимаются, и первая, а также вторая попытка получить данные имеют тайм-аут с временем ожидания 100 мс.