2

My Java app has a program which executes multiple threads on the same time to complete a task. It works really well on my local computer as it has 4 Cores and 8 Logical Processors but when I deploy my app on cloud foundry, it doesn't allow to create more than 1 thread. I debugged and found that Cloud Foundry JVM has only 1 CPU allocated therefore it cannot run multiple threads simultaneously.

How can I fix this problem?

Do I need to buy more CPUs or There is a way to change JVM configuration to set multiple CPUs for the java app.

Gippy Aulakh
  • 104
  • 7
  • Number of Java threads should not be dependent on the CPU Cores...What is the error you get if you start the second thread ? – saurav Aug 13 '20 at 13:21
  • I don't get any error. I have splitted a task into 4 threads which works fine on my local PC as it takes only 15 minutes to finish but when I deploy in CF, it takes around 8-10 hours even worst than the sequential (single-threaded) program. I found that threads are going on sleep for really long time ( around 4 hours). Wondering if configuring heap size will fix the issue. – Gippy Aulakh Aug 19 '20 at 05:41

2 Answers2

1

In the SAP Cloud Platform Cloud Foundry, a number of CPUs depends on allocated memory. You can get a maximum vertical scaling of 8GB RAM and 2 CPUs. See the ration in the quote below.

In the Cloud Foundry environment, applications get guaranteed CPU share of ¼ core per GB instance memory. As the maximum instance memory per application is 8 GB, this allows for vertical scaling up to 2 CPUs.

Here you can find more on quotas and limitations of SAP Cloud Platform.

This blog provides interesting insights on performance testing on SCP

To update your quota go to overview section of your App and follow the steps on the screenshot: enter image description here

Artyom Kovalyov
  • 374
  • 3
  • 11
  • 1
    Thanks for your response Artyom. I have tried increasing quota but no luck. I increased the quota to max (8GB) and it gives me 16 Logical Processors. These 16 logical processors are still not able to run my code in parallel processing. After a long research, I found that Cloud Foundry uses Open JDK for java VMs and these VMs are configured to use single core CPU and we need to configure it manually to use multi core CPUs. This [link](https://www.databasesandlife.com/java-docker-aws-ecs-multicore/) describes the situation. I'll update you once I solve the issue. – Gippy Aulakh Jul 29 '20 at 01:43
  • That probably skipped my radar, Gippy, I'm also curious how you configure the multi-core for Java on CF. I'll try to find out. Also, according to docs, you should have only 2 CPU units with 8GB RAM, where have you found that you have 16? They give you 0.25 CPU for every Gig of RAM as the documentation says. – Artyom Kovalyov Aug 03 '20 at 09:11
  • 1
    I haven't configured multi-core yet. I'll update you once I hear back from SAP. int availableProcessors = Runtime.getRuntime().availableProcessors(); gave me the available processors. – Gippy Aulakh Aug 05 '20 at 04:16
  • That's cool! I'll be curious about the final results of your efforts to get multi-core performance for your App. I also asked how to achieve this but haven't heard anything yet. – Artyom Kovalyov Aug 06 '20 at 07:22
0

I am giving an answer to my own question as I have figured out the issue. The thread deadlock was the root cause of the issue. Multiple threads were calling the same methods concurrently and the threads were getting trapped when waiting for each other to release the lock. Therefore the execution was becoming unresponsive. To fix it, I changed all the methods used in call method of Callable to have synchronisation using keyword "synchronized" in method declaration. It is now working fine locally and in the Cloud environment. The only thing, I still don't understand is why deadlock was only happening in cloud environment but not locally. I guess it might be the different JVM configuration in the cloud.

@Artyom Kovalyov, here is how I splited tasks for parallel processing.

final int numberOfWorkers = 4;
List<Callable<Void>> tasks = new ArrayList<Callable<Void>>();

//code here to create and add tasks to list

final List<List<Callable<Void>>> dividedTasks = Lists.partition(tasks, numberOfWorkers);
final ExecutorService executor = Executors.newFixedThreadPool(numberOfWorkers);
for (List<Callable<Void>> subsetOfTasks : dividedTasks) {
    try {

// you can invoke all tasks in one go but I prefer invoking number of taks same as thread pool max thread number

        executor.invokeAll(subsetOfTasks);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
executor.shutdownNow();
Gippy Aulakh
  • 104
  • 7