mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-03-04 10:38:12 +00:00
Add computer performance monitor
This commit is contained in:
parent
07d15caf6f
commit
83030df3ee
@ -195,6 +195,8 @@ public class ComputerThread
|
||||
thread.start();
|
||||
}
|
||||
|
||||
long start = System.nanoTime();
|
||||
|
||||
// Execute the task
|
||||
runner.submit( task );
|
||||
|
||||
@ -229,6 +231,10 @@ public class ComputerThread
|
||||
}
|
||||
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
|
||||
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.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.computer.Computer;
|
||||
import dan200.computercraft.core.computer.ComputerTimeTracker;
|
||||
import dan200.computercraft.shared.command.framework.*;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import net.minecraft.command.CommandException;
|
||||
@ -13,12 +14,12 @@ import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
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;
|
||||
}
|
||||
@ -284,4 +334,63 @@ public final class CommandComputerCraft extends CommandDelegate
|
||||
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();
|
||||
}
|
||||
|
||||
public Computer getComputer()
|
||||
{
|
||||
return m_computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user