attempt at pattern rebuild optimization

This commit is contained in:
PrototypeTrousers
2022-02-22 00:02:17 -03:00
parent ee9441474e
commit 30f4cdf545
5 changed files with 82 additions and 75 deletions
@@ -427,6 +427,8 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
return; return;
} }
boolean removed = false;
if( this.craftingList != null ) if( this.craftingList != null )
{ {
final Iterator<ICraftingPatternDetails> i = this.craftingList.iterator(); final Iterator<ICraftingPatternDetails> i = this.craftingList.iterator();
@@ -446,26 +448,36 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
if( !found ) if( !found )
{ {
removed = true;
i.remove(); i.remove();
} }
} }
} }
boolean newPattern = false;
for( int x = 0; x < accountedFor.length; x++ ) for( int x = 0; x < accountedFor.length; x++ )
{ {
if( !accountedFor[x] ) if( !accountedFor[x] )
{ {
newPattern = true;
this.addToCraftingList( this.patterns.getStackInSlot( x ) ); this.addToCraftingList( this.patterns.getStackInSlot( x ) );
} }
} }
try try
{ {
this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) ); if( removed )
{
this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) );
}
else if( newPattern )
{
this.provideCrafting( (ICraftingProviderHelper) this.gridProxy.getCrafting() );
}
} }
catch( final GridAccessException e ) catch( GridAccessException e )
{ {
// :P e.printStackTrace();
} }
} }
@@ -549,7 +561,6 @@ public class DualityInterface implements IGridTickable, IStorageMonitorable, IIn
{ {
try try
{ {
this.gridProxy.getGrid().postEvent( new MENetworkCraftingPatternChange( this, this.gridProxy.getNode() ) );
this.gridProxy.getTick().wakeDevice( this.gridProxy.getNode() ); this.gridProxy.getTick().wakeDevice( this.gridProxy.getNode() );
} }
catch( final GridAccessException e ) catch( final GridAccessException e )
+10 -7
View File
@@ -30,6 +30,7 @@ import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.LinkedListMultimap;
@@ -190,10 +191,11 @@ public class TickHandler
synchronized ( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world ); final Collection<CraftingJob> jobSet = this.craftingJobs.get( wte.world );
if (!jobSet.isEmpty()) { if( !jobSet.isEmpty() )
{
final int jobSize = jobSet.size(); final int jobSize = jobSet.size();
final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000; final int microSecondsPerTick = AEConfig.instance().getCraftingCalculationTimePerTick() * 1000;
final int simTime = Math.max(1, microSecondsPerTick / jobSize); final int simTime = Math.max( 1, microSecondsPerTick / jobSize );
jobSet.removeIf( cj -> !cj.simulateFor( simTime ) ); jobSet.removeIf( cj -> !cj.simulateFor( simTime ) );
} }
@@ -206,7 +208,7 @@ public class TickHandler
this.tickColors( this.srvPlayerColors ); this.tickColors( this.srvPlayerColors );
// ready tiles. // ready tiles.
final HandlerRep repo = this.getRepo(); final HandlerRep repo = this.getRepo();
while( !repo.tiles.isEmpty() ) while ( !repo.tiles.isEmpty() )
{ {
final AEBaseTile bt = repo.tiles.poll(); final AEBaseTile bt = repo.tiles.poll();
if( !bt.isInvalid() ) if( !bt.isInvalid() )
@@ -217,7 +219,8 @@ public class TickHandler
// tick networks. // tick networks.
this.getRepo().updateNetworks(); this.getRepo().updateNetworks();
for( final Grid g : this.getRepo().networks ) List<Grid> grids = new ArrayList<>( this.getRepo().networks );
for( final Grid g : grids )
{ {
g.update(); g.update();
} }
@@ -238,7 +241,7 @@ public class TickHandler
private void tickColors( final HashMap<Integer, PlayerColor> playerSet ) private void tickColors( final HashMap<Integer, PlayerColor> playerSet )
{ {
final Iterator<PlayerColor> i = playerSet.values().iterator(); final Iterator<PlayerColor> i = playerSet.values().iterator();
while( i.hasNext() ) while ( i.hasNext() )
{ {
final PlayerColor pc = i.next(); final PlayerColor pc = i.next();
if( pc.ticksLeft <= 0 ) if( pc.ticksLeft <= 0 )
@@ -259,7 +262,7 @@ public class TickHandler
final Stopwatch sw = Stopwatch.createStarted(); final Stopwatch sw = Stopwatch.createStarted();
IWorldCallable<?> c = null; IWorldCallable<?> c = null;
while( ( c = queue.poll() ) != null ) while ( ( c = queue.poll() ) != null )
{ {
try try
{ {
@@ -283,7 +286,7 @@ public class TickHandler
public void registerCraftingSimulation( final World world, final CraftingJob craftingJob ) public void registerCraftingSimulation( final World world, final CraftingJob craftingJob )
{ {
synchronized( this.craftingJobs ) synchronized ( this.craftingJobs )
{ {
this.craftingJobs.put( world, craftingJob ); this.craftingJobs.put( world, craftingJob );
} }
+1 -7
View File
@@ -19,12 +19,8 @@
package appeng.me; package appeng.me;
import java.util.Collection; import java.util.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import appeng.api.AEApi; import appeng.api.AEApi;
import appeng.api.networking.IGrid; import appeng.api.networking.IGrid;
@@ -220,9 +216,7 @@ public class Grid implements IGrid
@Override @Override
public MENetworkEvent postEvent( final MENetworkEvent ev ) public MENetworkEvent postEvent( final MENetworkEvent ev )
{ {
CraftingGridCache.pauseRebuilds();
final MENetworkEvent ret = this.eventBus.postEvent( this, ev ); final MENetworkEvent ret = this.eventBus.postEvent( this, ev );
CraftingGridCache.unpauseRebuilds();
return ret; return ret;
} }
+6 -9
View File
@@ -65,7 +65,7 @@ import net.minecraftforge.common.util.Constants;
public class GridNode implements IGridNode, IPathItem public class GridNode implements IGridNode, IPathItem
{ {
private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged(); private static final MENetworkChannelsChanged EVENT = new MENetworkChannelsChanged();
private static final int[] CHANNEL_COUNT = { 0, 8, 32 }; private static final int[] CHANNEL_COUNT = {0, 8, 32};
private final List<IGridConnection> connections = new ArrayList<>(); private final List<IGridConnection> connections = new ArrayList<>();
private final IGridBlock gridProxy; private final IGridBlock gridProxy;
@@ -166,8 +166,6 @@ public class GridNode implements IGridNode, IPathItem
{ {
final Object tracker = new Object(); final Object tracker = new Object();
CraftingGridCache.pauseRebuilds();
Deque<GridNode> nextRun = new ArrayDeque<>(); Deque<GridNode> nextRun = new ArrayDeque<>();
nextRun.add( this ); nextRun.add( this );
@@ -178,9 +176,9 @@ public class GridNode implements IGridNode, IPathItem
final Deque<IGridConnection> nextConn = new ArrayDeque<>(); final Deque<IGridConnection> nextConn = new ArrayDeque<>();
final IGridConnectionVisitor gcv = (IGridConnectionVisitor) g; final IGridConnectionVisitor gcv = (IGridConnectionVisitor) g;
while( !nextRun.isEmpty() ) while ( !nextRun.isEmpty() )
{ {
while( !nextConn.isEmpty() ) while ( !nextConn.isEmpty() )
{ {
gcv.visitConnection( nextConn.poll() ); gcv.visitConnection( nextConn.poll() );
} }
@@ -196,7 +194,7 @@ public class GridNode implements IGridNode, IPathItem
} }
else else
{ {
while( !nextRun.isEmpty() ) while ( !nextRun.isEmpty() )
{ {
final Iterable<GridNode> thisRun = nextRun; final Iterable<GridNode> thisRun = nextRun;
nextRun = new ArrayDeque<>(); nextRun = new ArrayDeque<>();
@@ -207,7 +205,6 @@ public class GridNode implements IGridNode, IPathItem
} }
} }
} }
CraftingGridCache.unpauseRebuilds();
} }
@Override @Override
@@ -269,7 +266,7 @@ public class GridNode implements IGridNode, IPathItem
@Override @Override
public void destroy() public void destroy()
{ {
while( !this.connections.isEmpty() ) while ( !this.connections.isEmpty() )
{ {
// not part of this network for real anymore. // not part of this network for real anymore.
if( this.connections.size() == 1 ) if( this.connections.size() == 1 )
@@ -378,7 +375,7 @@ public class GridNode implements IGridNode, IPathItem
@Override @Override
public boolean meetsChannelRequirements() public boolean meetsChannelRequirements()
{ {
return( !this.gridProxy.getFlags().contains( GridFlags.REQUIRE_CHANNEL ) || this.getUsedChannels() > 0 ); return ( !this.gridProxy.getFlags().contains( GridFlags.REQUIRE_CHANNEL ) || this.getUsedChannels() > 0 );
} }
@Override @Override
+49 -47
View File
@@ -113,9 +113,9 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private final GenericInterestManager<CraftingWatcher> interestManager = new GenericInterestManager<>( this.interests ); private final GenericInterestManager<CraftingWatcher> interestManager = new GenericInterestManager<>( this.interests );
private IStorageGrid storageGrid; private IStorageGrid storageGrid;
private IEnergyGrid energyGrid; private IEnergyGrid energyGrid;
int i;
private boolean updateList = false; private boolean updateList = false;
private static int pauseRebuilds = 0; private boolean updatePatterns = true;
private static Set<CraftingGridCache> rebuildNeeded = new HashSet<>();
public CraftingGridCache( final IGrid grid ) public CraftingGridCache( final IGrid grid )
{ {
@@ -140,8 +140,14 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
this.updateCPUClusters(); this.updateCPUClusters();
} }
if( updatePatterns )
{
this.recalculateCraftingPatterns();
this.updatePatterns = false;
}
final Iterator<CraftingLinkNexus> craftingLinkIterator = this.craftingLinks.values().iterator(); final Iterator<CraftingLinkNexus> craftingLinkIterator = this.craftingLinks.values().iterator();
while( craftingLinkIterator.hasNext() ) while ( craftingLinkIterator.hasNext() )
{ {
if( craftingLinkIterator.next().isDead( this.grid, this ) ) if( craftingLinkIterator.next().isDead( this.grid, this ) )
{ {
@@ -187,7 +193,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
if( machine instanceof ICraftingProvider ) if( machine instanceof ICraftingProvider )
{ {
this.craftingProviders.remove( machine ); this.craftingProviders.remove( machine );
this.updatePatterns(); this.updatePatterns = true;
} }
} }
@@ -221,7 +227,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
if( machine instanceof ICraftingProvider ) if( machine instanceof ICraftingProvider )
{ {
this.craftingProviders.add( (ICraftingProvider) machine ); this.craftingProviders.add( (ICraftingProvider) machine );
this.updatePatterns(); this.updatePatterns = true;
} }
} }
@@ -242,36 +248,15 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
// nothing! // nothing!
} }
public static void pauseRebuilds()
{
pauseRebuilds++;
}
public static void unpauseRebuilds()
{
pauseRebuilds--;
if (pauseRebuilds == 0 && rebuildNeeded.size() > 0)
{
ImmutableSet<CraftingGridCache> needed = ImmutableSet.copyOf(rebuildNeeded);
rebuildNeeded.clear();
for ( CraftingGridCache cache: needed )
{
cache.updatePatterns();
}
}
}
private void updatePatterns() private void updatePatterns()
{ {
// coalesce change events during a grid traversal to a single rebuild this.updatePatterns = true;
if (pauseRebuilds != 0) }
{
rebuildNeeded.add(this);
return;
}
final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = new Object2ObjectOpenHashMap<>(this.craftableItems); private void recalculateCraftingPatterns()
final Set<IAEItemStack> oldEmitableItems = new HashSet<>(this.emitableItems); {
final Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> oldItems = new Object2ObjectOpenHashMap<>( this.craftableItems );
final Set<IAEItemStack> oldEmitableItems = new HashSet<>( this.emitableItems );
// erase list. // erase list.
this.craftingMethods.clear(); this.craftingMethods.clear();
@@ -312,25 +297,29 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
this.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) ); this.craftableItems.put( e.getKey(), ImmutableList.copyOf( e.getValue() ) );
} }
Object2ObjectMap<IAEItemStack, ImmutableList<ICraftingPatternDetails>> craftablesChanged = new Object2ObjectArrayMap<>(); List<IAEItemStack> craftablesChanged = new ArrayList<>();
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> i = oldItems.entrySet(); ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> i = oldItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : i) { for( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : i )
if (!this.craftableItems.containsKey( ais.getKey() )) { {
if( !this.craftableItems.containsKey( ais.getKey() ) )
{
IAEItemStack changedStack = ais.getKey().copy(); IAEItemStack changedStack = ais.getKey().copy();
changedStack.reset(); changedStack.reset();
changedStack.setCraftable( false ); changedStack.setCraftable( false );
craftablesChanged.put( changedStack, ais.getValue() ); craftablesChanged.add( changedStack );
} }
} }
ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> j = this.craftableItems.entrySet(); ObjectSet<Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>>> j = this.craftableItems.entrySet();
for ( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : j) { for( Entry<IAEItemStack, ImmutableList<ICraftingPatternDetails>> ais : j )
if (!oldItems.containsKey( ais )){ {
if( !oldItems.containsKey( ais ) )
{
IAEItemStack changedStack = ais.getKey().copy(); IAEItemStack changedStack = ais.getKey().copy();
changedStack.reset(); changedStack.reset();
changedStack.setCraftable( true ); changedStack.setCraftable( true );
craftablesChanged.put( changedStack, ais.getValue() ); craftablesChanged.add( changedStack );
} }
} }
@@ -341,7 +330,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
IAEItemStack changedStack = st.copy(); IAEItemStack changedStack = st.copy();
changedStack.reset(); changedStack.reset();
changedStack.setCraftable( false ); changedStack.setCraftable( false );
craftablesChanged.put( changedStack, null ); craftablesChanged.add( changedStack );
} }
} }
@@ -352,12 +341,11 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
IAEItemStack changedStack = st.copy(); IAEItemStack changedStack = st.copy();
changedStack.reset(); changedStack.reset();
changedStack.setCraftable( true ); changedStack.setCraftable( true );
craftablesChanged.put( changedStack, null ); craftablesChanged.add( changedStack );
} }
} }
this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), craftablesChanged.keySet(), this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), craftablesChanged, new BaseActionSource() );
new BaseActionSource() );
} }
private void updateCPUClusters() private void updateCPUClusters()
@@ -423,6 +411,21 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
{ {
details.add( medium ); details.add( medium );
} }
if( !updatePatterns )
{
List<IAEItemStack> newCraftables = new ArrayList<>();
for( IAEItemStack stack : api.getOutputs() )
{
ImmutableList<ICraftingPatternDetails> a = this.craftableItems.get( stack );
if( a == null || a.get( 0 ).getPriority() < api.getPriority() )
{
this.craftableItems.put( stack, ImmutableList.of( api ) );
newCraftables.add( stack.copy().reset().setCraftable( true ) );
}
}
this.storageGrid.postCraftablesChanges( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), newCraftables, new BaseActionSource() );
}
} }
@Override @Override
@@ -596,8 +599,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
} }
} }
Collections.sort( validCpusClusters, ( firstCluster, nextCluster ) -> Collections.sort( validCpusClusters, ( firstCluster, nextCluster ) -> {
{
if( prioritizePower ) if( prioritizePower )
{ {
final int comparison1 = Long.compare( nextCluster.getCoProcessors(), firstCluster.getCoProcessors() ); final int comparison1 = Long.compare( nextCluster.getCoProcessors(), firstCluster.getCoProcessors() );
@@ -676,7 +678,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
public boolean hasCpu( final ICraftingCPU cpu ) public boolean hasCpu( final ICraftingCPU cpu )
{ {
if (cpu instanceof CraftingCPUCluster) if( cpu instanceof CraftingCPUCluster )
{ {
return this.craftingCPUClusters.contains( (CraftingCPUCluster) cpu ); return this.craftingCPUClusters.contains( (CraftingCPUCluster) cpu );
} }
@@ -710,7 +712,7 @@ public class CraftingGridCache implements ICraftingGrid, ICraftingProviderHelper
private void findNext() private void findNext()
{ {
while( this.iterator.hasNext() && this.cpuCluster == null ) while ( this.iterator.hasNext() && this.cpuCluster == null )
{ {
this.cpuCluster = this.iterator.next(); this.cpuCluster = this.iterator.next();
if( !this.cpuCluster.isActive() || this.cpuCluster.isDestroyed() ) if( !this.cpuCluster.isActive() || this.cpuCluster.isDestroyed() )