Можно ли написать код (или законченное программное обеспечение, а не кусок кода), который не будет работать должным образом при запуске на процессоре с числом ядер менее N? Без явной проверки и намеренного сбоя:
ЕСЛИ (noOfCores <4) ТОГДА не работают должным образом специально
Я смотрю на минимальные системные требования игры ( Dragon Age: Inquisition ), и в ней указан минимум четырехъядерный процессор. Многие игроки говорят, что он НЕ работает на двухъядерных процессорах и даже на Intel Core i3 с двумя физическими и двумя логическими ядрами. И это НЕ проблема вычислительной мощности.
Насколько я понимаю, потоки полностью изолированы от процессора операционной системой, поскольку это невозможно.
Просто чтобы прояснить ситуацию:
Я НЕ спрашиваю: «Могу ли я узнать количество ядер ЦП из кода и умышленно выйти из строя?» ... Такой код был бы злонамеренным (заставляет вас покупать более дорогой процессор для запуска программы - без необходимости в вычислительных ресурсах). Я спрашиваю, что ваш код, скажем, имеет четыре потока и дает сбой, когда два потока выполняются на одном физическом ядре (без явной проверки системной информации и преднамеренного сбоя) .
Короче говоря, может ли быть программное обеспечение, которое требует нескольких ядер, без необходимости дополнительной вычислительной мощности, которая исходит от нескольких ядер? Это просто потребовало бы N отдельных физических ядер.
источник
Ответы:
Может быть возможно сделать это "случайно" с небрежным использованием основного сродства. Рассмотрим следующий псевдокод:
Если вы запустите четыре из них на двухъядерном процессоре, то либо с настройкой привязки к ядру что-то пойдет не так, либо вы получите два потока, переключающие доступные ядра, и два потока, которые никогда не планируются. Ни в коем случае он прямо не спросил, сколько всего ядер.
(Если у вас есть долго работающие потоки, настройка соответствия процессоров обычно улучшает пропускную способность)
Идея о том, что игровые компании «заставляют» людей покупать более дорогое оборудование без веской причины, не очень правдоподобна. Это могут потерять только их клиенты.
Изменить: этот пост получил 33 голосов, что довольно много, учитывая, что оно основано на догадках!
Кажется, что у людей есть DA: я плохо работаю на двухъядерных системах: http://www.dsogaming.com/pc-performance-analyses/dragon-age-inquisition-pc-performance-analysis/ Этот анализ упоминает, что ситуация значительно улучшается, если включена гиперпоточность. Учитывая, что HT больше не добавляет единицы выдачи инструкций или кеш, он просто позволяет одному потоку работать, пока другой находится в стойке кеша, что говорит о том, что он связан исключительно с числом потоков.
Другой автор утверждает, что смена графических драйверов работает: http://answers.ea.com/t5/Dragon-Age-Inquisition/Working-solution-for-Intel-dual-core-CPUs/td-p/3994141 ; учитывая, что графические драйверы, как правило, жалкий улей мрази и подлости, это не удивительно. Один печально известный набор драйверов имел режим «правильный и медленный» по сравнению с «быстрым и неправильным», который был выбран при вызове из QUAKE.EXE. Вполне возможно, что драйверы ведут себя по-разному для разного количества видимых процессоров. Возможно (вернемся к размышлениям) используется другой механизм синхронизации. Злоупотребление спин-замками ?
«Неправильное использование примитивов блокировки и синхронизации» - очень и очень распространенный источник ошибок. (Ошибка, на которую я должен был смотреть при работе, это «сбой при изменении настроек принтера одновременно с завершением задания на печать»).
Редактирование 2: в комментариях упоминается, что ОС пытается избежать истощения потоков. Обратите внимание, что в игре может быть свой собственный внутренний квази-планировщик для распределения работы между потоками, и в самой видеокарте будет аналогичный механизм (который фактически является собственной многозадачной системой). Вероятность ошибки в одном из тех или взаимодействия между ними довольно высоки.
www.ecsl.cs.sunysb.edu/tr/ashok.pdf (2008) - дипломная работа по улучшению планирования для графических карт, в которой явно упоминается, что они обычно используют планирование «первым пришел - первым обслужен», что легко реализовать в не упреждающие системы. Ситуация улучшилась? Возможно нет.
источник
Может быть необходимо иметь 4 ядра, потому что приложение выполняет четыре задачи в параллельных потоках и ожидает, что они завершатся почти одновременно.
Когда каждый поток выполняется отдельным ядром и все потоки имеют одинаковую вычислительную нагрузку, они вполне вероятно (но далеко не гарантированы) завершить примерно в одно и то же время. Но когда два потока работают на одном ядре, время будет намного менее предсказуемым, потому что ядро будет постоянно переключать контекст между двумя потоками.
Ошибки, возникающие из-за непредвиденной синхронизации потоков, называются « состояниями гонки ».
В контексте разработки игр, одна правдоподобная архитектура с такой проблемой может быть такой, где различные функции игры моделируются в реальном времени различными потоками ЦП. Когда каждая функция работает на собственном ядре, все они моделируются примерно с одинаковой скоростью. Но когда две функции работают на одном ядре, обе будут имитироваться только вдвое быстрее, чем остальная часть игрового мира, что может вызвать все виды странного поведения.
Обратите внимание, что программная архитектура, которая зависит от независимых потоков, работающих с определенным временем, является чрезвычайно хрупкой и признаком очень плохого понимания параллельного программирования. Практически во всех многопоточных API имеются функции, позволяющие явно синхронизировать потоки для предотвращения подобных проблем.
источник
Вряд ли эти «минимальные требования» представляют собой нечто, ниже которого игра не запустится. Гораздо более вероятно, что они представляют собой нечто, ниже которого игра не будет работать с приемлемой производительностью. Ни одна игровая компания не хочет иметь дело с большим количеством клиентов, жалующихся на дурную производительность, когда они запускают ее на одноядерном устройстве с частотой 1 ГГц, даже если программное обеспечение может работать технически. Таким образом, они, вероятно, намеренно спроектируют так, чтобы они могли работать с ошибками на коробках с меньшим количеством ядер, чем могли бы дать им приемлемую производительность.
Одним из важных показателей производительности игры является частота кадров. Обычно они работают со скоростью 30 или 60 кадров в секунду. Это означает, что игровой движок должен визуализировать текущий вид из игрового состояния за фиксированное время. Чтобы достичь 60 кадров в секунду, для этого требуется чуть более 16 мсек. Игры с высококачественной графикой чрезвычайно сильно нагружены процессором, поэтому между попыткой добиться более высокого качества (что занимает больше времени) и необходимостью оставаться в этом временном бюджете существует огромная отдача. Таким образом, бюджет времени для каждого кадра чрезвычайно ограничен.
Поскольку бюджет времени ограничен, в идеале разработчик хочет иметь эксклюзивный доступ к одному или нескольким ядрам. Они также, вероятно, хотят иметь возможность выполнять свои операции рендеринга исключительно в ядре, так как именно это должно быть сделано с этим временным бюджетом, в то время как другие вещи, такие как вычисление состояния мира, происходят в отдельном процессе, где это не будет вторгаться.
Вы можете, теоретически, втиснуть все это в одно ядро, но тогда все станет намного сложнее. Внезапно вы должны убедиться, что все эти состояния игры происходят достаточно быстро и позволяют вашему рендерингу происходить. Вы не можете просто сделать их двумя программными потоками, потому что нет способа заставить ОС понять: «Поток A должен выполнить X работы за 16 мсек независимо от того, что делает поток B».
Разработчики игр не заинтересованы в том, чтобы заставить вас покупать новое оборудование. Причина, по которой они предъявляют системные требования, заключается в том, что стоимость поддержки более дешевых компьютеров не стоит этого.
источник
Три потока в реальном времени, которые никогда не спят, и один другой поток. Если имеется менее четырех ядер, четвертый поток никогда не запускается. Если четвертому потоку необходимо связаться с одним из потоков реального времени для завершения потока реального времени, код не будет завершен с менее чем четырьмя ядрами.
Очевидно, что если потоки реального времени ждут чего-то, что не позволяет им спать (например, спин-блокировки), разработчик программы облажался.
источник
Прежде всего программные потоки не имеют ничего общего с аппаратными потоками и часто перепутаны. Программные потоки - это фрагменты кода, которые можно отправлять и запускать самостоятельно в контексте процесса. Аппаратные потоки в основном управляются ОС и отправляются ядру процессора, когда речь идет об обычных программах. Эти аппаратные потоки отправляются в зависимости от нагрузки; аппаратный диспетчер потоков действует более или менее как балансировщик нагрузки.
Однако, когда дело доходит до игр, особенно игр высокого уровня, иногда аппаратные потоки управляются самой игрой, или игра указывает диспетчеру аппаратных потоков, что делать. Это потому, что каждая задача или группа задач не имеют такой же приоритет, как в обычной программе. Поскольку возраст драконов исходит от высококлассной игровой студии, использующей высокопроизводительные игровые движки, я могу себе представить, что она использует «ручную» диспетчеризацию, и тогда количество ядер становится минимальным системным требованием. Любая программа аварийно завершает работу, когда я отправляю кусок кода в третье физическое ядро, работающее на машине с одним или двумя ядрами.
источник
Поскольку можно использовать виртуализацию, чтобы иметь больше виртуальных ядер, чем физических, и программное обеспечение не будет знать, что оно работает в виртуализации, и вместо этого думает, что у него так много физических ядер, я бы сказал, что такое программное обеспечение невозможно.
Другими словами, невозможно написать программное обеспечение, которое всегда останавливается на менее чем N ядрах.
Как уже отмечали другие, существуют программные решения, которые могут потенциально проверять, особенно, если используемая ОС и код имеют низкую защиту от состояния гонки, когда N процессов работают на процессорах <N. Реальный трюк - это код, который не будет работать, если у вас меньше N процессоров, но не будет работать, если у вас N процессоров, но есть ОС, которая может назначать работу менее чем на N процессоров.
источник
Возможно, что три потока что-то делают (генерируют фон или генерируют движение NPC) и передают события четвертому, который должен агрегировать / фильтровать события и обновлять модель представления. Если четвертый поток не получает все события (потому что он не запланирован на ядре), тогда модель представления не обновляется правильно. Это может происходить только время от времени, но эти ядра должны быть доступны в любой момент. Это может объяснить, почему вы не видите высокой загрузки ЦП все время, но игра все равно не работает должным образом.
источник
Я думаю, что Иисус Навин идет по правильному пути, но не до конца.
Предположим, у вас есть архитектура, в которой написаны три потока, которые делают столько, сколько могут - когда они заканчивают то, что делают, они делают это снова. Чтобы сохранить производительность, эти потоки не освобождают управление для чего-либо - они не хотят рисковать отставанием от планировщика задач Windows. До тех пор, пока есть 4 или более ядер, это работает нормально, если их нет, это плохо.
В общем, это было бы плохим программированием, но игры - это другое дело, когда вы сталкиваетесь с выбором между дизайном, который уступает всем аппаратным средствам, или дизайном, который превосходит достаточно хорошее оборудование, или отказом в аппаратных играх низкого качества, которые обычно выбирают разработчики игр. требовать оборудования.
источник
Is it possible to write code (or complete software, rather than a piece of code) that won't work properly when run on a CPU that has less than N number of cores?
Абсолютно. Использование потоков в реальном времени было бы хорошим примером ситуации, в которой это не только возможно, но и является желательным (и часто единственным правильным) способом выполнения работы. Однако потоки реального времени обычно ограничиваются ядром ОС, обычно для драйверов, которые должны быть в состоянии гарантировать, что какое-либо аппаратное событие обрабатывается в течение некоторого определенного периода времени. Вы не должны иметь потоков в реальном времени в обычных пользовательских приложениях, и я не уверен, что даже возможно иметь потоки в приложении пользовательского режима Windows. Как правило, операционные системы преднамеренно делают это невозможным именно из земли пользователя, потому что это позволяет конкретному приложению взять на себя управление системой.
Относительно пользовательских приложений: Ваше предположение, что проверка заданного количества потоков для запуска обязательно является вредоносной по своему намерению, неверно. Например, у вас может быть две длительные задачи с высокой производительностью, для которых требуется ядро. Независимо от скорости ядра процессора, совместное использование ядра с другими потоками может быть серьезным и недопустимым ухудшением производительности из-за перегрузки кэша наряду с обычными потерями, возникающими при переключении потоков (которые довольно существенны). В этом случае это было бы совершенно разумно, особенно для игры, чтобы каждый из этих потоков имел сродство только на одном конкретном ядре для каждого из них, а затем все остальные потоки не должны иметь сродство с этими двумя ядрами. Для того, чтобы сделать это, вы
источник
Любой код, использующий спин-блокировки с любым заметным количеством конфликтов блокировки, будет работать ужасно (в той степени, в которой - для приложения, такого как игра - вы можете сказать «не работает» ), если количество потоков превышает количество ядер.
Представьте, например, поток производителя, отправляющий задачи в очередь, которая обслуживает 4 потока потребителя. Есть только два ядра:
Производитель пытается получить спин-блокировку, но она удерживается потребителем, работающим на другом ядре. Два ядра работают в режиме блокировки, пока производитель вращается, ожидая снятия блокировки. Это уже плохо, но не так плохо, как получится.
К сожалению, потребительский поток находится в конце своего кванта времени, поэтому он выгружается, и запланирован другой потребительский поток. Он пытается завладеть блокировкой, но, конечно, блокировка взята, поэтому теперь два ядра вращаются и ожидают чего-то, что не может произойти.
Поток производителя достигает конца своего временного интервала и прерывается, просыпается другой потребитель. Опять же, два потребителя ждут освобождения блокировки, и этого не произойдет, пока не пройдут еще два кванта времени.
[...] Наконец, потребитель, который держал спинлок, снял блокировку. Это немедленно взято, кто бы ни вращался на другом ядре. С вероятностью 75% (от 3 до 1) это еще один потребительский поток. Другими словами, вероятность того, что производитель все еще застопорился , составляет 75% . Конечно, это означает, что потребители тоже останавливаются. Без заданий производителя, им нечего делать.
Обратите внимание, что это работает в принципе с любым видом блокировки, а не только со спин-блокировками - но разрушительный эффект гораздо более заметен при спин-блокировках, потому что ЦП продолжает циклы горения, пока не достигает ничего.
Теперь представьте, что в дополнение к вышесказанному у некоторых программистов была блестящая идея использовать выделенный поток с привязкой, установленной для первого ядра, поэтому RDTSC даст надежные результаты на всех процессорах (в любом случае это не так, но некоторые люди так думают).
источник
Если я понимаю, что вы спрашиваете, это возможно, но это очень, очень плохо.
Каноническим примером того, что вы описываете, будет поддержание счетчика, который увеличивается на несколько потоков. Это почти ничего не требует в плане вычислительной мощности, но требует тщательной координации между потоками. Пока только один поток за раз делает приращение (которое фактически является чтением, за которым следует добавление, за которым следует запись), его значение всегда будет правильным. Это связано с тем, что один поток всегда будет читать правильное «предыдущее» значение, добавлять его и записывать правильное «следующее» значение. Получите два потока в действие одновременно, и оба будут читать одно и то же «предыдущее» значение, получать одинаковый результат из приращения и записывать одно и то же «следующее» значение. Счетчик будет эффективно увеличен только один раз, хотя два потока считают, что каждый из них это сделал.
Эта зависимость между временем и правильностью - это то, что информатика называет состоянием гонки .
Гоночных условий часто избегают, используя механизмы синхронизации, чтобы убедиться, что потоки, желающие работать с частью общих данных, должны получить доступ к линии. Счетчик, описанный выше, может использовать блокировку чтения-записи для этого.
Не имея доступа к внутреннему дизайну Dragon Age: Inquisition , все, что может сделать каждый, - это размышлять о том, почему он ведет себя так, как он. Но я попробую, основываясь на некоторых вещах, которые я видел в своем собственном опыте:
Возможно, программа основана на четырех настроенных потоках, поэтому все работает, когда потоки работают в основном непрерывно на своих физических ядрах. «Настройка» может происходить в форме перестановки кода или вставки спящих мест в стратегических местах, чтобы смягчить ошибки, вызванные состоянием гонки, которые возникают во время разработки. Опять же, это все догадки, но я видел, что условия гонки "разрешались" таким образом больше раз, чем я хотел бы сосчитать.
Выполнение подобной программы на чем-то менее способном, чем среда, для которой она была настроена, вносит изменения синхронизации, которые являются результатом того, что код работает не так быстро или, что более вероятно, переключением контекста. Переключение контекста происходит физическим (т. Е. Физические ядра ЦП переключаются между работой, которую держат его логические ядра) и логическим (т. Е. ОС на ЦП распределяет работу по ядрам) способами, но это либо существенно отличается от того, что будет "ожидаемым" временем выполнения. Это может выявить плохое поведение.
Если Dragon Age: Inquisition не предпримет простого шага, чтобы убедиться в наличии достаточного количества физических ядер, прежде чем продолжить, это вина EA. Вероятно, они тратят небольшое состояние, отправляя звонки в службу поддержки и электронные письма от людей, которые пытались запустить игру на слишком маленьком оборудовании.
источник
Для этого в Windows есть встроенная функциональность: функция GetLogicalProcessorInformation находится в Windows API . Вы можете вызвать его из своей программы, чтобы получить информацию о ядрах, виртуальных ядрах и гиперпоточности.
Таким образом, ответ на ваш вопрос будет: да.
источник
/proc/cpuinfo
иsysconf(_SC_NPROCESSORS_ONLN)
(последнее упомянуто в POSIX). Однако использование информации для обеспечения минимального порога производительности все еще является довольно плохой формой.