1

I'm trying to write a program that will stress test ALL logical cores on a system in C# (Up to 72 logical cores) and no matter what, System.Environment.ProcessorCount() only returns 32, no matter what. I ran it on a system with 40 cores and 72 cores and it only sees 32 cores.

I even tried running it on core 32 (index 0), for example, and it wraps around and stress tests CPU0 Node0 again.

Anyone have any ideas how to stress test ALL cores? I'm using the logic I found in this article (http://omegacoder.com/?p=94)

All 40 cores shown. Will run up to CPU15 Node1 (32nd Core)

Tried compiling as 64 bit and still nothing.

Edit: Added Code Sample Below: Usage: (Pass in the CPU number -> 31 = CPU12 Node1) System has 20 logical cores per physical processor)

public static void Usage(int cpuToStart) {
            // set cpu 
            int cpu = cpuToStart;
            ThreadProcessor tp = new ThreadProcessor();
            // Spikes CPU 1
            Console.WriteLine("Spike CPU 1");
            tp.SpikeCPU(cpu);

            // ouput error
            if (tp._ex != null) {
                Console.WriteLine(tp._ex.Message);
            }
            // No error
            else {
                // if multiple processors (logical cores)
                if (Environment.ProcessorCount > 1) {
                    while (++cpu < Environment.ProcessorCount) {
                        Thread.Sleep(1000);
                        // Spike each CPU
                        Console.WriteLine("Spike CPU " + (cpu + 1).ToString());
                        tp.SpikeCPU(cpu);

                        if (tp._ex != null) {
                            Console.WriteLine(tp._ex.Message);
                            break;
                        }
                    }

                }
                else // Either a single CPU or hyperthreading not enabled in the OS or the BIOS.
            {
                    Console.WriteLine("This PC does not have two processors available.");
                }
            }

        }

Spike CPU:

public void SpikeCPU(int targetCPU) {

            // Create a worker thread for the work.
            _worker = new Thread(DoBusyWork);

            // Background is set so not to not prevent the
            // mainprocess from terminating if someone closes it.
            _worker.IsBackground = true;

            _worker.Start((object)targetCPU);
            _worker.Join(); // Wait for it to be done.
        }

DoWork

public void DoBusyWork(object target) {
            try {
                int processor = (int)target;
                Thread tr = Thread.CurrentThread;

                if (Environment.ProcessorCount > 1) {
                    SetThreadAffinityMask(GetCurrentThread(),
                        new IntPtr(1 << processor));
                }

                CalculatePI.Process(PiSignificantDigits);
            }
            catch (Exception ex) {
                _ex = ex;
            }

        }

Maybe this will help everyone understand. I've labeled every CPU when I spike them up to 39 (40th CPU): 19 is CPU19 Node0, 20 is CPU0 Node1

Levi Fuller
  • 13,631
  • 4
  • 38
  • 44
  • 1
    What are you doing to make it run on core 32? – Scott Chamberlain Sep 25 '14 at 17:35
  • 2
    The CLR currently does not support more than one processor group. How cores are distributed among groups on that machine is not clear from your question, 32 is an odd number to have in one group. But ultimately likely to be a no-go. – Hans Passant Sep 25 '14 at 18:03
  • The reason it's getting back 32 is that the call 'System.Environment.ProcessorCount' is returning 32 no matter what. – Levi Fuller Sep 25 '14 at 19:12
  • So even if CLR only support a single processor group, can I change the "single" processor group it targets? Another solution would be welcome as well, we're just trying to do this in C# as that's what our framework is built in. Interop calls are welcome. – Levi Fuller Sep 25 '14 at 19:26

2 Answers2

0

How to use more cores:

  • use more processes and launch them in parallel
  • create threads by hand (with new Thread() ...) up to the point the core counts are used

Amdahl's law forces the scaling of your code based on locks, so make sure all computations are as parallel as possible.

As for me, I would say that if you want to work a (more) realistic scenario, I would launch multiple processes for other reasons: the GC can freeze all the 32+ (logical) cores to clean up memory from time to time, it would be great if you want to use as a web server (or something similar) to not freeze all your application with 72 cores as they are waiting the Full GC (Gen2 GC) to happen. It would be great that let's say just 16 cores are frozen and the other 3 processes do answer to requests and advance your computations.

Ciprian Khlud
  • 434
  • 3
  • 6
  • Using more cores isn't the issue here. Using SPECIFIC cores is what I'm trying to do. I am supposed to test each logical core individually. – Levi Fuller Sep 25 '14 at 19:29
  • According to this link: [MS Multicore Link](http://msdn.microsoft.com/en-us/library/windows/desktop/ms684251%28v=vs.85%29.aspx) you have to map with PInvoke the method you chose th processor but you don't have hard guarantees that the code will be working for you. – Ciprian Khlud Sep 25 '14 at 19:34
  • "When you specify a thread ideal processor, the scheduler runs the thread on the specified processor when possible. Use the SetThreadIdealProcessor function to specify a preferred processor for a thread. This does not guarantee that the ideal processor will be chosen but provides a useful hint to the scheduler. On systems with more than 64 processors, you can use the SetThreadIdealProcessorEx function to specify a preferred processor in a specific processor group." – Ciprian Khlud Sep 25 '14 at 19:35
  • Last comment with a (maybe) related [answer](http://stackoverflow.com/questions/13386855/windows-server-datacenter-set-cpu-affinity-with-64-cores). – Ciprian Khlud Sep 25 '14 at 19:42
  • Keep in mind, I'm not using "SetThreadIdealProcessor()", instead, I'm using "SetThreadAffinityMask" which will in fact utilize the cpu specified. I am able to successfully target and stress test the first 32 CPUs. if (Environment.ProcessorCount > 1) { SetThreadAffinityMask(GetCurrentThread(), new IntPtr(1 << processor)); } – Levi Fuller Sep 25 '14 at 19:42
  • Shouldn't affect me (40 logical cores) "Systems with fewer than 64 logical processors always have a single group, Group 0." http://msdn.microsoft.com/en-us/library/windows/desktop/dd405503(v=vs.85).aspx – Levi Fuller Sep 25 '14 at 20:13
0

So I figured out the issue and as I suspected, it was in this piece of code:

int processor = (int)target;
Thread tr = Thread.CurrentThread;
if (Environment.ProcessorCount > 1) {
    SetThreadAffinityMask(GetCurrentThread(), new IntPtr(1 << processor));
}

Because int is only 32 bits, when it tried to bit shift to set the 33rd processor to 1 and all the others to 0, it would wrap because it had nowhere to go. Simply passing a long fixed this issue. Will have to figure out a solution for a system with 72 logical cores, but that's tomorrow's problem.

int processor = (int)target;
long shift = 1;
long cpuToTest = shift << processor;
Thread tr = Thread.CurrentThread;

if (Environment.ProcessorCount > 1) {
    SetThreadAffinityMask(GetCurrentThread(), new IntPtr(cpuToTest));
}

CalculatePI.Process(PiSignificantDigits);
Levi Fuller
  • 13,631
  • 4
  • 38
  • 44
  • Forgot to mention, also if you don't compile it as 64-bit, the program will only be able to detect 32 logical cores, so you need to do that as well. Right Click Project -> Build -> Platform Target: x64 – Levi Fuller Sep 25 '14 at 21:39
  • This will probably help http://msdn.microsoft.com/en-us/library/system.collections.bitarray.aspx – reggaeguitar Sep 25 '14 at 22:36