I created a bunch of time measurements throughout the Lucee loader and core in order to measure what is taking all the time and found that nearly all of the time occurs outside lucee’s code or is doing I/O operations. I know lucee records some of the measurements in its own logs, but that wasn’t recording the full amount of time Lucee code is running during startup. Now that I have isolated the hot spots, I may work on those areas or eliminate some of these features.
When we click restart engine in the Lucee admin, the code tries to stop and remove the OSGi bundles before running a reduced version of the startup again. In addition to that looking unnecessary to me, the sleep(5000) looks wrong considering it was only taking 150ms of time to finish that code and it could use a loop with logic instead if it really needs this code to run. I don’t think Felix even requires you to keep reloading them like this, but maybe you have an edge case to worry about. I think Felix bundle installation is more of a one time occasion, and then you only have to do it again on upgrades for specific bundles. Lucee shutdown becomes like 150ms instead of 5150ms now with no consequence that I can see yet, which is pretty awesome, since this saves me significant time iterating on changes to Lucee now.
The full Tomcat/Lucee in windows takes about 10 seconds to shutdown, and about 4 seconds to start again. Sometimes more then that. Also, anyone using multiple contexts would experiencing much worse startup performance probably. I switched to developing everything as one context over 7 years ago to avoid that problem, but they could at least be made to load in parallel if others are using this feature.
1500ms of the start up time is happening after lucee CFMLServlet starts, so it seems like the majority of the wait to start is happening in Tomcat and servlet jars and we’d wait at least 2 seconds even if Lucee did nothing. This startup time also includes running and finishing the first CFML request, not just starting the server. I’m also using a fast SSD with a core i7 cpu, so it could be worse then this for others.
Felix is starting and loading all the OSGi bundles in about 500ms. 200ms of that could probably done in parallel saving up to 150ms. Most of it occurs in Felix outside of Lucee’s code unfortunately. Even if you delete all of Lucee’s extensions in a custom build, I think it would only start up to 100ms faster.
I think some of these startup and shutdown processes could verify if they are needed more, instead of always doing them for OSGi loading and the XMLConfigWebFactory and deploying server/web context files. At a glance, I think it could be made up to 4 times faster with the same feature set. With some reorganization, perhaps it is possible to get the OSGi, XML and Context loading systems all running on separate threads in parallel since they are each around 500ms+. Additionally, I think some of the code could be deleted or made only to happen during upgrade/install events and even then, it is rare for all the files to need to change.
On my version, I might not even have most of these features that slow down start-up eventually. I think there only needs to force a cfclasses and temp directory to exist for the language to work, and I don’t want the Lucee admin, the cfml functions, or any of the xml code later. I think the majority of the files should be trusted and already exist on repeat startups. It could wait until a user explicitly requests an upgrade before trying to repeat some of these steps, or upgrades could be handled outside the project with a command line tool instead. Sometimes tracking md5 hashes or date/size of the data is all you need to eliminate lots of processing time.
After the CFML engine is loaded, it seems like the first CFML request takes another 200ms to 300ms startup time for a hello world kind of page that usually takes less then a millisecond. Some of that is probably servlet and initialization work that might be able to sped up or eliminated.
A clean start would probably take under a second to be able to run CFML code if there was no servlet, no XML config system, no dependencies and no OSGi for the simplified core language, which is would be 3 to 5 times faster then the full Lucee feature set allows.
Most of these startup features are there in order to make Lucee work in multiple language modes, the ability to extend it externally easier and to make the Lucee admin able to work. The core language itself is much faster/simpler to build/deploy/start if you forego these features and look at developing your own fork or looking into what I’m doing with Lucee.
Here is the raw log of measurements I took for a clean start of my modified version of Lucee 5.3.2.16. I made up some of the names based on the surrounding code. These don’t include the time for tomcat to start. Each line is measuring the time spent since the previous log item in sequence. I don’t think threads are used anywhere in startup yet.
1ms for CFMLServlet init start
0ms for CFMLServlet init Servlet init end
5ms for CFMLEngineFactory getInstance begin
3ms for CFMLEngineFactory getInstance after new factory
0ms for CFMLEngineFactory getInstance after readInitParam
0ms for CFMLEngineFactory initEngine begin
1ms for CFMLEngineFactory after patch check
1ms for CFMLEngineFactory initEngine before loadBundles
0ms for BundleLoader loadBundles begin
3ms for CFMLEngineFactory before new Felix
70ms for CFMLEngineFactory after new Felix
182ms for CFMLEngineFactory after start Felix
0ms for BundleLoader loadBundles after close all bundles
54ms for BundleLoader loadBundles after addBundle set 1
1ms for BundleLoader loadBundles after addBundle set 1
6ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
1ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
4ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
1ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
1ms for BundleLoader loadBundles after addBundle set 1
3ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 1
1ms for BundleLoader loadBundles after addBundle set 1
2ms for BundleLoader loadBundles after addBundle set 2
10ms for BundleLoader loadBundles after addBundle core
1ms for BundleUtil.start begin
84ms for Bundle.start before bundle load wait
0ms for Bundle.start bundles loaded
12ms for CFMLEngineFactory initEngine after loadBundles
127ms for CFMLEngineImpl getConfigServerImpl begin
1ms for XMLConfigServerFactory begin
14ms for XMLConfigServerFactory after loadDocumentCreateIfFails
1ms for XMLConfigServerFactory after getDocumentElement
152ms for XMLConfigServerFactory after new ConfigServerImpl
18ms for XMLConfigWebFactory load begin
19ms for XMLConfigWebFactory load after deployWebContext
0ms for XMLConfigWebFactory load after deployWeb
1ms for XMLConfigWebFactory load after loadConfig
78ms for XMLConfigWebFactory load after many load operations
7ms for XMLConfigWebFactory load after loadLib
110ms for XMLConfigWebFactory load after many load operations
47ms for XMLConfigWebFactory load after many load operations
41ms for XMLConfigWebFactory load after many load operations
9ms for XMLConfigWebFactory load after many load operations
0ms for XMLConfigWebFactory load end
0ms for XMLConfigServerFactory after load
3ms for XMLConfigServerFactory after createContextFiles
0ms for XMLConfigServerFactory end
0ms for CFMLEngineImpl getConfigServerImpl after newInstance for the xml configServer
2ms for CFMLEngineFactory initEngine before getUpdateType
0ms for CFMLEngineImpl getConfigServerImpl begin
0ms for CFMLEngineFactory initEngine after getUpdateType
0ms for CFMLEngineFactory initEngine end
0ms for CFMLEngineFactory getInstance after initEngineIfNecessary
0ms for CFMLServlet addServletConfig start
28ms for CFMLServlet loadJSPFactory start
0ms for CFMLEngineImpl getConfigServerImpl begin
1ms for CFMLEngineImpl getConfigDirectory end
8ms for CFMLFactoryImpl created
37ms for XMLConfigWebFactory load begin
2ms for XMLConfigWebFactory load after deployWebContext
0ms for XMLConfigWebFactory load after deployWeb
0ms for XMLConfigWebFactory load after loadConfig
13ms for XMLConfigWebFactory load after many load operations
1ms for XMLConfigWebFactory load after loadLib
27ms for XMLConfigWebFactory load after many load operations
11ms for XMLConfigWebFactory load after many load operations
19ms for XMLConfigWebFactory load after many load operations
4ms for XMLConfigWebFactory load after many load operations
1ms for XMLConfigWebFactory load end
4ms for CFMLServlet loadJSPFactory end
0ms for CFMLServlet init context(s) end
0ms for CFMLEngineFactory getInstance after addServletConfig
0ms for CFMLEngineFactory getInstance(config) end
0ms for CFMLEngineFactory readInitParam end
0ms for CFMLEngineFactory initEngine end
0ms for CFMLServlet addServletConfig start
0ms for CFMLEngineFactory addServletConfig end
3ms for CFMLServlet init CFML factory instance end
90ms for CFMLServlet service start
0ms for CFMLEngineImpl getConfigServerImpl begin
0ms for CFMLEngineImpl getCFMLFactory end
0ms for CFMLEngineImpl _service begin
36ms for PageContextImpl created
40ms for PageContextImpl initialize start
5ms for PageContextImpl initialized
0ms for CFMLEngineImpl _service after create PageContextImpl
0ms for CFMLEngineImpl _service before Request.exe
1ms for PageContextImpl execute begin