[ https://issues.apache.org/jira/browse/FELIX-5247?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Dmitry Konstantinov updated FELIX-5247: --------------------------------------- Description: Thread creation is a quite expensive operation, so it make sense to reuse threads in ResolverImpl if they are needed to split some task and do it in parallel. For example: Apache Karaf startup with several features can install about 300 bundles. If each one will create Runtime.getRuntime().availableProcessors() threads - so, during a startup about 1000 threads will be created only by Resolver (in case of a server machine even much more). Thread creation takes let's say (depends on machine, JDK, OS, etc) about 10-20 ms, so we are spending about 1-2 seconds of startup time only to create some threads. it make sense to create a thread pool once (with a configurable thread number) and reuse it for resolving of different bundles. Threads creation, stack examples: {noformat} java.lang.Thread.<init>(ThreadGroup, Runnable, String, long) Thread.java java.util.concurrent.Executors$DefaultThreadFactory.newThread(Runnable) Executors.java:613 java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor, Runnable) ThreadPoolExecutor.java:612 java.util.concurrent.ThreadPoolExecutor.addWorker(Runnable, boolean) ThreadPoolExecutor.java:925 java.util.concurrent.ThreadPoolExecutor.execute(Runnable) ThreadPoolExecutor.java:1357 org.apache.felix.resolver.ResolverImpl$EnhancedExecutor.execute(Runnable) ResolverImpl.java:2436 org.apache.felix.resolver.ResolverImpl$1Computer.run() ResolverImpl.java:1150 org.apache.felix.resolver.ResolverImpl$EnhancedExecutor$1.run() ResolverImpl.java:2442 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) ThreadPoolExecutor.java:1142 java.util.concurrent.ThreadPoolExecutor$Worker.run() ThreadPoolExecutor.java:617 java.lang.Thread.run() Thread.java:745 {noformat} {noformat} java.lang.Thread.<init>(ThreadGroup, Runnable, String, long) Thread.java java.util.concurrent.Executors$DefaultThreadFactory.newThread(Runnable) Executors.java:613 java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor, Runnable) ThreadPoolExecutor.java:612 java.util.concurrent.ThreadPoolExecutor.addWorker(Runnable, boolean) ThreadPoolExecutor.java:925 java.util.concurrent.ThreadPoolExecutor.execute(Runnable) ThreadPoolExecutor.java:1357 org.apache.felix.resolver.ResolverImpl$EnhancedExecutor.execute(Runnable) ResolverImpl.java:2436 org.apache.felix.resolver.ResolverImpl.calculatePackageSpaces(Executor, ResolverImpl$ResolveSession, Candidates, Collection) ResolverImpl.java:1158 org.apache.felix.resolver.ResolverImpl.checkConsistency(Executor, ResolverImpl$ResolveSession, List, List, Candidates, Map, Map, boolean) ResolverImpl.java:471 org.apache.felix.resolver.ResolverImpl.resolve(ResolveContext, Executor) ResolverImpl.java:347 org.apache.felix.resolver.ResolverImpl.resolve(ResolveContext) ResolverImpl.java:158 org.apache.felix.framework.StatefulResolver.resolve(Set, Set) StatefulResolver.java:431 org.apache.felix.framework.Felix.resolveBundleRevision(BundleRevision) Felix.java:4118 org.apache.felix.framework.Felix.startBundle(BundleImpl, int) Felix.java:2124 org.apache.felix.framework.BundleImpl.start(int) BundleImpl.java:998 org.apache.felix.framework.BundleImpl.start() BundleImpl.java:984 org.apache.karaf.features.internal.FeaturesServiceImpl.startBundle(InstallationState, Bundle) FeaturesServiceImpl.java:520 org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(Set, EnumSet) FeaturesServiceImpl.java:478 org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(Feature, EnumSet) FeaturesServiceImpl.java:419 org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(String, String, EnumSet) FeaturesServiceImpl.java:394 org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(String, EnumSet) FeaturesServiceImpl.java:364 {noformat} was: Thread creation is a quite expensive operation, so it make sense to reuse threads in ResolverImpl if they are needed to split some task and do it in parallel. For example: Apache Karaf startup with several features can install about 300 bundles. If each one will create Runtime.getRuntime().availableProcessors() threads - so, during a startup about 1000 threads will be created only by Resolver (in case of a server machine even much more). Thread creation takes let's say (depends on machine, JDK, OS, etc) about 10-20 ms, so we are spending about 1-2 seconds of startup time only to create some threads. it make sense to create a thread pool once (with a configurable thread number) and reuse it for resolving of different bundles. > Reduce number of threads created by Resolver during a startup of OSGi-based > applications > ---------------------------------------------------------------------------------------- > > Key: FELIX-5247 > URL: https://issues.apache.org/jira/browse/FELIX-5247 > Project: Felix > Issue Type: Improvement > Components: Framework, Resolver > Affects Versions: framework-5.4.0, resolver-1.8.0 > Reporter: Dmitry Konstantinov > Labels: performance > Attachments: karaf_thread_creation.png > > > Thread creation is a quite expensive operation, so it make sense to reuse > threads in ResolverImpl if they are needed to split some task and do it in > parallel. > For example: Apache Karaf startup with several features can install about 300 > bundles. If each one will create Runtime.getRuntime().availableProcessors() > threads - so, during a startup about 1000 threads will be created only by > Resolver (in case of a server machine even much more). Thread creation takes > let's say (depends on machine, JDK, OS, etc) about 10-20 ms, so we are > spending about 1-2 seconds of startup time only to create some threads. > it make sense to create a thread pool once (with a configurable thread > number) and reuse it for resolving of different bundles. > Threads creation, stack examples: > {noformat} > java.lang.Thread.<init>(ThreadGroup, Runnable, String, long) Thread.java > java.util.concurrent.Executors$DefaultThreadFactory.newThread(Runnable) > Executors.java:613 > java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor, > Runnable) ThreadPoolExecutor.java:612 > java.util.concurrent.ThreadPoolExecutor.addWorker(Runnable, boolean) > ThreadPoolExecutor.java:925 > java.util.concurrent.ThreadPoolExecutor.execute(Runnable) > ThreadPoolExecutor.java:1357 > org.apache.felix.resolver.ResolverImpl$EnhancedExecutor.execute(Runnable) > ResolverImpl.java:2436 > org.apache.felix.resolver.ResolverImpl$1Computer.run() ResolverImpl.java:1150 > org.apache.felix.resolver.ResolverImpl$EnhancedExecutor$1.run() > ResolverImpl.java:2442 > java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) > ThreadPoolExecutor.java:1142 > java.util.concurrent.ThreadPoolExecutor$Worker.run() > ThreadPoolExecutor.java:617 > java.lang.Thread.run() Thread.java:745 > {noformat} > {noformat} > java.lang.Thread.<init>(ThreadGroup, Runnable, String, long) Thread.java > java.util.concurrent.Executors$DefaultThreadFactory.newThread(Runnable) > Executors.java:613 > java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor, > Runnable) ThreadPoolExecutor.java:612 > java.util.concurrent.ThreadPoolExecutor.addWorker(Runnable, boolean) > ThreadPoolExecutor.java:925 > java.util.concurrent.ThreadPoolExecutor.execute(Runnable) > ThreadPoolExecutor.java:1357 > org.apache.felix.resolver.ResolverImpl$EnhancedExecutor.execute(Runnable) > ResolverImpl.java:2436 > org.apache.felix.resolver.ResolverImpl.calculatePackageSpaces(Executor, > ResolverImpl$ResolveSession, Candidates, Collection) ResolverImpl.java:1158 > org.apache.felix.resolver.ResolverImpl.checkConsistency(Executor, > ResolverImpl$ResolveSession, List, List, Candidates, Map, Map, boolean) > ResolverImpl.java:471 > org.apache.felix.resolver.ResolverImpl.resolve(ResolveContext, Executor) > ResolverImpl.java:347 > org.apache.felix.resolver.ResolverImpl.resolve(ResolveContext) > ResolverImpl.java:158 > org.apache.felix.framework.StatefulResolver.resolve(Set, Set) > StatefulResolver.java:431 > org.apache.felix.framework.Felix.resolveBundleRevision(BundleRevision) > Felix.java:4118 > org.apache.felix.framework.Felix.startBundle(BundleImpl, int) Felix.java:2124 > org.apache.felix.framework.BundleImpl.start(int) BundleImpl.java:998 > org.apache.felix.framework.BundleImpl.start() BundleImpl.java:984 > org.apache.karaf.features.internal.FeaturesServiceImpl.startBundle(InstallationState, > Bundle) FeaturesServiceImpl.java:520 > org.apache.karaf.features.internal.FeaturesServiceImpl.installFeatures(Set, > EnumSet) FeaturesServiceImpl.java:478 > org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(Feature, > EnumSet) FeaturesServiceImpl.java:419 > org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(String, > String, EnumSet) FeaturesServiceImpl.java:394 > org.apache.karaf.features.internal.FeaturesServiceImpl.installFeature(String, > EnumSet) FeaturesServiceImpl.java:364 > {noformat} -- This message was sent by Atlassian JIRA (v6.3.4#6332)