Saturday, August 23, 2014

Probing CPU core number with a groovy script

I started playing with groovy and at the same time wanted to find a method to test how many cores a system has... so I'm sharing a small groovy script that does this.
It is very java-like as I used it to play with this language.

I looked on the web for a while and found no similar scripts, so I think it may be interesting. It works by first estimating the time needed for resolving a trivial time-consuming task in a single thread, then doing this again for multiple threads.
The comparison of these two values gives an estimate of the number of cores. Here's the script itself:

public class UselessThread extends Thread {
  private long result = 0;
  private final long loopIterations;

  public UselessThread(loopIterations) {
    this.loopIterations = loopIterations;
  }

  public void run() {
    println("thread started with " + loopIterations);
    for(long j=0; j < loopIterations; j++)
      result += j
    println("thread ended");
  }
}

public class MultiThread {
  public long startMultiThreads(loopIterations, nThreads) {
    Date before = new Date();

    Thread[] threadsToJoin = new Thread[nThreads];
    for (int i = 0 ; i < nThreads ; i++) {
      Thread thr = new UselessThread(loopIterations);
      thr.start();
      threadsToJoin[i] = thr;
    }

    for(Thread thr: threadsToJoin) {
      println("joining thread: " + thr);
      thr.join()
    }
    Date after = new Date()
    def elapsedTime = after.getTime()-before.getTime()

    return elapsedTime
  }
}

public class Start {
  def main() {
    final int thrToStart = 12
    // final long loopIterations = 1000 * 1000 * 1000
    final int TARGET_SECS = 5;
    final float MULT_FACTOR_MSECS = (TARGET_SECS+1)*1000;

    long loopIterations = 10000;
    float diffSecs = -1;
    long singleThreadTime = -1;
    System.out.println("Starting single thread, looking for enough loop length")
    for(loopIterations = 1000 ; diffSecs < TARGET_SECS ;) {
      print("Trying with " + loopIterations + "...");
      singleThreadTime = new MultiThread().startMultiThreads(loopIterations, 1)
      diffSecs = singleThreadTime/1000;
      if (singleThreadTime < 1) singleThreadTime = 1;
      if (diffSecs < TARGET_SECS)
        loopIterations *= (MULT_FACTOR_MSECS/singleThreadTime); // to be quick, point to 11000 instead of 10000 and be approximative
      println(", time: " + diffSecs);
    }
    println("Ended single thread, loopIterations: " + loopIterations)

    long multiThreadsTime = new MultiThread().startMultiThreads(loopIterations, thrToStart)

    double coresNum = singleThreadTime * thrToStart / (double) multiThreadsTime;

    println("multiThreadsTime: " + multiThreadsTime + ", singleThreadTime: " + singleThreadTime);
    println("coresNum: " + coresNum);
  }
}

new Start().main()


I found the result to be quite exact in practice, as it correctly report about two cores on a dual core system, about four cores on a four core system, and so on... please note that the script only "detected" real cores, that is, in CPUs with Hyperthreading only the real cores have an effect on the speed of multiple threads in this simple implementation. I tried this with a dual core with hyperthreading (two real cores with hyperthreading, that is, four logical cores), and the script reports two cores.
Maybe in the future I'll try going on... just to enjoy!