[
https://issues.apache.org/jira/browse/FELIX-4866?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14545962#comment-14545962
]
Pierre De Rop commented on FELIX-4866:
--------------------------------------
David,
Can you please take a look at the bndtools project that I have joined to this
issue, which seems to reproduce the problem I was talking about in the mailing
list. I have checked it 100 times, but I'm not able to find a bug and now, with
the last patches applied in the framework, I have some failing DM integrations
tests.
The tool is not based on dependency manager, but only on a little fluent APi
that replaces DM, and it is only based on standard service trackers.
It requires Java8, BndTools, and Eclipse Mars.
Using Felix 5.0.0, or using Equinox 3.10.1, the tool runs and completes
seamlessly.
but using the latest Felix fwk from trunk that includes the FELIX-4866 patch,
then the tool fails.
and I have now four failing DM integration tests.
What is doing this load test ?
============================
This loader creates a graph of service components that have dependencies
between each other. For
sake of simplicity, a simple scenario domain is used (actually, this example
domain has been
inspired from the "Java8 Lambdas" book, O'reilly) and we have the following
kind of services:
- Artist service: An Artist is an individual or group of musicians, who creates
some "Albums". One
Artist service depends on several Album services.
- Album service: is a single release of musics, comprising several music
Tracks. One Album depends
on several Track services.
- Track service: A piece of music.
The scenario consists in starting/stopping 10000 times a bundle that will
synchronously create the
graph of components (7 by default). A scenario constroller monitors the number
of created components
(Artists, Albums, Tracks) and when the number of expected components are
created, then the controller
stops the bundle. Finally, when the controller detects that all components are
unregistered, the
elapsed time is recorded in a list of time duration (in nano seconds).
The same is done for another bundle that does exactly the same, but using
concurrent component
registration. But when registering components concurrently, this does not
work with the latest framework.
At the end of the test (that is, when the bundle that creates the components
has been
started/stopped 100000 times), then the list of time duration is sorted: the
first element of the
list corresponds to the shortest elapsed time used by the bundle to create and
destroy the
components; and the last element in the list corresponds to the slowest elapsed
time. The
middle in the duration time list is the average. We display the first entry
(fastest), the entry at 1/4
of the list, the middle of the list, the entry at 3/4 of the list, and the last
entry (slowest time).
We don't do an average, because usually, when running
benchmark, some measurements don't reflect reality, especially, when there is a
full GC or when the
JVM is warming up. (we actually do the same as in Java Chronicle:
https://github.com/peter-lawrey/Java-Chronicle).
Bundle descriptions:
===============
- org.apache.felix.framework.loadtest.tracker: a test bundle that creates 7
components synchronously
when the bundle is started, and when it is stopped, then the components are
unregistered. This test works fine with the
latest Felix framework / trunk.
- org.apache.felix.framework.loadtest.tracker.parallel: same as before, but the
components are
created concurrently. this test fails with the FELIX-4866 patch applied in
the trunk.
- org.apache.felix.framework.loadtest.scenario: this bundle contains the
component classes that are
part of the scenario: we have an Artist service that depends on some Albums
services, each Album
also depends on some music Track services. The components are bounded using a
special "id" service
property.
- org.apache.felix.framework.loadtest.scenario.impl: the simple
Artist/Albums/Track implementations.
- org.apache.felix.framework.loadtest.controller: provides a ScenarioController
service that is
injected in all Artist/Album/Track components. When an Artist, an Album, or a
Track component is
started, it notifies the ScenerioController. Then when the controller detects
that all components
are properly created, it then stops the bundle, which in turns unregisters
all components.
- org.apache.felix.framework.loadtest.controller.impl: this is the
ScenarioController implementation.
API used to define service components:
=============================
Internally, basic Service Trackers are used to define dependencies between
components.
But we are using a light fluent api in order to describe component definitions,
which is used to
replace the DependencyManage API. Notice that DM is still used, but only to
activate the controller
bundle. And the Artist/Album/Track components are not defined using DM, and are
only defined using the
fluent API, which is simply based on standard ServiceTracker.
To create a component, a static "component" method of the
"org.apache.felix.framework.loadtest.tracker.Component" class is used, and
takes as parameter a java8 Supplier
object that will be used to instantiate the component implementation.
For example, to create an "Album" component, we are using the fluent API like
this:
{code}
import static org.apache.felix.framework.loadtest.tracker.Component.component;
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
Component<AlbumImpl> album = component(context, () -> new
AlbumImpl(context))
album.start();
}
}
{code}
Now, assuming that the Album component needs to be called in its start()
callback when all required dependencies are available, and in its stop()
callback when one of the required dependencies is lost, you can then define the
start/stop lifecycle callbacks using "onStart" and "onStop" methods, like this:
{code}
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
Component<AlbumImpl> album = component(context, () -> new
AlbumImpl(context))
.onStart(AlbumImpl::start)
.onStop(AlbumImpl::stop);
album.start();
}
}
{code}
Since an "Album" component depends on some musical "Track" components, you then
configure the
dependencies with the "dependsOn" method that takes as parameters the
dependency type, the
dependency filter, and a method reference to invoke on the AlbumImpl class in
order to bind the Track service to the AlbumImpl component instance:
{code}
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
Component<AlbumImpl> album = component(context, () -> new
AlbumImpl(context))
.onStart(AlbumImpl::start)
.onStop(AlbumImpl::stop)
.dependsOn(Track.class, "(title=some title)",
AlbumImpl::addTrack)
album.start();
}
}
{code}
Finally, since the AlbumImpl provides the "Album" service interface, you use
the "provides" method which takes are parameters the provided service, and a
varargs list of service properties (which size must be even, like "property1",
"value1", "property2", "value2", etc ...):
{code}
public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
Component<AlbumImpl> album = component(context, () -> new
AlbumImpl(context))
.onStart(AlbumImpl::start)
.onStop(AlbumImpl::stop)
.dependsOn(Track.class, "(title=track title)",
AlbumImpl::addTrack)
.provides(Album.class, "title", "album title")
album.start();
}
}
{code}
Running the loader with the last released Felix framework (5.0.0):
===============================================
First, use Eclipse Mars and BndTools 2.4.1. Eclise must be configured with a
Jdk8 JRE.
Then, import the project under bndtools, and click on the bnd.bnd file; then
click on the "Run" tab, then click on "Run OSGi".
You will then get the following output result:
{code}
g! Starting benchmarks (each tested bundle will add/remove 7 components during
bundle activation).
[Starting benchmarks with no processing done in components start
methods]
Benchmarking bundle: org.apache.felix.framework.loadtest.tracker ... \
-> results in nanos: [546,822 | 613,264 | 670,311 | 846,572 | 168,057,014]
Benchmarking bundle: org.apache.felix.framework.loadtest.tracker.parallel ... \
-> results in nanos: [525,062 | 651,846 | 748,940 | 1,006,306 | 84,381,682]
{code}
let's describe the result shown above:
1) The "org.apache.felix.framework.loadtest.tracker" bundle is the one that
synchronously creates the components. It is started/stopped 10000 times, and
the meaningful elapsed times are displayed:
Here, the shortest time used to create and remove the 7 components takes around
546,822 nanos. And
in the midle, you can see the average (670,311 nannoseconds), and in the last
entry, the slowest
time (168,057,014 nanos).
2) The "org.apache.felix.framework.loadtest.tracker.parallel" bundle is the
same as the previous
one, but creates components concurrently:
Here, the results are not better because by default, the size of the threadpool
is 10 (see the "-Dthreads=10" in bnd.bnd)
and I only have 4 cores my labtop.
With the latest framework 5.1.0, this test does not complete and at a point in
time, some components
are not created timely.
Running the loader with the last released Felix framework (5.1.0-SNAPSHOT):
=========================================================
Edit the bnd.bnd file, comment the current "-runfwk" option and uncomment the
other one, which uses
the latest version (5.1.0-SNAPSHOT) that is included in the local repository:
{code}
#-runfw:
org.eclipse.osgi;version='[3.10.1.v20140909-1633,3.10.1.v20140909-1633]'
#-runfw: org.apache.felix.main;version='[5.0.0, 5.0.0]'
-runfw: org.apache.felix.main;version=latest
{code}
Then click on the "Run OSGi".
You will normally see the following (under bndtools):
{code}
g! Starting benchmarks (each tested bundle will add/remove 7 components during
bundle activation).
[Starting benchmarks with no processing done in components start
methods]
Benchmarking bundle: org.apache.felix.framework.loadtest.tracker ... \
-> results in nanos: [546,681 | 614,242 | 673,661 | 1,012,047 | 43,224,831]
Benchmarking bundle: org.apache.felix.framework.loadtest.tracker.parallel ... -
Could not start components timely (7): started components: 5.
{code}
Here, the scenario controller has started the
"org.apache.felix.framework.loadtest.tracker.parallel" bundle, but only 5
components have been created, and two are missing.
I think that one possible issue would be that one ServiceTracker is not called
in its adding method, but it's hard to diagnose ...
> Improve service registry
> ------------------------
>
> Key: FELIX-4866
> URL: https://issues.apache.org/jira/browse/FELIX-4866
> Project: Felix
> Issue Type: Improvement
> Components: Framework
> Affects Versions: framework-5.0.0
> Reporter: Carsten Ziegeler
> Assignee: David Bosschaert
> Fix For: framework-5.2.0
>
>
> The current service registry is currently not using any of the Java 5
> concurrent data structures. Using those could improve the implementation, the
> readibility of the code and potentially the performance of the service
> registry.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)