Skip to content

Commit

Permalink
Allow lazy-loading chunk section data when using Vector API
Browse files Browse the repository at this point in the history
  • Loading branch information
SirYwell committed Dec 20, 2024
1 parent 74bb6e3 commit 30593c3
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.fastasyncworldedit.core.extent.filter;

import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;

public class CountFilter extends ForkedFilter<CountFilter> implements VectorizedFilter {
Expand Down Expand Up @@ -37,9 +37,8 @@ public int getTotal() {
}

@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
total += mask.trueCount();
return set;
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.fastasyncworldedit.core.extent.filter;

import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IChunk;
import com.sk89q.worldedit.regions.Region;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -78,9 +78,9 @@ public VectorizedLinkedFilter(final L left, final R right) {
}

@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
ShortVector res = getLeft().applyVector(get, set, mask);
return getRight().applyVector(get, res, mask);
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
getLeft().applyVector(get, set, mask);
getRight().applyVector(get, set, mask);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorFacade;
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.internal.simd.VectorizedMask;
Expand All @@ -11,6 +12,7 @@
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -82,13 +84,15 @@ public VectorizedMaskFilter(final T other, final Mask root, AtomicInteger change
}

@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
final T parent = getParent();
VectorMask<Short> masked = vectorizedMask.compareVector(set, get);
ShortVector res = parent.applyVector(get, set, mask.and(masked));
VectorMask<Short> changed = res.compare(VectorOperators.NE, set);
changes.getAndAdd(changed.trueCount());
return res;
final VectorSpecies<Short> species = mask.vectorSpecies();
VectorMask<Short> masked = this.vectorizedMask.compareVector(set, get, species);
ShortVector before = set.getOrZero(masked.vectorSpecies());
parent.applyVector(get, set, mask.and(masked));
ShortVector after = set.getOrZero(masked.vectorSpecies());
VectorMask<Short> changed = after.compare(VectorOperators.NE, before);
this.changes.getAndAdd(changed.trueCount());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ public class CharFilterBlock extends ChunkFilterBlock {

private int maxLayer;
private int minLayer;
private CharGetBlocks get;
private IChunkSet set;
protected CharGetBlocks get;
protected IChunkSet set;
protected char[] getArr;
@Nullable
protected char[] setArr;
protected SetDelegate delegate;
// local
private int layer;
protected int layer;
private int index;
private int x;
private int y;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,23 @@ public static boolean useVectorApi() {
if (base == null) {
yield null;
}
yield (set, get) -> base.compareVector(set, get).not();
yield (set, get, species) -> base.compareVector(set, get, species).not();
}
default -> null;
};
}

private static VectorizedMask vectorizedTargetMaskNonAir() {
// everything > VOID_AIR is not air
return (set, get) -> get.compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
return (set, get, species) -> get.get(species).compare(VectorOperators.UNSIGNED_GT, BlockTypesCache.ReservedIDs.VOID_AIR);
}

private static VectorizedMask vectorizedTargetMask(char ordinal) {
return (set, get) -> get.compare(VectorOperators.EQ, (short) ordinal);
return (set, get, species) -> get.get(species).compare(VectorOperators.EQ, (short) ordinal);
}

private static VectorizedMask vectorizedTargetMaskInverse(char ordinal) {
return (set, get) -> get.compare(VectorOperators.NE, (short) ordinal);
return (set, get, species) -> get.get(species).compare(VectorOperators.NE, (short) ordinal);
}

public static @Nullable VectorizedFilter vectorizedPattern(Pattern pattern) {
Expand Down Expand Up @@ -102,14 +102,16 @@ public VectorizedPattern(final T parent, char ordinal) {
}

@Override
public ShortVector applyVector(final ShortVector get, final ShortVector set, VectorMask<Short> mask) {
// only change the lanes the mask dictates us to change, keep the rest
return set.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
public Filter newInstance(final Filter other) {
return new VectorizedPattern<>(other, ordinal);
}

@Override
public Filter newInstance(final Filter other) {
return new VectorizedPattern<>(other, ordinal);
public void applyVector(final VectorFacade get, final VectorFacade set, final VectorMask<Short> mask) {
ShortVector s = set.getOrZero(mask.vectorSpecies());
// only change the lanes the mask dictates us to change, keep the rest
s = s.blend(ShortVector.broadcast(ShortVector.SPECIES_PREFERRED, ordinal), mask);
set.setOrIgnore(s);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.fastasyncworldedit.core.internal.simd;

import com.fastasyncworldedit.core.queue.IBlocks;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorSpecies;

public class VectorFacade {
private final IBlocks blocks;
private int layer;
private int index;
private char[] data;

public VectorFacade(final IBlocks blocks) {
this.blocks = blocks;
}

public ShortVector get(VectorSpecies<Short> species) {
if (this.data == null) {
load();
}
return ShortVector.fromCharArray(species, this.data, this.index);
}

public ShortVector getOrZero(VectorSpecies<Short> species) {
if (this.data == null) {
return species.zero().reinterpretAsShorts();
}
return ShortVector.fromCharArray(species, this.data, this.index);
}

public void setOrIgnore(ShortVector vector) {
if (this.data == null) {
if (vector.eq((short) BlockTypesCache.ReservedIDs.__RESERVED__).allTrue()) {
return;
}
load();
}
vector.intoCharArray(this.data, this.index);
}

private void load() {
this.data = this.blocks.load(this.layer);
}

public void setLayer(int layer) {
this.layer = layer;
this.data = null;
}

public void setIndex(int index) {
this.index = index;
}

public void setData(char[] data) {
this.data = data;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,17 @@ public synchronized void filter(final Filter filter) {
throw new IllegalStateException("Unexpected VectorizedCharFilterBlock " + filter);
}
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
// TODO can we avoid eager initSet?
initSet(); // set array is null before
char[] setArr = this.setArr;
assert setArr != null;
char[] getArr = this.getArr;
VectorFacade setFassade = new VectorFacade(this.set);
setFassade.setLayer(this.layer);
VectorFacade getFassade = new VectorFacade(this.get);
getFassade.setLayer(this.layer);
getFassade.setData(this.getArr);
// assume setArr.length == getArr.length == 4096
VectorMask<Short> affectAll = species.maskAll(true);
for (int i = 0; i < 4096; i += species.length()) {
ShortVector set = ShortVector.fromCharArray(species, setArr, i);
ShortVector get = ShortVector.fromCharArray(species, getArr, i);
ShortVector res = vecFilter.applyVector(get, set, affectAll);
res.intoCharArray(setArr, i);
setFassade.setIndex(i);
getFassade.setIndex(i);
vecFilter.applyVector(getFassade, setFassade, affectAll);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.fastasyncworldedit.core.internal.simd;

import com.fastasyncworldedit.core.queue.Filter;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorMask;

public interface VectorizedFilter extends Filter {
Expand All @@ -12,8 +11,7 @@ public interface VectorizedFilter extends Filter {
* @param get the get vector
* @param set the set vector
* @param mask the mask with the lanes set to true which should be affected by the filter
* @return the resulting set vector.
*/
ShortVector applyVector(ShortVector get, ShortVector set, VectorMask<Short> mask);
void applyVector(VectorFacade get, VectorFacade set, VectorMask<Short> mask);

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,50 @@
public interface VectorizedMask {

default void processChunks(IChunk chunk, IChunkGet get, IChunkSet set) {
VectorFacade setFassade = new VectorFacade(set);
VectorFacade getFassade = new VectorFacade(get);
for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) {
setFassade.setLayer(layer);
getFassade.setLayer(layer);
final char[] sectionSet = set.loadIfPresent(layer);
if (sectionSet == null) {
continue;
}
final char[] sectionGet = get.load(layer);
processSection(layer, sectionSet, sectionGet);
setFassade.setData(sectionSet);
processSection(layer, setFassade, getFassade);
}
}

default void processSection(int layer, char[] set, char[] get) {
default void processSection(int layer, VectorFacade set, VectorFacade get) {
final VectorSpecies<Short> species = ShortVector.SPECIES_PREFERRED;
// assume that set.length % species.elementSize() == 0
for (int i = 0; i < set.length; i += species.length()) {
ShortVector vectorSet = ShortVector.fromCharArray(species, set, i);
ShortVector vectorGet = ShortVector.fromCharArray(species, get, i);
vectorSet = processVector(vectorSet, vectorGet);
vectorSet.intoCharArray(set, i);
// assume that chunk sections have length 16 * 16 * 16 == 4096
for (int i = 0; i < 4096; i += species.length()) {
set.setIndex(i);
get.setIndex(i);
processVector(set, get, species);
}
}

/**
* {@return the set vector with all lanes that do not match this mask set to 0}
* Clears all blocks that aren't covered by the mask.
*
* @param set the set vector
* @param get the get vector
* @param set the set vector
* @param get the get vector
* @param species the species to use
*/
default ShortVector processVector(ShortVector set, ShortVector get) {
return set.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get).not());
default void processVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species) {
ShortVector s = set.getOrZero(species);
s = s.blend(BlockTypesCache.ReservedIDs.__RESERVED__, compareVector(set, get, species).not());
set.setOrIgnore(s);
}

/**
* {@return a mask with all lanes set that match this mask}
*
* @param set the set vector
* @param get the get vector
* @param set the set vector
* @param get the get vector
* @param species the species to use
*/
VectorMask<Short> compareVector(ShortVector set, ShortVector get);
VectorMask<Short> compareVector(VectorFacade set, VectorFacade get, VectorSpecies<Short> species);

}

0 comments on commit 30593c3

Please sign in to comment.