В настоящее время я пишу приложение в Windows, используя C ++, и я хотел бы имитировать загрузку процессора.
У меня есть следующий код:
void task1(void *param) {
unsigned elapsed =0;
unsigned t0;
while(1){
if ((t0=clock())>=50+elapsed){//if time elapsed is 50ms
elapsed=t0;
Sleep(50);
}
}
}
int main(){
int ThreadNr;
for(int i=0; i < 4;i++){//for each core (i.e. 4 cores)
_beginthread( task1, 0, &ThreadNr );//create a new thread and run the "task1" function
}
while(1){}
}
Я написал этот код, используя ту же методологию, что и в ответах, приведенных в этой теме: Имитировать постоянную нагрузку на процессор и пики
Мои вопросы:
РЕДАКТИРОВАТЬ: Причина, по которой я задаю этот вопрос, заключается в том, что я хочу, чтобы в конечном итоге я мог генерировать нагрузки на процессор в 10,20,30, …, 90% в разумных пределах. Этот код, кажется, хорошо работает для генерации нагрузки на 70%< но кажется очень неточным при любой нагрузке ниже 70% (как измерено показаниями загрузки ЦП менеджера задач).
Есть ли у кого-нибудь идеи относительно того, как я могу генерировать указанные нагрузки, но все же смогу использовать свою программу на разных компьютерах (то есть с разными процессорами)?
На первый взгляд, это выглядит не очень красиво, но правильно: C ++ или C (простой способ убедиться в этом — скомпилировать). Включения отсутствуют (<windows.h>
, <process.h>
, а также <time.h>
) но в остальном он компилируется нормально.
Обратите внимание, что clock
а также Sleep
не очень точны, и Sleep
не очень надежно либо. В среднем, функция потока должна работать как задумано, хотя (дать или взять несколько процентов вариации).
Тем не менее, что касается вопроса 2) вы должны заменить последний while(1){}
с чем-то, что блокирует, а не вращает (например, WaitForSingleObject
или же Sleep
если вы будете). в противном случае вся программа будет не 50% нагрузки на квадрок У вас будет 100% нагрузки на одно ядро из-за основного потока, плюс 4x 50% от ваших четырех рабочих. Это, очевидно, в сумме составит более 50% на ядро (и приведет к тому, что потоки отскочат от одного ядра к другому, что приведет к неприятным побочным эффектам).
Использование диспетчера задач или аналогичной утилиты для проверки того, получаете ли вы нужную нагрузку, является хорошим вариантом (и поскольку простой решение, это также лучший).
Также обратите внимание, что моделирование нагрузки таким образом будет наверное вид работы, но не на 100% надежный.
Могут быть эффекты (память, исполнительные блоки), которые трудно предсказать. Предположим, например, что вы используете 100% целочисленных исполнительных блоков ЦП с этим циклом (разумное предположение), но ноль его единиц с плавающей запятой или SSE. Современные процессоры могут распределять ресурсы между реальными или логическими ядрами, и вы не сможете точно предсказать, какие эффекты вы получите. Или другой поток может быть связан с памятью или иметь значительные сбои страниц, поэтому отнимаемое процессорное время не повлияет на него так сильно, как вы думаете (на самом деле может дать достаточно времени, чтобы предварительная выборка работала лучше). Или это может заблокировать передачу AGP. Или что-то еще, что вы не можете сказать.
РЕДАКТИРОВАТЬ:
Улучшенная версия, более короткий код, который исправляет несколько проблем, а также работает как задумано:
clock_t
для значения, возвращаемого clock
(что технически «более правильно», чем использование не специально typedef
целое число Кстати, это, вероятно, та самая причина, по которой оригинальный код не работает так, как задумано, поскольку clock_t
это подписанный целое число под Win32. Состояние в if()
всегда оценивает true
поэтому рабочие спят почти все время, не потребляя ресурсов процессора.getchar
заблокировать программу в конце. Это не сжигает процессорное время и позволяет завершить программу, нажав Войти. Потоки не заканчиваются должным образом, как обычно, но в этом простом случае, вероятно, можно просто позволить ОС прекратить их при выходе из процесса.clock
а также Sleep
используйте те же галочки. По общему признанию, это смелое предположение, но оно справедливо для Win32, который вы использовали в исходном коде (обе «галочки» — миллисекунды). С ++ не имеет ничего подобного Sleep
(без boost::thread
или C ++ 11 std::thread
), поэтому, если предполагается переносимость не в Windows, вам все равно придется переосмыслить.clock
а также Sleep
) которые являются неточными и ненадежными. Sleep(50)
равняется Sleep(63)
в моей системе без использования timeBeginPeriod
, Тем не менее, программа работает «почти идеально», что приводит к 50% +/- 0,5% нагрузки на мою машину.Как и в исходном коде, здесь не учитываются приоритеты потоков. Процесс, который имеет класс приоритета выше, чем обычно, не будет впечатлен этим кодом регулирования, потому что так работает планировщик Windows.
#include <windows.h>
#include <process.h>
#include <time.h>
#include <stdio.h>void task1(void *)
{
while(1)
{
clock_t wakeup = clock() + 50;
while(clock() < wakeup) {}
Sleep(50);
}
}
int main(int, char**)
{
int ThreadNr;
for(int i=0; i < 4; i++) _beginthread( task1, 0, &ThreadNr );
(void) getchar();
return 0;
}
Вы можете использовать Windows API счетчика перфорирования чтобы получить нагрузку на процессор. Либо для всей системы, либо для вашего процесса.
Вот пример кода, который загрузил мой процессор до 100% в Windows.
#include "windows.h"
DWORD WINAPI thread_function(void* data)
{
float number = 1.5;
while(true)
{
number*=number;
}
return 0;
}
void main()
{
while (true)
{
CreateThread(NULL, 0, &thread_function, NULL, 0, NULL);
}
}
Когда вы создадите приложение и запустите его, нажмите Ctrl-C, чтобы убить приложение.