mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-12-01 03:48:06 +00:00
Add computer performance monitor
This commit is contained in:
@@ -195,6 +195,8 @@ public class ComputerThread
|
|||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long start = System.nanoTime();
|
||||||
|
|
||||||
// Execute the task
|
// Execute the task
|
||||||
runner.submit( task );
|
runner.submit( task );
|
||||||
|
|
||||||
@@ -229,6 +231,10 @@ public class ComputerThread
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
long stop = System.nanoTime();
|
||||||
|
Computer computer = task.getOwner();
|
||||||
|
if( computer != null ) ComputerTimeTracker.addTiming( computer, stop - start );
|
||||||
|
|
||||||
// Re-add it back onto the queue or remove it
|
// Re-add it back onto the queue or remove it
|
||||||
synchronized( s_taskLock )
|
synchronized( s_taskLock )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package dan200.computercraft.core.computer;
|
||||||
|
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks timing information about computers, including how long they ran for
|
||||||
|
* and the number of events they handled.
|
||||||
|
*
|
||||||
|
* Note that this <em>will</em> track computers which have been deleted (hence
|
||||||
|
* the presence of {@link #timingLookup} and {@link #timings}
|
||||||
|
*/
|
||||||
|
public class ComputerTimeTracker
|
||||||
|
{
|
||||||
|
public static class Timings
|
||||||
|
{
|
||||||
|
private final WeakReference<Computer> computer;
|
||||||
|
private final int computerId;
|
||||||
|
|
||||||
|
private int tasks;
|
||||||
|
|
||||||
|
private long totalTime;
|
||||||
|
private long maxTime;
|
||||||
|
|
||||||
|
public Timings( @Nonnull Computer computer )
|
||||||
|
{
|
||||||
|
this.computer = new WeakReference<>( computer );
|
||||||
|
this.computerId = computer.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return computer.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getComputerId()
|
||||||
|
{
|
||||||
|
return computerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTasks()
|
||||||
|
{
|
||||||
|
return tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalTime()
|
||||||
|
{
|
||||||
|
return totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxTime()
|
||||||
|
{
|
||||||
|
return maxTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAverage()
|
||||||
|
{
|
||||||
|
return totalTime / (double) tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update( long time )
|
||||||
|
{
|
||||||
|
tasks++;
|
||||||
|
totalTime += time;
|
||||||
|
if( time > maxTime ) maxTime = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean tracking;
|
||||||
|
private static final List<Timings> timings = new ArrayList<>();
|
||||||
|
private static final Map<Computer, Timings> timingLookup = new MapMaker().weakKeys().makeMap();
|
||||||
|
|
||||||
|
public synchronized static void start()
|
||||||
|
{
|
||||||
|
tracking = true;
|
||||||
|
|
||||||
|
timings.clear();
|
||||||
|
timingLookup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static boolean stop()
|
||||||
|
{
|
||||||
|
if( !tracking ) return false;
|
||||||
|
|
||||||
|
tracking = false;
|
||||||
|
timingLookup.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized List<Timings> getTimings()
|
||||||
|
{
|
||||||
|
return new ArrayList<>( timings );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void addTiming( Computer computer, long time )
|
||||||
|
{
|
||||||
|
if( !tracking ) return;
|
||||||
|
|
||||||
|
Timings timings = ComputerTimeTracker.timingLookup.get( computer );
|
||||||
|
if( timings == null )
|
||||||
|
{
|
||||||
|
timings = new Timings( computer );
|
||||||
|
timingLookup.put( computer, timings );
|
||||||
|
ComputerTimeTracker.timings.add( timings );
|
||||||
|
}
|
||||||
|
|
||||||
|
timings.update( time );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
|
|||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.computer.Computer;
|
import dan200.computercraft.core.computer.Computer;
|
||||||
|
import dan200.computercraft.core.computer.ComputerTimeTracker;
|
||||||
import dan200.computercraft.shared.command.framework.*;
|
import dan200.computercraft.shared.command.framework.*;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import net.minecraft.command.CommandException;
|
import net.minecraft.command.CommandException;
|
||||||
@@ -13,12 +14,12 @@ import net.minecraft.entity.player.EntityPlayerMP;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.ITextComponent;
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
|
import static dan200.computercraft.shared.command.framework.ChatHelpers.*;
|
||||||
|
|
||||||
@@ -256,6 +257,55 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
CommandRoot track = new CommandRoot( "track", "Track execution times for computers.",
|
||||||
|
"Track how long computers execute for, as well as how many events they handle. This presents information in " +
|
||||||
|
"a similar way to /forge track and can be useful for diagnosing lag." );
|
||||||
|
root.register( track );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"start", "Start tracking all computers", UserLevel.OWNER_OP,
|
||||||
|
"Start tracking all computers' execution times and event counts. This will discard the results of previous runs."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
|
||||||
|
{
|
||||||
|
ComputerTimeTracker.start();
|
||||||
|
|
||||||
|
String stopCommand = "/" + context.parent().getFullPath() + " stop";
|
||||||
|
context.getSender().sendMessage( list(
|
||||||
|
text( "Run " ),
|
||||||
|
link( text( stopCommand ), stopCommand, "Click to stop tracking" ),
|
||||||
|
text( " to stop tracking and view the results" )
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"stop", "Stop tracking all computers", UserLevel.OWNER_OP,
|
||||||
|
"Stop tracking all computers' events and execution times"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
if( !ComputerTimeTracker.stop() ) throw new CommandException( "Tracking not enabled" );
|
||||||
|
displayTimings( context );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
track.register( new SubCommandBase(
|
||||||
|
"dump", "Dump the latest track results", UserLevel.OWNER_OP,
|
||||||
|
"Dump the latest results of computer tracking."
|
||||||
|
)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
|
||||||
|
{
|
||||||
|
displayTimings( context );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
@@ -284,4 +334,63 @@ public final class CommandComputerCraft extends CommandDelegate
|
|||||||
return position( computer.getPosition() );
|
return position( computer.getPosition() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void displayTimings( CommandContext context ) throws CommandException
|
||||||
|
{
|
||||||
|
List<ComputerTimeTracker.Timings> timings = ComputerTimeTracker.getTimings();
|
||||||
|
if( timings.isEmpty() ) throw new CommandException( "No timings available" );
|
||||||
|
|
||||||
|
timings.sort( Comparator.comparing( ComputerTimeTracker.Timings::getAverage ).reversed() );
|
||||||
|
TextTable table = new TextTable( "Computer", "Tasks", "Total", "Average", "Maximum" );
|
||||||
|
|
||||||
|
Map<Computer, ServerComputer> lookup = new HashMap<>();
|
||||||
|
int maxId = 0, maxInstance = 0;
|
||||||
|
for( ServerComputer server : ComputerCraft.serverComputerRegistry.getComputers() )
|
||||||
|
{
|
||||||
|
lookup.put( server.getComputer(), server );
|
||||||
|
|
||||||
|
if( server.getInstanceID() > maxInstance ) maxInstance = server.getInstanceID();
|
||||||
|
if( server.getID() > maxId ) maxId = server.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ICommandSender sender = context.getSender();
|
||||||
|
boolean isPlayer = sender instanceof EntityPlayerMP && !(sender instanceof FakePlayer);
|
||||||
|
|
||||||
|
for( ComputerTimeTracker.Timings entry : timings )
|
||||||
|
{
|
||||||
|
Computer computer = entry.getComputer();
|
||||||
|
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
|
||||||
|
|
||||||
|
ITextComponent computerComponent = new TextComponentString( "" )
|
||||||
|
.appendSibling( serverComputer == null ? text( "?" ) : linkComputer( serverComputer ) )
|
||||||
|
.appendText( " (id " + entry.getComputerId() + ")" );
|
||||||
|
|
||||||
|
if( serverComputer != null && UserLevel.OP.canExecute( context ) && isPlayer )
|
||||||
|
{
|
||||||
|
computerComponent
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u261b" ),
|
||||||
|
"/computercraft tp " + serverComputer.getInstanceID(),
|
||||||
|
"Teleport to this computer"
|
||||||
|
) )
|
||||||
|
.appendText( " " )
|
||||||
|
.appendSibling( link(
|
||||||
|
text( "\u20e2" ),
|
||||||
|
"/computercraft view " + serverComputer.getInstanceID(),
|
||||||
|
"View this computer"
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
table.addRow(
|
||||||
|
computerComponent,
|
||||||
|
formatted( "%4d", entry.getTasks() ),
|
||||||
|
text( String.format( "%7.1f", entry.getTotalTime() / 1e6 ) + "ms" ),
|
||||||
|
text( String.format( "%4.1f", entry.getAverage() / 1e6 ) + "ms" ),
|
||||||
|
text( String.format( "%5.1f", entry.getMaxTime() / 1e6 ) + "ms" )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.displayTo( context.getSender() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,11 @@ public class ServerComputer extends ServerTerminal
|
|||||||
return m_computer.getAPIEnvironment();
|
return m_computer.getAPIEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Computer getComputer()
|
||||||
|
{
|
||||||
|
return m_computer;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update()
|
public void update()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user