Skip to content

Performance

Max edited this page Oct 1, 2023 · 14 revisions

Performance Overview

For the Alchemist performance we can break it down into different parts:

  • Join Performance
  • Task Performance
  • Feature Performance

1st Part: Join Performance

For this type of performance, Alchemist monitors how fast everything happens when a player joins the server. It is based on how fast the profile is looked up from mongo. If the profile isn't in mongo we create a new one.

The best case time complexity for a login event is $O(1)$ which would represent the profile already existing in the cache. The worst possible time complexity is $O(log n)$ which is a pure mongodb search using an indexed _id field.

performance

This test was based off purely how fast it took to find and load the profile into the cache. 1,000,000+ entries showed a slight decrease in performance, but it was still very fast considering the conditions.

The things that we do in order after this has been dispatched go as following:

  1. Update the player's current IP address
  2. Update the player's username
  3. Set player's current server
  4. Make a new session and add it to the profile
  5. Add UUID and username into the UUID cache
  6. Save profile

2nd Part: Task Performance

This type of performance is subject to how we run tasks. The tasks that we run are not very impactful but could still be factored into the performance calculation.

We run 2 main tasks, ClearOutExpirablesTask and SyncTask. These tasks are pretty self-explanatory and are run using Bukkit's asynchronous schedular which means they do not appear on timings unless you factor in async-threads.

3rd Part: Profiling

We have ran a few JProfilers on our code to see what would happen. The work environment here was 1,300,000 profiles as well as 300 decoy players on the server. The results are below.

image image

As you can see, the object that our package 'ltd.matrixstudios.alchemist' used the most was the GameProfile. This number is based on the instances of the class in memory which does make sense because we do have 1.3 million profiles in the db. Although we do not load every single profile directly from mongo, there are still a lot of profiles being pulled and pushed from the database.

Our threading process was also pretty flawless as we had no blocked threads, which was expected, and very minimal pressure on the common pool for allocating a set amount of threads to attend to a task. As for memory, the most I saw the value jump to was about +340mb to a 1024mb allocated server running at the set 300 players. Of course, if you are ever to get 300 players you may want to consider adding more memory but this is just a starting benchmark.

The only other thing to go over is the CPU load which is a bit high but for reasons that you may expect. This was running on my main computer which is pretty chaotic considering how many things I have to have open in order to run this program so I do not really factor it into the equation that heavily but it does still spike because of how many minecraft connections I have open using mineflayer.

4th Part: Feature Performance

This type of performance is related to some of our more server-intensive features. Such as grants, punishments, and alts. The processing for all of these values happens asynchronously and is sent to a cache that is updated through redis to ensure that there is never desync between servers. Doing this allows Alchemist to pull items in a faster time because our caches use HashMaps which have an O(1) time complexity.

We also only call refreshes when they are actually required (such as when a player gets a new rank, gets a rank removed, or a rank gets deleted which then forces grants to be voided). This system allows Alchemist to be a lot less heavy when it comes to performance.

Clone this wiki locally