Re: Tomcat 10 startup time and JMX as an opt in fature?
Le lun. 28 déc. 2020 à 13:48, Rémy Maucherat a écrit : > On Sun, Dec 27, 2020 at 4:16 PM Romain Manni-Bucau > wrote: > > > Hi everyone, > > > > wonder if there is some work planned in tomcat 10 to 1. makes it start > > faster and 2. make jmx optional. > > > > I did some tests and locally a tomcat start is about 400ms. > > I was surprised to see that Registry.disableRegistry() was taking already > > 65ms whereas it should be almost nothing so refactored the code, added a > > RegistryFactory and really noop impl (not even a mock) and went down to > > 1ms, way better right? except the remaining 64ms went to the next line > (new > > StandardHost()). After some investigation time is mainly classloading > time > > (in all senses). > > > > So I wonder if it wouldnt make sense to optimize tomcat startup time + > > finally make JMX optional since it is no more used by users in most > cases - > > gues we must keep it as an optional plugin since it is used > "historically". > > > > The proposal would be to: > > > > 1. reduce classloading tree as much as possible for default case - here > > having jmx optional will help a lot > > 2. probably generate resource bundle as .java at build time to avoid all > > the classloading resource bundle implies (it is like 74 loadClass + as > much > > getResource for a simple startup and all loadclass are misses) > > 2.bis. probably add a mode where StringManager uses the default bundle > > without passing through the resource bundle layer > > 3. cut dead code when we know it is inactive (typically the case for jmx) > > 4. open point: bypassing Context: in "main" mode (as the code shared > > after), you just want to bind some logic in a servlet/filter/valve, you > > don't always care about handling contexts (or a single one) so wonder if > we > > shouldnt evaluate the fact to add the user logic in a valve for this kind > > of bench and maybe document this case (spring boot could inherit from it > > since it almost never use anything else that default spring servlet and > > binds everything in it). > > > > Here is the kind of case I'd like to see insanely fast (<100ms - and it > is > > possible regarding what it does): > > > > public class Main { > > public static void main(String[] args) throws LifecycleException, > > InterruptedException { > > final long start = System.nanoTime(); > > Registry.disableRegistry(); > > final long startDisableRegistry = System.nanoTime(); > > > > final Host host = new StandardHost(); > > host.setName("localhost"); > > final long startHost = System.nanoTime(); > > > > final Engine engine = new StandardEngine(); > > engine.setName("Tomcat"); > > engine.setDefaultHost("localhost"); > > engine.setRealm(new NullRealm()); > > engine.addChild(host); > > final long startEngine = System.nanoTime(); > > > > final var protocolHandler = new Http11Nio2Protocol(); > > protocolHandler.setPort(8080); > > final long startHttp11Nio2Protocol = System.nanoTime(); > > > > final Service service = new StandardService(); > > service.setName("Tomcat"); > > service.setContainer(engine); > > service.addConnector(new Connector(protocolHandler)); > > final long startService = System.nanoTime(); > > > > final StandardServer server = new StandardServer(); > > server.setPort(-1); > > server.addService(service); > > final long startServer = System.nanoTime(); > > > > final StandardContext context = new StandardContext(); > > context.setUseNaming(false); > > context.setClearReferencesStopThreads(false); > > context.setClearReferencesStopTimerThreads(false); > > context.setClearReferencesHttpClientKeepAliveThread(false); > > context.setClearReferencesRmiTargets(false); > > context.setClearReferencesThreadLocals(false); > > context.setClearReferencesObjectStreamClassCaches(false); > > context.setWorkDir(System.getProperty("java.io.tmpdir")); > > context.setName(""); > > context.setPath(""); > > context.setDocBase(null); > > context.addLifecycleListener(event -> { > > if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) > { > > context.setConfigured(true); > > if (context.getLoginConfig() == null) { > > context.setLoginConfig(new LoginConfig("NONE", null, > > null, null)); > > context.getPipeline().addValve(new > > NonLoginAuthenticator()); > > } > > } > > }); > > context.addServletContainerInitializer((classes, ctx) -> { > > ctx.addServlet("default", new DefaultServlet()) > > .addMapping("/"); > > }, Set.of()); > > final long startContext = System.nanoTime(); > > > > host.addChild(context); > > > >
Re: Tomcat 10 startup time and JMX as an opt in fature?
On Sun, Dec 27, 2020 at 4:16 PM Romain Manni-Bucau wrote: > Hi everyone, > > wonder if there is some work planned in tomcat 10 to 1. makes it start > faster and 2. make jmx optional. > > I did some tests and locally a tomcat start is about 400ms. > I was surprised to see that Registry.disableRegistry() was taking already > 65ms whereas it should be almost nothing so refactored the code, added a > RegistryFactory and really noop impl (not even a mock) and went down to > 1ms, way better right? except the remaining 64ms went to the next line (new > StandardHost()). After some investigation time is mainly classloading time > (in all senses). > > So I wonder if it wouldnt make sense to optimize tomcat startup time + > finally make JMX optional since it is no more used by users in most cases - > gues we must keep it as an optional plugin since it is used "historically". > > The proposal would be to: > > 1. reduce classloading tree as much as possible for default case - here > having jmx optional will help a lot > 2. probably generate resource bundle as .java at build time to avoid all > the classloading resource bundle implies (it is like 74 loadClass + as much > getResource for a simple startup and all loadclass are misses) > 2.bis. probably add a mode where StringManager uses the default bundle > without passing through the resource bundle layer > 3. cut dead code when we know it is inactive (typically the case for jmx) > 4. open point: bypassing Context: in "main" mode (as the code shared > after), you just want to bind some logic in a servlet/filter/valve, you > don't always care about handling contexts (or a single one) so wonder if we > shouldnt evaluate the fact to add the user logic in a valve for this kind > of bench and maybe document this case (spring boot could inherit from it > since it almost never use anything else that default spring servlet and > binds everything in it). > > Here is the kind of case I'd like to see insanely fast (<100ms - and it is > possible regarding what it does): > > public class Main { > public static void main(String[] args) throws LifecycleException, > InterruptedException { > final long start = System.nanoTime(); > Registry.disableRegistry(); > final long startDisableRegistry = System.nanoTime(); > > final Host host = new StandardHost(); > host.setName("localhost"); > final long startHost = System.nanoTime(); > > final Engine engine = new StandardEngine(); > engine.setName("Tomcat"); > engine.setDefaultHost("localhost"); > engine.setRealm(new NullRealm()); > engine.addChild(host); > final long startEngine = System.nanoTime(); > > final var protocolHandler = new Http11Nio2Protocol(); > protocolHandler.setPort(8080); > final long startHttp11Nio2Protocol = System.nanoTime(); > > final Service service = new StandardService(); > service.setName("Tomcat"); > service.setContainer(engine); > service.addConnector(new Connector(protocolHandler)); > final long startService = System.nanoTime(); > > final StandardServer server = new StandardServer(); > server.setPort(-1); > server.addService(service); > final long startServer = System.nanoTime(); > > final StandardContext context = new StandardContext(); > context.setUseNaming(false); > context.setClearReferencesStopThreads(false); > context.setClearReferencesStopTimerThreads(false); > context.setClearReferencesHttpClientKeepAliveThread(false); > context.setClearReferencesRmiTargets(false); > context.setClearReferencesThreadLocals(false); > context.setClearReferencesObjectStreamClassCaches(false); > context.setWorkDir(System.getProperty("java.io.tmpdir")); > context.setName(""); > context.setPath(""); > context.setDocBase(null); > context.addLifecycleListener(event -> { > if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { > context.setConfigured(true); > if (context.getLoginConfig() == null) { > context.setLoginConfig(new LoginConfig("NONE", null, > null, null)); > context.getPipeline().addValve(new > NonLoginAuthenticator()); > } > } > }); > context.addServletContainerInitializer((classes, ctx) -> { > ctx.addServlet("default", new DefaultServlet()) > .addMapping("/"); > }, Set.of()); > final long startContext = System.nanoTime(); > > host.addChild(context); > > server.init(); > final long inited = System.nanoTime(); > server.start(); > final long started = System.nanoTime(); > // new CountDownLatch(1).await(); > > final var contextClassLoader = > Thread.currentThread().getContextClassLoader(); >
Re: Tomcat 10 startup time and JMX as an opt in fature?
Hi, If it’s optional but still enabled, I think it’s a good idea to speedup bootstrapping. Just my $0.01 ;) Regards JB > Le 27 déc. 2020 à 16:15, Romain Manni-Bucau a écrit : > > Hi everyone, > > wonder if there is some work planned in tomcat 10 to 1. makes it start > faster and 2. make jmx optional. > > I did some tests and locally a tomcat start is about 400ms. > I was surprised to see that Registry.disableRegistry() was taking already > 65ms whereas it should be almost nothing so refactored the code, added a > RegistryFactory and really noop impl (not even a mock) and went down to > 1ms, way better right? except the remaining 64ms went to the next line (new > StandardHost()). After some investigation time is mainly classloading time > (in all senses). > > So I wonder if it wouldnt make sense to optimize tomcat startup time + > finally make JMX optional since it is no more used by users in most cases - > gues we must keep it as an optional plugin since it is used "historically". > > The proposal would be to: > > 1. reduce classloading tree as much as possible for default case - here > having jmx optional will help a lot > 2. probably generate resource bundle as .java at build time to avoid all > the classloading resource bundle implies (it is like 74 loadClass + as much > getResource for a simple startup and all loadclass are misses) > 2.bis. probably add a mode where StringManager uses the default bundle > without passing through the resource bundle layer > 3. cut dead code when we know it is inactive (typically the case for jmx) > 4. open point: bypassing Context: in "main" mode (as the code shared > after), you just want to bind some logic in a servlet/filter/valve, you > don't always care about handling contexts (or a single one) so wonder if we > shouldnt evaluate the fact to add the user logic in a valve for this kind > of bench and maybe document this case (spring boot could inherit from it > since it almost never use anything else that default spring servlet and > binds everything in it). > > Here is the kind of case I'd like to see insanely fast (<100ms - and it is > possible regarding what it does): > > public class Main { >public static void main(String[] args) throws LifecycleException, > InterruptedException { >final long start = System.nanoTime(); >Registry.disableRegistry(); >final long startDisableRegistry = System.nanoTime(); > >final Host host = new StandardHost(); >host.setName("localhost"); >final long startHost = System.nanoTime(); > >final Engine engine = new StandardEngine(); >engine.setName("Tomcat"); >engine.setDefaultHost("localhost"); >engine.setRealm(new NullRealm()); >engine.addChild(host); >final long startEngine = System.nanoTime(); > >final var protocolHandler = new Http11Nio2Protocol(); >protocolHandler.setPort(8080); >final long startHttp11Nio2Protocol = System.nanoTime(); > >final Service service = new StandardService(); >service.setName("Tomcat"); >service.setContainer(engine); >service.addConnector(new Connector(protocolHandler)); >final long startService = System.nanoTime(); > >final StandardServer server = new StandardServer(); >server.setPort(-1); >server.addService(service); >final long startServer = System.nanoTime(); > >final StandardContext context = new StandardContext(); >context.setUseNaming(false); >context.setClearReferencesStopThreads(false); >context.setClearReferencesStopTimerThreads(false); >context.setClearReferencesHttpClientKeepAliveThread(false); >context.setClearReferencesRmiTargets(false); >context.setClearReferencesThreadLocals(false); >context.setClearReferencesObjectStreamClassCaches(false); >context.setWorkDir(System.getProperty("java.io.tmpdir")); >context.setName(""); >context.setPath(""); >context.setDocBase(null); >context.addLifecycleListener(event -> { >if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { >context.setConfigured(true); >if (context.getLoginConfig() == null) { >context.setLoginConfig(new LoginConfig("NONE", null, > null, null)); >context.getPipeline().addValve(new > NonLoginAuthenticator()); >} >} >}); >context.addServletContainerInitializer((classes, ctx) -> { >ctx.addServlet("default", new DefaultServlet()) >.addMapping("/"); >}, Set.of()); >final long startContext = System.nanoTime(); > >host.addChild(context); > >server.init(); >final long inited = System.nanoTime(); >server.start(); >final long started = System.nanoTime(); >// new CountDownLatch(1).await(); > >
Tomcat 10 startup time and JMX as an opt in fature?
Hi everyone, wonder if there is some work planned in tomcat 10 to 1. makes it start faster and 2. make jmx optional. I did some tests and locally a tomcat start is about 400ms. I was surprised to see that Registry.disableRegistry() was taking already 65ms whereas it should be almost nothing so refactored the code, added a RegistryFactory and really noop impl (not even a mock) and went down to 1ms, way better right? except the remaining 64ms went to the next line (new StandardHost()). After some investigation time is mainly classloading time (in all senses). So I wonder if it wouldnt make sense to optimize tomcat startup time + finally make JMX optional since it is no more used by users in most cases - gues we must keep it as an optional plugin since it is used "historically". The proposal would be to: 1. reduce classloading tree as much as possible for default case - here having jmx optional will help a lot 2. probably generate resource bundle as .java at build time to avoid all the classloading resource bundle implies (it is like 74 loadClass + as much getResource for a simple startup and all loadclass are misses) 2.bis. probably add a mode where StringManager uses the default bundle without passing through the resource bundle layer 3. cut dead code when we know it is inactive (typically the case for jmx) 4. open point: bypassing Context: in "main" mode (as the code shared after), you just want to bind some logic in a servlet/filter/valve, you don't always care about handling contexts (or a single one) so wonder if we shouldnt evaluate the fact to add the user logic in a valve for this kind of bench and maybe document this case (spring boot could inherit from it since it almost never use anything else that default spring servlet and binds everything in it). Here is the kind of case I'd like to see insanely fast (<100ms - and it is possible regarding what it does): public class Main { public static void main(String[] args) throws LifecycleException, InterruptedException { final long start = System.nanoTime(); Registry.disableRegistry(); final long startDisableRegistry = System.nanoTime(); final Host host = new StandardHost(); host.setName("localhost"); final long startHost = System.nanoTime(); final Engine engine = new StandardEngine(); engine.setName("Tomcat"); engine.setDefaultHost("localhost"); engine.setRealm(new NullRealm()); engine.addChild(host); final long startEngine = System.nanoTime(); final var protocolHandler = new Http11Nio2Protocol(); protocolHandler.setPort(8080); final long startHttp11Nio2Protocol = System.nanoTime(); final Service service = new StandardService(); service.setName("Tomcat"); service.setContainer(engine); service.addConnector(new Connector(protocolHandler)); final long startService = System.nanoTime(); final StandardServer server = new StandardServer(); server.setPort(-1); server.addService(service); final long startServer = System.nanoTime(); final StandardContext context = new StandardContext(); context.setUseNaming(false); context.setClearReferencesStopThreads(false); context.setClearReferencesStopTimerThreads(false); context.setClearReferencesHttpClientKeepAliveThread(false); context.setClearReferencesRmiTargets(false); context.setClearReferencesThreadLocals(false); context.setClearReferencesObjectStreamClassCaches(false); context.setWorkDir(System.getProperty("java.io.tmpdir")); context.setName(""); context.setPath(""); context.setDocBase(null); context.addLifecycleListener(event -> { if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { context.setConfigured(true); if (context.getLoginConfig() == null) { context.setLoginConfig(new LoginConfig("NONE", null, null, null)); context.getPipeline().addValve(new NonLoginAuthenticator()); } } }); context.addServletContainerInitializer((classes, ctx) -> { ctx.addServlet("default", new DefaultServlet()) .addMapping("/"); }, Set.of()); final long startContext = System.nanoTime(); host.addChild(context); server.init(); final long inited = System.nanoTime(); server.start(); final long started = System.nanoTime(); // new CountDownLatch(1).await(); final var contextClassLoader = Thread.currentThread().getContextClassLoader(); server.stop(); server.destroy(); final long stopped = System.nanoTime(); System.out.println(TimeUnit.NANOSECONDS.toMillis(started - start) + "ms"); System.out.println(TimeUnit.NANOSECONDS.toMillis(stopped - started) + "ms");