Как прибить поток к ядру?

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Ответить
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Как прибить поток к ядру?

Сообщение CRobin »

Здравствуйте. Использую функции SetThreadAffinityMask и аналогичной pthread_getaffinity_np. Не могу понять как составить маску ЦП (группы ЦП) для того чтоб задать соответствие? Под Windows стабильно результат ноль с кодом ошибки 6. Под Линукс формально удается что то засетить, но судя по тому что результат отличается от ожидаемого, получается угадать по форме, но не по сути. Рабочие примеры из интернетов весьма противоречивы, вероятно не подходят под новые архитектуры.
Аватара пользователя
Pavia
постоялец
Сообщения: 290
Зарегистрирован: 07.01.2011 11:46:51

Сообщение Pavia »

Наблюдал пару раз глюки. Код просто не срабатывал до перезагрузки компа.
А так ничего там сложного нет.
Каждый бит соответствует одному логическому-ядру. Если у вас 8 логических ядер. То соответственно вы должны выставлять не более 8 бит.

То что у майкрософт логические ядра, то у интела потоками.
К примеру у меня 1 ЦП имеющий 4 ядра(физических) и каждое ядро может исполнять одновременно по 2 два потока итого 8 логических ядер.
255 Д= 11111111 Б - т.е поток может исполняться на всех 8 логических ядрах.
254 Д = 11111110 Б - все кроме нуливого.

Если делаете под свой процесс, то разрешения прав не требуется. Если чужой то нужны права админа.

Добавлено спустя 3 минуты 41 секунду:
Забыл сказать что SetThreadAffinityMask - носит рекомендательный характер. И если ядро загружено по полной, то виндоус перераспределит принудительно на другое.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

а ещё MSDN говорит, что назначать SetThreadAffinityMask нужно соответственно битам от GetProcessAffinityMask, а то ничё не получится.
A thread affinity mask must be a subset of the process affinity mask for the containing process of a thread. A thread can only run on the processors its process can run on. Therefore, the thread affinity mask cannot specify a 1 bit for a processor when the process affinity mask specifies a 0 bit for that processor

как то так:

Код: Выделить всё

program project1;

{$mode delphi}{$H+}

uses
  Windows, Classes, SysUtils;

var
  pm, sm : DWORD;
  l   : DWORD;
  res  : DWORD;
begin
  GetProcessAffinityMask( GetCurrentProcess, pm, sm);
  writeln('Process Id:   ', GetCurrentProcessId );
  writeln('Process Mask: ', IntToHex(pm, 8));
  writeln('System  Mask: ', IntToHex(sm, 8));
  l:=1;
  while (l<>0) and (l and pm = 0) do l:=l shl 1;
  if l = 0 then begin
    writeln('epic fail... no processors?');
    Halt(1);
  end;
  res:=SetThreadAffinityMask( GetCurrentThread, l and pm); // Новая маска для потока AND маска для процесса
  if res=0 then
    writeln('Error! ', GetLastError)
  else begin
    writelN('Thread mask was: ', INtToHex(res,8));
    writelN('Thread mask new: ', IntToHex(l, 8));
  end;
end.

(у меня на Windows 10 работает без ошибок)

Сам никогда не пробовал... а для каких задач такой функционал нужен?

PS. двойное переключение Affinity маски

Код: Выделить всё

program project1;

{$mode delphi}{$H+}

uses
  Windows, Classes, SysUtils;

var
  pm, sm : DWORD;
  l   : DWORD;
  res  : DWORD;
begin
  GetProcessAffinityMask( GetCurrentProcess, pm, sm);
  writeln('Process Id:   ', GetCurrentProcessId );
  writeln('Process Mask: ', IntToHex(pm, 8));
  writeln('System  Mask: ', IntToHex(sm, 8));

  writeln('First try:');
  l:=1;
  while (l<>0) and (l and pm = 0) do l:=l shl 1;
  if l = 0 then begin
    writeln('epic fail... no processors?');
    Halt(1);
  end;
  res:=SetThreadAffinityMask( GetCurrentThread, l and pm); // Новая маска для потока AND маска для процесса
  if res=0 then
    writeln('Error! ', GetLastError)
  else begin
    writelN('Thread mask was: ', INtToHex(res,8));
    writelN('Thread mask new: ', IntToHex(l, 8));
  end;

  writeln('Second try:');
  l:=l shl 1;
  while (l<>0) and (l and pm = 0) do l:=l shl 1;
  if l = 0 then begin
    writeln('no more processors to play :(');
    Halt(1);
  end;
  res:=SetThreadAffinityMask( GetCurrentThread, l and pm);
  if res=0 then
    writeln('Error! ', GetLastError)
  else begin
    writelN('Thread mask was: ', INtToHex(res,8));
    writelN('Thread mask new: ', IntToHex(l, 8));
  end;
end.

(опять же, у меня на Windows 10 работает без ошибок)
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

Нашел одну из своих ошибок. скалогрыз функция не работает с GetCurrentThread так же как и с self.ThreadID, у меня завелось только с self.Handle (разные численные значения на Win7) вы знаете что это за сущности?
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

ThreadID это точно не Handle, который функция ожидает.
ID - это уникальный индентификатор потока/процесса на системном уровне. (все другие процессы/потоки его таким увидят)
А хендл уникален разве что внутри одного процесса, и должен использоваться для API вызовов.

Курить (совсем чуток) здесь

я думаю у тебя заработал с GetCurrentThread (т.к. в моём коде работает), может быть ты вызвал GetCurrentThreadID?

Опять же, ты киваешь в сторону Self.Handle, а значит ты используешь TThread. Вот бы код посмотреть :roll:
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

скалогрыз функция GetCurrentThread понимается как не объявлена, зато GetCurrentThreadID сразу возвращает айди треда. Так что вы правы, видимо я пытался использовать его. Используется класс TThread, со свойством Self.Handle все работает корретно, только что проверил.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

CRobin писал(а):функция GetCurrentThread понимается как не объявлена

Понятно - модуль Windows не используется, а используется что-то своё.
Тогда действительно, использование Self.Handle это то, что тебе нужно.


а для каких задач такой функционал нужен?
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

скалогрыз это нужно для корретной работы таймера при измерении малых отрезков времени.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

CRobin писал(а):скалогрыз это нужно для корретной работы таймера при измерении малых отрезков времени.
допустим

а performancecounter не справляется с задачей?
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

скалогрыз у меня кросплатформенное решение на основе RDTSC
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

CRobin писал(а):скалогрыз у меня кросплатформенное решение на основе RDTSC

тогда понятно зачем тебе affinity.
В линуксе с pthread_setaffinity_np заработал?
CRobin
постоялец
Сообщения: 145
Зарегистрирован: 26.01.2016 11:15:39

Сообщение CRobin »

скалогрыз да, работает точно по тому же принципу
Ответить