#Code Optimization

295 messages · Page 1 of 1 (latest)

hardy nestBOT
#

This post has been reserved for your question.

Hey @true sorrel! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.

TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.

sleek crow
#

check a profiler to find out what's slow

#

Also, what's the point of that code?

        AtomicBoolean running = new AtomicBoolean(true);
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep((long) (TURN_TIME_LIMIT * 0.8));
                running.set(false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        thread.start();

Why don't you just check the current system time instead?

#

also synchronization etc could make your code slower

true sorrel
sleek crow
#

so the whole MCTS is synchronized? Which means that you cannot run it in multiple threads..?

true sorrel
sleek crow
#

Also, are you mutating your data classes anywhere?

true sorrel
sleek crow
#

well you could maybe attempt to use multiple threads for a speedup

sleek crow
#

Are you changing the variables in these data classes?

#

I am not talking about the names

#

it might be faster if you use records (so you can't change any of the variables) for some of the data classes and recreate them when they are changed

#

e.g. MCTSState5

true sorrel
#

I have never heard of records

sleek crow
#

that could be faster but it could also be slower

sleek crow
#

Which Java version are you using?

true sorrel
#

16

sleek crow
#

you could try updating your Java version - there are lots of performance updates with newer Java versions

#

¯_(ツ)_/¯

true sorrel
#

It's a task where u have to develop a bot for a game and you need to maximize your winning percentages. The file I sent above is the only file you can control.
I am getting decent results against minimax with alpha-beta pruning etc but I am looking to even get more wins.

sleek crow
#

Records are available in Java 16

true sorrel
#

Ah then I will definitly have a look at them. What makes them faster than classes?

sleek crow
#

The JIT knows that you cannot change the variables in there and can do some optimizations with that

#

especially in newer Java versions

#

not sure about 16

#

Also why don't you try using multiple threads

#

e.g. you could play 2 games at the same time

#

(or more)

#

and then combine the results

true sorrel
#

Ill try to explain it more clear.

Bot 1 and Bot 2 will play 1000 games against eachother.

8 threads will play 125 games simultaneously and the results will be combined.

sleek crow
#

e.g. you start 4 threads that all play 20 games and then you combine the results

true sorrel
#

Yes that's what happens, but thas has no influence on the performance of my bot right.

true sorrel
#

That doesnt speed up your actual bot, it just speeds up the time it takes to play 1000 games.

sleek crow
#

Are you pretraining your MCTS?

true sorrel
#

No

sleek crow
#

you could do that

#

then it would be faster for some moves

true sorrel
#

Where would the 'brains' be stored?

sleek crow
#

just create a file with an initial tree

#

and include that in the application

#

and when the application starts, it uses that

true sorrel
#

Alright well I like the idea, but everything is supposed to be in that 1 java-file I sent.

Could I store it in a list or something?

sleek crow
#

Also, if possible, keep objects confined to a method

#

that could also improve performance

true sorrel
#

What does that mean?

sleek crow
#

e.g. if a method creates an object, try to not pass that object to many other methods

#

and especially don't save that object anywhere else

#

if you do that, these objects might be stored on the stack hence less allocation/GC work etc

true sorrel
#

I actually had a version first where I did that, but now I made these global objects that every method uses.

sleek crow
#

make a copy of your version and change it to use fewer global objects

#

one by one

#

maybe making some more local improves performance

true sorrel
#

these:

    final MCTSNode5 rootNode = new MCTSNode5();
    final ArrayList<Action5> actionList = new ArrayList<>();

Adding these instead of always re-creating them in methods got me more than 10% improvement execution time wise

sleek crow
#

while it might not be the case with others

sleek crow
true sorrel
#

The global objects got me a massive improvement so I think the opposite is true in here unless I did something wrong in older versions with locals

sleek crow
#

but creating big lists can be slow

true sorrel
#

genereateAllActions is a huge switch case with tons of loops, do you see bad stuff in there?

sleek crow
#

well, the loops

true sorrel
sleek crow
#

(did that so it is easier readable for me)

#

You could try making Action5 a record

#

that could speed up something, also in that method

#

Can you show PylosSphere and PylosLocation?

true sorrel
#

yes I can but I am not allowed to change anything in these classes

true sorrel
sleek crow
#

Also, do you really need the public StudentPlayer2 player; in Action5?

#

if some fields are unnecessary, remove them

true sorrel
#

It is to access the pylosGamesimulator. First I had it static but it messed up when the tournement split up the games over multiple threads, since statics arent thread-safe.

#

So thats why i added that field to the actions class

sleek crow
#

yeah but what do you need it for?

#

in the MOVE case, you are iterating through all locations

#

maybe you can find a way to only iterate through usable locations or similar

true sorrel
#

I use the pylosgamesimulator in the switch cases here

sleek crow
#

you could try making the player.pylosGameSimulator a parameter

#

instead of a field

true sorrel
#

Whats the difference?

#

A paramter of the simulate, execute and undo methods?

sleek crow
#

parameters could be more efficient than fields

#

and if you have many Action5s, it could also result in you needing less memory

#

but for all of the optimizations, you'd need to check how well they work

true sorrel
#

I will definitly try them out. Are there also like libraries to speed up stuff?

true sorrel
#

Any other suggestions?

true sorrel
#

This is my project structure and I am trying to benchmark 1 file that is in pylos-student, but it uses the other packages aswell.

sleek crow
#

decide on a module where you want to do benchmarks in

#

then add both jmh-core and jmh-generator-annprocess to the annotation processor

true sorrel
#

what is the annotation processor?

sleek crow
#
<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <finalName>${uberjar.name}</finalName>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>org.openjdk.jmh.Main</mainClass>
                                </transformer>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                            </transformers>
                            <filters>
                                <filter>
                                    <!--
                                        Shading signed JARs will fail without this.
                                        http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
                                    -->
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
#

and you can use this configuration with the shade plugin

true sorrel
#

this is my current pom.xml of pylos-student:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>pylos</artifactId>
        <groupId>be.kuleuven</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>pylos-student</artifactId>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>16</source>
                    <target>16</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>be.kuleuven</groupId>
            <artifactId>pylos-core</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.1-jre</version>
        </dependency>
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.3</version>
        </dependency>
    </dependencies>

</project>
sleek crow
#

no JMH there

#

maybe you want to create another module for your benchmarks

#

if you want to

true sorrel
#

Ill do that but I am very new to this so I got no clue what to do to set it up

#

I installed maven

sleek crow
#
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>${jmh.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>${jmh.version}</version>
            <scope>provided</scope>
        </dependency>
#

you probably need these dependencies

sleek crow
true sorrel
#

I added a benchmark module:

sleek crow
#

and add a dependency on the other module you want to measure

true sorrel
#

So i need to add the 2 dependencies on the 2 modules?

sleek crow
#

if module A is dependent on module B, it should be sufficient to add a dependency on module A

true sorrel
#

ok

#

this is my pom.xml in benchmark module now:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>be.kuleuven</groupId>
        <artifactId>pylos</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>benchmark</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>1.37</version>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>1.37</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
#

I also added the 2 dependecies to the other module

sleek crow
#

to <plugins>

#

that allows you to create a JAR for doing your benchmarks

true sorrel
#

Ok i added it

#

What's next?

sleek crow
#

now write your benchmarks in that project

#

For now, I would start with an empty benchmark

sleek crow
#

and then you can just run the JAR with java -jar which will run your benchmarks

true sorrel
#

Or what do I do?

sleek crow
#

in the benchmark project:

@Benchmark
void someBenchmark(){
  whateverYouWantToTest();
}
#

if you need to do initialization work, you can do that as well

true sorrel
#

ill start with an empty one to test if its setup correctly then

sleek crow
#

yes

sleek crow
#

and JMH is especially for microbenchmarks - it will run your benchmark over and over

true sorrel
#

I got this. Is this a valid benchmark?

sleek crow
#

you don't need the main

#

and I wouldn't print to the console in benchmarks unless you want to measure that

true sorrel
#

ye its spamming test in my console rn

#

when i run the jar

sleek crow
#

because printing something to the console will result in console spam

#

and for more accurate results, you might want to close IntelliJ etc when you are actually measuring something

true sorrel
#

I would like to benchmark methods from the file you helped me with earlier. How can I do that then?

#

It's in a different module so I am not sure how to test that

true sorrel
sleek crow
#

if the module you are using is a dependency of the benchmark module

true sorrel
#

Can you give me an example on how I can test a certain method from the code we discussed this morning?

sleek crow
true sorrel
#

I am trying to optimize the class I indicated with red

true sorrel
#

How can I refer to that method then? its in a different module

sleek crow
#

Does the benchmark module have a dependency on the student module?

true sorrel
sleek crow
#

in your benchmark module

#

you add a <dependency>

#

with the group id/artifact id of the student module

true sorrel
#
    <dependencies>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>1.37</version>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>1.37</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>```
sleek crow
#

once you have that, you can use the classes from the student module in the benchmark module

true sorrel
#

These are my dependencies

sleek crow
#

you add another dependency

true sorrel
#

What do i type?

sleek crow
#

with group id, artifact id and version of your student module

sleek crow
#

you can find the values in the pom.xml of the student module

true sorrel
#
      <dependency>
            <groupId>be.kuleuven</groupId>
            <artifactId>pylos-student</artifactId>
        </dependency>

``` i added this
sleek crow
#

yes

true sorrel
#

How can i access the methods in the Benchmark class then?

sleek crow
#

you can access them like any other class

#

How do you access String methods?

true sorrel
#

I am trying to import it but i must be using a wrong path

sleek crow
#

if you just type the class name, IntelliJ can typically add the import automatically

true sorrel
#

it asks me if it should move the class from the pylos-student to the benchmark module

#

Thats not what we want right

sleek crow
#

reload the maven project in IntelliJ

true sorrel
#

just close and reopen?

sleek crow
#

on the right side, there's a Maven tab

#

that should have a reload symbol somewhere

#

at least that's where it was a few years ago

true sorrel
#

the symbol of my class changed to orange

sleek crow
#

that's a bit weird

#

Can you show your parent pom.xml?

true sorrel
#

What is the parent?

sleek crow
#

Is the benchmark module included in the maven tabL?

sleek crow
#

outside of all modules

true sorrel
#
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>be.kuleuven</groupId>
    <artifactId>pylos</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <modules>
        <module>pylos-core</module>
        <module>pylos-gui</module>
        <module>pylos-student</module>
        <module>benchmark</module>
    </modules>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

</project>

sleek crow
#

ok that looks good

#

is there a version in the student pom.xml?

#

not talking about dependencies or the <parent>

#

try executing mvn clean install

true sorrel
#

thats the student xml

#

ye its missing a version

#

Idk what to fill in as version

sleek crow
#

${project.version}

#

this means same version as current project

#

which is 1.0-SNAPSHOT in your case

true sorrel
#

that fixed some stuff

#

it failed on benchmark

sleek crow
#

if you scroll up, it should show you why

true sorrel
#

My main class of benchmark is corrupt

#

the class symbol should b e blue

#

not grey/orange

sleek crow
#

well you have a syntax error there

true sorrel
#
package org.example;
import org.openjdk.jmh.annotations.Benchmark;


import StudentPlayer2;


public class Main {

    @Benchmark
    public void someBenchmark(){


    }

}

sleek crow
#

import StudentPlayer2; is wrong

#

you'd need to use the full package name

true sorrel
#

What do i do?

#

oh i fixed it

#

Lets say I want to benchmark a certain method, how do I do that in the best way?

sleek crow
#

just run the method once in the benchmark method

#

And do initialization outside that method since you don't want to benchmark the initialization

true sorrel
sleek crow
#

You can use an @Setup method for initialization

#
public class Main{
  private StateClass whateverStateYouNeed;
  private StudentPlayer2 player;
  @Setup
  public void setup(){
    whateverStateYouNeed = initializeState();
    player = new StudentPlayer2();
  }
  @Benchmark
  public void someBenchmark(){
    player.whateverYouWantToMeasure();
  }
}
#

if the method to measure has some results, you should return it or use Blackhole

true sorrel
sleek crow
#

If you want to measure how performance battles are in general, set up everything necessary for the battle (players, maybe a battlefield) int he setup method

#

and run it in the benchmark method

true sorrel
#

This method starts a battle, but is there a point benchmarking this method?

sleek crow
#

Does the method wait for the battle to finish?

true sorrel
sleek crow
#

I would only do a single battle in your benchmark

#

since JMH runs your method over and over anyways

true sorrel
# sleek crow since JMH runs your method over and over anyways
package org.example;
import be.kuleuven.pylos.game.PylosBoard;
import be.kuleuven.pylos.game.PylosGame;
import be.kuleuven.pylos.player.student.StudentPlayer2;
import be.kuleuven.pylos.player.student.StudentPlayerJonas;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Setup;

import java.util.Random;

import static be.kuleuven.pylos.main.PylosMain.startSingleGame;


public class Main {
    
    @Setup
    public void init(){
        
    }
    @Benchmark
    public void someBenchmark(){
        startSingleGame();
    }

}
#

This is the current benchmark class

sleek crow
#

try it and see what happens

#

btw if you don't use the setup method, you don't need it

true sorrel
#

ok ill change it

#

What do i do now?

sleek crow
#

since like it is running the benchmark

sleek crow
#

seems*

true sorrel
#

I want to benchmark the MCTS method for example. I dont know how to do the properly setup a game.

#

I get tons of errors because it didnt initialize properly

sleek crow
#

well, you might find the code for initializing the game in the start methods

true sorrel
#

    public static void startSingleGame() {

        Random random = new Random(0);

        PylosPlayer playerLight = new StudentPlayerJonas();
        PylosPlayer playerDark = new StudentPlayer2();

        PylosBoard pylosBoard = new PylosBoard();
        PylosGame pylosGame = new PylosGame(pylosBoard, playerLight, playerDark, random,
                PylosGameObserver.CONSOLE_GAME_OBSERVER, PylosPlayerObserver.NONE);

        pylosGame.play();
    }


#

This is the code to start a single game

sleek crow
#

that's how a board is initialized

#

but maybe something happens inside the pylosGame.play(); method

#

seems like doing the stuff from startSingleGame might be enough

#

but maybe you want to do a few random moves with both players before starting your benchmarks

true sorrel
#

im getting nullpointer exceptions in my p1 class

sleek crow
#

then you need to check why you get them

#

I can't tell you that

true sorrel
#

I just started 1 game to test

#

What insights can i get from this?

sleek crow
#

well, it tells you how long a game takes on average

#

this is why whole games aren't good benchmarks

#

and why you should probably calculate a single move in each benchmark

true sorrel
#

Ok ill try to go deeper

true sorrel
#

A benchmark takes a pretty long time with the standard options

sleek crow
#

by default, it's 10 minutes per benchmark I think

#

you can reduce the number of iterations or similar

#

depends on what works for you

true sorrel
sleek crow
#

warmup is important, yes

true sorrel
#

What exactly are warmup / fork?

sleek crow
#

Java uses a JIT

#

meaning it will be fast once it has been run many times

true sorrel
#

I have to go soon but I want to tell you I really appreciate this.

sleek crow
#

warmup "warms up" your code so it gets fast

true sorrel
#

This will help me in my optimization and algorithm courses aswell

sleek crow
#

and regarding forks: JMH uses multiple Java processes (forks) to run multiple benchmarks independently

true sorrel
sleek crow
#

you can try reducing the fork count

true sorrel
#

Do i want to maximize them or minimize them?

sleek crow
#

if you are measuring throughput

true sorrel
#

And then compare if the amount of operations has gone up?

sleek crow
#

yeah

true sorrel
sleek crow
#

Is it not operations per second?

true sorrel
#

operations per sec i meant

sleek crow
#

well if you can run it many times per second, it's fast

true sorrel
#

Can i make multiple benchmark methods? or do i need to comment the other ones out when measuring

sleek crow
#

yes

#

if you have multiple benchmark methods, JMH will run all and give you a comparison of the results

hardy nestBOT
#

💤 Post marked as dormant

This post has been inactive for over 300 minutes, thus, it has been archived.
If your question was not answered yet, feel free to re-open this post or create a new one.
In case your post is not getting any attention, you can try to use /help ping.
Warning: abusing this will result in moderative actions taken against you.

hardy nestBOT
#

💤 Post marked as dormant

This post has been inactive for over 300 minutes, thus, it has been archived.
If your question was not answered yet, feel free to re-open this post or create a new one.
In case your post is not getting any attention, you can try to use /help ping.
Warning: abusing this will result in moderative actions taken against you.