This post can be seen as a continuation of Improve build speed in bndtools by using -compression: STORE (maybe I consider combining them in the future in a Performance tuning post)
TL;DR
The following describes how you can use 4 instructions to reduce bnd build time by telling bnd plugins which classes contain important annotations and which do not. If you know which packages are relevant for this annotations processing you can instruct bnd to do less work and build faster. Faster in our case meant 1.9 seconds vs. 4 seconds for a single bundle.
Annotation related bnd instructions
bnd has a couple of plugins which do various things during the build like scanning various kinds of OSGi related annotations.
and also some instructions to control scanning of those.
-
https://bnd.bndtools.org/instructions/metatypeannotations.html (code)
-
https://bnd.bndtools.org/instructions/cdiannotations.html (code)
-
https://bnd.bndtools.org/instructions/dsannotations.html (code)
-
https://bnd.bndtools.org/instructions/bundleannotations.html (code)
The default of each is *
(star - as in ALL / everything)
This default works great and most people never even think about changing them. But since I am notoriously trying to squeeze every second of our build time (especially in Eclipse during development where each additional second of build time is annoying when you save a file) , I stumbled over those annotations, during a debugging session in bnd where I placed various duration measurements in the Analyzer and Builder code. I found that some plugins scan more than necessary.
Bundle Classpath (BCP) is scanned too - not just your own code!
I found out *
means that bnd scans every .class
- every means also classes inside .jar
files on the BCP (Bundle Class Path).
The BCP is something we use in couple of places because e.g. we use Spring and Hibernate, and since Spring and Hibernate do not play well with OSGi, both dependencies need to be inside the same bundle as the Entity classes to have the same classloader.
So we are doing a:
-includeresource: ${repo;org.hibernate.orm:hibernate-core;latest}; lib:=true
Which embeds the hibernate-core-6.6.23.Final.jar
inside our bundle and puts in in the MANIFEST.MF’s Bundle-ClassPath
Hibernate was the main culprit with a big fat hibernate-core-6.6.23.Final.jar
of 11,51MB containing hundreds if not thousands of classes which added around 2 seconds to the build time of this bundle.
Solution
We have put the following in our cnf/build.bnd
(you can also put it in a bnd.bnd
of a single bundle)
## Speed up the build,
## because bnd needs to scan less classes
## by only scanning our packages or not scanning at all (empty).
## This avoids e.g. scanning .jars via -includeresource lib:=true
## which are on the BCP (bundle class path)
-bundleannotations: *com.our.packages*
-dsannotations: *com.our.packages*
-metatypeannotations:
-cdiannotations:
What it does: It tells bnd to
- only scan our own code packages for
-bundleannotations
and-dsannotations
e.g.com.our.packages.foo
,test.com.our.packages.bar
etc. All other packages are not scanned. - do not scan anything (basically skip the plugin) for
-metatypeannotations
and-cdiannotations
because we do not use it.
Warning - know what you are doing!
By doing this you trade the comfort of bnd’s “it just works” defaults for performance.
This has worked for us, because:
- we do not have annotations scanned by
-metatypeannotations
and-cdiannotations
so we are fine to disable that - we know that we want only our own bundle’s code (our
.class
files) to be scanned for annotations scanned by-bundleannotations
and-dsannotations
- we have a package structure with a common prefix which makes this easy
- we use quite a lot of jar-wrapping (with and without BCP) but where we are sure that those jars are not containing any relevant annotations - so we want bnd to ignore jars on the BCP
In case of doubt, just start with a single bundle’s bnd.bnd
Conclusion
For the problematic bundle we could reduce build time:
- from 4 seconds
- down to 1.9 seconds
- The bottom row shows the build time without the 4 instructions above (4.034s : everything is scanned)
- the first row shows with the 4 instructions but with
*com.our.packages*
on each instruction (2.4s: only our code is scanned)
Now I set -metatypeannotations:
and -cdiannotations:
to empty (no value), to basically disable it completely.
This brought the build time down to roughly 1.8s.
It all comes down to this: bnd has the plugins above, which are all are executed during a build for every bundle. Not all are relevant for your code base. It is up to you to find the right knobs to tell each plugin what to do or more important what not to do.