Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime.getRuntime().availableProcessors() returning 1 even though many cores available on ECS AWS

I am running a task via Docker on AWS's ECS. The task does some calculations which are CPU-bound, which I would like to run in parallel. I start a thread pool with the number of threads specified in Runtime.getRuntime().availableProcessors() which works fine locally on my PC. For some reason, on AWS ECS, this always returns 1, even though there are multiple cores available. Therefore my calculations run serially, and do not utilize the multiple cores.

For example, right now, I have a task running on a "t3.medium" instance which should have 2 cores according to the docs.

When I execute the following code:

System.out.println("Java reports " + 
    Runtime.getRuntime().availableProcessors() + " cores");

Then the following gets displayed on the log:

Java reports 1 cores

I do not specify the cpu parameter in ECS's task definition. I see that in the list of tasks within the ECS Management Console it has a column for "CPU" which reads 0 for my task. I also notice that in the list of instances (= VMs) it lists "CPU available" as 2048 which presumably has something to do with the fact the VM has 2 cores.

I would like my Java program to see all cores that the VM has to offer. (As would normally be the case when a Java program runs on a computer without Docker).

How do I go about doing that?

like image 286
Adrian Smith Avatar asked Apr 09 '19 15:04

Adrian Smith


People also ask

What does runtime getRuntime <UNK> availableProcessors return?

Runtime. getRuntime. availableProcessors to get the number of cores per node.

What is CPU units in ECS?

Amazon ECS uses a standard unit of measure for CPU resources called CPU units. 1024 CPU units is the equivalent of 1 vCPU. For example, 2048 CPU units is equal to 2 vCPU. Note: When defining task definitions, you can also use 1 vCPU instead of 1024.

What is Activeprocessorcount?

The number of active processing cores available on the computer.


1 Answers

Thanks to @stdunbar in the comments for pointing me in the right direction.

EDIT: Thanks to @Imran in the comments. If you start lots of threads, they will absolutely be scheduled to multiple cores. This answer is only about getting Runtime.getRuntime().availableProcessors() to return the right value. Many "thread pools" start as many threads as that method returns: it should return the number of cores available.

There seem to be two main solutions, neither of which is ideal:

  • Set the cpu parameter in the task definition. For example, if you have 2 cores and want to use them both you have to set "cpu":2048 in the task's definition. This isn't very convenient for two reasons:

    • If you choose a bigger instance, you have to make sure to update this parameter.

    • If you want to have two tasks running simultaneously, both of which can sporadically use all cores for short-term activities, AWS will not schedule two tasks on a 2-core system with "cpu":2048. It says the VM is "full" from a CPU perspective. This goes against the timesharing (Unix etc.) philosophy of every task taking what it needs (for example, imagine on a desktop PC, if you run Word and Excel on a dual-core computer, and Windows wouldn't allow you to start any other tasks, on the grounds that Word might need all of one core, and Excel might do too, so if another program might need all the core at the same time, there wouldn't be enough cores.)

  • Use the -XX:ActiveProcessorCount=xx JVM option in JDK 10 onwards, as described here. This isn't convenient because:

    • As above, you have to change the value if you change your instance type.

I wrote a longer blog post describing my findings here: https://www.databasesandlife.com/java-docker-aws-ecs-multicore/

like image 177
Adrian Smith Avatar answered Oct 07 '22 23:10

Adrian Smith