Core performance improvement [GameTimeController, movingobj]

This is not a Support area! Discuss about the Server here. Non-Server related discussion goes in Off-Topic Discussion.
Forum rules
READ NOW: L2j Forums Rules of Conduct
Post Reply
User avatar
Szponiasty
Advanced User
Advanced User
Posts: 557
Joined: Mon Apr 21, 2008 1:31 pm
Location: Eastern Poland

Core performance improvement [GameTimeController, movingobj]

Post by Szponiasty »

Hi. I've noticed in H5 beta, that you've also used javolution's FastMap, instead trove, for moving objects. Here is my implementation, that gives significant performance improvement over current H5 beta version.

http://pastebin.com/vRb4ptGf

Further performance gains can be achieved by using FastMap<ObjectAsKey, SomeValueNotNecessaryUsedForAnything> in other code fragments (eg. for keeping disabled skills in L2Character). You only have to make sure that ObjectAsKey has proper hashCode() method implementation. This is faster, than using eg. Integer as key. I've checked some time ago few most basic maps, lists etc, and from what I got, FastMap<ObjectAsKey, SomeValue> is fastest solution for iterating, adding, removing, getting non primitive objects. If you don't require objects to be contained in certain order, and you assume that there can be only one object copy in list, it's advantageous to even use FastMap over FastList or TIntObjHashMap.

Code: Select all

 -------------------------------------------------FastList: new FastList<L2Character>().shared()FastList 2: new FastList<Integer>().shared()FastMap: new FastMap<Integer, L2Character>().shared()FastMap 2: new FastMap<L2Character, Integer>().shared()TIntObjHashMap: new TIntObjectHashMap<L2Character>()-------------------------------------------------FastList: 5908ms (size=50000) [if (!contains(cha)) add(cha)]FastMap: 55ms (size=50000) [if (!containsKey(cha.getObjectId())) put(cha.getObjectId(), cha)] Result -> FastList vs FastMap: 10742%-------------------------------------------------FastList 2: 9080ms (size=50000) [if (!contains(cha.getObjectId())) add(cha.getObjectId())]FastMap 2: 13ms (size=50000) [if (!containsKey(cha)) put(cha, cha.getObjectId())]  Result -> FastList 2 vs FastMap 2: 69846%-------------------------------------------------FastList foreach: 19msFastMap 2 iterate keyset: 8ms Result -> FastList foreach vs FastMap 2 iterate keyset: 238%-------------------------------------------------FastMap values foreach: 8ms-------------------------------------------------TIntObjHashMap: 21ms (size=50000) [if (!containsKey(cha.getObjectId())) put(cha.getObjectId(), cha)]-------------------------------------------------TIntObjHashMap: 14454ms (size=50000) [if (!containsValue(cha)) put(cha.getObjectId(), cha)] 

Code: Select all

 package com.l2jbench; import gnu.trove.map.hash.TIntObjectHashMap;import javolution.util.FastList;import javolution.util.FastMap; import java.util.Iterator; public class Bench2{    public static class L2Character    {        private final int objectId;         public L2Character(int objId)        {            objectId = objId;        }         public int getObjectId()        {            return objectId;        }         @Override        public boolean equals(Object o)        {            if (this == o) return true;            if (!(o instanceof L2Character)) return false;             L2Character that = (L2Character) o;             return objectId == that.getObjectId();        }         @Override        public int hashCode()        {            return objectId;        }    }     public static void main(String[] args)    {        FastList<L2Character> fl = new FastList<L2Character>().shared();        FastList<Integer> fl2 = new FastList<Integer>().shared();        FastMap<Integer, L2Character> fm = new FastMap<Integer, L2Character>().shared();        FastMap<L2Character, Integer> fm2 = new FastMap<L2Character, Integer>().shared();        TIntObjectHashMap<L2Character> ioh = new TIntObjectHashMap<L2Character>();         long list = 0, map = 0;         System.out.println("-------------------------------------------------");        System.out.println("FastList: new FastList<L2Character>().shared()");        System.out.println("FastList 2: new FastList<Integer>().shared()");        System.out.println("FastMap: new FastMap<Integer, L2Character>().shared()");        System.out.println("FastMap 2: new FastMap<L2Character, Integer>().shared()");        System.out.println("TIntObjHashMap: new TIntObjectHashMap<L2Character>()");        System.out.println("-------------------------------------------------");        long start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!fl.contains(cha))                fl.add(cha);        }        long end = System.currentTimeMillis();        list = end - start;        System.out.println("FastList: " + list + "ms (size=" + fl.size() + ") [if (!contains(cha)) add(cha)]");        start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!fm.containsKey(cha.getObjectId()))                fm.put(cha.getObjectId(), cha);        }        end = System.currentTimeMillis();        map = end - start;        System.out.println("FastMap: " + map + "ms (size=" + fm.size() + ") [if (!containsKey(cha.getObjectId())) put(cha.getObjectId(), cha)]");        double result = (double)list * 100. / (double)map;        System.out.println(" Result -> FastList vs FastMap: " + Math.round(result) + "%");        System.out.println("-------------------------------------------------");          start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!fl2.contains(cha.getObjectId()))                fl2.add(cha.getObjectId());        }        end = System.currentTimeMillis();        list = end - start;        System.out.println("FastList 2: " + list + "ms (size=" + fl2.size() + ") [if (!contains(cha.getObjectId())) add(cha.getObjectId())]");        start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!fm2.containsKey(cha))                fm2.put(cha, cha.getObjectId());        }        end = System.currentTimeMillis();        map = end - start;        System.out.println("FastMap 2: " + map + "ms (size=" + fm2.size() + ") [if (!containsKey(cha)) put(cha, cha.getObjectId())]");        result = (double) list * 100. / (double) map;        System.out.println("  Result -> FastList 2 vs FastMap 2: " + Math.round(result) + "%");        System.out.println("-------------------------------------------------");         start = System.currentTimeMillis();        for (L2Character cha : fl)        {            cha.getObjectId();        }        end = System.currentTimeMillis();        list = end - start;        System.out.println("FastList foreach: " + list + "ms");         start = System.currentTimeMillis();        Iterator<L2Character> it = fm2.keySet().iterator();        while (it.hasNext())        {            L2Character cha = it.next();            cha.getObjectId();        }        end = System.currentTimeMillis();        map = end - start;        System.out.println("FastMap 2 iterate keyset: " + map + "ms");        result = (double) list * 100. / (double) map;        System.out.println(" Result -> FastList foreach vs FastMap 2 iterate keyset: " + Math.round(result) + "%");        System.out.println("-------------------------------------------------");         start = System.currentTimeMillis();        for (L2Character cha : fm.values())        {            cha.getObjectId();        }        end = System.currentTimeMillis();        System.out.println("FastMap values foreach: " + (end - start) + "ms");         System.out.println("-------------------------------------------------");         start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!ioh.containsKey(cha.getObjectId()))                ioh.put(cha.getObjectId(), cha);        }         end = System.currentTimeMillis();        System.out.println("TIntObjHashMap: " + (end - start) + "ms (size=" + ioh.size() + ") [if (!containsKey(cha.getObjectId())) put(cha.getObjectId(), cha)]");         System.out.println("-------------------------------------------------");        ioh.clear();         start = System.currentTimeMillis();        for (int i = 0; i < 50000; i++)        {            L2Character cha = new L2Character(i);            if (!ioh.containsValue(cha))                ioh.put(cha.getObjectId(), cha);        }         end = System.currentTimeMillis();        System.out.println("TIntObjHashMap: " + (end - start) + "ms (size=" + ioh.size() + ") [if (!containsValue(cha)) put(cha.getObjectId(), cha)]");    }} 
And in the next chronicle they went into space, fighting the evil empire... In a galaxy far, far away xD
User avatar
Szponiasty
Advanced User
Advanced User
Posts: 557
Joined: Mon Apr 21, 2008 1:31 pm
Location: Eastern Poland

Re: Core performance improvement [GameTimeController, moving

Post by Szponiasty »

Noticed that L2Character misses hashCode in beta. Add this to L2Character (or wherever it should be now :P) for above path to work correctly:

Code: Select all

      @Override    public boolean equals(Object o)    {        if (this == o) return true;        if (!(o instanceof L2Character)) return false;        return super.equals(o));    }     @Override    public int hashCode()    {        return getObjectId();    } 
And in the next chronicle they went into space, fighting the evil empire... In a galaxy far, far away xD
xban1x
L2j Veteran
L2j Veteran
Posts: 1228
Joined: Thu Jan 17, 2013 9:46 am

Re: Core performance improvement [GameTimeController, moving

Post by xban1x »

http://trac.l2jserver.com/changeset/6251#file3 - hashCode is missing still yes.

Why not use FastList<L2Character> instead of a FastMap if second value is of no usage to you?
User avatar
Szponiasty
Advanced User
Advanced User
Posts: 557
Joined: Mon Apr 21, 2008 1:31 pm
Location: Eastern Poland

Re: Core performance improvement [GameTimeController, moving

Post by Szponiasty »

xban1x wrote:http://trac.l2jserver.com/changeset/6251#file3 - hashCode is missing still yes.

Why not use FastList<L2Character> instead of a FastMap if second value is of no usage to you?
For speed. Any operation on FastLists takes much more time, than on indexed FastMap. If speed matters, I think lists should be used only when elements order is important or when there can be more than 1 occurrence of element in collection. To access element on fast list, that index is not known to you, you have foreach on whole list to find right element. In case of fast map, you access element directly, without need to iterate on all elements.
FastList 2: 9080ms (size=50000) [if (!contains(cha.getObjectId())) add(cha.getObjectId())]
FastMap 2: 13ms (size=50000) [if (!containsKey(cha)) put(cha, cha.getObjectId())]
Result -> FastList 2 vs FastMap 2: 69846%
It takes over 9s to do 50k loop "check if element is on list, if not add it" for fast list, and only 13ms to do the same on fast map.
And in the next chronicle they went into space, fighting the evil empire... In a galaxy far, far away xD
xban1x
L2j Veteran
L2j Veteran
Posts: 1228
Joined: Thu Jan 17, 2013 9:46 am

Re: Core performance improvement [GameTimeController, moving

Post by xban1x »

Try using L2FastMap and forEachMember for iteration...
User avatar
Szponiasty
Advanced User
Advanced User
Posts: 557
Joined: Mon Apr 21, 2008 1:31 pm
Location: Eastern Poland

Re: Core performance improvement [GameTimeController, moving

Post by Szponiasty »

xban1x wrote:Try using L2FastMap and forEachMember for iteration...
L2FastMap is not thread safe.
And in the next chronicle they went into space, fighting the evil empire... In a galaxy far, far away xD
User avatar
UnAfraid
L2j Veteran
L2j Veteran
Posts: 4199
Joined: Mon Jul 23, 2007 4:25 pm
Location: Bulgaria
Contact:

Re: Core performance improvement [GameTimeController, moving

Post by UnAfraid »

It is since its FastMap :) (With true parameter in constructor ofc)
Image
User avatar
BiggBoss
L2j Veteran
L2j Veteran
Posts: 1104
Joined: Wed Apr 15, 2009 3:11 pm
Location: Spain

Re: Core performance improvement [GameTimeController, moving

Post by BiggBoss »

System.currentTimeMilis() is wall-clock time, which not only takes your process execution time, but also all the process rounded by the kernel in the cpu. For those benchmark which takes a long time, like about 1 second or so, should be good enough (lets say it could be fine for the FastList tests), but the FastMap test are innacurates.
Use user + cpu time in future benchmarks, that way you will measure only your code execution time
Image
User avatar
Szponiasty
Advanced User
Advanced User
Posts: 557
Joined: Mon Apr 21, 2008 1:31 pm
Location: Eastern Poland

Re: Core performance improvement [GameTimeController, moving

Post by Szponiasty »

BiggBoss wrote:System.currentTimeMilis() is wall-clock time, which not only takes your process execution time, but also all the process rounded by the kernel in the cpu. For those benchmark which takes a long time, like about 1 second or so, should be good enough (lets say it could be fine for the FastList tests), but the FastMap test are innacurates.
Use user + cpu time in future benchmarks, that way you will measure only your code execution time
Yeah but for the sake of this "benchmark" it's enough.
And in the next chronicle they went into space, fighting the evil empire... In a galaxy far, far away xD
HorridoJoho
L2j Senior Developer
L2j Senior Developer
Posts: 795
Joined: Sun Aug 14, 2005 11:27 am

Re: Core performance improvement [GameTimeController, moving

Post by HorridoJoho »

I can confirm the performance improvement for map lookups when using the object as key.
The comparison with lists however is superfluous in this particular use case since a map must be used because of the horrifying lookup time of a list.

Comparing iteration time is not nessesary since javas HashMap uses linked entries, javolutions FastMap uses linked entries and trove maps use an array of indices into it's object arrays.

Here is the test i wrote(patch for L2J_Server_BETA, run com.l2jserver.tests.maplookup.Main): http://pastebin.com/q2A5g4aL

On my machine(the greater, the worse):

Code: Select all

 ### Test 1TroveMap<I, O>: 1.8405797101449275(1s 981ms 212700ns)TroveMap<O, I>: 1.3623188405797102(1s 466ms 409400ns)FastSet<O>: 1.5797101449275361(1s 700ms 410900ns)FastMap<I, O>: 1.536231884057971(1s 653ms 610600ns)FastMap<O, I>: 1.0(1s 76ms 406900ns)### Test 2TroveMap<I, O>: 1.2065217391304348(1s 731ms 611100ns)TroveMap<O, I>: 1.25(1s 794ms 11500ns)FastSet<O>: 1.065217391304348(1s 528ms 809800ns)FastMap<I, O>: 1.108695652173913(1s 591ms 210200ns)FastMap<O, I>: 1.0(1s 435ms 209200ns)### Test 3TroveMap<I, O>: 1.1590909090909092(1s 591ms 210200ns)TroveMap<O, I>: 1.3522727272727273(1s 856ms 411900ns)FastSet<O>: 1.1818181818181819(1s 622ms 410400ns)FastMap<I, O>: 1.1704545454545454(1s 606ms 810300ns)FastMap<O, I>: 1.0(1s 372ms 808800ns)### Test 4TroveMap<I, O>: 1.244186046511628(1s 669ms 210700ns)TroveMap<O, I>: 1.3255813953488371(1s 778ms 411400ns)FastSet<O>: 1.2790697674418605(1s 716ms 11000ns)FastMap<I, O>: 1.2209302325581395(1s 638ms 10500ns)FastMap<O, I>: 1.0(1s 341ms 608600ns)### Test 5TroveMap<I, O>: 1.1978021978021978(1s 700ms 410900ns)TroveMap<O, I>: 1.2857142857142858(1s 825ms 211700ns)FastSet<O>: 1.120879120879121(1s 591ms 210200ns)FastMap<I, O>: 1.1318681318681318(1s 606ms 810300ns)FastMap<O, I>: 1.0(1s 419ms 609100ns)### Test 6TroveMap<I, O>: 1.2857142857142858(1s 684ms 810800ns)TroveMap<O, I>: 1.4047619047619047(1s 840ms 811800ns)FastSet<O>: 1.2380952380952381(1s 622ms 410400ns)FastMap<I, O>: 1.2619047619047619(1s 653ms 610600ns)FastMap<O, I>: 1.0(1s 310ms 408400ns)### Test 7TroveMap<I, O>: 1.2962962962962963(1s 638ms 10500ns)TroveMap<O, I>: 1.3950617283950617(1s 762ms 811300ns)FastSet<O>: 1.3209876543209877(1s 669ms 210700ns)FastMap<I, O>: 1.4074074074074074(1s 778ms 411400ns)FastMap<O, I>: 1.0(1s 263ms 608100ns)### Test 8TroveMap<I, O>: 1.225(1s 528ms 809800ns)TroveMap<O, I>: 1.45(1s 809ms 611600ns)FastSet<O>: 1.3875(1s 731ms 611100ns)FastMap<I, O>: 1.375(1s 716ms 11000ns)FastMap<O, I>: 1.0(1s 248ms 8000ns)### Test 9TroveMap<I, O>: 1.2209302325581395(1s 638ms 10500ns)TroveMap<O, I>: 1.372093023255814(1s 840ms 811800ns)FastSet<O>: 1.197674418604651(1s 606ms 810300ns)FastMap<I, O>: 1.197674418604651(1s 606ms 810300ns)FastMap<O, I>: 1.0(1s 341ms 608600ns)### Test 10TroveMap<I, O>: 1.303370786516854(1s 809ms 611600ns)TroveMap<O, I>: 1.2584269662921348(1s 747ms 211200ns)FastSet<O>: 1.1235955056179776(1s 560ms 10000ns)FastMap<I, O>: 1.1348314606741574(1s 575ms 610100ns)FastMap<O, I>: 1.0(1s 388ms 408900ns) 
afk5min
Posts: 38
Joined: Tue Jan 31, 2012 4:02 pm
Location: Away From Keyboard

Re: Core performance improvement [GameTimeController, moving

Post by afk5min »

BiggBoss wrote:System.currentTimeMilis() is wall-clock time, which not only takes your process execution time, but also all the process rounded by the kernel in the cpu. For those benchmark which takes a long time, like about 1 second or so, should be good enough (lets say it could be fine for the FastList tests), but the FastMap test are innacurates.
Use user + cpu time in future benchmarks, that way you will measure only your code execution time
You must use an OS that supports a monotonic clock if you want the benchmark to have any value to the community. Further info: http://bugs.java.com/bugdatabase/view_b ... id=6458294
Compute sequentially, true or false?

Code: Select all

p :- p.p. ?- p.
Post Reply