Я изучаю, как запустить процесс на выделенном CPU, чтобы избежать контекстных переключений. На моем Ubuntu я выделил два процессора, используя параметры ядра «isolcpus = 3,7» и «irqaffinity = 0-2,4-6». Я уверен, что он правильно учтен:Невозможно избежать контекстных переключений процесса, запущенного отдельно на CPU
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-4.8.0-27-generic root=UUID=58c66f12-0588-442b-9bb8-1d2dd833efe2 ro quiet splash isolcpus=3,7 irqaffinity=0-2,4-6 vt.handoff=7
После перезагрузки я могу проверить, что все работает так, как ожидалось. На первой консоли я бегу
$ stress -c 24
stress: info: [31717] dispatching hogs: 24 cpu, 0 io, 0 vm, 0 hdd
А на второй, используя «сверху» я могу проверить использование моих процессоров:
top - 18:39:07 up 2 days, 20:48, 18 users, load average: 23,15, 10,46, 4,53
Tasks: 457 total, 26 running, 431 sleeping, 0 stopped, 0 zombie
%Cpu0 :100,0 us, 0,0 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu1 : 98,7 us, 1,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu2 : 99,3 us, 0,7 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu3 : 0,0 us, 0,0 sy, 0,0 ni,100,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu4 : 95,7 us, 4,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu5 : 98,0 us, 2,0 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu6 : 98,7 us, 1,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
%Cpu7 : 0,0 us, 0,0 sy, 0,0 ni,100,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
KiB Mem : 7855176 total, 385736 free, 5891280 used, 1578160 buff/cache
KiB Swap: 15624188 total, 10414520 free, 5209668 used. 626872 avail Mem
процессоры 3 и 7 свободны в то время как 6 других единиц полностью заняты. Хорошо.
Для остальной части моего теста, я буду использовать небольшое приложение, которое делает почти чистую обработку
- Он использует два Int буферов одного и того же размера
- Он читает один-на - все значения первого буфера
- каждое значение является случайным индексом во втором буфере
- Он считывает значение в индексе во втором буфере
- Он суммирует все значения, взятые из второго буфера
- Это все предыдущие шаги для большего и большего
- В конце, я печать количество и непроизвольного контекст CPU переходит
Я сейчас изучаю мое заявление, когда я запускаю его:
- на неизолированный CPU
- на изолированном CPU
я сделать это с помощью следующих командных строк:
$ ./TestCpuset ### launch on any non-isolated CPU
$ taskset -c 7 ./TestCpuset ### launch on isolated CPU 7
При запуске на любом процессоре, количество переключений контекста изменения от 20 ... ...
При запуске на изолированном ЦП количество переключателей контекста почти постоянное (между 10 и 20), даже если я запускаю параллельно «напряжение -c 24». (выглядит вполне нормально)
Но мой вопрос: почему он не 0 абсолютно 0? Когда переключатель выполняется в процессе, он должен заменить его другим процессом? Но в моем случае нет другого процесса для замены!
У меня есть гипотезы, что вариант «isolcpus» будет изолировать процессора формировать любой процесс (если не указано процесса сродство процессора будет дано, например, то, что делается с «набор задач»), но не из задачи ядра. Однако, я не нашел в документации об этом
Я был бы признателен за любую помощь, чтобы достичь 0 контекстно-переключателей
FYI, этот вопрос закрыт на другой я уже открыл: Cannot allocate exclusively a CPU for my process
Вот код программы я использую:
#include <limits.h>
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
const unsigned int BUFFER_SIZE = 4096;
using namespace std;
class TimedSumComputer
{
public:
TimedSumComputer() :
sum(0),
bufferSize(0),
valueBuffer(0),
indexBuffer(0)
{}
public:
virtual ~TimedSumComputer()
{
resetBuffers();
}
public:
void init(unsigned int bufferSize)
{
this->bufferSize = bufferSize;
resetBuffers();
initValueBuffer();
initIndexBuffer();
}
private:
void resetBuffers()
{
delete [] valueBuffer;
delete [] indexBuffer;
valueBuffer = 0;
indexBuffer = 0;
}
void initValueBuffer()
{
valueBuffer = new unsigned int[bufferSize];
for (unsigned int i = 0 ; i < bufferSize ; i++)
{
valueBuffer[i] = randomUint();
}
}
static unsigned int randomUint()
{
int value = rand() % UINT_MAX;
return value;
}
protected:
void initIndexBuffer()
{
indexBuffer = new unsigned int[bufferSize];
for (unsigned int i = 0 ; i < bufferSize ; i++)
{
indexBuffer[i] = rand() % bufferSize;
}
}
public:
unsigned int getSum() const
{
return sum;
}
unsigned int computeTimeInMicroSeconds()
{
struct timeval startTime, endTime;
gettimeofday(&startTime, NULL);
unsigned int sum = computeSum();
gettimeofday(&endTime, NULL);
return ((endTime.tv_sec - startTime.tv_sec) * 1000 * 1000) + (endTime.tv_usec - startTime.tv_usec);
}
unsigned int computeSum()
{
sum = 0;
for (unsigned int i = 0 ; i < bufferSize ; i++)
{
unsigned int index = indexBuffer[i];
sum += valueBuffer[index];
}
return sum;
}
protected:
unsigned int sum;
unsigned int bufferSize;
unsigned int * valueBuffer;
unsigned int * indexBuffer;
};
unsigned int runTestForBufferSize(TimedSumComputer & timedComputer, unsigned int bufferSize)
{
timedComputer.init(bufferSize);
unsigned int timeInMicroSec = timedComputer.computeTimeInMicroSeconds();
cout << "bufferSize = " << bufferSize << " - time (in micro-sec) = " << timeInMicroSec << endl;
return timedComputer.getSum();
}
void runTest(TimedSumComputer & timedComputer)
{
unsigned int result = 0;
for (unsigned int i = 1 ; i < 10 ; i++)
{
result += runTestForBufferSize(timedComputer, BUFFER_SIZE * i);
}
unsigned int factor = 1;
for (unsigned int i = 2 ; i <= 6 ; i++)
{
factor *= 10;
result += runTestForBufferSize(timedComputer, BUFFER_SIZE * factor);
}
cout << "result = " << result << endl;
}
void printPid()
{
cout << "###############################" << endl;
cout << "Pid = " << getpid() << endl;
cout << "###############################" << endl;
}
void printNbContextSwitch()
{
struct rusage usage;
getrusage(RUSAGE_THREAD, &usage);
cout << "Number of voluntary context switch: " << usage.ru_nvcsw << endl;
cout << "Number of involuntary context switch: " << usage.ru_nivcsw << endl;
}
int main()
{
printPid();
TimedSumComputer timedComputer;
runTest(timedComputer);
printNbContextSwitch();
return 0;
}
Откуда берутся ваши данные? Используете ли вы больше памяти, чем физическая машина? Я ожидаю, что доступ к выгружаемому разделу памяти заставит увеличить счетчик переключения контекста, когда процесс приостанавливается, ожидая операции подкачки. –
Программа, которую я использую, представляет собой просто простую тестовую программу, она только обращается к буферам, которые инициализируются случайными значениями (см. Функцию rand()) –