4

I have a workstation whose operating system is 64 bit windows server 2012 R2. I am using Delphi XE7 Update 1. The workstation has 72 cores including hyperthreading. I want all my applications to run on all the cores that are available each time the application is run. I wish to do this programmatically rather that using set affinity in task master (which only applies to one group at a time and I have two groups of 36 cpus which I want to engage simultaneously) or boot options in advance setting from msconfig.

I realise that the question is similar to or encompasses the following questions that have already been asked on Stackoverflow

Delphi TParallel not using all available cpu

Strange behaviour of TParallel.For default ThreadPool

SetProcessAffinityMask - Select more than one processor?.

and I have also looked at the suggestion edn.embarcadero.com/article/27267.

But my SetProcessAffinityMask question relates to more that 64 cores using a 64 bit operation system and is not confined to using TParallel.

The solution that I have tried is an adaptation of the one proffered by Marco van de Voort

   var 
   cpuset  : set of 0..71;
   i: integer;
   begin
   cpuset:=[];
   for i:=0 to 71 do
   cpuset:=cpuset+[i];

   SetProcessAffinityMask(ProcInfo.hProcess, dword(cpuset)); 

   end;

but it did not work.

I would be grateful for any suggestions.

Community
  • 1
  • 1
Jimmy Dean
  • 153
  • 2
  • 7
  • 2
    You can't. With more than 64 processors, they will be split into processor groups. Your process can only use processors from a single group. Read about processor groups on msdn. Also, you must be able to see that DWORD only has 32 bits. Is your process 64 bit? – David Heffernan Jul 18 '15 at 19:11
  • 1
    I'd also recommend not using set code like that. Very reliant on implementation detail. For all bits set use `$ffffffffffffffff`. For specific use shl and or. – David Heffernan Jul 18 '15 at 19:20
  • 1
    @davidHeffernan I have read msdn processor groups and it states "that an application that requires the use of mutliple groups so that is can run on more than 64 processors must explicitly determine where where to run its threads and is responsible for setting the threads' processor affinitities to the desired groups." - so it can be done. Point 2 DWORD is 32 bit what is the 64 bit equivalent -cardinal? – Jimmy Dean Jul 18 '15 at 19:21
  • You are right. I was under the impression that you need multiple processes. You can have multi group processes. What steps have you taken to assign your threads to different processor groups? As regards 64 bit affinities, did you read the documentation for the function you are calling. That has the answer. Frankly it's depressing that you don't seem to be reading the documentation before asking. I guess I should have read more closely too. – David Heffernan Jul 18 '15 at 19:51
  • @davidheffernan I did read the msdn function docs and the docs referring to SetThreadAffinityMask function. The comments following The SetProcessAffinityMask function seem to give conflicting views and those comments were made in 2010 and 2009 well before windows provided windows 2012 R2. so they may not be pertinent or relevant. I am looking for some stragetic assistance. I did not spell out all my research into this matter before I posed the question but resassured I have read the msdn docs relating to processor groups, numa groups and the numerous functions listed in those docs. – Jimmy Dean Jul 18 '15 at 20:28
  • OK, I guess I was misled by you trying to stuff 72 bits into a 32 bit value. – David Heffernan Jul 18 '15 at 20:30
  • Now I remember why I said you need multiple processes. To deal with heap allocation. In a multi group process, the Delphi MM is not going to be efficient. Either write your own NUMA aware MM, find a third party one, or use multiple processes. – David Heffernan Jul 19 '15 at 06:28

1 Answers1

2

As discussed in the comments, an affinity mask is 32 bits in 32 bit code, and 64 bits in 64 bit code. You are trying to set a 72 bit mask. Clearly that isn't going to work.

You are going to need to understand processor groups, covered in detail on MSDN: Processor Groups, including this link to Supporting Systems That Have More Than 64 Processors.

Since you've got 72 processors you'll have multiple processor groups. You need to either use multiple processes to reach all groups, or use a multi process group. From the doc:

After the thread is created, its affinity can be changed by calling SetThreadAffinityMask or SetThreadGroupAffinity. If a thread is assigned to a different group than the process, the process's affinity is updated to include the thread's affinity and the process becomes a multi-group process. Further affinity changes must be made for individual threads; a multi-group process's affinity cannot be modified using SetProcessAffinityMask.

This is pretty gnarly stuff. If you are in control of your threads then you should be able to do what you need with SetThreadGroupAffinity. If you are using the Delphi threading library then you don't control the threads. That probably makes a single process solution untenable.

Another problem to consider is memory locality. If the machine uses NUMA memory, then I know of no Delphi memory manager that can perform well with NUMA memory. In a NUMA environment, if performance is important to you, you probably need each thread to allocate memory on the thread's NUMA node.

The bottom line here is that there is no simple quick fix to produce code that will use all of this machine's resources effectively. Start with the documentation I linked to above and perform some trials to make sure you understand all the implications of processor groups and NUMA.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 4
    Also read: [Supporting Systems That Have More Than 64 Processors](https://msdn.microsoft.com/en-us/library/windows/hardware/dn653313.aspx) – Remy Lebeau Jul 19 '15 at 03:38