1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-09-28 15:08:47 +00:00

Add support for tracking server-thread tasks too

This allows us to track how much work various peripherals are doing.
This will not work with all systems, such as Plethora, as that has its
own execution system.
This commit is contained in:
SquidDev 2018-04-24 12:26:26 +01:00
parent cac65ef755
commit bfbb18bdfc
7 changed files with 118 additions and 23 deletions

View File

@ -69,17 +69,17 @@ public class ComputerThread
s_stopped = false; s_stopped = false;
if( s_threads == null || s_threads.length != ComputerCraft.computer_threads ) if( s_threads == null || s_threads.length != ComputerCraft.computer_threads )
{ {
s_threads = new Thread[ ComputerCraft.computer_threads ]; s_threads = new Thread[ComputerCraft.computer_threads];
} }
SecurityManager manager = System.getSecurityManager(); SecurityManager manager = System.getSecurityManager();
final ThreadGroup group = manager == null ? Thread.currentThread().getThreadGroup() : manager.getThreadGroup(); final ThreadGroup group = manager == null ? Thread.currentThread().getThreadGroup() : manager.getThreadGroup();
for( int i = 0; i < s_threads.length; i++ ) for( int i = 0; i < s_threads.length; i++ )
{ {
Thread thread = s_threads[ i ]; Thread thread = s_threads[i];
if( thread == null || !thread.isAlive() ) if( thread == null || !thread.isAlive() )
{ {
thread = s_threads[ i ] = new Thread( group, new TaskExecutor(), "ComputerCraft-Computer-Manager-" + s_ManagerCounter.getAndIncrement() ); thread = s_threads[i] = new Thread( group, new TaskExecutor(), "ComputerCraft-Computer-Manager-" + s_ManagerCounter.getAndIncrement() );
thread.setDaemon( true ); thread.setDaemon( true );
thread.start(); thread.start();
} }
@ -251,8 +251,8 @@ public class ComputerThread
{ {
long stop = System.nanoTime(); long stop = System.nanoTime();
Computer computer = task.getOwner(); Computer computer = task.getOwner();
if( computer != null ) Tracking.addTiming( computer, stop - start ); if( computer != null ) Tracking.addTaskTiming( 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 )
{ {

View File

@ -6,14 +6,17 @@
package dan200.computercraft.core.computer; package dan200.computercraft.core.computer;
import java.util.LinkedList; import dan200.computercraft.core.tracking.Tracking;
import java.util.ArrayDeque;
import java.util.Queue;
public class MainThread public class MainThread
{ {
private static final int MAX_TASKS_PER_TICK = 1000; private static final int MAX_TASKS_PER_TICK = 1000;
private static final int MAX_TASKS_TOTAL = 50000; private static final int MAX_TASKS_TOTAL = 50000;
private static final LinkedList<ITask> m_outstandingTasks = new LinkedList<>(); private static final Queue<ITask> m_outstandingTasks = new ArrayDeque<>();
private static final Object m_nextUnusedTaskIDLock = new Object(); private static final Object m_nextUnusedTaskIDLock = new Object();
private static long m_nextUnusedTaskID = 0; private static long m_nextUnusedTaskID = 0;
@ -31,7 +34,7 @@ public class MainThread
{ {
if( m_outstandingTasks.size() < MAX_TASKS_TOTAL ) if( m_outstandingTasks.size() < MAX_TASKS_TOTAL )
{ {
m_outstandingTasks.addLast( task ); m_outstandingTasks.offer( task );
return true; return true;
} }
} }
@ -46,14 +49,17 @@ public class MainThread
ITask task = null; ITask task = null;
synchronized( m_outstandingTasks ) synchronized( m_outstandingTasks )
{ {
if( m_outstandingTasks.size() > 0 ) task = m_outstandingTasks.poll();
{
task = m_outstandingTasks.removeFirst();
}
} }
if( task != null ) if( task != null )
{ {
long start = System.nanoTime();
task.execute(); task.execute();
long stop = System.nanoTime();
Computer computer = task.getOwner();
if( computer != null ) Tracking.addServerTiming( computer, stop - start );
++tasksThisTick; ++tasksThisTick;
} }
else else

View File

@ -15,6 +15,9 @@ public class ComputerTracker
private long totalTime; private long totalTime;
private long maxTime; private long maxTime;
private long serverCount;
private long serverTime;
private final TObjectLongHashMap<TrackingField> fields; private final TObjectLongHashMap<TrackingField> fields;
public ComputerTracker( Computer computer ) public ComputerTracker( Computer computer )
@ -32,10 +35,13 @@ public class ComputerTracker
this.tasks = timings.tasks; this.tasks = timings.tasks;
this.totalTime = timings.totalTime; this.totalTime = timings.totalTime;
this.maxTime = timings.maxTime; this.maxTime = timings.maxTime;
this.serverCount = timings.serverCount;
this.serverTime = timings.serverTime;
this.fields = new TObjectLongHashMap<>( timings.fields ); this.fields = new TObjectLongHashMap<>( timings.fields );
} }
@Nullable @Nullable
public Computer getComputer() public Computer getComputer()
{ {
@ -67,13 +73,19 @@ public class ComputerTracker
return totalTime / tasks; return totalTime / tasks;
} }
void addTiming( long time ) void addTaskTiming( long time )
{ {
tasks++; tasks++;
totalTime += time; totalTime += time;
if( time > maxTime ) maxTime = time; if( time > maxTime ) maxTime = time;
} }
void addMainTiming( long time )
{
serverCount++;
serverTime += time;
}
void addValue( TrackingField field, long change ) void addValue( TrackingField field, long change )
{ {
synchronized( fields ) synchronized( fields )
@ -89,6 +101,9 @@ public class ComputerTracker
if( field == TrackingField.TOTAL_TIME ) return totalTime; if( field == TrackingField.TOTAL_TIME ) return totalTime;
if( field == TrackingField.AVERAGE_TIME ) return totalTime / tasks; if( field == TrackingField.AVERAGE_TIME ) return totalTime / tasks;
if( field == TrackingField.SERVER_COUNT ) return serverCount;
if( field == TrackingField.SERVER_TIME ) return serverTime;
synchronized( fields ) synchronized( fields )
{ {
return fields.get( field ); return fields.get( field );

View File

@ -4,7 +4,46 @@ import dan200.computercraft.core.computer.Computer;
public interface Tracker public interface Tracker
{ {
void addTiming( Computer computer, long time ); @Deprecated
default void addTiming( Computer computer, long time )
{
}
void addValue( Computer computer, TrackingField field, long change ); /**
* Report how long a task executed on the computer thread took.
*
* Computer thread tasks include events or a computer being turned on/off.
*
* @param computer The computer processing this task
* @param time The time taken for this task.
*/
default void addTaskTiming( Computer computer, long time )
{
//noinspection deprecation
addTiming( computer, time );
}
/**
* Report how long a task executed on the server thread took.
*
* Server tasks include actions performed by peripherals.
*
* @param computer The computer processing this task
* @param time The time taken for this task.
*/
default void addServerTiming( Computer computer, long time )
{
}
/**
* Increment an arbitrary field by some value. Implementations may track how often this is called
* as well as the change, to compute some level of "average".
*
* @param computer The computer to increment
* @param field The field to increment.
* @param change The amount to increment said field by.
*/
default void addValue( Computer computer, TrackingField field, long change )
{
}
} }

View File

@ -35,14 +35,25 @@ public class Tracking
} }
} }
public static void addTiming( Computer computer, long time ) public static void addTaskTiming( Computer computer, long time )
{ {
if( tracking.get() == 0 ) return; if( tracking.get() == 0 ) return;
synchronized( contexts ) synchronized( contexts )
{ {
for( TrackingContext context : contexts.values() ) context.addTiming( computer, time ); for( TrackingContext context : contexts.values() ) context.addTaskTiming( computer, time );
for( Tracker tracker : trackers ) tracker.addTiming( computer, time ); for( Tracker tracker : trackers ) tracker.addTaskTiming( computer, time );
}
}
public static void addServerTiming( Computer computer, long time )
{
if( tracking.get() == 0 ) return;
synchronized( contexts )
{
for( TrackingContext context : contexts.values() ) context.addServerTiming( computer, time );
for( Tracker tracker : trackers ) tracker.addServerTiming( computer, time );
} }
} }

View File

@ -14,7 +14,7 @@ import java.util.Map;
* Note that this <em>will</em> track computers which have been deleted (hence * Note that this <em>will</em> track computers which have been deleted (hence
* the presence of {@link #timingLookup} and {@link #timings} * the presence of {@link #timingLookup} and {@link #timings}
*/ */
public class TrackingContext public class TrackingContext implements Tracker
{ {
private boolean tracking = false; private boolean tracking = false;
@ -52,7 +52,8 @@ public class TrackingContext
return new ArrayList<>( timings ); return new ArrayList<>( timings );
} }
public void addTiming( Computer computer, long time ) @Override
public void addTaskTiming( Computer computer, long time )
{ {
if( !tracking ) return; if( !tracking ) return;
@ -66,11 +67,31 @@ public class TrackingContext
timings.add( computerTimings ); timings.add( computerTimings );
} }
computerTimings.addTiming( time ); computerTimings.addTaskTiming( time );
} }
} }
public synchronized void addValue( Computer computer, TrackingField field, long change ) @Override
public void addServerTiming( Computer computer, long time )
{
if( !tracking ) return;
synchronized( this )
{
ComputerTracker computerTimings = timingLookup.get( computer );
if( computerTimings == null )
{
computerTimings = new ComputerTracker( computer );
timingLookup.put( computer, computerTimings );
timings.add( computerTimings );
}
computerTimings.addMainTiming( time );
}
}
@Override
public void addValue( Computer computer, TrackingField field, long change )
{ {
if( !tracking ) return; if( !tracking ) return;

View File

@ -14,6 +14,9 @@ public class TrackingField
public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", "Average time", x -> String.format( "%4.1fms", x / 1e6 ) ); public static final TrackingField AVERAGE_TIME = TrackingField.of( "average", "Average time", x -> String.format( "%4.1fms", x / 1e6 ) );
public static final TrackingField MAX_TIME = TrackingField.of( "max", "Max time", x -> String.format( "%5.1fms", x / 1e6 ) ); public static final TrackingField MAX_TIME = TrackingField.of( "max", "Max time", x -> String.format( "%5.1fms", x / 1e6 ) );
public static final TrackingField SERVER_COUNT = TrackingField.of( "server_count", "Server task count", x -> String.format( "%4d", x ) );
public static final TrackingField SERVER_TIME = TrackingField.of( "server_time", "Server task time", x -> String.format( "%7.1fms", x / 1e6 ) );
public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", "Peripheral calls", x -> String.format( "%6d", x ) ); public static final TrackingField PERIPHERAL_OPS = TrackingField.of( "peripheral", "Peripheral calls", x -> String.format( "%6d", x ) );
public static final TrackingField FS_OPS = TrackingField.of( "fs", "Filesystem operations", x -> String.format( "%6d", x ) ); public static final TrackingField FS_OPS = TrackingField.of( "fs", "Filesystem operations", x -> String.format( "%6d", x ) );
public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", "Turtle operations", x -> String.format( "%6d", x ) ); public static final TrackingField TURTLE_OPS = TrackingField.of( "turtle", "Turtle operations", x -> String.format( "%6d", x ) );