Some problems like DCL, synchronization, improvment idea

I really like your library and I’m thinking about using it. For now I just read the code and learn how things work.

I noticed this fragment
[java]
protected ComponentHandler getHandler( Class type ) {

    ComponentHandler result = handlers.get(type);
    if( result == null ) {
        // A little double checked locking to make sure we 
        // don't create a handler twice
        synchronized( this ) {
            result = handlers.get(type);
            if( result == null ) {
                result = lookupDefaultHandler(type);
                handlers.put(type, result);
            }
        }
    }
    return result;             
}

[java]

Not all operations on handlers hashmap are synchronized and in some cases it will cause livelocks on map access. If you have at least one concurrent hashmap.put operation then all hashmap.get must be synchronized as well. Double check locking will not work in Java and may cause weird problems: DLC problems

The best thing to do would be to remove lazy initialization and initialize handlers map when DefaultEntityData is created.

I actually wonder why component needs to be identified by class type? It is easy and straightforward but causes problems like handlers map or DefaultEntity.validate method.
I’m think about using java Enum as component type. You could pass it to DefaultEntityData and you would know all possible handlers. You could use structure like EnumMap which is much faster then HashMap and arrays(for most cases). You could use it in DefaultEntityData.handlers and in DefaultEntity.components. This would cause methods like DefaultEntity.set and DefaultEntity.get to be simpler and faster.

Only drawback that EntityComponent would need new method like ‘Enum<T> getType()’ to identify it.

The problem with using an enum as component type is that a) it buys you literally nothing but the “must know all components up front” and b) has the huge limitation that you must know all components up front. Therefore a general framework could not be written.

Using a type instead has all of the benefits of an enum but can expand at runtime to include whatever components the framework user wants to have. I have no idea what this means “but causes problems like handlers map or DefaultEntity.validate method.” You would still have to have generic storage even if you used an enum… and it would be possible for that generic storage to go ‘out of synch’ with your keys if you did something wrong (internally) somewhere else. You can see that there is only one place it is called and its comment is illuminating:
[java]
// Just a safety net… can maybe be removed
((DefaultEntity)e).validate();
[/java]

…it’s like a runtime assert. It can actually be removed but it does little harm.

There is literally nothing gained with an enum approach. Instead of getClass() you have getType() and now you must define all components up front… seems like a huge liability to me.

Regarding the threading issue, the hashmap itself is a ConcurrentHashMap so it is already thread safe. We aren’t synchronizing the put() we are synchronizing the creation. It should be safe in this case because ConcurrentHashMap is already internally thread safe.

Ahh, true, handlers map is my mistake but still DLC in is some rare case may cause problems

I don’t really understand why you would have to now all components upfront and why it is different with classes? Your framework could use Enum type provided by user (any kind of enum) and accept generic Enum<T> class the same way how it is done in EnumMap. When user defines new Component class is the same as he would add new value to his Enum.

By using Enum you gain performance and simplicity.
Performance by using EnumMap that have constant time O(1) for get/put operations. It is not big performance boost because number of components will be relatively small.
Some parts of code will be simpler and will have better performance. Check this POC:

public class DefaultEntity<CT extends Enum<CT>> implements Entity {
private final EnumMap&lt;CT, EntityComponent&gt; components;

@Override
public &lt;T extends EntityComponent&gt; T get(final CT type) {
	return components.get(type);
}

@Override
public void set(final EntityComponent c) {
	EntityComponent existing = components.get(c.getType());
	if (existing != null) {
		components.put(c.getType, c);
	} else {
		ed.setComponent(id, c);
	}
}

}

@tanku said: Ahh, true, handlers map is my mistake but still DLC in is some rare case may cause problems

I don’t really understand why you would have to now all components upfront and why it is different with classes? Your framework could use Enum type provided by user (any kind of enum) and accept generic Enum<T> class the same way how it is done in EnumMap. When user defines new Component class is the same as he would add new value to his Enum.

By using Enum you gain performance and simplicity.
Performance by using EnumMap that have constant time O(1) for get/put operations. It is not big performance boost because number of components will be relatively small.
Some parts of code will be simpler and will have better performance. Check this POC:

In order to have an enum map the user would have to define all of their components up front.

…and so far the only benefit noted is a vanishingly small performance gain. Benchmark it sometime. Most entities will have two or three components in them at any time. A three element == array search is often going to be just as fast as the method call overhead of any Map implementation.

And the huge down side of an enum map is that you have to touch two things every time you add a new component. First you have to add the component class and then you have to go add the redundant enum value to your global component enum type. It’s just not worth it.

With classes you do not have to know all of the components up front. The system adapts to the new classes that it sees.

re: double checked locking, I know my way around Java’s threading model in great detail at this point. I’ve been following double checked locking since back when it truly was impossible in Java to today where I know the cases where it can be done safely.

Just to present another possible solution for this, that is used in my own es:

before starting the application a seperate build step scanning for components must be done, this generats my main Registy.
Then I can just load them and use their index in the registy as the storage position, allowing a nicely constant runtime. (At a slightly higher memory as each arrays lenght must be equal to the amount of Componentclasses.)

But then most of my objects are inherintly more complex, and I very rarely objects with less than 5 components, often more.

Eg. every player in the world
->position
->rotation
->systemid (global position)
->cameraResrictionData (as this is actual data for my application due to different turrets with different max angle turnlimit)
->ReplicatedEntityComponent (marker for NetworkManagerSystem to process this entity)
->Humanoid (basic information, eg forces, jumpfactors, sprinting possible, ect)
->HumanoidSteeringData (coming from the humanoidSteeringSystem in case of Networked players or an AISystem for local ones)
->HumanoidMutableRuntimeData (stamina,onground,nextJumpTime state propagation for other Systems interested, eg can fire large guns only when standing on ground)
->Name
->Model
->AnimationState (abstract animation state, so the client can correctly determine and mix required animations)

Btw double checked locking does work fine in java, since java 1.5(2004) so for over 10 years by now, but stuff that was once written down is hard to get rid of.

@Empire Phoenix said: But then most of my objects are inherintly more complex, and I very rarely objects with less than 5 components, often more.

My objects can have upwards of 30 components… but I only ever use 2 or 3 at a time in a particular system. Thought I would clarify.

OP was criticizing my use of an array lookup in the view class that only ever has 2 or 3 components at a time.

@pspeed said: My objects can have upwards of 30 components... but I only ever use 2 or 3 at a time in a particular system. Thought I would clarify.

OP was criticizing my use of an array lookup in the view class that only ever has 2 or 3 components at a time.

Ah ok, then I misread :slight_smile: Might be because currently I simply do not generate this view but just send in alll data, I can always improve this later if it ever becomes a performance problem after all.

EnumMap basically works just as Empire Phoenix implementation.

There are two places that would benefit from using EnumMap the most: DefaultEntityData.handlers and DefaultEntity.components.
I’m planing to do implementation that uses EnumMap and implements this interfaces as I would like to reuse most of JME code. I will post it on forum, so maybe it can be the third implementation if pspeed will see some value in it.

I wrote some simple benchmarking classes that compares enum maps and current base implementations:
[java]
import java.util.EnumMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class EnumMapTestForDefaultDataEntity{
private static final int WARM_UP_LOOPS = 3000000;
private static final int TEST_LOOPS = 200000;

private static class Timings {
	private final double handlersAsEnumMap, handlersAsCHashMap;

	private Timings(final double enumGet, final double tableSearch) {
		handlersAsEnumMap = enumGet;
		handlersAsCHashMap = tableSearch;
	}
}

public static void main(final String... args) throws Exception {
	System.out.printf("Warming up JIT by passing %d loops\n", WARM_UP_LOOPS);
	loop(WARM_UP_LOOPS);

	System.out.printf("Starting test for %d loops...\n", TEST_LOOPS);
	final Timings timings = loop(TEST_LOOPS);
	System.out.printf("Avg timings in nanos:\nhandlersAsEnumMap:\t%f\nhandlersAsCHashMap:\t%f\n", timings.handlersAsEnumMap,
			timings.handlersAsCHashMap);
}

static class ComponentHandler {
}

static class Component {
}

static class ComponentA extends Component {
}

static class ComponentB extends Component {
}

static class ComponentC extends Component {
}

static class EnitityDataWithConcurrentHashMap {
	Map&lt;Class, ComponentHandler&gt; handlers = new ConcurrentHashMap&lt;Class, ComponentHandler&gt;();

	ComponentHandler getHandler(final Class type) {
		ComponentHandler result = handlers.get(type);
		if (result == null) {
			// A little double checked locking to make sure we
			// don't create a handler twice
			synchronized (this) {
				result = handlers.get(type);
				if (result == null) {
					result = lookupDefaultHandler(type);
					handlers.put(type, result);
				}
			}
		}
		return result;
	}

	private ComponentHandler lookupDefaultHandler(final Class type) {
		return new ComponentHandler();
	}

}

enum ComponentEnum {
	COMPONENT_A, COMPONENT_B, COMPONENT_C;
}

static class EnitityDataWithEnumMap {
	EnumMap&lt;ComponentEnum, ComponentHandler&gt; handlers = new EnumMap&lt;ComponentEnum, ComponentHandler&gt;(ComponentEnum.class);
	{
		handlers.put(ComponentEnum.COMPONENT_A, new ComponentHandler());
		handlers.put(ComponentEnum.COMPONENT_B, new ComponentHandler());
		handlers.put(ComponentEnum.COMPONENT_C, new ComponentHandler());
	}

	ComponentHandler getHandler(final ComponentEnum type) {
		return handlers.get(type);
	}
}

private static Timings loop(final int count) throws Exception {
	double tableSearch = 0;
	double enumGet = 0;
	long start = 0;

	final Component[] componentsByClass = new Component[] { new ComponentA(), new ComponentB(), new ComponentC() };
	for (int i = 0; i &lt; count; ++i) {
		final EnitityDataWithConcurrentHashMap ed = new EnitityDataWithConcurrentHashMap();
		final Class&lt;Component&gt; toFind = (Class&lt;Component&gt;) componentsByClass[i % 3].getClass();
		start = System.nanoTime();
		ed.getHandler(toFind);
		tableSearch += System.nanoTime() - start;
	}

	for (int i = 0; i &lt; count; ++i) {
		final EnitityDataWithEnumMap ed = new EnitityDataWithEnumMap();
		final ComponentEnum toFind = ComponentEnum.values()[i % 3];
		start = System.nanoTime();
		ed.getHandler(toFind);
		enumGet += System.nanoTime() - start;
	}

	return new Timings(enumGet / count, tableSearch / count);
}

}

[/java]

[java]
import java.util.EnumMap;

public class EnumMapTestForDefaultEntity {
private static final int WARM_UP_LOOPS = 3000000;
private static final int TEST_LOOPS = 200000;

private static class Timings {
	private final double enumGet, tableSearch;

	private Timings(final double enumGet, final double tableSearch) {
		this.enumGet = enumGet;
		this.tableSearch = tableSearch;
	}
}

public static void main(final String... args) throws Exception {
	System.out.printf("Warming up JIT by passing %d loops\n", WARM_UP_LOOPS);
	loop(WARM_UP_LOOPS);

	System.out.printf("Starting test for %d loops...\n", TEST_LOOPS);
	final Timings timings = loop(TEST_LOOPS);
	System.out.printf("Avg timings in nanos:\nenumGet:\t%f\ntableSearch:\t%f\n", timings.enumGet, timings.tableSearch);
}

static class Component {
}

static class ComponentA extends Component {
}

static class ComponentB extends Component {
}

static class ComponentC extends Component {
}

static class EnitityWithTable {
	Component[] components = new Component[] { new ComponentA(), new ComponentB(), new ComponentC() };

	&lt;T extends Component&gt; T get(final Class&lt;T&gt; type) {
		for (final Component c : components) {
			if ((c != null) &amp;&amp; (c.getClass() == type)) {
				return type.cast(c);
			}
		}
		return null;
	}
}

enum ComponentEnum {
	COMPONENT_A, COMPONENT_B, COMPONENT_C;
}

static class EnitityWithEnum {
	EnumMap&lt;ComponentEnum, Component&gt; enumMap = new EnumMap&lt;EnumMapTestForDefaultDataEntity.ComponentEnum, EnumMapTestForDefaultDataEntity.Component&gt;(ComponentEnum.class);
	{
		enumMap.put(ComponentEnum.COMPONENT_A, new ComponentA());
		enumMap.put(ComponentEnum.COMPONENT_B, new ComponentB());
		enumMap.put(ComponentEnum.COMPONENT_C, new ComponentC());
	}

	Component get(final ComponentEnum type) {
		return enumMap.get(type);
	}
}

private static Timings loop(final int count) throws Exception {
	double tableSearch = 0;
	double enumGet = 0;
	long start = 0;

	final Component[] componentsByClass = new Component[] { new ComponentA(), new ComponentB(), new ComponentC() };
	for (int i = 0; i &lt; count; ++i) {
		final EnitityWithTable enitityWithTable = new EnitityWithTable();
		final Class&lt;Component&gt; toFind = (Class&lt;Component&gt;) componentsByClass[i % 3].getClass();
		start = System.nanoTime();
		enitityWithTable.get(toFind);
		tableSearch += System.nanoTime() - start;
	}

	for (int i = 0; i &lt; count; ++i) {
		final EnitityWithEnum enitityWithEnum = new EnitityWithEnum();
		final ComponentEnum toFind = ComponentEnum.values()[i % 3];
		start = System.nanoTime();
		enitityWithEnum.get(toFind);
		enumGet += System.nanoTime() - start;
	}

	return new Timings(enumGet / count, tableSearch / count);
}

}

[/java]

@tanku said: EnumMap basically works just as Empire Phoenix implementation.

There are two places that would benefit from using EnumMap the most: DefaultEntityData.handlers and DefaultEntity.components.
I’m planing to do implementation that uses EnumMap and implements this interfaces as I would like to reuse most of JME code. I will post it on forum, so maybe it can be the third implementation if pspeed will see some value in it.

So you will essentially have to parameterize the whole ES around your component enum type, yes?

The thing is, these methods you talk about aren’t called that often as compared to everything else in a 3D app. And even still, I’d expect the differences to be marginal for typical use cases. (You didn’t post any benchmark results so I’m only guessing based on having followed both code paths.)

The down sides:

-applications must now setup their ES to work with one enum type that they manage all of the component types in one place. If they add a new component class then they need to go back and add it to the enum and so on.

-every DefaultEntity will include the full array for both all of the enum types expanded and all of the potential values they might have. So if you have 30 component types then every entity will have two Object[30] arrays in it. (Actually one of the array seems to be shared… but still.)

-instantiating a DefaultEntity becomes slightly more expensive (this happens on average about half as often as setting a component, I guess) because creating an EnumMap is more expensive than instantiating two arrays.

The up sides:
-marginally faster access to some methods that aren’t called that often, relatively speaking.

-???

It will be interesting to see if this makes one difference at all in an actual game. Though if you find a case where it does then please post back because I can probably help improve the game design. :slight_smile:

Just a note on your micro-benchmarks, because you time inside the loop you run the risk (especially in this case) where the time between nanoTime() calls might be less than the measurable resolution. In that case, entire loop iterations will be left out completely. Since the looping and loop iteration setup are likely to be about as long then you also risk aligning things so that several iterations in a row are skipped.

It’s possible that your EntityWithEnum case gets special treatment then because it instantiates a new array every time in the loop. Most of the loop time will be taken up finding which Enum value to pass in and you may get several loop iterations that measure 0 nanoseconds just across the get() call.

It would be better to time the whole loop and make sure that the inner loop setup is equivalent between the approaches. This would amortize any errors due to System.nanoTime() precision.

Edit: changes “accuracy” to “resolution” as it is a more accurate description.

It is quick benchmark. On new processors with JDK 1.6/1.7 you should have pretty accurate results.

I put System.nanoTime() inside loop because it was faster to write test that way.
Putting System.nanoTime() outside the loop and balancing what loop does in those two approaches requires more thinking about JIT.
If loop is simple enough JIT will just ignore whole loop because state of memory before and after loop execution is the same.

Probably the most accurate test would be with test game and FPS count in both approaches.

@tanku said: It is quick benchmark. On new processors with JDK 1.6/1.7 you should have pretty accurate results.

I put System.nanoTime() inside loop because it was faster to write test that way.
Putting System.nanoTime() outside the loop and balancing what loop does in those two approaches requires more thinking about JIT.
If loop is simple enough JIT will just ignore whole loop because state of memory before and after loop execution is the same.

Probably the most accurate test would be with test game and FPS count in both approaches.

System.nanoTime() may return resolution as high as 1000 nanos. (It’s kind of system dependent, not Java version dependent… Java is just returning the hardware counter.) But even if it’s as low as 10 nanos resolution you could probably fit several get() calls in less time than 10 nanos. What happens is that those calls will show up as taking 0 time. Do enough of those and it really throws the results off. It ends up counting whatever happens to cross the resolution barrier.

Hotspot should not remove the whole loop but you can guard against it by accumulating a value or something that might affect things outside the loop. As long as all of the loops do it then the comparisons will still be valid. So maybe have the components return an int and add that to a total or something.

Edit: An addendum to this: I did a micro benchmark of System.nanoTime() itself to try to see if I could get it to return the same value twice… and even though the resolution is greater than a microsecond, I can’t get it to return the same value twice in row. Apparently the overhead of nanoTime() itself will make sure it doesn’t happen. (this is on a 6 core box so I’m reasonably sure that one core was dedicated to running this thread. Typical delta sequence looks like: 1117, 1397, 1117, 1117, 1118, 1117, 1397. That variance is troubling but at least it won’t swallow loops.)

Sorry, didn’t notice your first replay.

On my PC, test result for EnumMapTestForDefaultEntity:

Warming up JIT by passing 3000000 loops Starting test for 200000 loops... Avg timings in nanos: enumGet: 10,438525 tableSearch: 40,598840

And for EnumMapTestForDefaultDataEntity:

Warming up JIT by passing 3000000 loops Starting test for 200000 loops... Avg timings in nanos: handlersAsEnumMap: 8,397105 handlersAsCHashMap: 95,919100

Even if performance will not be gain by using enums then I personally would use Enum because for me they increase code readability. You avoid things like cast, instanceof, isInstance, etc. and method calls just look better if parameter is enum rather then class.

Enum design can be done smart and you should not need type parametrization. I was thinking about using class annotation for components instead of getType method.

Anyway I will threat this more like exercise and we will see what happens.

@tanku said: Even if performance will not be gain by using enums then I personally would use Enum because for me they increase code readability. You avoid things like cast, instanceof, isInstance, etc. and method calls just look better if parameter is enum rather then class.

This I don’t understand. How do you avoid user-code casting with enum? User code does not have to cast with Zay-ES.

I can do:
String name = myEntity.get(Name.class).getName();

Or:
Vector3f v = myEntity.get(Position.class).getLocation();

How do you do that when you are passing an enum instead? Seems like it would be much worse to me.

Or are you saying that the code internal to the ES would be cleaner at the cost of lots of extra code in user space?

I made attempt at rewriting for Enums and it helped me see big picture :slight_smile: Current class approach seems to be optimal solution but for DefaultEntityData.handlers initialization I would chose Empire Phoenix approach.