Skip to content

Commit

Permalink
Release of version 0.0.4 - first C++-based version using LLVM for cod…
Browse files Browse the repository at this point in the history
…e-generation;
  • Loading branch information
sommerlukas committed Mar 12, 2020
2 parents 6074db2 + 3e93f0c commit 8ed3970
Show file tree
Hide file tree
Showing 185 changed files with 27,669 additions and 5,139 deletions.
36 changes: 3 additions & 33 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
# Statistics files
*.spns

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
# Ignore CMake build output directory
build

# Ignore .idea directory
Expand All @@ -28,32 +25,5 @@ build
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml

# Gradle:
.idea/**/gradle.xml
.idea/**/libraries

# Mongo Explorer plugin:
.idea/**/mongoSettings.xml

## File-based project format:
*.iws

## Plugin-specific files:

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# CMake
cmake-build-*/
20 changes: 20 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(spnc VERSION 0.0.4 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(spdlog REQUIRED)

include(Doxygen.cmake)
doxygen_setup()

add_subdirectory(common)
add_subdirectory(compiler)
add_subdirectory(compiler-rt)
add_subdirectory(execute)
add_subdirectory(runtime)
add_subdirectory(python-interface)

doxygen_toplevel()
67 changes: 67 additions & 0 deletions Doxygen.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
macro(doxygen_setup)
option(SPNC_BUILD_DOC "Build Doxygen documentation" ON)

if (${SPNC_BUILD_DOC})
find_package(Doxygen REQUIRED dot)
if (${DOXYGEN_FOUND})
message(STATUS "Found Doxygen ${DOXYGEN_VERSION}")
else (${DOXYGEN_FOUND})
message(STATUS "Doxygen required to generate documentation!")
endif (${DOXYGEN_FOUND})
else (${SPNC_BUILD_DOC})
set(DOXYGEN_FOUND false)
endif (${SPNC_BUILD_DOC})
add_custom_target(doxygen-all)
endmacro(doxygen_setup)

function(doxygen_toplevel)

if (${SPNC_BUILD_DOC} AND ${DOXYGEN_FOUND})
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE ${PROJECT_SOURCE_DIR}/docs/index.md)
set(DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/doc)

doxygen_add_docs(doxygen-toplevel
${PROJECT_SOURCE_DIR}/docs
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

add_dependencies(doxygen-toplevel doxygen-all)
add_custom_target(doxygen-doc ALL)
add_dependencies(doxygen-doc doxygen-toplevel)
endif (${SPNC_BUILD_DOC} AND ${DOXYGEN_FOUND})
endfunction(doxygen_toplevel)

function(doxygen_doc)
set(oneValueArgs TARGET_NAME)
set(multiValueArgs SRC_DIRECTORIES DEPENDS EXCLUDES)
cmake_parse_arguments(DOXY "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if (${SPNC_BUILD_DOC} AND ${DOXYGEN_FOUND})
set(DOXY_BASE_DIR ${PROJECT_BINARY_DIR}/doc)
set(DOXYGEN_OUTPUT_DIRECTORY ${DOXY_BASE_DIR}/${DOXY_TARGET_NAME})
set(DOXYGEN_LAYOUT_FILE ${PROJECT_SOURCE_DIR}/docs/DoxygenLayout.xml)
set(DOXYGEN_EXCLUDE ${DOXY_EXCLUDES})
# Generate own tag-file for use by targets depending on this one.
set(DOXYGEN_GENERATE_TAGFILE ${DOXYGEN_OUTPUT_DIRECTORY}/${DOXY_TARGET_NAME}.tag)
# Fill DOXYGEN_TAGFILES with the tag-files of the dependencies.
foreach (target ${DOXY_DEPENDS})
list(APPEND tagfiles "${DOXY_BASE_DIR}/${target}/${target}.tag=${DOXY_BASE_DIR}/${target}/html")
list(APPEND dependencies "DOC_${target}")
# Add dependencies to ensure compilation happens before doxygen.
add_dependencies(DOC_${target} ${DOXY_TARGET_NAME})
endforeach (target)
message(STATUS "TAGFILES: ${tagfiles}")
set(DOXYGEN_TAGFILES ${tagfiles})
# Generate Doxygen
doxygen_add_docs("DOC_${DOXY_TARGET_NAME}"
${DOXY_SRC_DIRECTORIES}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Specify dependency on the Doxygen generation of the dependencies.
if (dependencies)
message(STATUS "DEPENDENCIES: ${dependencies}")
add_dependencies("DOC_${DOXY_TARGET_NAME}" ${dependencies})
endif (dependencies)
add_dependencies("DOC_${DOXY_TARGET_NAME}" ${DOXY_TARGET_NAME})
add_dependencies(doxygen-all "DOC_${DOXY_TARGET_NAME}")
endif (${SPNC_BUILD_DOC} AND ${DOXYGEN_FOUND})
# Add a dependency to the "doxygen-all" target to trigger execution of this target.
endfunction(doxygen_doc)
89 changes: 56 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,69 @@
# SPN Compiler #

## About `spnc` ##

`spnc` is a multi-target compiler for Sum-Product Networks,
a class of machine learning models.
`spnc` is a multi-target compiler for Sum-Product Networks, a class of machine learning models.

As of release 0.0.4, `spnc` is completely implemented in `C++` and uses the LLVM compiler framework
for code generation for the different targets.

## Installation ##

`spnc` currently supports three different kinds of code generation for SPNs:
* Serial C++ code, using `-t cpp`.
* OpenMP thread parallel C++ code, using `-t cpp` and `--openmp-parallel`
in combination.
* CUDA code for Nvidia GPUs, using `-t cuda`.
### Prerequisites ###

Support for generating SIMD execution with OpenMP is under way.
Additionally, `spnc` allows to compute
statistics about an SPNs graph and output them to JSON.
`spnc` requires a C++ compiler that supports at least the `C++14` standard as well as a
modern CMake (>= version 3.5)).

### Prerequisites ###
### Building from source ###

`spnc` requires a recent version of Java to run. For compilation and execution
of C++/OpenMP code, at least one of `g++` or `clang++` needs to be installed on
your machine. If you want to use CUDA compilation for Nvidia GPUs, you need to
have `nvcc`.
The following procedure has been tested under Ubuntu 19.10, after installing the packages
`doxygen graphviz llvm-dev clang`.

### Installation ###
`$BASE_DIR` is used as a placeholder for a directory of your choice, replace it in the
following commands:

Either download one of the release zips from the github page or
compile `spnc` from source. To compile from source, simply run
`./gradlew installDist` in the root folder of `spnc` and use the executable
found at `build/install/spnc/bin/spnc`.
First, install and build pybind11:
```
cd $BASE_DIR
git clone https://github.com/pybind/pybind11.git
cd pybind11
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$BASE_DIR/pybind11/install \
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 ..
make
make install
```

### Usage ###
Second, install and build spdlog:
```
cd $BASE_DIR
git clone https://github.com/gabime/spdlog.git
cd spdlog
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=$BASE_DIR/spdlog/install -DSPDLOG_BUILD_SHARED=ON ..
make
make install
```

`spnc` compiles SPNs from a textual representation
(see `src/main/resources/NIPS5.spn` for an example).
Now, download and build `spnc`:
```
cd $BASE_DIR
git clone [email protected]:esa-tu-darmstadt/spn-compiler.git
cd spn-compiler
mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH="$BASE_DIR/pybind11/install/share/cmake/pybind11;$BASE_DIR/spdlog/install/lib/cmake/spdlog" ..
make
make install
```

Running `spnc` with the desired input-file will generate an executable.
The executable contains an automatically generated `main`-method which will
read input-data from a plain-text file and, if a second file-name is given,
compare them to the reference data from the reference-file (also plain text).
The executable will also track the time spent to execute the SPN inference
for all examples in the input sample. This works independent from the actual
execution mode (C++ serial, OpenMP, CUDA on Nvidia GPU).
## Usage ##

Run `spnc --help` to see additional options.
The `execute`-subproject contains a simple `driver` that can be used to run the compiler
on an SPN serialized to a JSON-file.

##### Limitations #####
`spnc` *currently does not yet support Poisson or Gaussian distributions.*
In addition, the compiler also has a pybind11-based Python interface (see `python-interface`).
A demonstration of the interface can be found in the
[Python examples](https://github.com/esa-tu-darmstadt/spn-examples).
64 changes: 0 additions & 64 deletions build.gradle

This file was deleted.

8 changes: 8 additions & 0 deletions common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
add_library(spnc-common INTERFACE)

target_include_directories(spnc-common
INTERFACE
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)

doxygen_doc(TARGET_NAME spnc-common SRC_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include)
58 changes: 58 additions & 0 deletions common/include/Kernel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// This file is part of the SPNC project.
// Copyright (c) 2020 Embedded Systems and Applications Group, TU Darmstadt. All rights reserved.
//

#ifndef SPNC_KERNEL_H
#define SPNC_KERNEL_H

#include <optional>
#include <cstdlib>

///
/// Namespace for all entities related to the SPN compiler.
///
namespace spnc {

///
/// Represents a kernel that is generated by the compiler and can be loaded and executed by the runtime.
/// Contains information about the file-path of the generated kernel and the name of the generated
/// function inside that file.
///
class Kernel {

public:

///
/// Constructor.
/// \param fN The full path to the kernel file (shared object).
/// \param kN The full name of the toplevel SPN function to be called by the runtime.
Kernel(const std::string& fN, const std::string& kN) : _fileName{fN}, _kernelName{kN} {
_unique_id = std::hash<std::string>{}(fN + kN);
}

/// Get the full file-path for this Kernel.
/// \return The full file-path.
std::string fileName() const { return std::string{_fileName}; }

/// Get the name of the function to call.
/// \return Name of the SPN function.
const std::string& kernelName() const { return _kernelName; }

/// Get the unique ID of this Kernel used to identify it.
/// \return An integer value containing a unique ID.
size_t unique_id() const { return _unique_id; }

private:

std::string _fileName;

std::string _kernelName;

size_t _unique_id;

};

}

#endif //SPNC_KERNEL_H
Loading

0 comments on commit 8ed3970

Please sign in to comment.