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

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

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

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

Сообщение CRobin » 22.09.2016 22:11:36

Здравствуйте. Использую функции SetThreadAffinityMask и аналогичной pthread_getaffinity_np. Не могу понять как составить маску ЦП (группы ЦП) для того чтоб задать соответствие? Под Windows стабильно результат ноль с кодом ошибки 6. Под Линукс формально удается что то засетить, но судя по тому что результат отличается от ожидаемого, получается угадать по форме, но не по сути. Рабочие примеры из интернетов весьма противоречивы, вероятно не подходят под новые архитектуры.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

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

Сообщение Pavia » 22.09.2016 23:40:54

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

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

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

Добавлено спустя 3 минуты 41 секунду:
Забыл сказать что SetThreadAffinityMask - носит рекомендательный характер. И если ядро загружено по полной, то виндоус перераспределит принудительно на другое.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

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

Сообщение скалогрыз » 23.09.2016 00:53:44

а ещё 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 работает без ошибок)
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение CRobin » 23.09.2016 01:14:39

Нашел одну из своих ошибок. скалогрыз функция не работает с GetCurrentThread так же как и с self.ThreadID, у меня завелось только с self.Handle (разные численные значения на Win7) вы знаете что это за сущности?
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

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

Сообщение скалогрыз » 23.09.2016 01:24:30

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

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

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

Опять же, ты киваешь в сторону Self.Handle, а значит ты используешь TThread. Вот бы код посмотреть :roll:
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение CRobin » 23.09.2016 01:40:34

скалогрыз функция GetCurrentThread понимается как не объявлена, зато GetCurrentThreadID сразу возвращает айди треда. Так что вы правы, видимо я пытался использовать его. Используется класс TThread, со свойством Self.Handle все работает корретно, только что проверил.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

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

Сообщение скалогрыз » 23.09.2016 02:45:16

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

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


а для каких задач такой функционал нужен?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение CRobin » 23.09.2016 14:27:40

скалогрыз это нужно для корретной работы таймера при измерении малых отрезков времени.
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

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

Сообщение скалогрыз » 23.09.2016 20:39:21

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

а performancecounter не справляется с задачей?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение CRobin » 23.09.2016 22:34:52

скалогрыз у меня кросплатформенное решение на основе RDTSC
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39

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

Сообщение скалогрыз » 24.09.2016 01:13:00

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

тогда понятно зачем тебе affinity.
В линуксе с pthread_setaffinity_np заработал?
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение CRobin » 24.09.2016 02:40:51

скалогрыз да, работает точно по тому же принципу
CRobin
постоялец
 
Сообщения: 145
Зарегистрирован: 26.01.2016 12:15:39


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9

Рейтинг@Mail.ru
cron