Skip to content

Commit

Permalink
Refactor reducer (#7)
Browse files Browse the repository at this point in the history
* Refactored reducer so that it is less fragment shader-centric.

* Added an additional test for empty block removal.

* Small refactoring to live output variable reduction opportunities.
  • Loading branch information
afd committed Sep 26, 2018
1 parent e6dc338 commit c675e99
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 242 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,35 +16,16 @@


package com.graphicsfuzz.common.util; package com.graphicsfuzz.common.util;


import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;


public class FileHelper { public class FileHelper {


public static File fileWithAppendedString(File file, String extra) {
String ext = FilenameUtils.getExtension(file.toString());
String basename = FilenameUtils.removeExtension(file.toString());
return new File(basename + extra + "." + ext);
}

public static String firstLine(File file) throws IOException {
try (BufferedReader r = new BufferedReader(new FileReader(file));) {
return r.readLine();
}
}

public static File replaceExtension(File file, String ext) { public static File replaceExtension(File file, String ext) {
return new File(FilenameUtils.removeExtension(file.toString()) + ext); return new File(FilenameUtils.removeExtension(file.toString()) + ext);
} }


public static File replaceDir(File file, File dir) {
return new File(dir, file.getName());
}

public static void checkExists(File file) throws FileNotFoundException { public static void checkExists(File file) throws FileNotFoundException {
if (!file.exists()) { if (!file.exists()) {
throw new FileNotFoundException("Could not find: " + file); throw new FileNotFoundException("Could not find: " + file);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;


public final class ReductionStepHelper { public final class ReductionProgressHelper {


private ReductionStepHelper() { private ReductionProgressHelper() {
// Utility class // Utility class
} }


Expand All @@ -39,17 +39,18 @@ static int compareReductionTemporaryFiles(File first, File second, String shader
} }


static boolean isAReductionStepFile(String name, String shaderPrefix, boolean restrictToSuccess) { static boolean isAReductionStepFile(String name, String shaderPrefix, boolean restrictToSuccess) {
if (!name.startsWith(shaderPrefix)) { final String shaderPrefixBasename = FilenameUtils.getBaseName(shaderPrefix);
if (!name.startsWith(shaderPrefixBasename)) {
return false; return false;
} }
if (!name.contains("reduced")) { if (!name.contains("reduced")) {
return false; return false;
} }
if (!name.endsWith("success.frag")) { if (!name.endsWith("success.json")) {
if (restrictToSuccess) { if (restrictToSuccess) {
return false; return false;
} }
if (!name.endsWith("fail.frag")) { if (!name.endsWith("fail.json")) {
return false; return false;
} }
} }
Expand All @@ -69,23 +70,28 @@ private static String[] getNameComponents(String name) {


public static Optional<Integer> getLatestReductionStep(boolean restrictToSuccess, public static Optional<Integer> getLatestReductionStep(boolean restrictToSuccess,
File reductionDir, File reductionDir,
String shaderPrefix) { String shaderJobPrefix) {
final File[] fragmentShaders = reductionDir final File[] jsonFiles = reductionDir
.listFiles((dir, name) -> isAReductionStepFile(name, shaderPrefix, restrictToSuccess)); .listFiles((dir, name) -> isAReductionStepFile(name, shaderJobPrefix,
return Arrays.stream(fragmentShaders) restrictToSuccess));
return Arrays.stream(jsonFiles)
.map(item -> item.getName()) .map(item -> item.getName())
.max((item1, item2) -> compareReductionTemporaryFiles(item1, item2, shaderPrefix)) .max((item1, item2) -> compareReductionTemporaryFiles(item1, item2, shaderJobPrefix))
.flatMap(item -> Optional.of(getReductionStepFromFile(item, shaderPrefix))); .flatMap(item -> Optional.of(getReductionStepFromFile(item, shaderJobPrefix)));
} }


public static Optional<Integer> getLatestReductionStepAny(File reductionDir, public static Optional<Integer> getLatestReductionStepAny(File reductionDir,
String shaderPrefix) { String shaderJobPrefix) {
return getLatestReductionStep(false, reductionDir, shaderPrefix); return getLatestReductionStep(false, reductionDir, shaderJobPrefix);
} }


public static Optional<Integer> getLatestReductionStepSuccess(File reductionDir, public static Optional<Integer> getLatestReductionStepSuccess(File reductionDir,
String shaderPrefix) { String shaderPrefix) {
return getLatestReductionStep(true, reductionDir, shaderPrefix); return getLatestReductionStep(true, reductionDir, shaderPrefix);
} }


public static File getReductionExceptionFile(String shaderJobPrefix, File reductionDir) {
return new File(reductionDir, shaderJobPrefix + ".exception");
}

} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@


public interface IReductionState { public interface IReductionState {


UniformsInfo computeRemainingUniforms(File uniformsJson) throws FileNotFoundException;

boolean hasFragmentShader(); boolean hasFragmentShader();


boolean hasVertexShader(); boolean hasVertexShader();
Expand All @@ -33,4 +31,6 @@ public interface IReductionState {


TranslationUnit getVertexShader(); TranslationUnit getVertexShader();


UniformsInfo getUniformsInfo();

} }
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


public interface IReductionStateFileWriter { public interface IReductionStateFileWriter {


void writeFileFromState(IReductionState state, String outputFilesPrefix) void writeFilesFromState(IReductionState state, String outputFilesPrefix)
throws FileNotFoundException; throws FileNotFoundException;


} }
48 changes: 22 additions & 26 deletions reducer/src/main/java/com/graphicsfuzz/reducer/ReductionDriver.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ public String doReduction(
LOGGER.info("Result from initial state is interesting - proceeding with reduction."); LOGGER.info("Result from initial state is interesting - proceeding with reduction.");
} }


final String variantName = FilenameUtils.getBaseName(initialFilePrefix); final String variantName = Paths.get(workDir.getAbsolutePath(),

FilenameUtils.getBaseName(initialFilePrefix)).toString();
final File initialFileJson = new File(initialFilePrefix + ".json");


boolean isInteresting = true; boolean isInteresting = true;
int stepCount = 0; int stepCount = 0;
Expand All @@ -116,12 +115,9 @@ public String doReduction(
} }
++stepCount; ++stepCount;
final int currentReductionAttempt = numReductionAttempts + fileCountOffset; final int currentReductionAttempt = numReductionAttempts + fileCountOffset;
String outputFilesPrefix = Paths.get(workDir.getAbsolutePath(), String outputFilesPrefix = getReductionStepFilenamePrefix(variantName,
getReductionStepFilenamePrefix(variantName, currentReductionAttempt)) currentReductionAttempt);
.toString(); fileWriter.writeFilesFromState(newState, outputFilesPrefix);
fileWriter.writeFileFromState(newState, outputFilesPrefix);
Helper.emitUniformsInfo(newState.computeRemainingUniforms(initialFileJson),
new PrintStream(new FileOutputStream(outputFilesPrefix + ".json")));
isInteresting = isInterestingWithCache(judge, outputFilesPrefix); isInteresting = isInterestingWithCache(judge, outputFilesPrefix);
renameReductionStepFiles(isInteresting, variantName, currentReductionAttempt, workDir); renameReductionStepFiles(isInteresting, variantName, currentReductionAttempt, workDir);


Expand All @@ -135,17 +131,13 @@ public String doReduction(


IReductionState finalState = getSimplifiedState(); IReductionState finalState = getSimplifiedState();


String finalOutputFilePrefix = Paths.get(workDir.getAbsolutePath(), String finalOutputFilePrefix = variantName + "_reduced_final";
variantName + "_reduced_final").toString(); fileWriter.writeFilesFromState(finalState, finalOutputFilePrefix);
fileWriter.writeFileFromState(finalState, finalOutputFilePrefix);
Helper.emitUniformsInfo(finalState.computeRemainingUniforms(initialFileJson),
new PrintStream(new FileOutputStream(
finalOutputFilePrefix + ".json")));


if (!judge.isInteresting(finalOutputFilePrefix)) { if (!judge.isInteresting(finalOutputFilePrefix)) {
LOGGER.info( LOGGER.info(
"Failed to simplify final reduction state! Reverting to the non-simplified state."); "Failed to simplify final reduction state! Reverting to the non-simplified state.");
fileWriter.writeFileFromState(finalState, finalOutputFilePrefix); fileWriter.writeFilesFromState(finalState, finalOutputFilePrefix);
} }


if (stoppedEarly) { if (stoppedEarly) {
Expand Down Expand Up @@ -195,11 +187,14 @@ private void renameReductionStepFiles(boolean isInteresting, String variantName,
File workDir) throws IOException { File workDir) throws IOException {
for (String fileName : workDir.list((dir, name) -> FilenameUtils.removeExtension(name) for (String fileName : workDir.list((dir, name) -> FilenameUtils.removeExtension(name)
.equals(getReductionStepFilenamePrefix(variantName, currentReductionAttempt)))) { .equals(getReductionStepFilenamePrefix(variantName, currentReductionAttempt)))) {
final File srcFile = new File(workDir, fileName);
final File dstFile = new File(workDir, getReductionStepFilenamePrefix(variantName,
currentReductionAttempt,
Optional.of(isInteresting ? "success" : "fail"))
+ "." + FilenameUtils.getExtension(fileName));
FileUtils.moveFile( FileUtils.moveFile(
new File(workDir, fileName), srcFile,
new File(workDir, getReductionStepFilenamePrefix(variantName, currentReductionAttempt, dstFile);
Optional.of(isInteresting ? "success" : "fail"))
+ "." + FilenameUtils.getExtension(fileName)));
} }
} }


Expand Down Expand Up @@ -298,13 +293,14 @@ private void giveUp() {


public final GlslReductionState finaliseReduction() { public final GlslReductionState finaliseReduction() {
// Do final cleanup pass to get rid of macros // Do final cleanup pass to get rid of macros
// TODO: need to make this work for vertex shaders too. final Optional<TranslationUnit> simplifiedVertexShader =
state.hasVertexShader() ? Optional.of(Simplify.simplify(state.getVertexShader()))
: Optional.empty();
final Optional<TranslationUnit> simplifiedFragmentShader = final Optional<TranslationUnit> simplifiedFragmentShader =
Optional.of(Simplify.simplify(state.getFragmentShader())); state.hasFragmentShader() ? Optional.of(Simplify.simplify(state.getFragmentShader()))
Optional<TranslationUnit> vertexShader = state.hasVertexShader() : Optional.empty();
? Optional.of(state.getVertexShader()) return new GlslReductionState(simplifiedVertexShader, simplifiedFragmentShader,
: Optional.empty(); state.getUniformsInfo());
return new GlslReductionState(simplifiedFragmentShader, vertexShader);
} }




Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
Expand All @@ -36,28 +37,28 @@ public class ImageShaderFileJudge implements IFileJudge {


private static final Logger LOGGER = LoggerFactory.getLogger(ImageShaderFileJudge.class); private static final Logger LOGGER = LoggerFactory.getLogger(ImageShaderFileJudge.class);


private File referenceShaderFile; private static final String REFERENCE_IMAGE_NAME = "reference_image.png";
private File referenceShaderImage;
private File workDir; private File workDir;
private IImageFileComparator fileComparator; private IImageFileComparator fileComparator;
private IShaderDispatcher imageGenerator; private IShaderDispatcher imageGenerator;
private final boolean throwExceptionOnValidationError; private final boolean throwExceptionOnValidationError;


public ImageShaderFileJudge( public ImageShaderFileJudge(
File referenceShaderFile,
File referenceShaderImage,
File workDir, File workDir,
IImageFileComparator fileComparator, IImageFileComparator fileComparator,
IShaderDispatcher imageGenerator, IShaderDispatcher imageGenerator,
boolean throwExceptionOnValidationError) { boolean throwExceptionOnValidationError) {
this.referenceShaderFile = referenceShaderFile;
this.referenceShaderImage = referenceShaderImage;
this.workDir = workDir; this.workDir = workDir;
this.fileComparator = fileComparator; this.fileComparator = fileComparator;
this.imageGenerator = imageGenerator; this.imageGenerator = imageGenerator;
this.throwExceptionOnValidationError = throwExceptionOnValidationError; this.throwExceptionOnValidationError = throwExceptionOnValidationError;
} }


public static File getReferenceImageInWorkDir(File workDir) {
return Paths.get(workDir.toString(), REFERENCE_IMAGE_NAME).toFile();
}

@Override @Override
public boolean isInteresting(String filesPrefix) throws FileJudgeException { public boolean isInteresting(String filesPrefix) throws FileJudgeException {


Expand Down Expand Up @@ -88,7 +89,7 @@ public boolean isInteresting(String filesPrefix) throws FileJudgeException {
outputText, outputText,
JobStatus.SAME_AS_REFERENCE.toString() + "\n", JobStatus.SAME_AS_REFERENCE.toString() + "\n",
StandardCharsets.UTF_8); StandardCharsets.UTF_8);
outputImage = referenceShaderImage; outputImage = getReferenceImageInWorkDir(workDir);
break; break;
default: default:
LOGGER.info("Failed to run get_image on shader. Not interesting."); LOGGER.info("Failed to run get_image on shader. Not interesting.");
Expand All @@ -100,7 +101,7 @@ public boolean isInteresting(String filesPrefix) throws FileJudgeException {
// Success or same as ref: // Success or same as ref:


// 3. // 3.
if (!fileComparator.areFilesInteresting(referenceShaderImage, outputImage)) { if (!fileComparator.areFilesInteresting(getReferenceImageInWorkDir(workDir), outputImage)) {
LOGGER.info("Shader image was not deemed interesting by file comparator. Not interesting."); LOGGER.info("Shader image was not deemed interesting by file comparator. Not interesting.");
return false; return false;
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -31,17 +31,21 @@


public class GlslReductionState implements IReductionState { public class GlslReductionState implements IReductionState {


private final Optional<TranslationUnit> fragmentShader;
private final Optional<TranslationUnit> vertexShader; private final Optional<TranslationUnit> vertexShader;
private final Optional<TranslationUnit> fragmentShader;
private final UniformsInfo uniformsInfo;


public GlslReductionState(Optional<TranslationUnit> fragmentShader, public GlslReductionState(Optional<TranslationUnit> vertexShader,
Optional<TranslationUnit> vertexShader) { Optional<TranslationUnit> fragmentShader,
this.fragmentShader = fragmentShader; UniformsInfo uniformsInfo) {
this.vertexShader = vertexShader; this.vertexShader = vertexShader;
this.fragmentShader = fragmentShader;
this.uniformsInfo = uniformsInfo;
} }


public GlslReductionState(Optional<TranslationUnit> fragmentShader) { @Override
this(fragmentShader, Optional.empty()); public boolean hasVertexShader() {
return vertexShader.isPresent();
} }


@Override @Override
Expand All @@ -50,8 +54,9 @@ public boolean hasFragmentShader() {
} }


@Override @Override
public boolean hasVertexShader() { public TranslationUnit getVertexShader() {
return vertexShader.isPresent(); assert hasVertexShader();
return vertexShader.get();
} }


@Override @Override
Expand All @@ -61,27 +66,8 @@ public TranslationUnit getFragmentShader() {
} }


@Override @Override
public TranslationUnit getVertexShader() { public UniformsInfo getUniformsInfo() {
assert hasVertexShader(); return uniformsInfo;
return vertexShader.get();
}

@Override
public UniformsInfo computeRemainingUniforms(File uniformsJson) throws FileNotFoundException {
assert fragmentShader.isPresent();
final UniformsInfo result = new UniformsInfo(
new File(uniformsJson.getAbsolutePath()));

Set<String> remainingUniforms = new HashSet<>();
remainingUniforms.addAll(getUniforms(fragmentShader));
remainingUniforms.addAll(getUniforms(vertexShader));

for (String name : result.getUniformNames().stream()
.filter(item -> !remainingUniforms.contains(item)).collect(
Collectors.toList())) {
result.removeUniform(name);
}
return result;
} }


private Set<String> getUniforms(Optional<TranslationUnit> maybeTu) { private Set<String> getUniforms(Optional<TranslationUnit> maybeTu) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.graphicsfuzz.reducer.IReductionState; import com.graphicsfuzz.reducer.IReductionState;
import com.graphicsfuzz.reducer.IReductionStateFileWriter; import com.graphicsfuzz.reducer.IReductionStateFileWriter;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream; import java.io.PrintStream;


public class GlslReductionStateFileWriter implements IReductionStateFileWriter { public class GlslReductionStateFileWriter implements IReductionStateFileWriter {
Expand All @@ -35,14 +36,16 @@ public GlslReductionStateFileWriter(ShadingLanguageVersion shadingLanguageVersio
} }


@Override @Override
public void writeFileFromState(IReductionState state, String outputFilesPrefix) public void writeFilesFromState(IReductionState state, String outputFilesPrefix)
throws FileNotFoundException { throws FileNotFoundException {
if (state.hasFragmentShader()) {
writeFile(state.getFragmentShader(), ShaderKind.FRAGMENT, outputFilesPrefix);
}
if (state.hasVertexShader()) { if (state.hasVertexShader()) {
writeFile(state.getVertexShader(), ShaderKind.VERTEX, outputFilesPrefix); writeFile(state.getVertexShader(), ShaderKind.VERTEX, outputFilesPrefix);
} }
if (state.hasFragmentShader()) {
writeFile(state.getFragmentShader(), ShaderKind.FRAGMENT, outputFilesPrefix);
}
Helper.emitUniformsInfo(state.getUniformsInfo(),
new PrintStream(new FileOutputStream(outputFilesPrefix + ".json")));
} }


private void writeFile(TranslationUnit shader, ShaderKind shaderKind, String outputFilesPrefix) private void writeFile(TranslationUnit shader, ShaderKind shaderKind, String outputFilesPrefix)
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private IReductionState stateFromWorkingShader(TranslationUnit workingShader,
default: default:
throw new RuntimeException("Unsupported shader kind: " + shaderKind); throw new RuntimeException("Unsupported shader kind: " + shaderKind);
} }
return new GlslReductionState(fragmentShader, vertexShader); return new GlslReductionState(vertexShader, fragmentShader, originalState.getUniformsInfo());
} }


} }
Loading

0 comments on commit c675e99

Please sign in to comment.