EntityID + Performance Improvement?

Discussion in 'Plugin Development' started by Korvacs, Jun 15, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Korvacs

    Is this unique?
     
  2. I guess it's unique (unique in the way that none of the <current> spawned mobs will have the same id), but it's not persistent. If you want it to be persistent, you probably want to use .getUniqueId().
     
  3. Offline

    Korvacs

    Thats fine, was just trying to find a more efficient way to check entities instead of by username, and if EntityID is unique then any and all plugins which temperarily store players and usernames in collections but dont store that information in files should switch their entity checks to use EntityID instead of using names.
     
  4. I wouldn't say they should. It doesn't make any difference does it? You need to loop through the list of entities no matter if you search it by id or - in case of a player - by username. For entities there's no way other than using the entityid (when persistent: uniqueid).
     
  5. Offline

    Korvacs

    Your performing string comparisons instead of integer comparisons so you are intentionally writing in an inefficiency many times over, and if theres one application ive seen that requires efficiency improvements its minecraft.
     
  6. I tested it and as far as I can see, they're about the same speed (string comparison is even faster by about 1 ~ 2 ms) for a loop with 1.000.000 entries. I tested integer comparison with .equals as well as ==, both having about the same speed. Size/length of integer/string doesn't matter as far as I could see from the results. So I'm pretty sure it doesn't make any difference at all.
     
  7. Offline

    Korvacs

    Not sure why that would be true, its not true for any other language...
     
  8. I had though that as well, but testing things yourself is always better :)
     
  9. Offline

    Korvacs

    Well, I'll have to do my own research into why that might be the case for Java, but straight up that shouldn't be the case integers can be compared by the processor using 1 function in assembly, strings take many more functions, so i have no idea why this would be true unless Java deliberately makes integer checking inefficient, or your code is incorrect.
     
  10. Code:
            List<String> s = new ArrayList<String>();
            List<Integer> i = new ArrayList<Integer>();
            for(int i2 = 0; i2 < 1000000; i2++)
            {
                s.add("qwertyuiopasdfghjklzxcvbnm");
            }
         
            for(int i2 = 0; i2 < 1000000; i2++)
            {
                i.add(1123583431);
            }
         
            long time = System.currentTimeMillis();
            for(Integer in : i)
            {
                in.equals(1255222);
            }
            System.out.println("interger : " + (System.currentTimeMillis() - time) + "ms");
            time = System.currentTimeMillis();
            for(String sn : s)
            {
                sn.equals("qwertyuiopasdfghjklzxcvbnm");
            }
            System.out.println("string : " + (System.currentTimeMillis() - time) + "ms");
    output:
     
  11. If you store players' entity ids instead of their names to identify them, it's not the same.
    A player as a person/account on a server is uniquely identified by its username (even on offline servers), they just happen to be represented by an entity with a specific id. As soon as the player reconnects (or even dies/respawns, that's not confirmed, though), it's going to be a new entity, but the same player, so your code, won't recognize him anymore.

    Saying that "plugins that store players should switch to their entity id" is invalid, because a player isn't always represented by the exact same entity.
     
  12. Offline

    Njol

    I don't think that this code is valid for comparing the speed of the comparisons as Java optimizes the code very well, e.g. it might completely remove the .equals checks since they don't have any effect (i.e. are basically NOPs), and/or compare the strings with == as they are literals and are thus only stored once in the code but simply referenced by the variables.
     
  13. in that case both have the same speed.
     
  14. Offline

    Korvacs

    I take it you dont understand the difference between persistent data and none persistent data, if the plugin simply takes and stores player entities while the server is online and never stores that information outside of memory then an improvement like this should be applied. I did state that only in that case should this be used.

    So unless the EntityId is altered when a player changes position or if the player dies then switching to this would be an improvement.

    kumpelblase2

    Your code is completely unreliable, having ran it several times to test it i get results such as:

    integer : 20ms
    string : 10ms

    integer : 10ms
    string : 10ms

    integer : 10ms
    string : 0ms <--- ??

    Also having made it loop through 100000000 values i got the results:

    integer : 577ms
    string : 188ms

    So, i have modified your code to be more realistic and the results look more like the norm that i was expecting:

    Code:
            System.out.println("Starting Loading Process");
         
            ArrayList<String> s = new ArrayList<String>();
            ArrayList<Integer> i = new ArrayList<Integer>();
            ArrayList<UUID> u = new ArrayList<UUID>();
            UUID cu = UUID.randomUUID();
         
            for(int i2 = 0; i2 < 10000000; i2++)
            {
                s.add(String.valueOf(i2));
            }
     
            for(int i2 = 0; i2 < 10000000; i2++)
            {
                i.add(i2);
            }
         
            for(int i2 = 0; i2 < 10000000; i2++)
            {
                u.add(UUID.randomUUID());
            }
         
            System.out.println("Loading Complete");
     
            long time = System.currentTimeMillis();
            for(Integer in : i)
            {
                if(in == 1255222) {             
             
                }
                 
            }
            System.out.println("integer == : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();
            for(Integer in : i)
            {
                if(in.equals(1255222)) {             
             
                }
                 
            }
            System.out.println("integer.equals : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();
            for(Integer in : i)
            {
                if(in.compareTo(1255222) == 0) {             
             
                }
                 
            }
            System.out.println("integer.compareTo : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();     
            for(UUID uid : u)
            {
                if(uid == cu) {             
             
                }
                 
            }
            System.out.println("UUID == : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();     
            for(UUID uid : u)
            {
                if(uid.equals(cu)) {             
             
                }
                 
            }
            System.out.println("UUID.equals : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();
            for(UUID uid : u)
            {
                if(uid.compareTo(cu) == 0) {             
             
                }
                 
            }
            System.out.println("UUID.compareTo : " + (System.currentTimeMillis() - time) + "ms");
         
            time = System.currentTimeMillis();
            for(String sn : s)
            {
                if(sn == "500"){
                 
                }
            }
            System.out.println("string == : " + (System.currentTimeMillis() - time) + "ms"); 
         
            time = System.currentTimeMillis();
            for(String sn : s)
            {
                if(sn.equals("500")){
                 
                }
            }
            System.out.println("string.equals : " + (System.currentTimeMillis() - time) + "ms");     
         
            time = System.currentTimeMillis();
            for(String sn : s)
            {
                if(sn.compareTo("500") == 0){
                 
                }
            }
            System.out.println("string.compareTo : " + (System.currentTimeMillis() - time) + "ms");
    And here are the times using a stopwatch from the springsource framework:

    I added the UUID for myself to see how comparable the results were to string, if there was a performance increase it would have been a nice alternative for those plugins which require persistent data. However i would still argue to use the UUID rather than the player name on the grounds of security.

    Thoughts people?
     
  15. It is irrelevant wether or not the plugin would store the id persistently or just in memory. The player can disconnect whenever he wants, without a server reload.

    I have to take back the point of the id changing when the player dies, though. I just tested that and it doesn't happen.

    The UUID is persisted for the player (any entity, to be precise), though, so that's fine to use from my side.

    Regarding your funky speed testing: It's great that you want to find out the exact performance difference, but it honestly doesn't matter. We are not talking about millions of iterations in a single tick here.
    That micro-optimization that you are trying to accomplish is not going to make your plugin any better, its impact is just neglectible in any possible way.
    Even if the comparison (by the way, Collections backed by hashing such as HashSet and HashMap don't even use "iterating & comparing" as you did in your benchmarks) would be 100 times faster, both is in an area that can just be considered "not time-consuming".

    Let's say you have 100 players stored in your collection, which already corresponds to a HUGE server. How what time would a (for example) HashSet contains()-check take? A couple of nanoseconds, maybe? Maybe even 100ns. You know how much that is?

    What I am saying is that you shouldn't bother with such small performance differences, code readability and reliance is more important than that.
    Those don't suffer in this example, but saying that one should use that for performance reasons is not valid.

    Please don't understand me wrong. I'm definately no supporter of "teh code workz, ima use that, dont care about it slowing down serverz", but when the difference is simply that small, it's just redundant.
     
  16. Offline

    Korvacs

    Bone008
    The problem is that there are so many lines of inefficient code in minecraft that you have to start somewhere, and it just so happens that I have picked up on the heavy use of strings which should be avoided at all costs, at no point in any application should you be heavily relying on strings for identification its just bad practice.

    Also yes i am aware of how collections work thank you very much, I have written private servers for games which can happily support 500+ players at the same time, I know that the best way to get performance out of your code is to write it correctly first time every time, unfortunately minecraft hasnt had that level of care from what i can tell.

    As for :
    Yes, i understand that, but the fact of the matter is that if some did disconnect and reconnect they should be treated as a new player and every trace of them should be removed from the server on disconnect and not maintained. So actually this behaviour would be preferred, if any trace of the player is to be maintained then it should be done so through physically storing the data and not keeping it in memory.
     
  17. Offline

    krisdestruction

    If you require a unique int ID but can't afford a UUID, you can also hash the UUID using .getUniqueId().hashCode().
     
  18. Offline

    frozenpoptartmc

    >________________________________________<
    why is this bumped
     
Thread Status:
Not open for further replies.

Share This Page