Commit b803ac87 authored by Julian Oppermann's avatar Julian Oppermann

Initial import.

parents
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Gradle and IntelliJ
/gradle.properties
/.gradle
/out
/build
/.idea
/gg
This diff is collapsed.
# GeMS - A Generator for Modulo Scheduling Problems
GeMS is a customisable, open-source toolkit for generating random, yet constrained, modulo scheduling problems with a known optimal initiation interval. These can then be used to evaluate the behavior of different scheduling algorithms under controlled conditions [1].
GeMS was designed and implemented by Sebastian Vollbrecht as part of his B.Sc. thesis project, supervised by Julian Oppermann and Andreas Koch, at TU Darmstadt's Embedded Systems and Applications group.
## License
GeMS is licensed under the Apache License, Version 2.0. Please cite [1] if GeMS was useful to you in an academic context.
## Requirements and building
You'll need:
* a Java 1.8 compatible VM
* IBM ILOG CPLEX 12.6 or newer
* JGraphT 1.2.0 (will be pulled automatically)
This project uses Gradle 4.9. In order to make your CPLEX installation known, copy `gradle.properties.sample` to `gradle.properties` and adjust the path and architecture tag (e.g. `x86-64_osx` or `x86-64_linux`) there.
Run:
* `./gradlew classes` to compile the sources
* `./gradlew javadoc` to generate the Javadoc (-> `build/docs/javadoc/index.html`)
* `./gradlew clean` to clean the build directory
* `./gradlew test` to run the provided unit tests. Depending on your system, this may take up to 1 hour.
Use `./gradlew eclipse` to generate the files required to import the project into Eclipse. Gradle projects are supported natively by IntelliJ IDEA.
## Usage
GeMS is intended to be a toolkit to plug together generators for modulo scheduling problems, and therefore does not provide a command-line interface. See the class `graphgen.main.Main` for annotated examples. Execute `$ ./gradlew run` to start the `Main` class (with the required classpath (JGraphT, CPLEX) java.library.path (CPLEX native library)).
The internal representation of the generated graphs is simple (~ collections of nodes and edges, see `graphgen.graph.Graph`), and thus can be easily mapped to API calls, or exported to a file format. GeMS provides (see `graphgen.util.GraphFileUtils`) an export to Graphviz DOT, and to the XML-based format used by the HatScheT scheduler library [2].
## Limitations and future work
See the [issues](https://git.esa.informatik.tu-darmstadt.de/groups/gems/-/issues). Bug reports and contributions are welcome; please contact [Julian](mailto:oppermann@esa.tu-darmstadt.de).
## Internals
GeMS has the unique capability to construct dependence graphs that are guaranteed to be feasible, or infeasible, at the lower bound for the II search space (i.e. the usual MinII = max(RecMII, ResMII)). This is a two-part approach: First, a cycle in the dependence graph is constructed that defines the instance's desired MinII. Then, during the edge generation phase, GeMS has to ensure that no MinII-changing edge is added. We employ several quick checks to handle common situations, but have to invoke an actual modulo scheduler to check the (in-)feasibility of smaller subgraphs in some cases. GeMS internally uses two ILP-based modulo schedulers for this purpose: The formulation by Eichenberger and Davidson [3], and the Moovac formation [4].
## References
```
[1] Julian Oppermann, Sebastian Vollbrecht, Melanie Reuter-Oppermann, Oliver Sinnen, Andreas Koch
Work in Progress: GeMS: A Generator for Modulo Scheduling Problems.
International Conference on Compilers, Architectures and Synthesis For Embedded Systems (CASES), 2018.
pre-print: https://www.esa.informatik.tu-darmstadt.de/twiki/pub/Staff/AndreasKochPublications/2018_CASES_JO.pdf
[2] Patrick Sittel, Julian Oppermann, Martin Kumm, Andreas Koch, Peter Zipf
HatScheT: A Contribution to Agile HLS.
FPGAs for Software Programmers (FSP), 2018.
pre-print: https://www.uni-kassel.de/eecs/fileadmin/datas/fb16/Fachgebiete/Digitaltechnik/HatScheT.pdf
project: http://uni-kassel.de/go/hatschet
[3] Alexandre E. Eichenberger, Edward S. Davidson
Efficient Formulation for Optimal Modulo Schedulers
SIGPLAN Conference on Programming Language Design and Implementation (PLDI), 1997
https://doi.org/10.1145/258916.258933
[4] Julian Oppermann, Andreas Koch, Melanie Reuter-Oppermann, Oliver Sinnen
ILP-based Modulo Scheduling for High-level Synthesis.
International Conference on Compilers, Architectures and Synthesis For Embedded Systems (CASES), 2016.
https://doi.org/10.1145/2968455.2968512
```
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building an application
id 'application'
// Enable Eclipse support
id 'eclipse'
}
// Define the main class for the application
mainClassName = 'graphgen.main.Main'
dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'org.jgrapht:jgrapht-core:1.2.0'
// specify cplex.home in gradle.properties
compile files(project.ext["cplex.home"] + '/cplex/lib/cplex.jar')
// Use JUnit test framework
testCompile 'junit:junit:4.12'
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
// use cplex native libs when running/testing
tasks.withType(JavaExec) {
systemProperty "java.library.path", project.ext["cplex.home"] + '/cplex/bin/' + project.ext["cplex.arch"]
}
tasks.withType(Test) {
systemProperty "java.library.path", project.ext["cplex.home"] + '/cplex/bin/' + project.ext["cplex.arch"]
}
cplex.home=/Library/CPLEX_Studio128
cplex.arch=x86-64_osx
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
rootProject.name = 'gems'
/*
* Copyright 2018 Sebastian Vollbrecht, Julian Oppermann
* Embedded Systems and Applications Group, TU Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package graphgen.datastructures;
import java.util.Objects;
/**
* A basic class for arranging objects in pairs. Every pairing is immutable once
* created. To create a pair, use the static
* {@link Pair#makePair(Object, Object)} constructor.
*
* @param <T1> the type of the first element
* @param <T2> the type of the second element
* @author Sebastian Vollbrecht
*/
public class Pair<T1, T2> {
/**
* The pair's first element.
*/
public final T1 first;
/**
* The pair's second element.
*/
public final T2 second;
private Pair(T1 first, T2 second) {
this.first = Objects.requireNonNull(first);
this.second = Objects.requireNonNull(second);
}
/**
* Creates a new pair from the given objects.
*
* @param <X> the first element's type
* @param <Y> the second element's type
* @param first the first element
* @param second the second element
* @return a (first, second) pair
* @throws NullPointerException if an element is null
*/
public static <X, Y> Pair<X, Y> makePair(X first, Y second) {
return new Pair<>(first, second);
}
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((second == null) ? 0 : second.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Pair))
return false;
Pair<?, ?> other = (Pair<?, ?>) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (second == null) {
return other.second == null;
} else return second.equals(other.second);
}
}
/*
* Copyright 2018 Sebastian Vollbrecht, Julian Oppermann
* Embedded Systems and Applications Group, TU Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package graphgen.datastructures;
import java.util.Optional;
import java.util.Random;
/**
* A wrapper class for {@link Random} instances. This class disallows random
* number generation without having seeded the wrapped random instance
* beforehand, so that the graph generator does not generate 'true' random
* numbers by accident.
*
* @author Sebastian Vollbrecht
*/
public class SeededRandom {
private Optional<Long> seed;
private final Random rng;
/**
* Creates a new, unseeded SeededRandom instance. Before random numbers can be
* generated, a call to the {@link #setSeed(long)} method will be necessary.
*/
public SeededRandom() {
this.rng = new Random();
this.seed = Optional.empty();
}
/**
* Creates a new, seeded SeededRandom instance. Using this constructor, a call
* to the {@link #setSeed(long)} method is unnecessary.
*
* @param seed the seed to pass to the random instance
*/
public SeededRandom(long seed) {
this();
setSeed(seed);
}
/**
* Sets the seed of the wrapped random instance.
*
* @param seed the seed to pass to the wrapped random instance
*/
public void setSeed(long seed) {
this.seed = Optional.of(seed);
rng.setSeed(seed);
}
/**
* Returns a random integer value between 0 (inclusive) and the given bound
* (exclusive).
*
* @param bound the given bound
* @return the random integer value
* @throws UnsupportedOperationException if this instance has not yet been
* seeded
*/
public int nextInt(int bound) {
checkSeededStatus();
return rng.nextInt(bound);
}
/**
* Returns a random double value between 0.0 (inclusive) and 1.0 (exclusive).
*
* @return the random double value
* @throws UnsupportedOperationException if this instance has not yet been
* seeded
*/
public double nextDouble() {
checkSeededStatus();
return rng.nextDouble();
}
/**
* Returns the wrapped random instance.
*
* @return the wrapped instance
* @throws UnsupportedOperationException if this instance has not yet been
* seeded
*/
public Random getRandom() {
checkSeededStatus();
return rng;
}
private void checkSeededStatus() {
if (!seed.isPresent()) {
throw new UnsupportedOperationException("Must set the seed first.");
}
}
}
/*
* Copyright 2018 Sebastian Vollbrecht, Julian Oppermann
* Embedded Systems and Applications Group, TU Darmstadt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package graphgen.enums;
import modsched.Edge;
import modsched.Node;
/**
* An enumeration which stores possible edge types. The {@link #ALL} type is
* meant to be a representative of both forward edges and backedges, similar to
* a wildcard.
*
* @author Sebastian Vollbrecht
*/
public enum EdgeType {
/**
* Represents forward edges.
*/
FORWARD,
/**
* Represents backedges.
*/
BACKWARD,
/**
* Represents both forward edges and backedges.
*/
ALL;
/**
* Returns whether the given edge matches this edge type constant.
*
* @param <N> the edge's node type
* @param edge the given edge