[ufo-core] 04/08: Imported Upstream version 0.5.3
Frédéric-Emmanuel Picca
picca at moszumanska.debian.org
Sat Nov 30 20:54:12 UTC 2013
This is an automated email from the git hooks/post-receive script.
picca pushed a commit to branch master
in repository ufo-core.
commit a143cf2354d98606fec552fd4853545f1818efff
Author: Picca Frédéric-Emmanuel <picca at debian.org>
Date: Mon Nov 11 19:50:08 2013 +0100
Imported Upstream version 0.5.3
---
.gitignore | 2 +-
CMakeLists.txt | 190 ++++++--
NEWS | 204 ++++++++
README.md | 21 +
common/cmake/FindOpenCL.cmake | 1 +
docs/CMakeLists.txt | 8 +-
docs/manual/_templates/indexcontent.html | 48 --
docs/manual/_templates/indexsidebar.html | 5 -
docs/manual/_templates/layout.html | 5 -
docs/manual/changelog.rst | 4 +
docs/manual/conf.py.in | 14 +-
docs/manual/contents.rst | 17 -
docs/manual/index.rst | 35 ++
docs/manual/using/cluster.rst | 18 +
docs/manual/using/filters.rst | 29 +-
docs/manual/whatsnew/0.1.rst | 12 -
docs/manual/whatsnew/0.2.rst | 69 ---
docs/manual/whatsnew/0.3.rst | 31 --
docs/manual/whatsnew/index.rst | 15 -
python/CMakeLists.txt | 2 +-
python/setup.py.in | 78 +++-
python/ufonp.c | 136 ++++++
python/ufotools/__init__.py | 27 --
tests/CMakeLists.txt | 31 +-
tests/test-buffer.c | 130 ++++++
tests/test-config.c | 31 +-
tests/test-graph.c | 193 ++++++--
tests/test-mpi-remote-node.c | 126 +++++
tests/test-profiler.c | 3 +-
tests/test-remote-node.c | 84 ++++
tests/test-suite.c | 19 +-
tests/test-suite.h | 4 +
tests/test-zmq-messenger.c | 111 +++++
tools/CMakeLists.txt | 7 +-
tools/runjson.c | 134 +++++-
tools/ufod.c | 374 ++-------------
ufo/CMakeLists.txt | 151 +++---
ufo/config.h.in | 4 +-
ufo/ufo-arch-graph.c | 17 +-
ufo/ufo-basic-ops.c | 681 +++++++++++++++++++++++++++
ufo/ufo-basic-ops.cl | 326 +++++++++++++
ufo/ufo-basic-ops.h | 89 ++++
ufo/ufo-buffer.c | 679 +++++++++++++++++++++------
ufo/ufo-buffer.h | 24 +-
ufo/ufo-config.c | 96 ++--
ufo/ufo-config.h | 26 +-
ufo/ufo-cpu-task-iface.c | 17 -
ufo/ufo-cpu-task-iface.h | 34 +-
ufo/ufo-daemon.c | 586 +++++++++++++++++++++++
ufo/ufo-daemon.h | 72 +++
ufo/ufo-gpu-task-iface.c | 35 +-
ufo/ufo-gpu-task-iface.h | 40 +-
ufo/ufo-graph.c | 302 +++++++++---
ufo/ufo-graph.h | 11 +-
ufo/ufo-group.c | 18 +-
ufo/ufo-group.h | 1 +
ufo/ufo-input-task.c | 70 +--
ufo/ufo-messenger-iface.c | 119 +++++
ufo/ufo-messenger-iface.h | 152 ++++++
ufo/ufo-mpi-messenger.c | 261 +++++++++++
ufo/ufo-mpi-messenger.h | 70 +++
ufo/ufo-node.c | 81 +++-
ufo/ufo-node.h | 2 +
ufo/ufo-output-task.c | 2 +-
ufo/ufo-plugin-manager.c | 200 +++++---
ufo/ufo-plugin-manager.h | 16 +-
ufo/ufo-profiler.c | 185 +++++---
ufo/ufo-profiler.h | 65 ++-
ufo/ufo-remote-node.c | 333 ++++++-------
ufo/ufo-remote-node.h | 55 +--
ufo/ufo-resources.c | 772 ++++++++++++++++++++++---------
ufo/ufo-resources.h | 24 +-
ufo/ufo-scheduler.c | 605 ++++++++++++++++++------
ufo/ufo-scheduler.h | 29 +-
ufo/ufo-task-graph.c | 189 +++++---
ufo/ufo-task-graph.h | 11 +-
ufo/ufo-task-iface.h | 21 +-
ufo/ufo-task-node.c | 92 +++-
ufo/ufo-task-node.h | 10 +
ufo/ufo-zmq-messenger.c | 309 +++++++++++++
ufo/ufo-zmq-messenger.h | 70 +++
ufo/ufo.h | 3 +
ufo/ufo.pc.in | 12 +-
ufo/zmq-shim.h | 22 +
84 files changed, 7136 insertions(+), 2071 deletions(-)
diff --git a/.gitignore b/.gitignore
index 567609b..a5309e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-build/
+build*/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a608d96..911ecb2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,17 +2,21 @@ cmake_minimum_required(VERSION 2.6)
project(ufo C)
set(TARNAME "libufo")
+
+set(UFO_DESCRIPTION "UFO high-speed image processing core library")
+set(UFO_DESCRIPTION_SUMMARY "UFO high-speed image processing core library")
+
+#{{{ Library version
set(UFO_VERSION_MAJOR "0")
-set(UFO_VERSION_MINOR "3")
-set(UFO_VERSION_PATCH "1")
+set(UFO_VERSION_MINOR "5")
+set(UFO_VERSION_PATCH "3")
set(UFO_GIR_VERSION "${UFO_VERSION_MAJOR}.${UFO_VERSION_MINOR}")
# increase UFO_SO_VERSION on each version that breaks ABI compatibility
-set(UFO_SO_VERSION "3")
-
-set(UFO_DESCRIPTION "UFO high-speed image processing core library")
-set(UFO_DESCRIPTION_SUMMARY "UFO high-speed image processing core library")
+set(UFO_SO_VERSION "4")
+#}}}
+#{{{ Package version
set(PACKAGE_VERSION_MAJOR ${UFO_VERSION_MAJOR})
set(PACKAGE_VERSION_MINOR ${UFO_VERSION_MINOR})
set(PACKAGE_VERSION_PATCH ${UFO_VERSION_PATCH})
@@ -21,38 +25,114 @@ set(PACKAGE_NAME ${TARNAME})
set(PACKAGE_TARNAME ${TARNAME})
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "http://ufo.kit.edu/ufo/newticket")
+#}}}
+#{{{ CMake
enable_testing()
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/common/cmake")
+#}}}
-include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
-include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ufo")
-include_directories("${CMAKE_CURRENT_BINARY_DIR}/ufo")
-
+find_program (MPICC "mpicc")
-# --- Options -----------------------------------------------------------------
+#{{{ Options
option(WITH_PROFILING "Enable profiling" OFF)
+option(WITH_TESTS "Build test suite" ON)
+option(WITH_MPI "Build with MPI support" OFF)
+option(WITH_DEBUG "Build with DEBUG support" OFF)
+
if (WITH_PROFILING)
add_definitions("-pg")
set(CMAKE_C_FLAGS "-pg")
endif ()
+if (WITH_DEBUG)
+ add_definitions ("-DDEBUG")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -ggdb")
+endif ()
+
+if (WITH_MPI)
+ add_definitions ("-DMPI")
+
+ if (NOT MPICC)
+ message (FATAL_ERROR "No mpicc compiler be found but MPI was explicitly enabled")
+ endif ()
+
+ set(CMAKE_C_COMPILER ${MPICC})
+endif ()
+#}}}
+
+#{{{ Installation directories
+
+# Set what the user passed
+set(UFO_PREFIX "${PREFIX}")
+set(UFO_EPREFIX "${EXEC_PREFIX}")
+set(UFO_INCLUDEDIR "${INCLUDEDIR}")
+set(UFO_BINDIR "${BINDIR}")
+set(UFO_LIBDIR "${LIBDIR}")
+set(UFO_DATAROOTDIR "${DATAROOTDIR}")
+set(UFO_DATADIR "${DATAROOTDIR}")
+set(UFO_PKGCONFIGDIR "${PKGCONFIGDIR}")
+set(UFO_GIRDIR "${GIRDIR}")
+set(UFO_TYPELIBDIR "${TYPELIBDIR}")
+
+# Fix in the same way configure does
+if(UFO_PREFIX STREQUAL "")
+ set(UFO_PREFIX "${CMAKE_INSTALL_PREFIX}")
+endif()
+
+if(UFO_EPREFIX STREQUAL "")
+ set(UFO_EPREFIX "${UFO_PREFIX}")
+endif()
+
+if(UFO_INCLUDEDIR STREQUAL "")
+ set(UFO_INCLUDEDIR "${UFO_PREFIX}/include")
+endif()
+
+if(UFO_BINDIR STREQUAL "")
+ set(UFO_BINDIR "${UFO_EPREFIX}/bin")
+endif()
+
+if(UFO_LIBDIR STREQUAL "")
+ set(UFO_LIBDIR "${UFO_EPREFIX}/lib")
+endif()
+
+if(UFO_DATAROOTDIR STREQUAL "")
+ set(UFO_DATAROOTDIR "${UFO_PREFIX}/share")
+endif()
-# --- Find packages and libraries ---------------------------------------------
+if(UFO_DATADIR STREQUAL "")
+ set(UFO_DATADIR "${UFO_DATAROOTDIR}")
+endif()
-# These packages are required in all sub-directories because Glib and GObject is
-# part of the API/ABI.
+if(UFO_PKGCONFIGDIR STREQUAL "")
+ set(UFO_PKGCONFIGDIR "${UFO_LIBDIR}/pkgconfig")
+endif()
+
+if(UFO_GIRDIR STREQUAL "")
+ set(UFO_GIRDIR "${UFO_DATADIR}/gir-1.0")
+endif()
+
+if(UFO_TYPELIBDIR STREQUAL "")
+ set(UFO_TYPELIBDIR "${UFO_LIBDIR}/girepository-1.0")
+endif()
+#}}}
+
+#{{{ Dependencies
+set(PKG_GLIB2_MIN_REQUIRED "2.22")
+set(PKG_JSON_GLIB_MIN_REQUIRED "0.7.6")
+set(PKG_ZMQ_MIN_REQUIRED "2.1")
find_package(OpenCL REQUIRED)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(GLIB2 glib-2.0>=2.22 REQUIRED)
-pkg_check_modules(GOBJECT2 gobject-2.0>=2.22 REQUIRED)
-pkg_check_modules(GMODULE2 gmodule-2.0>=2.22 REQUIRED)
-pkg_check_modules(GTHREAD2 gthread-2.0>=2.22 REQUIRED)
-pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
-pkg_check_modules(ZMQ libzmq>=3.2 REQUIRED)
+pkg_check_modules(GLIB2 glib-2.0>=${PKG_GLIB2_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(GOBJECT2 gobject-2.0>=${PKG_GLIB2_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(GMODULE2 gmodule-2.0>=${PKG_GLIB2_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(GTHREAD2 gthread-2.0>=${PKG_GLIB2_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(GIO2 gio-2.0>=${PKG_GLIB2_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(JSON_GLIB json-glib-1.0>=${PKG_JSON_GLIB_MIN_REQUIRED} REQUIRED)
+pkg_check_modules(ZMQ libzmq>=${PKG_ZMQ_MIN_REQUIRED} REQUIRED)
set(UFOCORE_DEPS
${OPENCL_LIBRARIES}
@@ -60,42 +140,60 @@ set(UFOCORE_DEPS
${GOBJECT2_LIBRARIES}
${GMODULE2_LIBRARIES}
${GTHREAD2_LIBRARIES}
+ ${GIO2_LIBRARIES}
${JSON_GLIB_LIBRARIES}
${ZMQ_LIBRARIES})
-
+#{{{ Add include directories
include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo
${CMAKE_CURRENT_BINARY_DIR}
- ${CMAKE_CURRENT_BINARY_DIR}/src
+ ${CMAKE_CURRENT_BINARY_DIR}/ufo
${GLIB2_INCLUDE_DIRS}
+ ${GIO2_INCLUDE_DIRS}
${OPENCL_INCLUDE_DIRS}
${JSON_GLIB_INCLUDE_DIRS}
${ZMQ_INCLUDE_DIRS})
-
-link_directories(
- ${ZMQ_LIBRARY_DIRS}
- ${JSON_GLIB_LIBRARY_DIRS})
-
-add_definitions("-std=c99 -pedantic -Wall -Wextra -fPIC")
-
-if (CMAKE_COMPILER_IS_GNUCC)
- add_definitions("-Wmissing-prototypes -Wmissing-declarations -Wshadow
- -Wpointer-arith -Wcast-align -Wwrite-strings -Wredundant-decls -Wcast-qual
- -Wnested-externs -Winline -Wno-long-long -Wconversion -Wstrict-prototypes")
-
- add_definitions("-Wno-unused-parameter -Wno-missing-field-initializers")
+#}}}
+#}}}
+
+#{{{ Definitions
+add_definitions("-std=c99 -pedantic -Wall -Wextra -Werror -fPIC")
+
+if (CMAKE_COMPILER_IS_GNUCC OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang"))
+ add_definitions("-Wcast-align
+ -Wcast-qual
+ -Winline
+ -Wmissing-declarations
+ -Wmissing-prototypes
+ -Wnested-externs
+ -Wno-deprecated-declarations
+ -Wno-long-long
+ -Wno-missing-field-initializers
+ -Wno-unused-parameter
+ -Wpointer-arith
+ -Wredundant-decls
+ -Wshadow
+ -Wstrict-prototypes
+ -Wwrite-strings")
endif()
add_definitions(-DG_LOG_DOMAIN=\"Ufo\")
+#}}}
+#{{{ Subdirectories
add_subdirectory(ufo)
add_subdirectory(docs)
-#add_subdirectory(python)
-add_subdirectory(tests)
+add_subdirectory(python)
add_subdirectory(tools)
+if (WITH_TESTS)
+ add_subdirectory(tests)
+endif()
+#}}}
-# --- Package generation ------------------------------------------------------
+#{{{ CPack
set(CPACK_PACKAGE_DESCRIPTION ${UFO_DESCRIPTION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${UFO_DESCRIPTION_SUMMARY})
set(CPACK_PACKAGE_NAME ${TARNAME})
@@ -110,10 +208,20 @@ set(VERSION ${PACKAGE_VERSION})
set(CPACK_GENERATOR "DEB;RPM;")
set(CPACK_SOURCE_GENERATOR "TGZ")
-set(CPACK_SOURCE_IGNORE_FILES "tags" ".bzr" ".swp" "~1~" ".git" ".xml")
+set(CPACK_SOURCE_IGNORE_FILES "/build/;.git/;tags;.swp;${CPACK_SOURCE_IGNORE_FILES}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}" CACHE INTERNAL "tarball basename")
-# --- Distro specific
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.6), libgcc1 (>= 1:4.1)")
+#{{{ Debian
+set(CPACK_DEBIAN_PACKAGE_DEPENDS
+ "libglib2.0-0 (>= ${PKG_GLIB2_MIN_REQUIRED}),
+ libjson-glib-1.0-0 (>= ${PKG_JSON_GLIB_MIN_REQUIRED}),
+ libzmq1 (>= ${PKG_ZMQ_MIN_REQUIRED})")
+#}}}
+
+#{{{ RPM
+set(CPACK_RPM_PACKAGE_AUTOREQPROV " no")
+set(CPACK_RPM_PACKAGE_REQUIRES "libjson-glib-1_0-0, libzmq1")
+#}}}
include(CPack)
+#}}}
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..1fdaec4
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,204 @@
+=========
+Changelog
+=========
+
+Here you can see the full list of changes between each ufo-core release.
+
+
+Version 0.5
+===========
+
+Released on October 28th 2013.
+
+- Added MPI support as an alternative to ZMQ.
+- Added basic math operations for use with filters.
+- UFO can now be used reliably in a multithreaded Python context. That means,
+ calling ``ufo_scheduler_run`` in a Python thread will "just work". This change
+ allows run-time injection of NumPy buffers into the task graph.
+
+Developers
+----------
+- Add ``-DDEBUG`` when debug is enabled so we can #ifdef it
+- Add GLib version guards
+- ufo-core compiles with Clang
+- CMake 2.6 is used solely throughout the sources
+- Add convenience function ufo_buffer_new_with_size
+- Add a shim macros to support both zmq 2 and 3
+- Add ``UFO_USE_GPU`` env var to restrict to single GPU
+- Added ufo_resource_manager_get_cached_kernel that always returns the same
+ kernel object when given the same file and kernel name. Note, that you have to
+ guard it properly and do not call ``clSetKernelArg`` from multiple threads at
+ the same time.
+- Add profile tracing to produce a JSON trace event file, that can be read and
+ visualized with Google's Chrome browser. It can be enabled with
+ UfoScheduler::enable-tracing set to TRUE.
+
+Bug fixes
+---------
+- Fix #6: Don't use enum values as bit flags
+- Fix bug: no plugin name is sent to remote nodes
+- Fix copy segfault in when source has not alloc'd
+- Removed dependency on a C++ compiler
+- Fix reduction problem
+
+
+Version 0.4
+===========
+
+Released on July 18th 2013.
+
+Major changes
+-------------
+
+- Rewrote internal architecture for better scheduling.
+- Remove profiler levels and add more output
+- Implement input data partitioning: On clusters where distributed data access
+ is possible, we can achieve perfect linear scalability by partitioning the
+ input data set.
+- Install SIGTERM handler for cleanup of node server
+
+
+Features
+--------
+
+- Add ufo_task_graph_get_json_data
+- Streamline and simplify scheduling
+- Provide function to flatten graph
+- Provide graph copy functionality
+- Add node indices for copies
+- Add all paths as OpenCL include paths
+- Write out JSON version
+- Search in UFO_PLUGIN_PATH env var
+
+
+Bug fixes
+---------
+
+- Fix problems with AMD platforms
+- Fix timestamp readout
+- Fix potential single integer overflow
+- Exit when JSON tasks could not be found
+- Fix remote tasks getting stuck
+- Unref expanded nodes explicitly
+- Fix #189: don't copy nodes with more than one input
+- Fix #219: Warn instead of segfault
+- Fix annotation for older GI compiler
+- Fix problem with first remote data item
+- Fix platform selection
+- Fix problems with objects that are not unreffed
+- Refactor buffer and add support for #184
+- Refactor resources and fix #183
+- Fix buffer for broadcast operations
+
+
+Version 0.3
+===========
+
+Released on February 8th 2013.
+
+Major breakage
+--------------
+
+- A graph is now a simple data structure and not a specific graph of task nodes.
+ This is implemented by a TaskGraph.
+
+- Filters are now called TaskNodes and connected with
+ ``ufo_task_graph_connect_nodes`` and ``ufo_task_graph_connect_nodes_full``
+ respectively.
+
+
+Graph expansion
+---------------
+
+With 0.2, Using multiple GPUs was possible by manually splitting paths in the
+graph and assigning GPUs. Now, task graphs are automatically expanded depending
+on the number of available GPUs and remote processing slaves that are started
+with the newly added ``ufod`` server software.
+
+
+Minor improvements
+------------------
+
+- A ``deploy.sh`` script has been added for easier deployment of the software
+ stack. This is especially useful to install everything in the home directory
+ of the user, who only needs to setup ``LD_LIBRARY_PATH`` and
+ ``GI_TYPELIB_PATH`` correctly to run the software.
+
+
+Version 0.2
+===========
+
+Released on November 8th 2012.
+
+Major breakage
+--------------
+
+- Filters are now prefixed again with ``libfilter`` to allow introspected
+ documentation. Thus, any filter built for 0.1 cannot be used because they are
+ simply not found.
+
+- :c:func:`ufo_plugin_manager_get_filter` received a new third parameter
+ ``error`` that reports errors when opening and loading a UfoFilter from a
+ shared object.
+
+- :c:func:`ufo_resource_manager_add_program` is removed.
+
+- The kernel file name must be passed to :c:func:`ufo_resource_manager_get_kernel`.
+
+- The ``CHECK_ERROR`` macro defined in ``ufo-resource-manager.h`` was renamed to
+ ``CHECK_OPENCL_ERROR`` to better reflect its real purpose.
+
+- The old JSON specification has been changed to reflect the possibilities of
+ the current API. Thus, JSON files that worked under Ufo 0.1 cannot be read
+ with Ufo 0.2.
+
+- Removed the otherwise unused :c:func:`ufo_buffer_get_transfer_time` and
+ replaced this with the more flexible :c:func:`ufo_buffer_get_transfer_timer`.
+
+- Rename :c:func:`ufo_filter_initialize` to
+ :c:func:`ufo_filter_set_plugin_name` that reflects its true meaning.
+
+
+Scheduling
+~~~~~~~~~~
+
+A more scheduable way to run filters has been implemented with the virtual
+:c:func:`process_cpu` and :c:func:`process_gpu` methods. Contrary to the old
+way, they act on *one* working set at a time that is passed as an array of
+pointers to :c:type:`UfoBuffer`. Sometimes, a filter needs to setup data
+depending on the input size. For this reason, the virtual method
+:c:func:`initialize` takes a second parameter that is again a list of pointers
+to buffer objects.
+
+Moreover, the :c:type:`UfoScheduler` class has been added that is combining
+the work previously accomplished by :c:func:`ufo_filter_process` and
+:c:func:`ufo_graph_run`. The scheduler orchestrates the filters and
+assigns resources in a meaningful way.
+
+If written in the new kernel style, producer filters must return a boolean flag
+denoting if data was produced or not.
+
+
+General improvements
+--------------------
+
+- The manual was restructured considerably.
+
+- Saving graphs as JSON files has been added via
+ :c:func:`ufo_graph_save_to_json()`.
+
+- Filters can now wait until their properties satisfy a condition using
+ :c:func:`ufo_filter_wait_until`, see also :ref:`filters-block`.
+
+- A new method :c:func:`ufo_resource_manager_get_kernel_from_source` so that
+ filters can load kernels directly from source.
+
+- Streamlined error handling: Filters should not issue ``g_warnings`` or
+ ``g_errors`` on their own anymore but create an error with ``g_error_new`` and
+ return that.
+
+
+Version 0.1.1
+=============
+
+- Ticket #55: tests/test-channel blocks indefinitely
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c50d260
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+## What is the UFO framework?
+
+UFO is a multi-threaded, GPU-enabled and distributed data processing
+*framework*. It provides base classes, scheduler implementations and run-time
+management to describe a workflow as a graph of processing nodes. The nodes are
+implemented as plugins in the
+[ufo-filters](https://github.com/ufo-kit/ufo-filters) sister project.
+
+
+## Further information
+
+More information can be found at various locations:
+
+* [User manual](http://ufo.kit.edu/extra/manual/html/)
+* [API reference](http://ufo.kit.edu/extra/reference/)
+* [Task reference](http://ufo.kit.edu/extra/filters/reference/)
+
+
+## License
+
+Both ufo-core and ufo-filters are licensed under LGPL 3.
diff --git a/common/cmake/FindOpenCL.cmake b/common/cmake/FindOpenCL.cmake
index f1b1301..222cfcb 100644
--- a/common/cmake/FindOpenCL.cmake
+++ b/common/cmake/FindOpenCL.cmake
@@ -53,6 +53,7 @@ ELSE (APPLE)
/usr/lib64/nvidia
/opt/nvidia-current
/opt/AMDAPP/lib
+ /opt/AMDAPP/lib/x86_64
)
GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH)
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index 0e9eecc..ab90d6e 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.6)
find_program(SPHINX sphinx-build PATHS /usr/local/bin /usr/bin)
mark_as_advanced(SPHINX)
@@ -15,11 +15,7 @@ if(SPHINX)
list(APPEND sphinx_source "${output_dir}/conf.py")
set(sphinx_static
- _static/ufo-logo.png
- _templates/indexcontent.html
- _templates/indexsidebar.html
- _templates/layout.html
- )
+ _static/ufo-logo.png)
configure_file(${input_dir}/conf.py.in ${output_dir}/conf.py)
diff --git a/docs/manual/_templates/indexcontent.html b/docs/manual/_templates/indexcontent.html
deleted file mode 100644
index 33883d4..0000000
--- a/docs/manual/_templates/indexcontent.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{% extends "defindex.html" %}
-{% block tables %}
- <p><strong>Parts of the documentation:</strong></p>
- <table class="contentstable" align="center"><tr>
- <td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("whatsnew/" + version) }}">What's new in UFO {{ version }}?</a><br/>
- <span class="linkdescr">or <a href="{{ pathto("whatsnew/index") }}">all "What's new" documents</a></span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installation</a><br/>
- <span class="linkdescr">install from either packages or source</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("using/index") }}">Using UFO</a><br/>
- <span class="linkdescr">how to use UFO on different platforms</span></p>
- </td><td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("json") }}">JSON Configuration</a><br/>
- <span class="linkdescr">configure UFO graphs textual</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("api/index") }}">UFO API</a><br/>
- <span class="linkdescr">reference for C/C++ programmers</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("faq") }}">FAQ</a><br/>
- <span class="linkdescr">frequently asked questions</span></p>
- </td></tr>
- </table>
-
- <p><strong>Indices and tables:</strong></p>
- <table class="contentstable" align="center"><tr>
- <td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/>
- <span class="linkdescr">all functions, classes, terms</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("glossary") }}">Glossary</a><br/>
- <span class="linkdescr">the most important terms explained</span></p>
- </td><td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
- <span class="linkdescr">search this documentation</span></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Complete Table of Contents</a><br/>
- <span class="linkdescr">lists all sections and subsections</span></p>
- </td></tr>
- </table>
-
- <p><strong>Meta information:</strong></p>
- <table class="contentstable" align="center"><tr>
- <td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("todo") }}">TODO</a></p>
- <p class="biglink"><a class="biglink" href="{{ pathto("bugs") }}">Reporting bugs</a></p>
- </td><td width="50%">
- <p class="biglink"><a class="biglink" href="{{ pathto("copyright") }}">Copyright</a></p>
- </td></tr>
- </table>
-
-{% endblock %}
-
diff --git a/docs/manual/_templates/indexsidebar.html b/docs/manual/_templates/indexsidebar.html
deleted file mode 100644
index f6b3914..0000000
--- a/docs/manual/_templates/indexsidebar.html
+++ /dev/null
@@ -1,5 +0,0 @@
- <h3>Other resources</h3>
- <ul>
- <li><a href="http://ufo.kit.edu">Project Homepage</a></li>
- <li><a href="http://ufo.kit.edu/ufo">Development Homepage</a></li>
- </ul>
diff --git a/docs/manual/_templates/layout.html b/docs/manual/_templates/layout.html
deleted file mode 100644
index 0429147..0000000
--- a/docs/manual/_templates/layout.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "!layout.html" %}
-{% block rootrellink %}
- <li><a href="{{ pathto('index') }}">Index</a> | </li>
- <li><a href="{{ pathto('contents') }}">Contents</a> »</li>
-{% endblock %}
diff --git a/docs/manual/changelog.rst b/docs/manual/changelog.rst
new file mode 100644
index 0000000..99ab554
--- /dev/null
+++ b/docs/manual/changelog.rst
@@ -0,0 +1,4 @@
+.. _whatsnew-index:
+
+
+.. include:: ../../NEWS
diff --git a/docs/manual/conf.py.in b/docs/manual/conf.py.in
index 6f40fca..8f7dac8 100644
--- a/docs/manual/conf.py.in
+++ b/docs/manual/conf.py.in
@@ -34,7 +34,7 @@ source_suffix = '.rst'
source_encoding = 'utf-8'
# The master toctree document.
-#master_doc = 'index'
+master_doc = 'index'
# General information about the project.
project = u'UFO'
@@ -135,15 +135,15 @@ html_static_path = ['_static']
html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-html_sidebars = {
- 'index' : 'indexsidebar.html'
-}
+# html_sidebars = {
+# 'index' : 'indexsidebar.html'
+# }
# Additional templates that should be rendered to pages, maps page names to
# template names.
-html_additional_pages = {
- 'index' : 'indexcontent.html'
-}
+# html_additional_pages = {
+# 'index' : 'indexcontent.html'
+# }
# If false, no module index is generated.
#html_use_modindex = True
diff --git a/docs/manual/contents.rst b/docs/manual/contents.rst
deleted file mode 100644
index 25e0e23..0000000
--- a/docs/manual/contents.rst
+++ /dev/null
@@ -1,17 +0,0 @@
-==========================
-UFO Documentation contents
-==========================
-
-.. toctree::
-
- whatsnew/index.rst
- install/index.rst
- using/index.rst
- api/index.rst
- json.rst
- faq.rst
- glossary.rst
-
- bugs.rst
- copyright.rst
-
diff --git a/docs/manual/index.rst b/docs/manual/index.rst
new file mode 100644
index 0000000..c332563
--- /dev/null
+++ b/docs/manual/index.rst
@@ -0,0 +1,35 @@
+=================
+UFO Documentation
+=================
+
+User documentation
+==================
+
+.. toctree::
+ :maxdepth: 2
+
+ install/index
+ using/index
+ json
+
+
+Developer documentation
+=======================
+
+.. toctree::
+ :maxdepth: 2
+
+ api/index
+ bugs
+ faq
+ changelog
+
+
+Additional notes
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ glossary
+ copyright
diff --git a/docs/manual/using/cluster.rst b/docs/manual/using/cluster.rst
index 66ac63a..7496b25 100644
--- a/docs/manual/using/cluster.rst
+++ b/docs/manual/using/cluster.rst
@@ -21,3 +21,21 @@ In Python this would look like this::
sched = Ufo.Scheduler(remotes=['tcp://foo.bar.org:5555'])
Address are notated according to `ZeroMQ <http://api.zeromq.org/3-2:zmq-tcp>`_.
+
+
+Streaming vs. replication
+=========================
+
+Work can be executed in two ways: `streaming`, which means data is transferred
+from a master machine to all slaves and returned to the master after computation
+is finished and `replicated` in which each slaves works on its own subset of the
+initial input data. The former must be used if the length of the stream is
+unknown before execution, otherwise the stream could not be split up into equal
+partitions.
+
+Initially, the scheduler is set to streaming mode. To switch to replication
+mode, you have to prepare the scheduler::
+
+ sched = Ufo.Scheduler(remotes=remotes)
+ sched.set_remote_mode(Ufo.RemoteMode.REPLICATE)
+ sched.run(graph)
diff --git a/docs/manual/using/filters.rst b/docs/manual/using/filters.rst
index 57f26b7..a9142ed 100644
--- a/docs/manual/using/filters.rst
+++ b/docs/manual/using/filters.rst
@@ -71,7 +71,7 @@ processing mode your task runs ::
UfoInputParam **in_params,
UfoTaskMode *mode)
{
- *mode = UFO_TASK_MODE_SINGLE;
+ *mode = UFO_TASK_MODE_PROCESSOR;
*n_inputs = 1;
*in_params = g_new0 (UfoInputParam, 1);
(*in_params)[0].n_dims = 2;
@@ -80,6 +80,20 @@ processing mode your task runs ::
This task expects one two-dimensional input. Be aware, that the callee must
allocate memory for the ``in_params`` data structure.
+The mode decides which functions of a task are called. Each task can provide a
+``process`` function that takes input data and optionally writes output data and
+a ``generate`` function that does not take input data but writes data. Both
+functions return a boolean value to signal if data was produced or not (e.g. end
+of stream):
+
+* ``UFO_TASK_MODE_PROCESSOR``: The task reads data and optionally writes data.
+ For that it must implement ``process``.
+* ``UFO_TASK_MODE_GENERATOR``: The task only produces data (e.g. file readers)
+ and must implement ``generate``.
+* ``UFO_TASK_MODE_REDUCTOR``: The tasks reads the input stream and produces
+ another output stream. Reading is accomplished by implementing ``process``
+ whereas production is done by ``generate``.
+
``setup`` can be used to initialize data that depends on run-time resources like
OpenCL contexts etc. This method is called only *once* ::
@@ -113,21 +127,26 @@ specify ::
}
Finally, you have to override the ``process`` method. Note, that the function
-signatures differ for GPU and CPU tasks ::
+signatures is essentially the same for GPU and CPU tasks ::
static gboolean
ufo_awesome_task_process (UfoGpuTask *task,
UfoBuffer **inputs,
UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
+ UfoRequisition *requisition)
{
- /* Now we can request cl_mem or float arrays from in and outputs. */
+ UfoGpuNode *node;
cl_command_queue cmd_queue;
cl_mem host_in;
cl_mem host_out;
+ /* We have to know to which GPU device we are assigned to */
+ node = UFO_GPU_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (task)));
+
+ /* Now, we can get the command queue */
cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+
+ /* ... and get hold of the data */
host_in = ufo_buffer_get_device_array (inputs[0], cmd_queue);
host_out = ufo_buffer_get_device_array (output, cmd_queue);
diff --git a/docs/manual/whatsnew/0.1.rst b/docs/manual/whatsnew/0.1.rst
deleted file mode 100644
index 7499916..0000000
--- a/docs/manual/whatsnew/0.1.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-==========================
-What's New in ufo-core 0.1
-==========================
-
-:Author: Matthias Vogelgesang
-
-Changes from version 0.1.0 to 0.1.1
-===================================
-
-Fixed bugs
-----------
- - Ticket #55: tests/test-channel blocks indefinitely
diff --git a/docs/manual/whatsnew/0.2.rst b/docs/manual/whatsnew/0.2.rst
deleted file mode 100644
index e6dc9a3..0000000
--- a/docs/manual/whatsnew/0.2.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-==========================
-What's New in ufo-core 0.2
-==========================
-
-Major breakage
-==============
-
-- Filters are now prefixed again with ``libfilter`` to allow introspected
- documentation. Thus, any filter built for 0.1 cannot be used because they are
- simply not found.
-
-- :c:func:`ufo_plugin_manager_get_filter` received a new third parameter
- ``error`` that reports errors when opening and loading a UfoFilter from a
- shared object.
-
-- :c:func:`ufo_resource_manager_add_program` is removed.
-
-- The kernel file name must be passed to :c:func:`ufo_resource_manager_get_kernel`.
-
-- The ``CHECK_ERROR`` macro defined in ``ufo-resource-manager.h`` was renamed to
- ``CHECK_OPENCL_ERROR`` to better reflect its real purpose.
-
-- The old JSON specification has been changed to reflect the possibilities of
- the current API. Thus, JSON files that worked under Ufo 0.1 cannot be read
- with Ufo 0.2.
-
-- Removed the otherwise unused :c:func:`ufo_buffer_get_transfer_time` and
- replaced this with the more flexible :c:func:`ufo_buffer_get_transfer_timer`.
-
-- Rename :c:func:`ufo_filter_initialize` to
- :c:func:`ufo_filter_set_plugin_name` that reflects its true meaning.
-
-Scheduling
-----------
-
-A more scheduable way to run filters has been implemented with the virtual
-:c:func:`process_cpu` and :c:func:`process_gpu` methods. Contrary to the old
-way, they act on *one* working set at a time that is passed as an array of
-pointers to :c:type:`UfoBuffer`. Sometimes, a filter needs to setup data
-depending on the input size. For this reason, the virtual method
-:c:func:`initialize` takes a second parameter that is again a list of pointers
-to buffer objects.
-
-Moreover, the :c:type:`UfoScheduler` class has been added that is combining
-the work previously accomplished by :c:func:`ufo_filter_process` and
-:c:func:`ufo_graph_run`. The scheduler orchestrates the filters and
-assigns resources in a meaningful way.
-
-If written in the new kernel style, producer filters must return a boolean flag
-denoting if data was produced or not.
-
-
-General improvements
-====================
-
-- The manual was restructured considerably.
-
-- Saving graphs as JSON files has been added via
- :c:func:`ufo_graph_save_to_json()`.
-
-- Filters can now wait until their properties satisfy a condition using
- :c:func:`ufo_filter_wait_until`, see also :ref:`filters-block`.
-
-- A new method :c:func:`ufo_resource_manager_get_kernel_from_source` so that
- filters can load kernels directly from source.
-
-- Streamlined error handling: Filters should not issue ``g_warnings`` or
- ``g_errors`` on their own anymore but create an error with ``g_error_new`` and
- return that.
diff --git a/docs/manual/whatsnew/0.3.rst b/docs/manual/whatsnew/0.3.rst
deleted file mode 100644
index 51f3201..0000000
--- a/docs/manual/whatsnew/0.3.rst
+++ /dev/null
@@ -1,31 +0,0 @@
-==========================
-What's New in ufo-core 0.3
-==========================
-
-Major breakage
-==============
-
-- A graph is now a simple data structure and not a specific graph of task nodes.
- This is implemented by a TaskGraph.
-
-- Filters are now called TaskNodes and connected with
- ``ufo_task_graph_connect_nodes`` and ``ufo_task_graph_connect_nodes_full``
- respectively.
-
-
-Graph expansion
-===============
-
-With 0.2, Using multiple GPUs was possible by manually splitting paths in the
-graph and assigning GPUs. Now, task graphs are automatically expanded depending
-on the number of available GPUs and remote processing slaves that are started
-with the newly added ``ufod`` server software.
-
-
-Minor improvements
-==================
-
-- A ``deploy.sh`` script has been added for easier deployment of the software
- stack. This is especially useful to install everything in the home directory
- of the user, who only needs to setup ``LD_LIBRARY_PATH`` and
- ``GI_TYPELIB_PATH`` correctly to run the software.
diff --git a/docs/manual/whatsnew/index.rst b/docs/manual/whatsnew/index.rst
deleted file mode 100644
index f02388c..0000000
--- a/docs/manual/whatsnew/index.rst
+++ /dev/null
@@ -1,15 +0,0 @@
-.. _whatsnew-index:
-
-======================
-What's New in ufo-core
-======================
-
-The "What's New in ufo-core" series documents the most important changes between
-major versions of the UFO core package.
-
-.. toctree::
- :maxdepth: 2
-
- 0.3.rst
- 0.2.rst
- 0.1.rst
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index f93a571..bad3bd3 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -9,7 +9,7 @@ if (PYTHON)
if (WITH_PYTHON_TOOLS)
set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py")
- set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/ufotools/__init__.py")
+ set(DEPS "${CMAKE_CURRENT_SOURCE_DIR}/ufonp.c")
set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp")
configure_file(${SETUP_PY_IN} ${SETUP_PY})
diff --git a/python/setup.py.in b/python/setup.py.in
index 21bd87d..d885308 100644
--- a/python/setup.py.in
+++ b/python/setup.py.in
@@ -1,13 +1,71 @@
+import os
+import subprocess
+from numpy import get_include
from distutils.core import setup, Extension
+
+def parse_pkg_config(pkg_names):
+ """Call `pkg-config` with each package in pkg_name and return a tuple with
+ stripped (include_dirs, library_dirs, libraries, extra_cflags)
+ """
+ include_dirs = []
+ libraries = []
+ lib_dirs = []
+ extra_cflags = []
+
+ for pkg_name in pkg_names:
+ try:
+ proc = subprocess.Popen(['pkg-config', '--libs', pkg_name],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ proc.wait()
+
+ if proc.returncode != 0:
+ raise Exception('package `%s\' not found' % pkg_name)
+
+ r = proc.stdout.read()
+
+ libraries.extend([l.replace('-l', '') for l in r.split() if
+ l.startswith('-l')])
+
+ extra_cflags.extend([l for l in r.split() if not
+ l.startswith('-l')])
+
+ proc = subprocess.Popen(['pkg-config', '--cflags', pkg_name],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ r = proc.stdout.read()
+
+ include_dirs.extend([i.replace('-I', '') for i in r.split() if
+ i.startswith('-I')])
+ except OSError:
+ raise Exception('`pkg-config\' is not installed')
+
+ return (include_dirs, lib_dirs, libraries, extra_cflags)
+
+
if __name__ == '__main__':
- setup(name='ufotools',
- version='${PACKAGE_VERSION}',
- author='Matthias Vogelgesang',
- author_email='matthias.vogelgesang at kit.edu',
- url='http://ufo.kit.edu',
- license='GPL v3',
- description='ufo extension module',
- long_description='ufo extension module',
- package_dir={ '': '${CMAKE_CURRENT_SOURCE_DIR}' },
- packages=['ufotools'])
+ packages = ['gobject-2.0', 'pygobject-2.0']
+
+ try:
+ inc_dirs, lib_dirs, libs, extra = parse_pkg_config(packages)
+ inc_dirs.append(get_include())
+ inc_dirs.append('${PROJECT_SOURCE_DIR}')
+ inc_dirs.append('${PROJECT_BINARY_DIR}')
+ libs.append('ufo')
+ lib_dirs.append('${PROJECT_BINARY_DIR}/ufo')
+ extra.append('-std=c99')
+
+ setup(name='ufotools',
+ version='${PACKAGE_VERSION}',
+ author='Matthias Vogelgesang',
+ author_email='matthias.vogelgesang at kit.edu',
+ url='http://ufo.kit.edu',
+ license='GPL v3',
+ description='ufo extension module',
+ long_description='ufo extension module',
+ ext_modules=[Extension('ufonp', ['${CMAKE_CURRENT_SOURCE_DIR}/ufonp.c'],
+ include_dirs=inc_dirs,
+ library_dirs=lib_dirs,
+ libraries=libs,
+ extra_compile_args=extra)])
+ except Exception as e:
+ print 'Configure error:', e
diff --git a/python/ufonp.c b/python/ufonp.c
new file mode 100644
index 0000000..588acab
--- /dev/null
+++ b/python/ufonp.c
@@ -0,0 +1,136 @@
+#include <Python.h>
+#include <pygobject.h>
+#include <numpy/arrayobject.h>
+#include <ufo/ufo.h>
+
+static PyTypeObject *PyGObject_Type = NULL;
+
+static PyObject *
+ufo_asarray(PyObject *self, PyObject *args)
+{
+ PyObject *py_buffer;
+ PyObject *np_array;
+ UfoRequisition req;
+ UfoBuffer *buffer;
+ gfloat *host_array;
+
+ if (!PyArg_ParseTuple(args, "O", &py_buffer))
+ return NULL;
+
+ buffer = UFO_BUFFER (pygobject_get (py_buffer));
+ host_array = ufo_buffer_get_host_array (buffer, NULL);
+ ufo_buffer_get_requisition (buffer, &req);
+
+ npy_intp np_dim_size[req.n_dims];
+
+ for (int i = 0; i < req.n_dims; i++)
+ np_dim_size[i] = req.dims[i];
+
+ np_array = PyArray_NewFromDescr (&PyArray_Type, PyArray_DescrFromType(NPY_FLOAT32),
+ req.n_dims, np_dim_size, NULL, host_array, 0, NULL);
+
+ return np_array;
+}
+
+static void
+resize_buffer (UfoBuffer *buffer, guint np_ndims, npy_intp *np_dim_size)
+{
+ UfoRequisition req;
+
+ req.n_dims = np_ndims;
+
+ for (int i = 0; i < np_ndims; i++)
+ req.dims[i] = np_dim_size[i];
+
+ ufo_buffer_resize (buffer, &req);
+}
+
+static PyObject *
+ufo_fromarray (PyObject *self, PyObject *args)
+{
+ PyArrayObject *np_array;
+ guint np_ndims;
+ npy_intp *np_dims;
+ UfoBuffer *buffer;
+ UfoRequisition req;
+ float *host_array;
+
+ if (!PyArg_ParseTuple (args, "O!", &PyArray_Type, &np_array))
+ return NULL;
+
+ np_ndims = PyArray_NDIM (np_array);
+ np_dims = PyArray_DIMS (np_array);
+
+ req.n_dims = np_ndims;
+
+ for (guint i = 0; i < np_ndims; i++)
+ req.dims[i] = np_dims[i];
+
+ buffer = ufo_buffer_new (&req, NULL);
+ host_array = ufo_buffer_get_host_array (buffer, NULL);
+ memcpy (host_array, PyArray_DATA(np_array), ufo_buffer_get_size (buffer));
+
+ return pygobject_new (G_OBJECT (buffer));
+}
+
+static PyObject *
+ufo_fromarray_inplace (PyObject *self, PyObject *args)
+{
+ PyObject *py_buffer;
+ UfoBuffer *buffer;
+ UfoRequisition req;
+ PyArrayObject *np_array;
+ int np_ndims;
+ npy_intp *np_dims;
+ float *host_array;
+
+ if (!PyArg_ParseTuple(args, "OO!", &py_buffer, &PyArray_Type, &np_array))
+ return NULL;
+
+ buffer = UFO_BUFFER (pygobject_get (py_buffer));
+ ufo_buffer_get_requisition (buffer, &req);
+
+ np_ndims = PyArray_NDIM (np_array);
+ np_dims = PyArray_DIMS (np_array);
+
+ if (req.n_dims == np_ndims) {
+ for (int i = 0; i < np_ndims; i++) {
+ if (req.dims[i] != np_dims[i]) {
+ resize_buffer (buffer, req.n_dims, np_dims);
+ break;
+ }
+ }
+ }
+ else {
+ resize_buffer (buffer, np_ndims, np_dims);
+ }
+
+ host_array = ufo_buffer_get_host_array (buffer, NULL);
+ memcpy (host_array, PyArray_DATA (np_array), ufo_buffer_get_size (buffer));
+ return Py_BuildValue("");
+}
+
+static PyMethodDef exported_methods[] = {
+ {"asarray", ufo_asarray, METH_VARARGS, "Convert UfoBuffer to Numpy array"},
+ {"fromarray", ufo_fromarray, METH_VARARGS, "Convert Numpy array to UfoBuffer"},
+ {"fromarray_inplace", ufo_fromarray_inplace, METH_VARARGS, "Convert Numpy array to UfoBuffer in-place"},
+ {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC
+initufonp(void)
+{
+ PyObject *module = Py_InitModule("ufonp", exported_methods);
+
+ if (module == NULL)
+ return;
+
+ import_array();
+ init_pygobject();
+ module = PyImport_ImportModule("gobject");
+
+ if (module) {
+ PyGObject_Type = (PyTypeObject *) PyObject_GetAttrString(module, "GObject");
+ Py_DECREF(module);
+ }
+}
diff --git a/python/ufotools/__init__.py b/python/ufotools/__init__.py
deleted file mode 100644
index 30ecdf7..0000000
--- a/python/ufotools/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-class CallableFilter(object):
- def __init__(self, gobject, graph):
- self.gobject = gobject
- self.graph = graph
- self.name = gobject.get_plugin_name()
-
- def __call__(self, *args, **kwargs):
- n_inputs = self.gobject.get_num_inputs()
-
- if n_inputs != len(args):
- raise TypeError("`%s' receives only %i argument(s) but was called with %i parameters" % (self.name, n_inputs, len(args)))
-
- for i, target in enumerate(args):
- self.graph.connect_filters_full(target.gobject, 0, self.gobject, i, Ufo.TransferMode.DISTRIBUTE)
-
- return self
-
-
-class NodeFactory(object):
- def __init__(self, plugin_manager, graph):
- self.pm = plugin_manager
- self.graph = graph
-
- def get(self, name, **kwargs):
- gobject = self.pm.get_filter(name)
- gobject.set_properties(kwargs)
- return CallableFilter(gobject, graph)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 84736dd..a9b75cf 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,33 +1,24 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.6)
-# configure unit tests
set(TEST_SRCS
test-suite.c
- #test-buffer.c
- #test-channel.c
+ test-buffer.c
test-config.c
- #test-filter.c
- #test-filter-direct.c
test-graph.c
test-profiler.c
+ test-remote-node.c
+ test-mpi-remote-node.c
+ test-zmq-messenger.c
)
set(SUITE_BIN "test-suite")
-option(WITH_TESTS "Build test suite" ON)
+add_executable(${SUITE_BIN} ${TEST_SRCS})
-if (WITH_TESTS)
- include_directories(
- {CMAKE_CURRENT_SOURCE_DIR})
+target_link_libraries(${SUITE_BIN} ufo ${UFOCORE_DEPS})
- add_executable(${SUITE_BIN} ${TEST_SRCS})
+add_test(${SUITE_BIN} ${SUITE_BIN})
- target_link_libraries(${SUITE_BIN}
- ufo
- ${UFOCORE_DEPS})
-
- add_test(${SUITE_BIN} ${SUITE_BIN})
-
- configure_file("${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl"
- "${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl" @ONLY IMMEDIATE)
-endif()
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/gtester.xsl"
+ "${CMAKE_CURRENT_BINARY_DIR}/gtester.xsl"
+ @ONLY IMMEDIATE)
diff --git a/tests/test-buffer.c b/tests/test-buffer.c
new file mode 100644
index 0000000..89bf503
--- /dev/null
+++ b/tests/test-buffer.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <ufo.h>
+#include "test-suite.h"
+
+typedef struct {
+ UfoBuffer *buffer;
+ guint n_data;
+ const guint8 *data8;
+ const guint16 *data16;
+} Fixture;
+
+static void
+setup (Fixture *fixture, gconstpointer data)
+{
+ static const guint8 data8[8] = { 1, 2, 1, 3, 1, 255, 1, 254 };
+ static const guint16 data16[8] = { 1, 2, 1, 3, 1, 65535, 1, 65534 };
+
+ UfoRequisition requisition = {
+ .n_dims = 1,
+ .dims[0] = 8,
+ };
+
+ fixture->buffer = ufo_buffer_new (&requisition, NULL);
+ fixture->data8 = data8;
+ fixture->data16 = data16;
+ fixture->n_data = 8;
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer data)
+{
+ g_object_unref (fixture->buffer);
+}
+
+static void
+test_convert_8 (Fixture *fixture,
+ gconstpointer unused)
+{
+ gfloat *host_data;
+
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+ g_memmove (host_data, fixture->data8, fixture->n_data);
+
+ ufo_buffer_convert (fixture->buffer, UFO_BUFFER_DEPTH_8U);
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+
+ for (guint i = 0; i < fixture->n_data; i++)
+ g_assert (host_data[i] == ((gfloat) fixture->data8[i]));
+}
+
+static void
+test_convert_8_from_data (Fixture *fixture,
+ gconstpointer unused)
+{
+ gfloat *host_data;
+
+ ufo_buffer_convert_from_data (fixture->buffer, fixture->data8, UFO_BUFFER_DEPTH_8U);
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+
+ for (guint i = 0; i < fixture->n_data; i++)
+ g_assert (host_data[i] == ((gfloat) fixture->data8[i]));
+}
+
+static void
+test_convert_16 (Fixture *fixture,
+ gconstpointer unused)
+{
+ gfloat *host_data;
+
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+ g_memmove (host_data, fixture->data16, fixture->n_data * sizeof (guint16));
+
+ ufo_buffer_convert (fixture->buffer, UFO_BUFFER_DEPTH_16U);
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+
+ for (guint i = 0; i < fixture->n_data; i++)
+ g_assert (host_data[i] == ((gfloat) fixture->data16[i]));
+}
+
+static void
+test_convert_16_from_data (Fixture *fixture,
+ gconstpointer unused)
+{
+ gfloat *host_data;
+
+ ufo_buffer_convert_from_data (fixture->buffer, fixture->data16, UFO_BUFFER_DEPTH_16U);
+ host_data = ufo_buffer_get_host_array (fixture->buffer, NULL);
+
+ for (guint i = 0; i < fixture->n_data; i++)
+ g_assert (host_data[i] == ((gfloat) fixture->data16[i]));
+}
+
+void
+test_add_buffer (void)
+{
+ g_test_add ("/buffer/convert/8/host",
+ Fixture, NULL,
+ setup, test_convert_8, teardown);
+
+ g_test_add ("/buffer/convert/8/data",
+ Fixture, NULL,
+ setup, test_convert_8_from_data, teardown);
+
+ g_test_add ("/buffer/convert/16/host",
+ Fixture, NULL,
+ setup, test_convert_16, teardown);
+
+ g_test_add ("/buffer/convert/16/data",
+ Fixture, NULL,
+ setup, test_convert_16_from_data, teardown);
+}
diff --git a/tests/test-config.c b/tests/test-config.c
index 1f479e8..3000091 100644
--- a/tests/test-config.c
+++ b/tests/test-config.c
@@ -20,6 +20,27 @@
#include <ufo.h>
#include "test-suite.h"
+static gboolean
+path_in_array (const gchar *path,
+ GValueArray *array)
+{
+ gboolean found = FALSE;
+
+ for (guint i = 0; i < array->n_values; i++) {
+ if (!g_strcmp0 (path, g_value_get_string (g_value_array_get_nth (array, i))))
+ found = TRUE;
+ }
+
+ return found;
+}
+
+static gboolean
+path_in_list (const gchar *path,
+ GList *list)
+{
+ return g_list_find_custom (list, path, (GCompareFunc) g_strcmp0) != NULL;
+}
+
static void
test_path (void)
{
@@ -50,11 +71,9 @@ test_path (void)
"paths", &array,
NULL);
- g_assert (array->n_values == 2);
-
/* Check that paths match the ones we added */
- g_assert (g_strcmp0 (p1, g_value_get_string (g_value_array_get_nth (array, 0))) == 0);
- g_assert (g_strcmp0 (p2, g_value_get_string (g_value_array_get_nth (array, 1))) == 0);
+ g_assert (path_in_array (p1, array));
+ g_assert (path_in_array (p2, array));
g_value_array_free (array);
@@ -64,8 +83,8 @@ test_path (void)
g_assert (paths != NULL);
g_assert (g_list_length (paths) >= 2);
- g_assert (g_strcmp0 (p1, g_list_nth_data (paths, 0)) == 0);
- g_assert (g_strcmp0 (p2, g_list_nth_data (paths, 1)) == 0);
+ g_assert (path_in_list (p1, paths));
+ g_assert (path_in_list (p2, paths));
g_list_free (paths);
g_object_unref (object);
diff --git a/tests/test-graph.c b/tests/test-graph.c
index e9759ec..9cbfad3 100644
--- a/tests/test-graph.c
+++ b/tests/test-graph.c
@@ -23,11 +23,18 @@
typedef struct {
UfoGraph *graph;
UfoGraph *sequence;
+ UfoGraph *diamond;
UfoNode *root;
UfoNode *target1;
UfoNode *target2;
+ UfoNode *target3;
} Fixture;
+typedef struct {
+ const gchar *path;
+ void (*test_func) (Fixture *, gconstpointer);
+} TestCase;
+
static gpointer FOO_LABEL = GINT_TO_POINTER (0xDEADF00D);
static gpointer BAR_LABEL = GINT_TO_POINTER (0xF00BA);
static gpointer BAZ_LABEL = GINT_TO_POINTER (0xBA22BA22);
@@ -39,13 +46,15 @@ fixture_setup (Fixture *fixture, gconstpointer data)
g_assert (UFO_IS_GRAPH (fixture->graph));
fixture->sequence = ufo_graph_new ();
+ g_assert (UFO_IS_GRAPH (fixture->sequence));
- ufo_graph_register_node_type (fixture->graph, UFO_TYPE_NODE);
- ufo_graph_register_node_type (fixture->sequence, UFO_TYPE_NODE);
+ fixture->diamond = ufo_graph_new ();
+ g_assert (UFO_IS_GRAPH (fixture->diamond));
fixture->root = ufo_node_new (FOO_LABEL);
fixture->target1 = ufo_node_new (BAR_LABEL);
fixture->target2 = ufo_node_new (BAZ_LABEL);
+ fixture->target3 = ufo_node_new (FOO_LABEL);
ufo_graph_connect_nodes (fixture->graph,
fixture->root,
@@ -66,6 +75,26 @@ fixture_setup (Fixture *fixture, gconstpointer data)
fixture->target1,
fixture->target2,
FOO_LABEL);
+
+ ufo_graph_connect_nodes (fixture->diamond,
+ fixture->root,
+ fixture->target1,
+ BAR_LABEL);
+
+ ufo_graph_connect_nodes (fixture->diamond,
+ fixture->root,
+ fixture->target2,
+ BAR_LABEL);
+
+ ufo_graph_connect_nodes (fixture->diamond,
+ fixture->target1,
+ fixture->target3,
+ BAR_LABEL);
+
+ ufo_graph_connect_nodes (fixture->diamond,
+ fixture->target2,
+ fixture->target3,
+ BAR_LABEL);
}
static void
@@ -73,6 +102,10 @@ fixture_teardown (Fixture *fixture, gconstpointer data)
{
g_object_unref (fixture->graph);
g_object_unref (fixture->sequence);
+ g_object_unref (fixture->diamond);
+ g_object_unref (fixture->target1);
+ g_object_unref (fixture->target2);
+ g_object_unref (fixture->target3);
}
static void
@@ -124,6 +157,20 @@ test_get_num_edges (Fixture *fixture, gconstpointer data)
}
static void
+test_get_num_successors (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_get_num_successors (fixture->sequence, fixture->root) == 1);
+ g_assert (ufo_graph_get_num_successors (fixture->diamond, fixture->root) == 2);
+}
+
+static void
+test_get_num_predecessors (Fixture *fixture, gconstpointer data)
+{
+ g_assert (ufo_graph_get_num_predecessors (fixture->sequence, fixture->target1) == 1);
+ g_assert (ufo_graph_get_num_predecessors (fixture->diamond, fixture->target3) == 2);
+}
+
+static void
test_get_edges (Fixture *fixture, gconstpointer data)
{
GList *edges;
@@ -193,6 +240,8 @@ test_expansion (Fixture *fixture, gconstpointer data)
GList *successors;
UfoNode *node;
GList *path = NULL;
+ guint index;
+ guint other_index;
path = g_list_append (path, fixture->root);
path = g_list_append (path, fixture->target1);
@@ -205,6 +254,16 @@ test_expansion (Fixture *fixture, gconstpointer data)
g_assert (g_list_length (successors) == 2);
node = UFO_NODE (g_list_nth_data (successors, 0));
+ index = ufo_node_get_index (node);
+
+ g_assert ((index == 0) || (index == 1));
+ g_assert (ufo_node_get_total (node) == 2);
+
+ node = UFO_NODE (g_list_nth_data (successors, 1));
+ other_index = 1 - index;
+ g_assert (ufo_node_get_index (node) == other_index);
+ g_assert (ufo_node_get_total (node) == 2);
+
g_list_free (successors);
successors = ufo_graph_get_successors (fixture->sequence, node);
@@ -215,6 +274,48 @@ test_expansion (Fixture *fixture, gconstpointer data)
g_assert (ufo_node_equal (node, fixture->target2));
}
+static void
+test_copy (Fixture *fixture, gconstpointer data)
+{
+ UfoGraph *copy;
+ GList *roots;
+ GList *successors;
+ GError *error = NULL;
+
+ copy = ufo_graph_copy (fixture->graph, &error);
+ g_assert (copy != NULL);
+ g_assert_no_error (error);
+ g_assert (ufo_graph_get_num_edges (copy) == 2);
+ g_assert (ufo_graph_get_num_nodes (copy) == 3);
+
+ /* Check that copying preserved the order */
+ roots = ufo_graph_get_roots (copy);
+ g_assert (ufo_node_get_label (g_list_nth_data (roots, 0)) == FOO_LABEL);
+
+ successors = ufo_graph_get_successors (copy,
+ g_list_nth_data (roots, 0));
+
+ g_assert (ufo_node_get_label (g_list_nth_data (successors, 0)) == BAR_LABEL);
+ g_assert (ufo_node_get_label (g_list_nth_data (successors, 1)) == BAZ_LABEL);
+ g_list_free (successors);
+ g_list_free (roots);
+ g_object_unref (copy);
+
+ copy = ufo_graph_copy (fixture->sequence, &error);
+ g_assert (copy != NULL);
+ g_assert_no_error (error);
+ g_assert (ufo_graph_get_num_edges (copy) == 2);
+ g_assert (ufo_graph_get_num_nodes (copy) == 3);
+ g_object_unref (copy);
+
+ copy = ufo_graph_copy (fixture->diamond, &error);
+ g_assert (copy != NULL);
+ g_assert_no_error (error);
+ g_assert (ufo_graph_get_num_edges (copy) == 4);
+ g_assert (ufo_graph_get_num_nodes (copy) == 4);
+ g_object_unref (copy);
+}
+
static gboolean
always_true (UfoNode *node, gpointer user_data)
{
@@ -234,50 +335,60 @@ test_get_nodes_filtered (Fixture *fixture, gconstpointer data)
g_list_free (nodes);
}
-void
-test_add_graph (void)
+static void
+test_flatten (Fixture *fixture, gconstpointer data)
{
- g_test_add ("/graph/connected",
- Fixture, NULL,
- fixture_setup, test_connected, fixture_teardown);
-
- g_test_add ("/graph/nodes/number",
- Fixture, NULL,
- fixture_setup, test_get_num_nodes, fixture_teardown);
-
- g_test_add ("/graph/nodes/roots",
- Fixture, NULL,
- fixture_setup, test_get_roots, fixture_teardown);
-
- g_test_add ("/graph/nodes/successors",
- Fixture, NULL,
- fixture_setup, test_get_successors, fixture_teardown);
-
- g_test_add ("/graph/nodes/predecessors",
- Fixture, NULL,
- fixture_setup, test_get_predecessors, fixture_teardown);
+ GList *levels;
+ GList *roots;
+ GList *second_level;
+ GList *third_level;
- g_test_add ("/graph/nodes/filtered",
- Fixture, NULL,
- fixture_setup, test_get_nodes_filtered, fixture_teardown);
+ levels = ufo_graph_flatten (fixture->diamond);
+ g_assert (g_list_length (levels) == 3);
- g_test_add ("/graph/edges/number",
- Fixture, NULL,
- fixture_setup, test_get_num_edges, fixture_teardown);
+ roots = g_list_nth_data (levels, 0);
+ g_assert (g_list_length (roots) == 1);
+ g_assert (g_list_nth_data (roots, 0) == fixture->root);
+ g_list_free (roots);
- g_test_add ("/graph/edges/all",
- Fixture, NULL,
- fixture_setup, test_get_edges, fixture_teardown);
+ second_level = g_list_nth_data (levels, 1);
+ g_assert (g_list_length (second_level) == 2);
+ g_assert (g_list_find (second_level, fixture->target1) != NULL);
+ g_assert (g_list_find (second_level, fixture->target2) != NULL);
+ g_list_free (second_level);
- g_test_add ("/graph/edges/remove",
- Fixture, NULL,
- fixture_setup, test_remove_edge, fixture_teardown);
+ third_level = g_list_nth_data (levels, 2);
+ g_assert (g_list_length (third_level) == 1);
+ g_assert (g_list_find (third_level, fixture->target3) != NULL);
+ g_list_free (third_level);
- g_test_add ("/graph/labels",
- Fixture, NULL,
- fixture_setup, test_get_labels, fixture_teardown);
+ g_list_free (levels);
+}
- g_test_add ("/graph/expansion",
- Fixture, NULL,
- fixture_setup, test_expansion, fixture_teardown);
+void
+test_add_graph (void)
+{
+ TestCase test_cases[] = {
+ { "/graph/connected", test_connected },
+ { "/graph/nodes/number", test_get_num_nodes },
+ { "/graph/nodes/roots", test_get_roots },
+ { "/graph/nodes/successors", test_get_successors },
+ { "/graph/nodes/successors/num", test_get_num_successors },
+ { "/graph/nodes/predecessors", test_get_predecessors },
+ { "/graph/nodes/predecessors/num", test_get_num_predecessors },
+ { "/graph/nodes/filtered", test_get_nodes_filtered },
+ { "/graph/edges/number", test_get_num_edges },
+ { "/graph/edges/all", test_get_edges },
+ { "/graph/edges/remove", test_remove_edge },
+ { "/graph/labels", test_get_labels },
+ { "/graph/expansion", test_expansion },
+ { "/graph/copy", test_copy },
+ { "/graph/flatten", test_flatten },
+ { NULL, NULL }
+ };
+
+ for (guint i = 0; test_cases[i].path != NULL; i++) {
+ g_test_add (test_cases[i].path, Fixture, NULL,
+ fixture_setup, test_cases[i].test_func, fixture_teardown);
+ }
}
diff --git a/tests/test-mpi-remote-node.c b/tests/test-mpi-remote-node.c
new file mode 100644
index 0000000..fc55c71
--- /dev/null
+++ b/tests/test-mpi-remote-node.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* needed to avoid emty translation unit warning */
+void __unused_test_mpi_remote_fn_(void);
+
+#ifdef MPI
+
+#include <string.h>
+#include <ufo.h>
+#include "test-suite.h"
+#include <mpi.h>
+#include <unistd.h>
+
+typedef struct {
+ UfoDaemon *daemon;
+ UfoConfig *config;
+ UfoRemoteNode **remote_nodes;
+ gint global_size;
+ gint rank;
+} Fixture;
+
+static void
+setup (Fixture *fixture, gconstpointer data)
+{
+ fixture->config = ufo_config_new ();
+ int size, rank;
+
+ MPI_Comm_rank (MPI_COMM_WORLD, &rank);
+ MPI_Comm_size (MPI_COMM_WORLD, &size);
+ fixture->global_size = size;
+ fixture->rank = rank;
+
+ if (fixture->rank == 0) {
+ g_message ("Number of mpi processes: %d", fixture->global_size);
+ g_message ("Number of remote_nodes: %d", fixture->global_size - 1);
+ fixture->remote_nodes = g_malloc0 (fixture->global_size - 1);
+ // create remote nodes
+ for (int i = 0; i < fixture->global_size - 1; i++) {
+ gchar *addr = g_strdup_printf("%d", i+1);
+ fixture->remote_nodes[i] = (UfoRemoteNode *) ufo_remote_node_new (addr);
+ }
+ } else {
+ gchar *addr = g_strdup_printf("%d", rank);
+ fixture->daemon = ufo_daemon_new (fixture->config, addr);
+ ufo_daemon_start (fixture->daemon);
+ }
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer data)
+{
+ g_message ("teardown");
+ if (fixture->rank == 0) {
+ for (int i = 1; i <= fixture->global_size - 1; i++) {
+ UfoRemoteNode *node = fixture->remote_nodes[i-1];
+ ufo_remote_node_terminate (node);
+ g_object_unref (node);
+ g_message ("teardown node %d done", i-1);
+ }
+ } else {
+ ufo_daemon_wait_finish (fixture->daemon);
+ g_object_unref (fixture->daemon);
+ g_message ("teardown done");
+ }
+}
+
+static void
+test_remote_node_get_num_cpus (Fixture *fixture,
+ gconstpointer unused)
+{
+ if (fixture->rank == 0) {
+ for (int i = 1; i <= fixture->global_size - 1; i++) {
+ guint n_gpus = ufo_remote_node_get_num_gpus (fixture->remote_nodes[i-1]);
+ g_message ("Found %d number of GPUs at remotenode %d", n_gpus, i);
+ g_assert (n_gpus > 0);
+ }
+ }
+}
+
+static void
+test_remote_node_get_structure (Fixture *fixture,
+ gconstpointer unused)
+{
+ if (fixture->rank == 0) {
+ for (int i = 1; i <= fixture->global_size - 1 ; i++) {
+ UfoTaskMode mode;
+ UfoInputParam *in_params;
+ guint n_inputs;
+ ufo_remote_node_get_structure (fixture->remote_nodes[i-1], &n_inputs, &in_params, &mode);
+ g_message ("received n_inputs == %d from remote node %d", n_inputs, i);
+ g_assert (n_inputs == 1);
+ g_message ("received n_dims == %d from remote node %d", in_params->n_dims, i);
+ g_assert (in_params->n_dims == 2);
+ }
+ }
+}
+
+void
+test_add_mpi_remote_node (void)
+{
+ g_test_add ("/remotenode/get_structure",
+ Fixture, NULL,
+ setup, test_remote_node_get_structure, teardown);
+ g_test_add ("/remotenode/get_num_cpus",
+ Fixture, NULL,
+ setup, test_remote_node_get_num_cpus, teardown);
+}
+
+#endif
\ No newline at end of file
diff --git a/tests/test-profiler.c b/tests/test-profiler.c
index ce9b4ae..a0ab79d 100644
--- a/tests/test-profiler.c
+++ b/tests/test-profiler.c
@@ -32,8 +32,7 @@ typedef struct {
static void
fixture_setup (Fixture *fixture, gconstpointer data)
{
- fixture->profiler = ufo_profiler_new (UFO_PROFILER_LEVEL_OPENCL |
- UFO_PROFILER_LEVEL_IO);
+ fixture->profiler = ufo_profiler_new ();
g_assert (UFO_IS_PROFILER (fixture->profiler));
}
diff --git a/tests/test-remote-node.c b/tests/test-remote-node.c
new file mode 100644
index 0000000..8642988
--- /dev/null
+++ b/tests/test-remote-node.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <ufo.h>
+#include "test-suite.h"
+
+typedef struct {
+ UfoDaemon *daemon;
+ UfoConfig *config;
+ UfoRemoteNode *remote_node;
+} Fixture;
+
+static void
+setup (Fixture *fixture, gconstpointer data)
+{
+ gchar *addr = g_strdup ("tcp://127.0.0.1:5555");
+ fixture->config = ufo_config_new ();
+
+ fixture->daemon = ufo_daemon_new (fixture->config, addr);
+ ufo_daemon_start (fixture->daemon);
+
+ fixture->remote_node = (UfoRemoteNode *) ufo_remote_node_new (addr);
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer data)
+{
+ g_object_unref (fixture->remote_node);
+ ufo_daemon_stop (fixture->daemon);
+
+ g_object_unref (fixture->daemon);
+}
+
+static void
+test_remote_node_get_num_cpus (Fixture *fixture,
+ gconstpointer unused)
+{
+ guint n_gpus = ufo_remote_node_get_num_gpus (fixture->remote_node);
+ g_debug ("Found %d number of GPUs at remotenode", n_gpus);
+ g_assert (n_gpus > 0);
+}
+
+static void
+test_remote_node_get_structure (Fixture *fixture,
+ gconstpointer unused)
+{
+ UfoTaskMode mode;
+ UfoInputParam *in_params;
+ guint n_inputs;
+ ufo_remote_node_get_structure (fixture->remote_node, &n_inputs, &in_params, &mode);
+ g_message ("received n_inputs == %d", n_inputs);
+ g_assert (n_inputs == 1);
+ g_message ("received n_dims == %d", in_params->n_dims);
+ g_assert (in_params->n_dims == 2);
+
+}
+
+void
+test_add_remote_node (void)
+{
+ g_test_add ("/remotenode/get_structure",
+ Fixture, NULL,
+ setup, test_remote_node_get_structure, teardown);
+ g_test_add ("/remotenode/get_num_cpus",
+ Fixture, NULL,
+ setup, test_remote_node_get_num_cpus, teardown);
+}
diff --git a/tests/test-suite.c b/tests/test-suite.c
index d16b214..a649369 100644
--- a/tests/test-suite.c
+++ b/tests/test-suite.c
@@ -19,6 +19,9 @@
#include <glib-object.h>
#include "test-suite.h"
+#ifdef MPI
+#include <mpi.h>
+#endif
static void
ignore_log (const gchar *domain,
@@ -26,6 +29,7 @@ ignore_log (const gchar *domain,
const gchar *message,
gpointer data)
{
+ g_print ("%s\n",message);
}
int main(int argc, char *argv[])
@@ -34,14 +38,27 @@ int main(int argc, char *argv[])
g_test_init(&argc, &argv, NULL);
g_test_bug_base("http://ufo.kit.edu/ufo/ticket");
+ // g_log_set_handler ("Ufo", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO, ignore_log, NULL);
g_log_set_handler ("Ufo", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, ignore_log, NULL);
g_log_set_handler ("ocl", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, ignore_log, NULL);
+ test_add_buffer ();
test_add_config ();
test_add_graph ();
test_add_profiler ();
-
+#ifdef MPI
+ int provided;
+ MPI_Init_thread (&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
+ test_add_mpi_remote_node ();
+#else
+ test_add_zmq_messenger ();
+ test_add_remote_node ();
+#endif
g_test_run();
+#ifdef MPI
+ MPI_Finalize ();
+#endif
+
return 0;
}
diff --git a/tests/test-suite.h b/tests/test-suite.h
index 02bf8ff..bae1d66 100644
--- a/tests/test-suite.h
+++ b/tests/test-suite.h
@@ -1,8 +1,12 @@
#ifndef TEST_SUITE_H
#define TEST_SUITE_H
+void test_add_buffer (void);
void test_add_config (void);
void test_add_graph (void);
void test_add_profiler (void);
+void test_add_remote_node (void);
+void test_add_mpi_remote_node (void);
+void test_add_zmq_messenger (void);
#endif
diff --git a/tests/test-zmq-messenger.c b/tests/test-zmq-messenger.c
new file mode 100644
index 0000000..76fc96c
--- /dev/null
+++ b/tests/test-zmq-messenger.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo.h>
+#include <ufo/ufo-zmq-messenger.h>
+#include "test-suite.h"
+
+typedef struct {
+ gchar *addr;
+} Fixture;
+
+static void
+setup (Fixture *fixture, gconstpointer data)
+{
+ fixture->addr = g_strdup ("tcp://127.0.0.1:5555");
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer data)
+{
+ g_free (fixture->addr);
+}
+
+static void send_num_devices_request (gpointer unused)
+{
+ UfoMessenger *msger = UFO_MESSENGER (ufo_zmq_messenger_new ());
+ gchar *addr = g_strdup ("tcp://127.0.0.1:5555");
+ ufo_messenger_connect (msger, addr, UFO_MESSENGER_CLIENT);
+
+ guint x = 0;
+ while (x++ < 10) {
+ UfoMessage *request = ufo_message_new (UFO_MESSAGE_GET_NUM_DEVICES, 0);
+ UfoMessage *response;
+
+ response = ufo_messenger_send_blocking (msger, request, NULL);
+
+ guint16 num_devices = *(guint16 *) response->data;
+ g_assert (num_devices == x);
+
+ ufo_message_free (request);
+ ufo_message_free (response);
+ }
+ ufo_zmq_messenger_disconnect (msger);
+ g_object_unref (msger);
+}
+
+static void handle_num_devices (gpointer unused)
+{
+ UfoMessenger *msger = UFO_MESSENGER (ufo_zmq_messenger_new ());
+ gchar *addr = g_strdup ("tcp://127.0.0.1:5555");
+ ufo_messenger_connect (msger, addr, UFO_MESSENGER_SERVER);
+
+ guint16 x = 0;
+ GError *err = NULL;
+ while (x++ < 10) {
+ UfoMessage *msg = ufo_messenger_recv_blocking (UFO_MESSENGER (msger), &err);
+ if (err != NULL)
+ g_critical ("%s", err->message);
+
+ UfoMessage *resp;
+ switch (msg->type) {
+ case UFO_MESSAGE_GET_NUM_DEVICES:
+ resp = ufo_message_new (UFO_MESSAGE_ACK, sizeof (guint16));
+ *(guint16 *)resp->data = x;
+ ufo_zmq_messenger_send_blocking (msger, resp, NULL);
+ ufo_message_free (resp);
+ break;
+ default:
+ g_critical ("Unexpected message type: %d", msg->type);
+ break;
+ }
+ ufo_message_free (msg);
+ };
+
+ ufo_zmq_messenger_disconnect (msger);
+ g_object_unref (msger);
+}
+
+static void test_zmq_messenger (Fixture *fixture, gconstpointer unused)
+{
+ GThread *server = g_thread_create ((GThreadFunc) handle_num_devices, NULL, TRUE, NULL);
+ GThread *client = g_thread_create ((GThreadFunc) send_num_devices_request, NULL, TRUE, NULL);
+
+ g_thread_join (client);
+ g_thread_join (server);
+}
+
+
+void
+test_add_zmq_messenger (void)
+{
+ g_test_add ("/zmq_messenger/test_messenger",
+ Fixture, NULL,
+ setup, test_zmq_messenger, teardown);
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 48af150..f64f29f 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.6)
add_executable(runjson runjson.c)
add_executable(ufod ufod.c)
@@ -7,7 +7,4 @@ target_link_libraries(runjson ufo ${UFOCORE_DEPS})
target_link_libraries(ufod ufo ${UFOCORE_DEPS})
install(TARGETS ufod runjson
- RUNTIME DESTINATION bin)
-
-install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/clprof
- DESTINATION bin)
+ RUNTIME DESTINATION ${UFO_BINDIR})
diff --git a/tools/runjson.c b/tools/runjson.c
index e108437..f121688 100644
--- a/tools/runjson.c
+++ b/tools/runjson.c
@@ -21,6 +21,12 @@
#include <stdlib.h>
#include <ufo/ufo.h>
+#ifdef MPI
+#include <mpi.h>
+#include <ufo/ufo-mpi-messenger.h>
+#include <unistd.h>
+#endif
+
static void
handle_error (const gchar *prefix, GError *error, UfoGraph *graph)
{
@@ -45,25 +51,31 @@ string_array_to_list (gchar **array)
return result;
}
+static UfoConfig *
+get_config (gchar **paths)
+{
+ GList *path_list = NULL;
+ UfoConfig *config;
+
+ config = ufo_config_new ();
+ path_list = string_array_to_list (paths);
+ ufo_config_add_paths (config, path_list);
+
+ g_list_free (path_list);
+ return config;
+}
+
static void
execute_json (const gchar *filename,
- gchar **paths,
+ UfoConfig *config,
gchar **addresses)
{
- UfoConfig *config;
UfoTaskGraph *task_graph;
UfoScheduler *scheduler;
UfoPluginManager *manager;
- GList *path_list = NULL;
GList *address_list = NULL;
GError *error = NULL;
- config = ufo_config_new ();
-
- path_list = string_array_to_list (paths);
- ufo_config_add_paths (config, path_list);
- g_list_free (path_list);
-
manager = ufo_plugin_manager_new (config);
task_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
@@ -80,9 +92,76 @@ execute_json (const gchar *filename,
g_object_unref (task_graph);
g_object_unref (scheduler);
g_object_unref (manager);
- g_object_unref (config);
}
+#ifdef MPI
+
+static void
+mpi_terminate_processes (gint global_size)
+{
+ for (int i = 1; i < global_size; i++) {
+ gchar *addr = g_strdup_printf ("%d", i);
+ UfoMessage *poisonpill = ufo_message_new (UFO_MESSAGE_TERMINATE, 0);
+ UfoMessenger *msger = UFO_MESSENGER (ufo_mpi_messenger_new ());
+ ufo_mpi_messenger_connect (msger, addr, UFO_MESSENGER_CLIENT);
+ g_debug ("sending poisonpill to %s", addr);
+ ufo_messenger_send_blocking (msger, poisonpill, NULL);
+ ufo_message_free (poisonpill);
+ ufo_messenger_disconnect (msger);
+ }
+}
+
+static gchar**
+mpi_build_addresses (gint global_size)
+{
+ /* build addresses by MPI_COMM_WORLD size, exclude rank 0 but
+ have room for NULL termination */
+ gchar **addresses = g_malloc (sizeof (gchar *) * global_size);
+ for (int i = 1; i < global_size; i++) {
+ addresses[i - 1] = g_strdup_printf ("%d", i);
+ }
+ addresses[global_size - 1] = NULL;
+
+ return addresses;
+}
+
+static void
+mpi_init (int *argc, char *argv[], gint *rank, gint *global_size)
+{
+ gint provided;
+ MPI_Init_thread (argc, &argv, MPI_THREAD_MULTIPLE, &provided);
+
+ MPI_Comm_rank (MPI_COMM_WORLD, rank);
+ MPI_Comm_size (MPI_COMM_WORLD, global_size);
+
+ if (*global_size == 1) {
+ g_critical ("Warning: running MPI instance but found only single process");
+ exit (0);
+ }
+
+#ifdef DEBUG
+ // get us some time to attach a gdb session to the pids
+ g_debug ("Process PID %d ranked %d of %d - ready for attach\n",
+ getpid(), rank, *global_size - 1);
+
+ sleep (3);
+#endif
+
+}
+
+#endif
+
+#ifdef DEBUG
+static void
+ignore_log (const gchar *domain,
+ GLogLevelFlags flags,
+ const gchar *message,
+ gpointer data)
+{
+ g_print ("%s\n",message);
+}
+#endif
+
int main(int argc, char *argv[])
{
GOptionContext *context;
@@ -90,12 +169,15 @@ int main(int argc, char *argv[])
gchar **paths = NULL;
gchar **addresses = NULL;
gboolean show_version = FALSE;
+ UfoConfig *config = NULL;
GOptionEntry entries[] = {
{ "path", 'p', 0, G_OPTION_ARG_STRING_ARRAY, &paths,
"Path to node plugins or OpenCL kernels", NULL },
+#ifndef MPI
{ "address", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &addresses,
"Address of remote server running `ufod'", NULL },
+#endif
{ "version", 'v', 0, G_OPTION_ARG_NONE, &show_version,
"Show version information", NULL },
{ NULL }
@@ -103,6 +185,10 @@ int main(int argc, char *argv[])
g_type_init();
+#ifdef DEBUG
+ g_log_set_handler ("Ufo", G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, ignore_log, NULL);
+#endif
+
context = g_option_context_new ("FILE");
g_option_context_add_main_entries (context, entries, NULL);
@@ -125,11 +211,37 @@ int main(int argc, char *argv[])
return 1;
}
- execute_json (argv[argc-1], paths, addresses);
+ config = get_config (paths);
+
+#ifdef MPI
+ gint rank, size;
+ mpi_init (&argc, argv, &rank, &size);
+
+ if (rank == 0) {
+ addresses = mpi_build_addresses (size);
+ } else {
+ gchar *addr = g_strdup_printf("%d", rank);
+ UfoDaemon *daemon = ufo_daemon_new (config, addr);
+ ufo_daemon_start (daemon);
+ ufo_daemon_wait_finish (daemon);
+ MPI_Finalize ();
+ exit(EXIT_SUCCESS);
+ }
+#endif
+
+ execute_json (argv[argc-1], config, addresses);
+
+#ifdef MPI
+ if (rank == 0) {
+ mpi_terminate_processes (size);
+ MPI_Finalize ();
+ }
+#endif
g_strfreev (paths);
g_strfreev (addresses);
g_option_context_free (context);
+ g_object_unref (config);
return 0;
}
diff --git a/tools/ufod.c b/tools/ufod.c
index 6caabae..d7f29b7 100644
--- a/tools/ufod.c
+++ b/tools/ufod.c
@@ -24,293 +24,18 @@
#else
#include <CL/cl.h>
#endif
-#include <zmq.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <ufo/ufo.h>
-typedef struct {
- UfoConfig *config;
- UfoPluginManager *manager;
- UfoTaskGraph *task_graph;
- UfoScheduler *scheduler;
- gpointer socket;
- UfoNode *input_task;
- UfoNode *output_task;
- UfoBuffer *input;
-} ServerPrivate;
+static UfoDaemon *daemon;
typedef struct {
gchar **paths;
gchar *addr;
} Options;
-#define CHECK_ZMQ(r) if (r == -1) g_warning ("%s:%i: zmq_error: %s\n", __FILE__, __LINE__, zmq_strerror (errno));
-
-static gpointer run_scheduler (ServerPrivate *priv);
-
-static void
-ufo_msg_send (UfoMessage *msg, gpointer socket, gint flags)
-{
- zmq_msg_t reply;
-
- zmq_msg_init_size (&reply, sizeof (UfoMessage));
- memcpy (zmq_msg_data (&reply), msg, sizeof (UfoMessage));
- zmq_msg_send (&reply, socket, flags);
- zmq_msg_close (&reply);
-}
-
-static void
-send_ack (gpointer socket)
-{
- UfoMessage msg;
- msg.type = UFO_MESSAGE_ACK;
- ufo_msg_send (&msg, socket, 0);
-}
-
-static void
-handle_get_num_devices (ServerPrivate *priv)
-{
- UfoMessage msg;
- cl_context context;
-
- context = ufo_scheduler_get_context (priv->scheduler);
-
- UFO_RESOURCES_CHECK_CLERR (clGetContextInfo (context,
- CL_CONTEXT_NUM_DEVICES,
- sizeof (cl_uint),
- &msg.d.n_devices,
- NULL));
-
- ufo_msg_send (&msg, priv->socket, 0);
-}
-
-static UfoNode *
-remove_dummy_if_present (UfoGraph *graph,
- UfoNode *first)
-{
- UfoNode *real = first;
-
- if (UFO_IS_DUMMY_TASK (first)) {
- UfoNode *dummy;
- GList *successors;
-
- dummy = first;
- successors = ufo_graph_get_successors (graph, dummy);
- g_assert (g_list_length (successors) == 1);
- real = UFO_NODE (successors->data);
- g_list_free (successors);
- ufo_graph_remove_edge (graph, dummy, real);
- }
-
- return real;
-}
-
-static void
-handle_json (ServerPrivate *priv)
-{
- zmq_msg_t json_msg;
- gsize size;
- gchar *json;
- GList *roots;
- GList *leaves;
- UfoNode *first;
- UfoNode *last;
- GError *error = NULL;
-
- zmq_msg_init (&json_msg);
- size = (gsize) zmq_msg_recv (&json_msg, priv->socket, 0);
-
- json = g_malloc0 (size + 1);
- memcpy (json, zmq_msg_data (&json_msg), size);
- zmq_msg_close (&json_msg);
-
- /* Setup local task graph */
- priv->task_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
- ufo_task_graph_read_from_data (priv->task_graph, priv->manager, json, &error);
-
- if (error != NULL) {
- g_printerr ("%s\n", error->message);
- /* Send error to master */
- return;
- }
-
- roots = ufo_graph_get_roots (UFO_GRAPH (priv->task_graph));
- g_assert (g_list_length (roots) == 1);
-
- leaves = ufo_graph_get_leaves (UFO_GRAPH (priv->task_graph));
- g_assert (g_list_length (leaves) == 1);
-
- first = UFO_NODE (g_list_nth_data (roots, 0));
- last = UFO_NODE (g_list_nth_data (leaves, 0));
-
- first = remove_dummy_if_present (UFO_GRAPH (priv->task_graph), first);
-
- priv->input_task = ufo_input_task_new ();
- priv->output_task = ufo_output_task_new (2);
-
- ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
- priv->input_task, first,
- GINT_TO_POINTER (0));
-
- ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
- last, priv->output_task,
- GINT_TO_POINTER (0));
-
- g_thread_create ((GThreadFunc) run_scheduler, priv, FALSE, NULL);
- g_free (json);
- send_ack (priv->socket);
-}
-
-static void
-handle_setup (ServerPrivate *priv)
-{
- g_message ("Setup requested");
- send_ack (priv->socket);
-}
-
-static void
-handle_get_structure (ServerPrivate *priv)
-{
- UfoMessage header;
- UfoInputParam in_param;
- zmq_msg_t data_msg;
-
- g_message ("Structure requested");
- header.type = UFO_MESSAGE_STRUCTURE;
-
- /* TODO: do not hardcode these */
- header.d.n_inputs = 1;
- in_param.n_dims = 2;
-
- zmq_msg_init_size (&data_msg, sizeof (UfoInputParam));
- memcpy (zmq_msg_data (&data_msg), &in_param, sizeof (UfoInputParam));
-
- ufo_msg_send (&header, priv->socket, ZMQ_SNDMORE);
- zmq_msg_send (&data_msg, priv->socket, 0);
- zmq_msg_close (&data_msg);
-}
-
-static void
-handle_send_inputs (ServerPrivate *priv)
-{
- UfoRequisition *requisition;
- zmq_msg_t requisition_msg;
- zmq_msg_t data_msg;
- gpointer context;
-
- context = ufo_scheduler_get_context (priv->scheduler);
-
- /* Receive buffer size */
- zmq_msg_init (&requisition_msg);
- zmq_msg_recv (&requisition_msg, priv->socket, 0);
- g_assert (zmq_msg_size (&requisition_msg) >= sizeof (UfoRequisition));
- requisition = zmq_msg_data (&requisition_msg);
-
- if (priv->input == NULL) {
- priv->input = ufo_buffer_new (requisition, context);
- }
- else {
- if (ufo_buffer_cmp_dimensions (priv->input, requisition))
- ufo_buffer_resize (priv->input, requisition);
- }
-
- zmq_msg_close (&requisition_msg);
-
- /* Receive actual buffer */
- zmq_msg_init (&data_msg);
- zmq_msg_recv (&data_msg, priv->socket, 0);
-
- memcpy (ufo_buffer_get_host_array (priv->input, NULL),
- zmq_msg_data (&data_msg),
- ufo_buffer_get_size (priv->input));
-
- ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task), priv->input);
- zmq_msg_close (&data_msg);
-
- send_ack (priv->socket);
-}
-
-static void
-handle_get_requisition (ServerPrivate *priv)
-{
- UfoRequisition requisition;
- zmq_msg_t reply_msg;
-
- /* We need to get the requisition from the last node */
- g_message ("Requisition requested");
- ufo_output_task_get_output_requisition (UFO_OUTPUT_TASK (priv->output_task),
- &requisition);
-
- zmq_msg_init_size (&reply_msg, sizeof (UfoRequisition));
- memcpy (zmq_msg_data (&reply_msg), &requisition, sizeof (UfoRequisition));
- zmq_msg_send (&reply_msg, priv->socket, 0);
- zmq_msg_close (&reply_msg);
-}
-
-static
-void handle_get_result (ServerPrivate *priv)
-{
- UfoBuffer *buffer;
- zmq_msg_t reply_msg;
- gsize size;
-
- buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (priv->output_task));
- size = ufo_buffer_get_size (buffer);
-
- zmq_msg_init_size (&reply_msg, size);
- memcpy (zmq_msg_data (&reply_msg), ufo_buffer_get_host_array (buffer, NULL), size);
- zmq_msg_send (&reply_msg, priv->socket, 0);
- zmq_msg_close (&reply_msg);
- ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (priv->output_task), buffer);
-}
-
-static void
-unref_and_free (GObject **object)
-{
- if (*object) {
- g_object_unref (*object);
- *object = NULL;
- }
-}
-
-static
-void handle_cleanup (ServerPrivate *priv)
-{
- /*
- * We send the ACK early on, because we don't want to let the host wait for
- * actually cleaning up (and waiting some time to unref the input task).
- */
- send_ack (priv->socket);
-
- if (priv->input_task) {
- ufo_input_task_stop (UFO_INPUT_TASK (priv->input_task));
-
- ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task),
- priv->input);
-
- g_usleep (1.5 * G_USEC_PER_SEC);
- unref_and_free ((GObject **) &priv->input_task);
- unref_and_free ((GObject **) &priv->input);
- }
-
- unref_and_free ((GObject **) &priv->output_task);
- unref_and_free ((GObject **) &priv->task_graph);
-}
-
-static gpointer
-run_scheduler (ServerPrivate *priv)
-{
- g_message ("Start scheduler");
- ufo_scheduler_run (priv->scheduler, priv->task_graph, NULL);
-
- g_message ("Done");
- g_object_unref (priv->scheduler);
-
- priv->scheduler = ufo_scheduler_new (priv->config, NULL);
- return NULL;
-}
-
static Options *
opts_parse (gint *argc, gchar ***argv)
{
@@ -354,7 +79,7 @@ opts_parse (gint *argc, gchar ***argv)
}
static UfoConfig *
-opts_new_config (Options *opts)
+opts_new_config (const Options *opts)
{
UfoConfig *config;
GList *paths = NULL;
@@ -363,7 +88,7 @@ opts_new_config (Options *opts)
if (opts->paths != NULL) {
for (guint i = 0; opts->paths[i] != NULL; i++)
- paths = g_list_append (paths, opts->paths[i]);
+ paths = g_list_append (paths, g_strdup (opts->paths[i]));
ufo_config_add_paths (config, paths);
g_list_free (paths);
@@ -380,12 +105,25 @@ opts_free (Options *opts)
g_free (opts);
}
+static void
+terminate (int signum)
+{
+ if (signum == SIGTERM)
+ g_print ("Received SIGTERM, exiting...\n");
+ if (signum == SIGINT)
+ g_print ("Received SIGINT, exiting...\n");
+
+ if (daemon != NULL) {
+ ufo_daemon_stop(daemon);
+ g_object_unref (daemon);
+ }
+ exit (EXIT_SUCCESS);
+}
+
int
main (int argc, char * argv[])
{
- gpointer context;
Options *opts;
- ServerPrivate priv;
g_type_init ();
g_thread_init (NULL);
@@ -393,75 +131,21 @@ main (int argc, char * argv[])
if ((opts = opts_parse (&argc, &argv)) == NULL)
return 1;
- memset (&priv, 0, sizeof (ServerPrivate));
-
- priv.config = opts_new_config (opts);
- priv.manager = ufo_plugin_manager_new (priv.config);
- priv.scheduler = ufo_scheduler_new (priv.config, NULL);
+ /* Now, install SIGTERM/SIGINT handler */
+ (void) signal (SIGTERM, terminate);
+ (void) signal (SIGINT, terminate);
- /* start zmq service */
- context = zmq_ctx_new ();
- priv.socket = zmq_socket (context, ZMQ_REP);
- zmq_bind (priv.socket, opts->addr);
+ UfoConfig *config = opts_new_config (opts);
- g_print ("ufod %s - waiting for requests ...\n", UFO_VERSION);
+ daemon = ufo_daemon_new (config, opts->addr);
+ ufo_daemon_start(daemon);
+ g_print ("ufod %s - waiting for requests on %s ...\n", UFO_VERSION,
+ opts->addr);
- while (1) {
- zmq_msg_t request;
-
- zmq_msg_init (&request);
- zmq_msg_recv (&request, priv.socket, 0);
-
- if (zmq_msg_size (&request) < sizeof (UfoMessage)) {
- g_warning ("Message is smaller than expected\n");
- send_ack (priv.socket);
- }
- else {
- UfoMessage *msg;
-
- msg = (UfoMessage *) zmq_msg_data (&request);
-
- switch (msg->type) {
- case UFO_MESSAGE_GET_NUM_DEVICES:
- handle_get_num_devices (&priv);
- break;
- case UFO_MESSAGE_TASK_JSON:
- handle_json (&priv);
- break;
- case UFO_MESSAGE_SETUP:
- handle_setup (&priv);
- break;
- case UFO_MESSAGE_GET_STRUCTURE:
- handle_get_structure (&priv);
- break;
- case UFO_MESSAGE_SEND_INPUTS:
- handle_send_inputs (&priv);
- break;
- case UFO_MESSAGE_GET_REQUISITION:
- handle_get_requisition (&priv);
- break;
- case UFO_MESSAGE_GET_RESULT:
- handle_get_result (&priv);
- break;
- case UFO_MESSAGE_CLEANUP:
- handle_cleanup (&priv);
- break;
- default:
- g_print ("unhandled case\n");
- }
- }
-
- zmq_msg_close (&request);
+ while (TRUE) {
+ g_usleep (G_MAXULONG);
}
- g_object_unref (priv.task_graph);
- g_object_unref (priv.config);
- g_object_unref (priv.manager);
- g_object_unref (priv.scheduler);
-
- zmq_close (priv.socket);
- zmq_ctx_destroy (context);
-
opts_free (opts);
return 0;
diff --git a/ufo/CMakeLists.txt b/ufo/CMakeLists.txt
index 6dc6dee..8573fc6 100644
--- a/ufo/CMakeLists.txt
+++ b/ufo/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 2.6)
-# --- Set sources -------------------------------------------------------------
+#{{{ Sources
set(ufocore_SRCS
ufo-arch-graph.c
ufo-buffer.c
@@ -8,12 +8,14 @@ set(ufocore_SRCS
ufo-config.c
ufo-cpu-node.c
ufo-cpu-task-iface.c
+ ufo-daemon.c
ufo-dummy-task.c
ufo-gpu-node.c
ufo-gpu-task-iface.c
ufo-graph.c
ufo-group.c
ufo-input-task.c
+ ufo-messenger-iface.c
ufo-node.c
ufo-output-task.c
ufo-plugin-manager.c
@@ -25,8 +27,12 @@ set(ufocore_SRCS
ufo-task-iface.c
ufo-task-graph.c
ufo-task-node.c
+ ufo-basic-ops.c
+ ufo-zmq-messenger.c
)
+#}}}
+#{{{ Public headers
set(ufocore_HDRS
ufo-arch-graph.h
ufo-buffer.h
@@ -34,12 +40,14 @@ set(ufocore_HDRS
ufo-config.h
ufo-cpu-node.h
ufo-cpu-task-iface.h
+ ufo-daemon.h
ufo-dummy-task.h
ufo-gpu-node.h
ufo-gpu-task-iface.h
ufo-graph.h
ufo-group.h
ufo-input-task.h
+ ufo-messenger-iface.h
ufo-node.h
ufo-output-task.h
ufo-plugin-manager.h
@@ -51,44 +59,32 @@ set(ufocore_HDRS
ufo-task-iface.h
ufo-task-graph.h
ufo-task-node.h
+ ufo-basic-ops.h
+ ufo-zmq-messenger.h
)
+#}}}
+if(WITH_MPI)
+ set(ufocore_HDRS ${ufocore_HDRS}
+ ufo-mpi-messenger.h
+ )
+ set(ufocore_SRCS ${ufocore_SRCS}
+ ufo-mpi-messenger.c
+ )
+endif ()
-# --- Find packages and libraries ---------------------------------------------
-find_program(INTROSPECTION_SCANNER "g-ir-scanner")
-find_program(INTROSPECTION_COMPILER "g-ir-compiler")
-find_program(GLIB2_MKENUMS glib-mkenums REQUIRED)
-
-# --- Add enum generation targets ---------------------------------------------
-add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
- COMMAND ${GLIB2_MKENUMS}
- ARGS
- --template ufo-enums.h.template
- ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DEPENDS ${ufocore_HDRS}
- ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.h.template
-)
-
-add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
- COMMAND ${GLIB2_MKENUMS}
- ARGS
- --template ufo-enums.c.template
- ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- DEPENDS ${ufocore_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
- ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.c.template
-)
+#{{{ Optional dependencies
+pkg_check_modules(PYTHON python)
-# --- Target ------------------------------------------------------------------
-get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
+if(PYTHON_FOUND)
+ set(HAVE_PYTHON "1")
+endif()
+#}}}
-set(LIBDIR "lib${LIB_SUFFIX}")
-set(INCLUDEDIR "include/ufo")
+#{{{ libufo target
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/config.h)
-include_directories("${CMAKE_CURRENT_BINARY_DIR}")
add_definitions(-DUFO_COMPILATION)
if(CMAKE_BUILD_TYPE MATCHES "Release")
@@ -100,43 +96,64 @@ add_library(ufo SHARED
${ufocore_NODOC_SRCS}
${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c)
+if(PYTHON_FOUND)
+ include_directories(${PYTHON_INCLUDE_DIRS})
+ target_link_libraries(ufo ${PYTHON_LIBRARIES})
+endif()
+
set_target_properties(ufo PROPERTIES
VERSION ${PACKAGE_VERSION}
SOVERSION ${UFO_SO_VERSION})
target_link_libraries(ufo ${UFOCORE_DEPS})
+#{{{ install target
install(TARGETS ufo
- ARCHIVE DESTINATION ${LIBDIR}
- LIBRARY DESTINATION ${LIBDIR})
+ ARCHIVE DESTINATION ${UFO_LIBDIR}
+ LIBRARY DESTINATION ${UFO_LIBDIR})
install(FILES ${ufocore_HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/ufo.h
${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
- DESTINATION ${INCLUDEDIR})
+ DESTINATION ${UFO_INCLUDEDIR}/ufo)
+install(FILES ufo-basic-ops.cl
+ DESTINATION ${UFO_LIBDIR}/ufo)
+#}}}
+#}}}
-# --- pkg-config --------------------------------------------------------------
-set(UFO_PKG_PREFIX "${CMAKE_INSTALL_PREFIX}")
-set(UFO_PKG_EXEC_PREFIX "${UFO_PKG_PREFIX}/bin")
-set(UFO_PKG_INCLUDEDIR "${UFO_PKG_PREFIX}/include")
-set(UFO_PKG_GIRDIR "${UFO_PKG_PREFIX}/share/gir-1.0")
-set(UFO_PKG_LIBDIR "${UFO_PKG_PREFIX}/${LIBDIR}")
-set(UFO_PKG_TYPELIBDIR "${UFO_PKG_PREFIX}/${LIBDIR}/girepository-1.0")
+#{{{ glib-mkenums targets
+find_program(GLIB2_MKENUMS glib-mkenums REQUIRED)
-# FIXME: inside the ufo.pc.in we should set the lib names that we found out, not
-# hard coded values
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ufo.pc.in"
- "${CMAKE_CURRENT_BINARY_DIR}/ufo.pc" @ONLY IMMEDIATE)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ COMMAND ${GLIB2_MKENUMS}
+ ARGS
+ --template ufo-enums.h.template
+ ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${ufocore_HDRS}
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.h.template
+)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ufo.pc
- DESTINATION ${LIBDIR}/pkgconfig)
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
+ COMMAND ${GLIB2_MKENUMS}
+ ARGS
+ --template ufo-enums.c.template
+ ${ufocore_HDRS} > ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.c
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${ufocore_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/ufo-enums.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/ufo-enums.c.template
+)
+#}}}
+#{{{ g-ir-scanner and g-ir-compiler targets
+find_program(INTROSPECTION_SCANNER "g-ir-scanner")
+find_program(INTROSPECTION_COMPILER "g-ir-compiler")
-# --- Introspection files -----------------------------------------------------
if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER)
option(WITH_GIR "Build introspection files" ON)
-
if (WITH_GIR)
set(GIR_PREFIX "Ufo-${UFO_GIR_VERSION}")
set(GIR_XML "${GIR_PREFIX}.gir")
@@ -161,7 +178,8 @@ if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER)
-DUFO_COMPILATION
--output ${GIR_XML}
--warn-all
- ${_gir_input} > /dev/null
+ --quiet
+ ${_gir_input} 2> /dev/null
DEPENDS ${ufocore_SRCS}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -176,19 +194,15 @@ if (INTROSPECTION_SCANNER AND INTROSPECTION_COMPILER)
add_dependencies(gir ufo)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_XML}
- DESTINATION share/gir-1.0)
+ DESTINATION ${UFO_GIRDIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${GIR_TYPELIB}
- DESTINATION ${LIBDIR}/girepository-1.0)
+ DESTINATION ${UFO_TYPELIBDIR})
endif()
endif()
+#}}}
-
-# --- Generate config.h -------------------------------------------------------
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
-
-
-# --- Build API reference -----------------------------------------------------
+#{{{ gtk-doc targets
pkg_check_modules(GTK_DOC gtk-doc)
if(GTK_DOC_FOUND)
option(WITH_GTK_DOC "Build API reference" ON)
@@ -218,6 +232,11 @@ if(GTK_DOC_FOUND)
endif()
endforeach()
+ get_directory_property(_current_link_dirs LINK_DIRECTORIES)
+ foreach(_linkdir ${_current_link_dirs})
+ set(GTK_DOC_LDFLAGS "-L${_linkdir} ${GTK_DOC_LDFLAGS}")
+ endforeach()
+
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../docs/Ufo-docs.xml.in" "${docs_out}/Ufo-docs.xml")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../docs/scangobj.sh.in" "${docs_out}/scangobj.sh")
@@ -240,6 +259,7 @@ if(GTK_DOC_FOUND)
COMMAND ${GTK_DOC_SCAN}
--module=Ufo
--source-dir=${CMAKE_CURRENT_SOURCE_DIR}
+ --ignore-headers=ufo-mpi-messenger.h
DEPENDS ${ufocore_SRCS}
WORKING_DIRECTORY ${docs_out})
@@ -269,3 +289,14 @@ if(GTK_DOC_FOUND)
install(FILES ${reference_files} DESTINATION share/gtk-doc/html/Ufo)
endif()
endif(GTK_DOC_FOUND)
+#}}}
+
+#{{{ pkg-config
+# FIXME: inside the ufo.pc.in we should set the lib names that we found out, not
+# hard coded values
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/ufo.pc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/ufo.pc" @ONLY IMMEDIATE)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ufo.pc
+ DESTINATION ${UFO_PKGCONFIGDIR})
+#}}}
diff --git a/ufo/config.h.in b/ufo/config.h.in
index a3cada3..2f34fda 100644
--- a/ufo/config.h.in
+++ b/ufo/config.h.in
@@ -1,3 +1,5 @@
#cmakedefine WITH_PROFILING 1
-#define UFO_PLUGIN_DIR "${CMAKE_INSTALL_PREFIX}/${LIBDIR}/ufo"
+#cmakedefine HAVE_VIENNACL 1
+#cmakedefine HAVE_PYTHON 1
+#define UFO_PLUGIN_DIR "${UFO_LIBDIR}/ufo"
#define UFO_VERSION "${PACKAGE_VERSION}"
diff --git a/ufo/ufo-arch-graph.c b/ufo/ufo-arch-graph.c
index 9e44f1f..b1608ba 100644
--- a/ufo/ufo-arch-graph.c
+++ b/ufo/ufo-arch-graph.c
@@ -39,8 +39,6 @@ G_DEFINE_TYPE (UfoArchGraph, ufo_arch_graph, UFO_TYPE_GRAPH)
struct _UfoArchGraphPrivate {
UfoResources *resources;
- gpointer zmq_context;
- gpointer ocl_context;
UfoNode **cpu_nodes;
UfoNode **gpu_nodes;
UfoNode **remote_nodes;
@@ -71,7 +69,6 @@ ufo_arch_graph_new (UfoResources *resources,
g_object_ref (resources);
priv->resources = resources;
- priv->ocl_context = ufo_resources_get_context (resources);
/* Create CPU nodes */
priv->n_cpus = (guint) get_nprocs ();
@@ -96,12 +93,10 @@ ufo_arch_graph_new (UfoResources *resources,
priv->n_remotes = g_list_length (remote_addresses);
if (priv->n_remotes > 0) {
- priv->zmq_context = zmq_ctx_new ();
priv->remote_nodes = g_new0 (UfoNode *, priv->n_remotes);
for (guint i = 0; i < priv->n_remotes; i++) {
- priv->remote_nodes[i] = ufo_remote_node_new (priv->zmq_context,
- (gchar *) g_list_nth_data (remote_addresses, i));
+ priv->remote_nodes[i] = ufo_remote_node_new ((gchar *) g_list_nth_data (remote_addresses, i));
}
}
@@ -248,12 +243,6 @@ ufo_arch_graph_finalize (GObject *object)
priv = UFO_ARCH_GRAPH_GET_PRIVATE (object);
- if (priv->zmq_context != NULL) {
- g_debug ("Destroy zmq_context=%p", priv->zmq_context);
- zmq_ctx_destroy (priv->zmq_context);
- priv->zmq_context = NULL;
- }
-
g_free (priv->cpu_nodes);
g_free (priv->gpu_nodes);
g_free (priv->remote_nodes);
@@ -285,8 +274,4 @@ ufo_arch_graph_init (UfoArchGraph *self)
priv->cpu_nodes = NULL;
priv->gpu_nodes = NULL;
priv->remote_nodes = NULL;
-
- ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_CPU_NODE);
- ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_GPU_NODE);
- ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_REMOTE_NODE);
}
diff --git a/ufo/ufo-basic-ops.c b/ufo/ufo-basic-ops.c
new file mode 100644
index 0000000..44c9686
--- /dev/null
+++ b/ufo/ufo-basic-ops.c
@@ -0,0 +1,681 @@
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#include <math.h>
+#include <ufo/ufo-basic-ops.h>
+#define OPS_FILENAME "ufo-basic-ops.cl"
+
+static cl_event
+operation (const gchar *kernel_name,
+ UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+
+static cl_event
+operation2 (const gchar *kernel_name,
+ UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+
+/**
+ * ufo_op_set:
+ * @arg: A #UfoBuffer
+ * @value: Value to fill @arg with
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Fill a buffer with a value using OpenCL.
+ *
+ * Returns: (transfer full): Event of the set operation
+ */
+gpointer
+ufo_op_set (UfoBuffer *arg,
+ gfloat value,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition requisition;
+ cl_kernel kernel;
+ cl_mem d_arg;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &requisition);
+ d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "operation_set", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ return NULL;
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(gfloat), (void *) &value));
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ requisition.n_dims, NULL, requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_inv:
+ * @arg: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Invert @arg.
+ *
+ * Returns: (transfer full): Event of the invert operation
+ */
+gpointer
+ufo_op_inv (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition requisition;
+ cl_event event;
+ cl_kernel kernel;
+ cl_mem d_arg;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &requisition);
+
+ d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "operation_inv", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ return NULL;
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 1, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel(command_queue, kernel,
+ requisition.n_dims, NULL, requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_mul:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * out = arg1 * arg2
+ *
+ * Returns: (transfer full): Event of the mul operation
+ */
+gpointer
+ufo_op_mul (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return operation ("operation_mul", arg1, arg2, out, resources, command_queue);
+}
+
+/**
+ * ufo_op_add:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * out = arg1 + arg2
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_add (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return operation ("operation_add", arg1, arg2, out, resources, command_queue);
+}
+
+/**
+ * ufo_op_add2:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @modifier: Scalar value
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * @out = @arg1 + @modifier * @arg2
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_add2 (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return operation2 ("operation_add2", arg1, arg2, modifier, out, resources, command_queue);
+}
+
+/**
+ * ufo_op_deduction:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * @out = @arg1 - @arg2
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_deduction (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return operation ("operation_deduction", arg1, arg2, out, resources, command_queue);
+}
+
+/**
+ * ufo_op_deduction2:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @modifier: Scalar value
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * @out = @arg1 - @modifier * @arg2
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_deduction2 (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return operation2 ("operation_deduction2", arg1, arg2, modifier, out, resources, command_queue);
+}
+
+/**
+ * ufo_op_mul_rows:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @offset: Offset
+ * @n: n ?
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * @out = @arg1 - @modifier * @arg2
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_mul_rows (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ guint offset,
+ guint n,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ cl_event event;
+ UfoRequisition arg1_requisition, arg2_requisition, out_requisition;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg1, &arg1_requisition);
+ ufo_buffer_get_requisition (arg2, &arg2_requisition);
+ ufo_buffer_get_requisition (out, &out_requisition);
+
+ if (arg1_requisition.dims[0] != arg2_requisition.dims[0] ||
+ arg1_requisition.dims[0] != out_requisition.dims[0]) {
+ g_error ("Number of columns is different.");
+ return NULL;
+ }
+
+ if (arg1_requisition.dims[1] < offset + n ||
+ arg2_requisition.dims[1] < offset + n ||
+ out_requisition.dims[1] < offset + n) {
+ g_error ("Rows are not enough.");
+ return NULL;
+ }
+
+ cl_mem d_arg1 = ufo_buffer_get_device_image (arg1, command_queue);
+ cl_mem d_arg2 = ufo_buffer_get_device_image (arg2, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "op_mulRows", &error);
+
+ if (error != NULL) {
+ g_error ("Error: %s\n", error->message);
+ return NULL;
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg1));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(void *), (void *) &d_arg2));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof(void *), (void *) &d_out));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 3, sizeof(unsigned int), (void *) &offset));
+
+ UfoRequisition operation_requisition = out_requisition;
+ operation_requisition.dims[1] = n;
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ operation_requisition.n_dims, NULL, operation_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+static cl_event
+operation (const gchar *kernel_name,
+ UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg1_requisition, arg2_requisition, out_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg1, &arg1_requisition);
+ ufo_buffer_get_requisition (arg2, &arg2_requisition);
+ ufo_buffer_get_requisition (out, &out_requisition);
+
+ if ((arg1_requisition.dims[0] != arg2_requisition.dims[0] &&
+ arg1_requisition.dims[0] != out_requisition.dims[0]) ||
+ (arg1_requisition.dims[1] != arg2_requisition.dims[1] &&
+ arg1_requisition.dims[1] != out_requisition.dims[1])) {
+ g_error ("Incorrect volume size.");
+ return NULL;
+ }
+
+ cl_mem d_arg1 = ufo_buffer_get_device_image (arg1, command_queue);
+ cl_mem d_arg2 = ufo_buffer_get_device_image (arg2, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, kernel_name, &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ return NULL;
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg1));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(void *), (void *) &d_arg2));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg1_requisition.n_dims, NULL, arg1_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+static cl_event
+operation2 (const gchar *kernel_name,
+ UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg1_requisition, arg2_requisition, out_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg1, &arg1_requisition);
+ ufo_buffer_get_requisition (arg2, &arg2_requisition);
+ ufo_buffer_get_requisition (out, &out_requisition);
+
+ if ((arg1_requisition.dims[0] != arg2_requisition.dims[0] &&
+ arg1_requisition.dims[0] != out_requisition.dims[0]) ||
+ (arg1_requisition.dims[1] != arg2_requisition.dims[1] &&
+ arg1_requisition.dims[1] != out_requisition.dims[1])) {
+ g_error ("Incorrect volume size.");
+ return NULL;
+ }
+
+ cl_mem d_arg1 = ufo_buffer_get_device_image (arg1, command_queue);
+ cl_mem d_arg2 = ufo_buffer_get_device_image (arg2, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, kernel_name, &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ return NULL;
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 0, sizeof(void *), (void *) &d_arg1));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 1, sizeof(void *), (void *) &d_arg2));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 2, sizeof(gfloat), (void *) &modifier));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 3, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg1_requisition.n_dims, NULL, arg1_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_gradient_magnitudes:
+ * @arg: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Compute magnitude of gradients
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_gradient_magnitudes (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &arg_requisition);
+ ufo_buffer_resize (out, &arg_requisition);
+
+ cl_mem d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "operation_gradient_magnitude", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg_requisition.n_dims, NULL, arg_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_gradient_directions:
+ * @arg: A #UfoBuffer
+ * @magnitudes: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Compute magnitude of gradients
+ *
+ * Returns: (transfer full): Event of the add operation
+ */
+gpointer
+ufo_op_gradient_directions (UfoBuffer *arg,
+ UfoBuffer *magnitudes,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &arg_requisition);
+ ufo_buffer_resize (out, &arg_requisition);
+
+ cl_mem d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ cl_mem d_magnitudes = ufo_buffer_get_device_image (magnitudes, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "operation_gradient_direction", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(void *), (void *) &d_magnitudes));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg_requisition.n_dims, NULL, arg_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_l1_norm:
+ * @arg: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Returns: L1 norm.
+ */
+gfloat
+ufo_op_l1_norm (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg_requisition;
+ gfloat *values;
+ gfloat norm = 0;
+
+ ufo_buffer_get_requisition (arg, &arg_requisition);
+ values = ufo_buffer_get_host_array (arg, command_queue);
+
+ for (guint i = 0; i < arg_requisition.dims[0]; ++i) {
+ for (guint j = 0; j < arg_requisition.dims[1]; ++j) {
+ norm += (gfloat) fabs (values[i * arg_requisition.dims[0] + j]);
+ }
+ }
+
+ return norm;
+}
+
+/**
+ * ufo_op_euclidean_distance:
+ * @arg1: A #UfoBuffer
+ * @arg2: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Returns: Euclidean distance between @arg1 and @arg2.
+ */
+gfloat
+ufo_op_euclidean_distance (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg1_requisition, arg2_requisition;
+ guint length;
+ gfloat diff;
+ gfloat norm = 0;
+ guint length1 = 0;
+ guint length2 = 0;
+ gfloat *values1;
+ gfloat *values2;
+
+ ufo_buffer_get_requisition (arg1, &arg1_requisition);
+ ufo_buffer_get_requisition (arg2, &arg2_requisition);
+
+ for (guint i = 0; i < arg1_requisition.n_dims; ++i)
+ length1 += (guint)arg1_requisition.dims[i];
+
+ for (guint i = 0; i < arg2_requisition.n_dims; ++i)
+ length2 += (guint)arg2_requisition.dims[i];
+
+ if (length2 != length1)
+ g_warning ("Sizes of buffers are not the same. Zero-padding applied.");
+
+ length = length2 < length1 ? length2 : length1;
+ values1 = ufo_buffer_get_host_array (arg1, command_queue);
+ values2 = ufo_buffer_get_host_array (arg2, command_queue);
+
+ for (guint i = 0; i < length; ++i) {
+ diff = values1[i] - values2[i];
+ norm += powf (diff, 2);
+ }
+
+ for (guint i = length; i < length2; ++i)
+ norm += powf (values2[i], 2);
+
+ for (guint i = length; i < length1; ++i)
+ norm += powf (values1[i], 2);
+
+ norm = sqrtf(norm);
+ return norm;
+}
+
+/**
+ * ufo_op_l2_norm:
+ * @arg: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Returns: L2 norm.
+ */
+gfloat
+ufo_op_l2_norm (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ return ufo_op_euclidean_distance (arg, arg, resources, command_queue);
+}
+
+/**
+ * ufo_op_POSC:
+ * @arg: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Returns: (transfer full): Event of the POSC operation
+ */
+gpointer
+ufo_op_POSC (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &arg_requisition);
+ ufo_buffer_resize (out, &arg_requisition);
+
+ cl_mem d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "POSC", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg_requisition.n_dims, NULL, arg_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
+
+/**
+ * ufo_op_gradient_descent:
+ * @arg: A #UfoBuffer
+ * @out: A #UfoBuffer
+ * @resources: #UfoResources object
+ * @command_queue: A valid cl_command_queue
+ *
+ * Returns: (transfer full): Event of the POSC operation
+ */
+gpointer
+ufo_op_gradient_descent (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue)
+{
+ UfoRequisition arg_requisition;
+ cl_event event;
+ GError *error = NULL;
+ static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+
+ ufo_buffer_get_requisition (arg, &arg_requisition);
+ ufo_buffer_resize (out, &arg_requisition);
+
+ cl_mem d_arg = ufo_buffer_get_device_image (arg, command_queue);
+ cl_mem d_out = ufo_buffer_get_device_image (out, command_queue);
+
+ cl_kernel kernel = ufo_resources_get_cached_kernel (resources, OPS_FILENAME, "descent_grad", &error);
+
+ if (error) {
+ g_error ("%s\n", error->message);
+ }
+
+ g_static_mutex_lock (&mutex);
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 0, sizeof(void *), (void *) &d_arg));
+ UFO_RESOURCES_CHECK_CLERR (clSetKernelArg(kernel, 1, sizeof(void *), (void *) &d_out));
+
+ UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (command_queue, kernel,
+ arg_requisition.n_dims, NULL, arg_requisition.dims,
+ NULL, 0, NULL, &event));
+ g_static_mutex_unlock (&mutex);
+
+ return event;
+}
diff --git a/ufo/ufo-basic-ops.cl b/ufo/ufo-basic-ops.cl
new file mode 100644
index 0000000..a75e63a
--- /dev/null
+++ b/ufo/ufo-basic-ops.cl
@@ -0,0 +1,326 @@
+const sampler_t imageSampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
+const sampler_t imageSampler2 = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
+
+__kernel
+void operation_set (__write_only image2d_t out,
+ const float value)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_inv (__read_only image2d_t in,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(in, imageSampler, coord_r).s0;
+ value = (value != 0)? 1.0f / value : 0;
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_mul (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 *
+ read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_add (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 +
+ read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_deduction (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 -
+ read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_deduction2 (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ const float modifier,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 -
+ modifier * read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_add2 (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ const float modifier,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 +
+ modifier * read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void op_mulRows (__read_only image2d_t arg1_r,
+ __read_only image2d_t arg2_r,
+ __write_only image2d_t out,
+ const uint offset)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ float2 coord_r;
+ coord_r.x = (float)X + 0.5f;
+ coord_r.y = (float)offset + (float)Y + 0.5f;
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = offset + Y;
+
+ float value = read_imagef(arg1_r, imageSampler, coord_r).s0 *
+ read_imagef(arg2_r, imageSampler, coord_r).s0;
+
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_gradient_magnitude (__read_only image2d_t arg_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float2 coord_r[5];
+ coord_r[0].x = (float)X + 0.5f;
+ coord_r[0].y = (float)Y + 0.5f;
+ coord_r[1].x = coord_r[0].x + 1;
+ coord_r[1].y = coord_r[0].y;
+ coord_r[2].x = coord_r[0].x - 1;
+ coord_r[2].y = coord_r[0].y;
+ coord_r[3].x = coord_r[0].x;
+ coord_r[3].y = coord_r[0].y + 1;
+ coord_r[4].x = coord_r[0].x;
+ coord_r[4].y = coord_r[0].y - 1;
+
+ float cell_value = read_imagef(arg_r, imageSampler2, coord_r[0]).s0;
+ float d1 = read_imagef(arg_r, imageSampler2, coord_r[1]).s0 - cell_value;
+ float d2 = read_imagef(arg_r, imageSampler2, coord_r[2]).s0 - cell_value;
+ float d3 = read_imagef(arg_r, imageSampler2, coord_r[3]).s0 - cell_value;
+ float d4 = read_imagef(arg_r, imageSampler2, coord_r[4]).s0 - cell_value;
+
+ float value = sqrt ( (pow (d1, 2) + pow (d2, 2) + pow (d3, 2) + pow (d4, 2)) / 2.0f);
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void operation_gradient_direction (__read_only image2d_t arg_r,
+ __read_only image2d_t magnitude,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float2 coord_r[5];
+ coord_r[0].x = (float)X + 0.5f;
+ coord_r[0].y = (float)Y + 0.5f;
+ coord_r[1].x = coord_r[0].x + 1;
+ coord_r[1].y = coord_r[0].y;
+ coord_r[2].x = coord_r[0].x - 1;
+ coord_r[2].y = coord_r[0].y;
+ coord_r[3].x = coord_r[0].x;
+ coord_r[3].y = coord_r[0].y + 1;
+ coord_r[4].x = coord_r[0].x;
+ coord_r[4].y = coord_r[0].y - 1;
+
+ float values[5];
+ values[0] = read_imagef(arg_r, imageSampler2, coord_r[0]).s0;
+ values[1] = read_imagef(arg_r, imageSampler2, coord_r[1]).s0;
+ values[2] = read_imagef(arg_r, imageSampler2, coord_r[2]).s0;
+ values[3] = read_imagef(arg_r, imageSampler2, coord_r[3]).s0;
+ values[4] = read_imagef(arg_r, imageSampler2, coord_r[4]).s0;
+
+ float magnitudes[5];
+ magnitudes[0] = read_imagef(magnitude, imageSampler2, coord_r[0]).s0;
+ magnitudes[1] = read_imagef(magnitude, imageSampler2, coord_r[1]).s0;
+ magnitudes[2] = read_imagef(magnitude, imageSampler2, coord_r[2]).s0;
+ magnitudes[3] = read_imagef(magnitude, imageSampler2, coord_r[3]).s0;
+ magnitudes[4] = read_imagef(magnitude, imageSampler2, coord_r[4]).s0;
+
+ float direction = 0;
+ if (magnitudes[0]) direction += (4 * values[0] - values[1] - values[2] - values[3] - values[4]) / magnitudes[0];
+ if (magnitudes[1]) direction += (values[0] - values[1]) / magnitudes[1];
+ if (magnitudes[2]) direction += (values[0] - values[2]) / magnitudes[2];
+ if (magnitudes[3]) direction += (values[0] - values[3]) / magnitudes[3];
+ if (magnitudes[4]) direction += (values[0] - values[4]) / magnitudes[4];
+
+ write_imagef(out, coord_w, direction);
+}
+
+
+__kernel
+void POSC (__read_only image2d_t arg_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float2 coord_r;
+ coord_r.x = X + 0.5f;
+ coord_r.y = Y + 0.5f;
+
+ float value = read_imagef(arg_r, imageSampler2, coord_r).s0;
+ value = value > 0 ? value : 0;
+ write_imagef(out, coord_w, value);
+}
+
+__kernel
+void descent_grad (__read_only image2d_t arg_r,
+ __write_only image2d_t out)
+{
+ const uint X = get_global_id(0);
+ const uint Y = get_global_id(1);
+
+ int2 coord_w;
+ coord_w.x = X;
+ coord_w.y = Y;
+
+ float2 coord_r[7];
+ coord_r[0].x = X;
+ coord_r[0].y = Y;
+ coord_r[1].x = coord_r[0].x - 1;
+ coord_r[1].y = coord_r[0].y;
+ coord_r[2].x = coord_r[0].x;
+ coord_r[2].y = coord_r[0].y - 1;
+ coord_r[3].x = coord_r[0].x + 1;
+ coord_r[3].y = coord_r[0].y;
+ coord_r[4].x = coord_r[0].x;
+ coord_r[4].y = coord_r[0].y + 1;
+ coord_r[5].x = coord_r[0].x + 1;
+ coord_r[5].y = coord_r[0].y - 1;
+ coord_r[6].x = coord_r[0].x - 1;
+ coord_r[6].y = coord_r[0].y + 1;
+
+ float eps = 1E-8;
+ float values[7];
+ values[0] = read_imagef(arg_r, imageSampler2, coord_r[0]).s0;
+ values[1] = read_imagef(arg_r, imageSampler2, coord_r[1]).s0;
+ values[2] = read_imagef(arg_r, imageSampler2, coord_r[2]).s0;
+ values[3] = read_imagef(arg_r, imageSampler2, coord_r[3]).s0;
+ values[4] = read_imagef(arg_r, imageSampler2, coord_r[4]).s0;
+ values[5] = read_imagef(arg_r, imageSampler2, coord_r[5]).s0;
+ values[6] = read_imagef(arg_r, imageSampler2, coord_r[6]).s0;
+
+ float t1, t2;
+ float part[3];
+ t1 = values[0] - values[1];
+ t2 = values[0] - values[2];
+ part[0] = (t1 + t2) / sqrt(eps + pow(t1, 2) + pow (t2, 2));
+ t1 = values[3] - values[0];
+ t2 = values[3] - values[5];
+ part[1] = t1 / sqrt(eps + pow(t1, 2) + pow (t2, 2));
+ t1 = values[4] - values[0];
+ t2 = values[4] - values[6];
+ part[2] = t1 / sqrt(eps + pow(t1, 2) + pow (t2, 2));
+
+ float value = part[0] - part[1] - part[2];
+ write_imagef(out, coord_w, value);
+}
\ No newline at end of file
diff --git a/ufo/ufo-basic-ops.h b/ufo/ufo-basic-ops.h
new file mode 100644
index 0000000..ef08984
--- /dev/null
+++ b/ufo/ufo-basic-ops.h
@@ -0,0 +1,89 @@
+#ifndef __UFO_BASIC_OPS
+#define __UFO_BASIC_OPS
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+#include <ufo/ufo-buffer.h>
+#include <ufo/ufo-resources.h>
+
+G_BEGIN_DECLS
+
+gpointer ufo_op_set (UfoBuffer *arg,
+ gfloat value,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_inv (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_mul (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_add (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_add2 (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_deduction (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_deduction2 (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ gfloat modifier,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_mul_rows (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoBuffer *out,
+ guint offset,
+ guint n,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_gradient_magnitudes
+ (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_gradient_directions
+ (UfoBuffer *arg,
+ UfoBuffer *magnitudes,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gfloat ufo_op_l1_norm (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue);
+gfloat ufo_op_l2_norm (UfoBuffer *arg,
+ UfoResources *resources,
+ gpointer command_queue);
+gfloat ufo_op_euclidean_distance
+ (UfoBuffer *arg1,
+ UfoBuffer *arg2,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_POSC (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+gpointer ufo_op_gradient_descent
+ (UfoBuffer *arg,
+ UfoBuffer *out,
+ UfoResources *resources,
+ gpointer command_queue);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-buffer.c b/ufo/ufo-buffer.c
index cf97967..4910408 100644
--- a/ufo/ufo-buffer.c
+++ b/ufo/ufo-buffer.c
@@ -37,6 +37,13 @@ G_DEFINE_TYPE(UfoBuffer, ufo_buffer, G_TYPE_OBJECT)
#define UFO_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_BUFFER, UfoBufferPrivate))
+typedef enum {
+ UFO_LOCATION_HOST = 0,
+ UFO_LOCATION_DEVICE,
+ UFO_LOCATION_DEVICE_IMAGE,
+ UFO_LOCATION_INVALID
+} UfoMemLocation;
+
enum {
PROP_0,
PROP_ID,
@@ -44,56 +51,159 @@ enum {
N_PROPERTIES
};
-typedef struct {
- guint num_dims;
- gfloat *data;
- gsize dim_size[UFO_BUFFER_MAX_NDIMS];
-} nd_array;
-
struct _UfoBufferPrivate {
- nd_array host_array;
+ UfoRequisition requisition;
+ gfloat *host_array;
cl_mem device_array;
+ cl_mem device_image;
cl_context context;
cl_command_queue last_queue;
gsize size; /**< size of buffer in bytes */
UfoMemLocation location;
- GTimer *timer;
+ UfoMemLocation last_location;
};
static void
-alloc_mem (UfoBufferPrivate *priv,
- UfoRequisition *requisition)
+copy_requisition (UfoRequisition *src,
+ UfoRequisition *dst)
{
- cl_int err;
+ const guint n_dims = src->n_dims;
+
+ dst->n_dims = n_dims;
+
+ for (guint i = 0; i < n_dims; i++)
+ dst->dims[i] = src->dims[i];
+}
+
+static gsize
+compute_required_size (UfoRequisition *requisition)
+{
+ gsize size = sizeof (gfloat);
+
+ for (guint i = 0; i < requisition->n_dims; i++)
+ size *= requisition->dims[i];
- if (priv->host_array.data != NULL)
- g_free (priv->host_array.data);
+ return size;
+}
+
+static void
+alloc_host_mem (UfoBufferPrivate *priv)
+{
+ if (priv->host_array != NULL)
+ g_free (priv->host_array);
+
+ priv->host_array = g_malloc0 (priv->size);
+}
+
+static void
+alloc_device_array (UfoBufferPrivate *priv)
+{
+ cl_int err;
+ cl_mem mem;
if (priv->device_array != NULL)
- clReleaseMemObject (priv->device_array);
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_array));
- priv->size = sizeof(gfloat);
- priv->host_array.num_dims = requisition->n_dims;
+ mem = clCreateBuffer (priv->context,
+ CL_MEM_READ_WRITE,
+ priv->size,
+ NULL, &err);
- for (guint i = 0; i < requisition->n_dims; i++) {
- priv->host_array.dim_size[i] = requisition->dims[i];
- priv->size *= requisition->dims[i];
+ UFO_RESOURCES_CHECK_CLERR (err);
+ priv->device_array = mem;
+}
+
+#ifdef CL_VERSION_1_2
+static void
+alloc_device_image (UfoBufferPrivate *priv)
+{
+ cl_image_desc desc;
+ cl_image_format format;
+ cl_int errcode;
+ cl_mem mem;
+
+ g_assert ((priv->requisition.n_dims == 2) ||
+ (priv->requisition.n_dims == 3));
+
+ if (priv->device_image != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_image));
+
+ format.image_channel_order = CL_R;
+ format.image_channel_data_type = CL_FLOAT;
+
+ if (priv->requisition.n_dims == 2) {
+ desc.image_type = CL_MEM_OBJECT_IMAGE2D;
+ desc.image_depth = 1;
+ }
+ else {
+ desc.image_type = CL_MEM_OBJECT_IMAGE3D;
+ desc.image_depth = priv->requisition.dims[2];
+ }
+
+ desc.image_width = priv->requisition.dims[0];
+ desc.image_height = priv->requisition.dims[1];
+ desc.image_array_size = 0;
+ desc.image_row_pitch = 0;
+ desc.image_slice_pitch = 0;
+ desc.num_mip_levels = 0;
+ desc.num_samples = 0;
+ desc.buffer = NULL;
+
+ mem = clCreateImage (priv->context,
+ CL_MEM_READ_WRITE,
+ &format, &desc,
+ NULL, &errcode);
+
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ priv->device_image = mem;
+}
+#else
+static void
+alloc_device_image (UfoBufferPrivate *priv)
+{
+ cl_image_format format;
+ cl_mem_flags flags;
+ cl_int err;
+ gsize width, height, depth;
+ cl_mem mem = NULL;
+
+ g_assert ((priv->requisition.n_dims == 2) ||
+ (priv->requisition.n_dims == 3));
+
+ if (priv->device_image != NULL)
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_image));
+
+ format.image_channel_order = CL_R;
+ format.image_channel_data_type = CL_FLOAT;
+
+ flags = CL_MEM_READ_WRITE;
+ width = priv->requisition.dims[0];
+ height = priv->requisition.dims[1];
+ depth = priv->requisition.dims[2];
+
+ if (priv->requisition.n_dims == 2) {
+ mem = clCreateImage2D (priv->context,
+ flags, &format,
+ width, height, 0,
+ NULL, &err);
+ }
+ else if (priv->requisition.n_dims == 3) {
+ mem = clCreateImage3D (priv->context,
+ flags, &format,
+ width, height, depth, 0, 0,
+ NULL, &err);
}
- priv->host_array.data = g_malloc0 (priv->size);
- priv->device_array = clCreateBuffer (priv->context,
- CL_MEM_READ_WRITE, /* XXX: we _should_ evaluate USE_HOST_PTR */
- priv->size,
- NULL,
- &err);
UFO_RESOURCES_CHECK_CLERR (err);
- priv->location = UFO_LOCATION_HOST;
+ g_assert (mem != NULL);
+ priv->device_image = mem;
}
+#endif
/**
* ufo_buffer_new:
* @requisition: (in): size requisition
- * @context: (in): cl_context to use for creating the device array
+ * @context: (in) (allow-none): cl_context to use for creating the device array
*
* Create a new #UfoBuffer.
*
@@ -104,16 +214,45 @@ ufo_buffer_new (UfoRequisition *requisition,
gpointer context)
{
UfoBuffer *buffer;
+ UfoBufferPrivate *priv;
- g_return_val_if_fail ((requisition->n_dims <= UFO_BUFFER_MAX_NDIMS), NULL);
+ g_return_val_if_fail ((requisition->n_dims <= UFO_BUFFER_MAX_NDIMS) &&
+ (requisition->n_dims > 0), NULL);
buffer = UFO_BUFFER (g_object_new (UFO_TYPE_BUFFER, NULL));
- buffer->priv->context = context;
+ priv = buffer->priv;
+ priv->context = context;
+
+ priv->size = compute_required_size (requisition);
+ copy_requisition (requisition, &priv->requisition);
- alloc_mem (buffer->priv, requisition);
return buffer;
}
/**
+ * ufo_buffer_new_with_size:
+ * @dims: (element-type guint64): size requisition
+ * @context: (allow-none): cl_context to use for creating the device array
+ *
+ * Create a new #UfoBuffer with a list of dimensions.
+ *
+ * Return value: A new #UfoBuffer with the given dimensions.
+ */
+UfoBuffer *
+ufo_buffer_new_with_size (GList *dims,
+ gpointer context)
+{
+ UfoRequisition req;
+
+ req.n_dims = g_list_length (dims);
+ g_assert (req.n_dims < 16);
+
+ for (guint i = 0; i < req.n_dims; i++)
+ req.dims[i] = (gsize) g_list_nth_data (dims, i);
+
+ return ufo_buffer_new (&req, context);
+}
+
+/**
* ufo_buffer_get_size:
* @buffer: A #UfoBuffer
*
@@ -129,29 +268,82 @@ ufo_buffer_get_size (UfoBuffer *buffer)
}
static void
-copy_host_to_host (UfoBufferPrivate *src_priv,
- UfoBufferPrivate *dst_priv)
+set_region_from_requisition (size_t region[3],
+ UfoRequisition *requisition)
{
- g_memmove (dst_priv->host_array.data,
- src_priv->host_array.data,
+ region[0] = requisition->dims[0];
+ region[1] = requisition->dims[1];
+
+ if (requisition->n_dims == 3)
+ region[2] = requisition->dims[2];
+ else
+ region[2] = 1;
+}
+
+static void
+transfer_host_to_host (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ g_memmove (dst_priv->host_array,
+ src_priv->host_array,
src_priv->size);
}
static void
-copy_device_to_device (UfoBufferPrivate *src_priv,
- UfoBufferPrivate *dst_priv)
+transfer_host_to_device (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
{
- cl_event event;
cl_int errcode;
- cl_command_queue cmd_queue;
- cmd_queue = src_priv->last_queue != NULL ? src_priv->last_queue : dst_priv->last_queue;
- g_assert (cmd_queue != NULL);
+ errcode = clEnqueueWriteBuffer (queue,
+ dst_priv->device_array,
+ CL_TRUE,
+ 0, src_priv->size,
+ src_priv->host_array,
+ 0, NULL, NULL);
- errcode = clEnqueueCopyBuffer (cmd_queue,
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+}
+
+static void
+transfer_host_to_image (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ cl_int errcode;
+ cl_event event;
+ size_t region[3];
+ size_t origin[] = { 0, 0, 0 };
+
+ set_region_from_requisition (region, &src_priv->requisition);
+
+ errcode = clEnqueueWriteImage (queue,
+ dst_priv->device_image,
+ CL_TRUE,
+ origin, region,
+ 0, 0,
+ src_priv->host_array,
+ 0, NULL, &event);
+
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event));
+}
+
+static void
+transfer_device_to_device (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ cl_event event;
+ cl_int errcode;
+
+ errcode = clEnqueueCopyBuffer (queue,
src_priv->device_array,
dst_priv->device_array,
- 0, 0, /* offsets */
+ 0, 0,
src_priv->size,
0, NULL, &event);
@@ -161,60 +353,114 @@ copy_device_to_device (UfoBufferPrivate *src_priv,
}
static void
-ufo_buffer_to_host (UfoBuffer *buffer, gpointer cmd_queue)
+transfer_device_to_host (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
{
- UfoBufferPrivate *priv;
- cl_int cl_err;
- cl_command_queue queue;
+ cl_int errcode;
- g_return_if_fail (UFO_IS_BUFFER (buffer));
- priv = buffer->priv;
+ errcode = clEnqueueReadBuffer (queue,
+ src_priv->device_array,
+ CL_TRUE,
+ 0, src_priv->size,
+ dst_priv->host_array,
+ 0, NULL, NULL);
- queue = cmd_queue == NULL ? priv->last_queue : cmd_queue;
- priv->last_queue = cmd_queue;
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+}
- if (priv->location == UFO_LOCATION_HOST)
- return;
+static void
+transfer_device_to_image (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ cl_event event;
+ cl_int errcode;
+ size_t region[3];
+ size_t origin[] = { 0, 0, 0 };
- cl_err = clEnqueueReadBuffer (queue,
- priv->device_array,
- CL_TRUE,
- 0, priv->size,
- priv->host_array.data,
- 0, NULL, NULL);
+ set_region_from_requisition (region, &src_priv->requisition);
+
+ errcode = clEnqueueCopyBufferToImage (queue,
+ src_priv->device_array,
+ dst_priv->device_image,
+ 0, origin, region,
+ 0, NULL, &event);
- priv->location = UFO_LOCATION_HOST;
- UFO_RESOURCES_CHECK_CLERR (cl_err);
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event));
}
static void
-ufo_buffer_to_device (UfoBuffer *buffer, gpointer cmd_queue)
+transfer_image_to_image (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
{
- UfoBufferPrivate *priv;
- cl_int cl_err;
- cl_command_queue queue;
+ cl_event event;
+ cl_int errcode;
+ size_t region[3];
+ size_t origin[] = { 0, 0, 0 };
- g_return_if_fail (UFO_IS_BUFFER (buffer));
- priv = buffer->priv;
+ set_region_from_requisition (region, &src_priv->requisition);
- queue = cmd_queue == NULL ? priv->last_queue : cmd_queue;
- priv->last_queue = cmd_queue;
- g_assert (cmd_queue);
+ errcode = clEnqueueCopyImage (queue,
+ src_priv->device_image,
+ dst_priv->device_image,
+ origin, origin, region,
+ 0, NULL, &event);
- if (priv->location == UFO_LOCATION_DEVICE)
- return;
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event));
+}
- cl_err = clEnqueueWriteBuffer ((cl_command_queue) queue,
- priv->device_array,
- CL_TRUE,
- 0, priv->size,
- priv->host_array.data,
- 0, NULL, NULL);
+static void
+transfer_image_to_host (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ cl_int errcode;
+ size_t region[3];
+ size_t origin[] = { 0, 0, 0 };
+
+ set_region_from_requisition (region, &src_priv->requisition);
+
+ errcode = clEnqueueReadImage (queue,
+ src_priv->device_image,
+ CL_TRUE,
+ origin, region,
+ 0, 0,
+ dst_priv->host_array,
+ 0, NULL, NULL);
- priv->location = UFO_LOCATION_DEVICE;
- UFO_RESOURCES_CHECK_CLERR (cl_err);
+ UFO_RESOURCES_CHECK_CLERR (errcode);
}
+static void
+transfer_image_to_device (UfoBufferPrivate *src_priv,
+ UfoBufferPrivate *dst_priv,
+ cl_command_queue queue)
+{
+ cl_event event;
+ cl_int errcode;
+ size_t region[3];
+ size_t origin[] = { 0, 0, 0 };
+
+ set_region_from_requisition (region, &src_priv->requisition);
+
+ errcode = clEnqueueCopyImageToBuffer (queue,
+ src_priv->device_image,
+ dst_priv->device_array,
+ origin, region, 0,
+ 0, NULL, &event);
+
+ UFO_RESOURCES_CHECK_CLERR (errcode);
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clReleaseEvent (event));
+}
+
+
/**
* ufo_buffer_copy:
* @src: Source #UfoBuffer
@@ -226,41 +472,40 @@ ufo_buffer_to_device (UfoBuffer *buffer, gpointer cmd_queue)
void
ufo_buffer_copy (UfoBuffer *src, UfoBuffer *dst)
{
+ typedef void (*TransferFunc) (UfoBufferPrivate *, UfoBufferPrivate *, cl_command_queue);
+ typedef void (*AllocFunc) (UfoBufferPrivate *priv);
+
UfoBufferPrivate *spriv;
UfoBufferPrivate *dpriv;
+ cl_command_queue queue;
+
+ TransferFunc transfer[3][3] = {
+ { transfer_host_to_host, transfer_host_to_device, transfer_host_to_image },
+ { transfer_device_to_host, transfer_device_to_device, transfer_device_to_image },
+ { transfer_image_to_host, transfer_image_to_device, transfer_image_to_image }
+ };
+
+ AllocFunc alloc[3] = { alloc_host_mem, alloc_device_array, alloc_device_image };
g_return_if_fail (UFO_IS_BUFFER (src) && UFO_IS_BUFFER (dst));
g_return_if_fail (src->priv->size == dst->priv->size);
spriv = src->priv;
dpriv = dst->priv;
+ queue = spriv->last_queue != NULL ? spriv->last_queue : dpriv->last_queue;
- if (spriv->location == dpriv->location) {
- switch (spriv->location) {
- case UFO_LOCATION_HOST:
- copy_host_to_host (spriv, dpriv);
- break;
- case UFO_LOCATION_DEVICE:
- copy_device_to_device (spriv, dpriv);
- break;
- default:
- g_warning ("oops, we should not copy invalid data");
- }
+ if (spriv->location == UFO_LOCATION_INVALID) {
+ alloc_host_mem (spriv);
+ spriv->location = UFO_LOCATION_HOST;
}
- else {
- cl_command_queue cmd_queue;
-
- cmd_queue = spriv->last_queue != NULL ? spriv->last_queue : dpriv->last_queue;
-
- if (cmd_queue == NULL || dpriv->location == UFO_LOCATION_HOST) {
- ufo_buffer_to_host (src, cmd_queue);
- copy_host_to_host (spriv, dpriv);
- }
- else {
- ufo_buffer_to_device (src, cmd_queue);
- copy_device_to_device (spriv, dpriv);
- }
+
+ if (dpriv->location == UFO_LOCATION_INVALID) {
+ alloc[spriv->location](dpriv);
+ dpriv->location = spriv->location;
}
+
+ transfer[spriv->location][dpriv->location](spriv, dpriv, queue);
+ dpriv->last_queue = queue;
}
/**
@@ -303,9 +548,9 @@ ufo_buffer_resize (UfoBuffer *buffer,
priv = UFO_BUFFER_GET_PRIVATE (buffer);
- if (priv->host_array.data != NULL) {
- g_free (priv->host_array.data);
- priv->host_array.data = NULL;
+ if (priv->host_array != NULL) {
+ g_free (priv->host_array);
+ priv->host_array = NULL;
}
if (priv->device_array != NULL) {
@@ -313,7 +558,7 @@ ufo_buffer_resize (UfoBuffer *buffer,
priv->device_array = NULL;
}
- alloc_mem (priv, requisition);
+ copy_requisition (requisition, &priv->requisition);
}
/**
@@ -329,14 +574,17 @@ gint
ufo_buffer_cmp_dimensions (UfoBuffer *buffer,
UfoRequisition *requisition)
{
+ UfoBufferPrivate *priv;
gint result;
+
g_return_val_if_fail (UFO_IS_BUFFER(buffer), FALSE);
+ priv = buffer->priv;
result = 0;
- for (guint i = 0; i < buffer->priv->host_array.num_dims; i++) {
+ for (guint i = 0; i < priv->requisition.n_dims; i++) {
gint req_dim = (gint) requisition->dims[i];
- gint host_dim = (gint) buffer->priv->host_array.dim_size[i];
+ gint host_dim = (gint) priv->requisition.dims[i];
result += req_dim - host_dim;
}
@@ -358,10 +606,24 @@ ufo_buffer_get_requisition (UfoBuffer *buffer,
g_return_if_fail (UFO_IS_BUFFER (buffer) && (requisition != NULL));
priv = buffer->priv;
- requisition->n_dims = priv->host_array.num_dims;
- for (guint i = 0; i < priv->host_array.num_dims; i++)
- requisition->dims[i] = priv->host_array.dim_size[i];
+ copy_requisition (&priv->requisition, requisition);
+}
+
+static void
+update_last_queue (UfoBufferPrivate *priv,
+ cl_command_queue queue)
+{
+ if (queue != NULL)
+ priv->last_queue = queue;
+}
+
+static void
+update_location (UfoBufferPrivate *priv,
+ UfoMemLocation new_location)
+{
+ priv->last_location = priv->location;
+ priv->location = new_location;
}
/**
@@ -376,9 +638,25 @@ ufo_buffer_get_requisition (UfoBuffer *buffer,
gfloat *
ufo_buffer_get_host_array (UfoBuffer *buffer, gpointer cmd_queue)
{
+ UfoBufferPrivate *priv;
+
g_return_val_if_fail (UFO_IS_BUFFER (buffer), NULL);
- ufo_buffer_to_host (buffer, cmd_queue);
- return buffer->priv->host_array.data;
+ priv = buffer->priv;
+
+ update_last_queue (priv, cmd_queue);
+
+ if (priv->host_array == NULL)
+ alloc_host_mem (priv);
+
+ if (priv->location == UFO_LOCATION_DEVICE && priv->device_array)
+ transfer_device_to_host (priv, priv, priv->last_queue);
+
+ if (priv->location == UFO_LOCATION_DEVICE_IMAGE && priv->device_image)
+ transfer_image_to_host (priv, priv, priv->last_queue);
+
+ update_location (priv, UFO_LOCATION_HOST);
+
+ return priv->host_array;
}
/**
@@ -395,59 +673,100 @@ ufo_buffer_get_host_array (UfoBuffer *buffer, gpointer cmd_queue)
gpointer
ufo_buffer_get_device_array (UfoBuffer *buffer, gpointer cmd_queue)
{
+ UfoBufferPrivate *priv;
+
g_return_val_if_fail (UFO_IS_BUFFER (buffer), NULL);
- ufo_buffer_to_device (buffer, cmd_queue);
- return buffer->priv->device_array;
+ priv = buffer->priv;
+
+ update_last_queue (priv, cmd_queue);
+
+ if (priv->device_array == NULL)
+ alloc_device_array (priv);
+
+ if (priv->location == UFO_LOCATION_HOST && priv->host_array)
+ transfer_host_to_device (priv, priv, priv->last_queue);
+
+ if (priv->location == UFO_LOCATION_DEVICE_IMAGE && priv->device_array)
+ transfer_image_to_device (priv, priv, priv->last_queue);
+
+ update_location (priv, UFO_LOCATION_DEVICE);
+
+ return priv->device_array;
}
/**
- * ufo_buffer_discard_location:
- * @buffer: A #UfoBuffer
- * @location: Location to discard
+ * ufo_buffer_get_device_image:
+ * @buffer: A #UfoBuffer.
+ * @cmd_queue: (allow-none): A cl_command_queue object or %NULL.
*
- * Discard @location and use "other" location without copying to it first.
+ * Return the current cl_mem image object of @buffer. If the data is not yet in
+ * device memory, it is transfered via @cmd_queue to the object. If @cmd_queue
+ * is %NULL @cmd_queue, the last used command queue is used.
+ *
+ * Returns: (transfer none): A cl_mem image object associated with @buffer.
*/
-void
-ufo_buffer_discard_location (UfoBuffer *buffer,
- UfoMemLocation location)
+gpointer
+ufo_buffer_get_device_image (UfoBuffer *buffer,
+ gpointer cmd_queue)
{
- g_return_if_fail (UFO_IS_BUFFER (buffer));
- buffer->priv->location = location == UFO_LOCATION_HOST ? UFO_LOCATION_DEVICE : UFO_LOCATION_HOST;
+ UfoBufferPrivate *priv;
+
+ g_return_val_if_fail (UFO_IS_BUFFER (buffer), NULL);
+ priv = buffer->priv;
+
+ update_last_queue (priv, cmd_queue);
+
+ if (priv->device_image == NULL)
+ alloc_device_image (priv);
+
+ if (priv->location == UFO_LOCATION_HOST && priv->host_array)
+ transfer_host_to_image (priv, priv, priv->last_queue);
+
+ if (priv->location == UFO_LOCATION_DEVICE && priv->device_array)
+ transfer_device_to_image (priv, priv, priv->last_queue);
+
+ update_location (priv, UFO_LOCATION_DEVICE_IMAGE);
+
+ return priv->device_image;
}
/**
- * ufo_buffer_convert:
+ * ufo_buffer_discard_location:
* @buffer: A #UfoBuffer
- * @depth: Source bit depth of host data
*
- * Convert host data according to its @depth to the internal 32-bit floating
- * point representation.
+ * Discard the current and use the last location without copying to it first.
*/
void
-ufo_buffer_convert (UfoBuffer *buffer,
- UfoBufferDepth depth)
+ufo_buffer_discard_location (UfoBuffer *buffer)
+{
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+
+ buffer->priv->location = buffer->priv->last_location;
+}
+
+static void
+convert_data (UfoBufferPrivate *priv,
+ gconstpointer data,
+ UfoBufferDepth depth)
{
- UfoBufferPrivate *priv;
gint n_pixels;
gfloat *dst;
- g_return_if_fail (UFO_IS_BUFFER (buffer));
- priv = buffer->priv;
n_pixels = (gint) (priv->size / 4);
- dst = priv->host_array.data;
+ dst = priv->host_array;
/* To save a memory allocation and several copies, we process data from back
* to front. This is possible if src bit depth is at most half as wide as
* the 32-bit target buffer. The processor cache should not be a
* problem. */
if (depth == UFO_BUFFER_DEPTH_8U) {
- guint8 *src = (guint8 *) priv->host_array.data;
+ const guint8 *src = (const guint8 *) data;
for (gint i = (n_pixels - 1); i >= 0; i--)
dst[i] = ((gfloat) src[i]);
}
else if (depth == UFO_BUFFER_DEPTH_16U) {
- guint16 *src = (guint16 *) priv->host_array.data;
+ const guint16 *src = (const guint16 *) data;
for (gint i = (n_pixels - 1); i >= 0; i--)
dst[i] = ((gfloat) src[i]);
@@ -455,6 +774,56 @@ ufo_buffer_convert (UfoBuffer *buffer,
}
/**
+ * ufo_buffer_convert:
+ * @buffer: A #UfoBuffer
+ * @depth: Source bit depth of host data
+ *
+ * Convert host data according to its @depth to the internal 32-bit floating
+ * point representation.
+ *
+ * Deprecated: 0.4: Use ufo_buffer_convert_from_data() instead.
+ */
+void
+ufo_buffer_convert (UfoBuffer *buffer,
+ UfoBufferDepth depth)
+{
+ UfoBufferPrivate *priv;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ priv = buffer->priv;
+
+ if (priv->host_array != NULL)
+ convert_data (priv, priv->host_array, depth);
+}
+
+/**
+ * ufo_buffer_convert_from_data:
+ * @buffer: A #UfoBuffer
+ * @data: Pointer to data that should be converted
+ * @depth: Source bit depth of host data
+ *
+ * Convert @data according from @depth to the internal 32-bit floating
+ * point representation.
+ *
+ * Note: @data must provide as many bytes as the buffer was initialized with.
+ */
+void
+ufo_buffer_convert_from_data (UfoBuffer *buffer,
+ gconstpointer data,
+ UfoBufferDepth depth)
+{
+ UfoBufferPrivate *priv;
+
+ g_return_if_fail (UFO_IS_BUFFER (buffer));
+ priv = buffer->priv;
+
+ if (priv->host_array == NULL)
+ alloc_host_mem (priv);
+
+ convert_data (priv, data, depth);
+}
+
+/**
* ufo_buffer_param_spec:
* @name: canonical name of the property specified
* @nick: nick name for the property specified
@@ -481,23 +850,27 @@ ufo_buffer_param_spec(const gchar *name, const gchar *nick, const gchar *blurb,
}
static void
+free_cl_mem (cl_mem *mem)
+{
+ g_assert (mem != NULL);
+
+ if (*mem != NULL) {
+ UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (*mem));
+ *mem = NULL;
+ }
+}
+
+static void
ufo_buffer_finalize (GObject *gobject)
{
UfoBuffer *buffer = UFO_BUFFER (gobject);
UfoBufferPrivate *priv = UFO_BUFFER_GET_PRIVATE (buffer);
- g_free (priv->host_array.data);
- priv->host_array.data = NULL;
-
- if (priv->device_array != NULL) {
- UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->device_array));
- priv->device_array = NULL;
- }
+ g_free (priv->host_array);
+ priv->host_array = NULL;
- if (priv->timer != NULL) {
- g_timer_destroy (priv->timer);
- priv->timer = NULL;
- }
+ free_cl_mem (&priv->device_array);
+ free_cl_mem (&priv->device_image);
G_OBJECT_CLASS(ufo_buffer_parent_class)->finalize(gobject);
}
@@ -518,10 +891,12 @@ ufo_buffer_init (UfoBuffer *buffer)
buffer->priv = priv = UFO_BUFFER_GET_PRIVATE(buffer);
priv->last_queue = NULL;
priv->device_array = NULL;
- priv->host_array.data = NULL;
- priv->host_array.num_dims = 0;
- priv->timer = g_timer_new ();
- g_timer_stop (priv->timer);
+ priv->device_image = NULL;
+ priv->host_array = NULL;
+
+ priv->location = UFO_LOCATION_INVALID;
+ priv->last_location = UFO_LOCATION_INVALID;
+ priv->requisition.n_dims = 0;
}
static void
diff --git a/ufo/ufo-buffer.h b/ufo/ufo-buffer.h
index de6c0f6..0dc56e8 100644
--- a/ufo/ufo-buffer.h
+++ b/ufo/ufo-buffer.h
@@ -39,20 +39,6 @@ G_BEGIN_DECLS
#define UFO_IS_PARAM_SPEC_BUFFER(pspec) (G_TYPE_CHECK_INSTANCE_TYPE((pspec), UFO_TYPE_PARAM_BUFFER))
#define UFO_BUFFER_PARAM_SPEC(pspec) (G_TYPE_CHECK_INSTANCE_CAST((pspec), UFO_TYPE_PARAM_BUFFER, UfoBufferParamSpec))
-/**
- * UfoMemLocation:
- * @UFO_LOCATION_INVALID: Memory is neither valid on host nor on device.
- * @UFO_LOCATION_HOST: Memory is valid on host memory.
- * @UFO_LOCATION_DEVICE: Memory is valid on device memory.
- *
- * Memory locations of a #UfoBuffer.
- */
-typedef enum {
- UFO_LOCATION_INVALID,
- UFO_LOCATION_HOST,
- UFO_LOCATION_DEVICE
-} UfoMemLocation;
-
typedef struct _UfoBuffer UfoBuffer;
typedef struct _UfoBufferClass UfoBufferClass;
typedef struct _UfoBufferPrivate UfoBufferPrivate;
@@ -129,6 +115,8 @@ typedef enum {
UfoBuffer* ufo_buffer_new (UfoRequisition *requisition,
gpointer context);
+UfoBuffer* ufo_buffer_new_with_size (GList *dims,
+ gpointer context);
void ufo_buffer_resize (UfoBuffer *buffer,
UfoRequisition *requisition);
gint ufo_buffer_cmp_dimensions (UfoBuffer *buffer,
@@ -143,10 +131,14 @@ gfloat* ufo_buffer_get_host_array (UfoBuffer *buffer,
gpointer cmd_queue);
gpointer ufo_buffer_get_device_array (UfoBuffer *buffer,
gpointer cmd_queue);
-void ufo_buffer_discard_location (UfoBuffer *buffer,
- UfoMemLocation location);
+gpointer ufo_buffer_get_device_image (UfoBuffer *buffer,
+ gpointer cmd_queue);
+void ufo_buffer_discard_location (UfoBuffer *buffer);
void ufo_buffer_convert (UfoBuffer *buffer,
UfoBufferDepth depth);
+void ufo_buffer_convert_from_data (UfoBuffer *buffer,
+ gconstpointer data,
+ UfoBufferDepth depth);
GType ufo_buffer_get_type (void);
GParamSpec* ufo_buffer_param_spec (const gchar* name,
diff --git a/ufo/ufo-config.c b/ufo/ufo-config.c
index afebe19..aad6a7b 100644
--- a/ufo/ufo-config.c
+++ b/ufo/ufo-config.c
@@ -42,18 +42,16 @@ static void add_path (const gchar *path, UfoConfigPrivate *priv);
enum {
PROP_0,
PROP_PATHS,
- PROP_PROFILE_LEVEL,
- PROP_PROFILE_OUTPUT_PREFIX,
+ PROP_DEVICE_TYPE,
N_PROPERTIES
};
struct _UfoConfigPrivate {
- GValueArray *path_array;
- UfoProfilerLevel profile_level;
- gchar *profile_output_prefix;
+ GValueArray *path_array;
+ UfoDeviceType device_type;
};
-static GParamSpec *config_properties[N_PROPERTIES] = { NULL, };
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
/**
* ufo_config_new:
@@ -98,6 +96,13 @@ ufo_config_get_paths (UfoConfig *config)
return paths;
}
+UfoDeviceType
+ufo_config_get_device_type (UfoConfig *config)
+{
+ g_return_val_if_fail (UFO_IS_CONFIG (config), 0);
+ return config->priv->device_type;
+}
+
/**
* ufo_config_add_paths:
* @config: A #UfoConfig object
@@ -136,25 +141,21 @@ ufo_config_set_property (GObject *object,
switch (property_id) {
case PROP_PATHS:
{
- GValueArray *array;
+ GValueArray *more_paths;
- if (priv->path_array != NULL)
- g_value_array_free (priv->path_array);
+ more_paths = g_value_get_boxed (value);
- array = g_value_get_boxed (value);
-
- if (array != NULL)
- priv->path_array = g_value_array_copy (array);
+ if (more_paths != NULL) {
+ for (guint i = 0; i < more_paths->n_values; i++) {
+ g_value_array_append (priv->path_array,
+ g_value_array_get_nth (more_paths, i));
+ }
+ }
}
break;
- case PROP_PROFILE_LEVEL:
- priv->profile_level = g_value_get_flags (value);
- break;
-
- case PROP_PROFILE_OUTPUT_PREFIX:
- g_free (priv->profile_output_prefix);
- priv->profile_output_prefix = g_strdup (g_value_get_string (value));
+ case PROP_DEVICE_TYPE:
+ priv->device_type = g_value_get_flags (value);
break;
default:
@@ -176,12 +177,8 @@ ufo_config_get_property (GObject *object,
g_value_set_boxed (value, priv->path_array);
break;
- case PROP_PROFILE_LEVEL:
- g_value_set_flags (value, priv->profile_level);
- break;
-
- case PROP_PROFILE_OUTPUT_PREFIX:
- g_value_set_string (value, priv->profile_output_prefix);
+ case PROP_DEVICE_TYPE:
+ g_value_set_flags (value, priv->device_type);
break;
default:
@@ -211,11 +208,11 @@ ufo_config_finalize (GObject *object)
static void
ufo_config_class_init (UfoConfigClass *klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gobject_class->set_property = ufo_config_set_property;
- gobject_class->get_property = ufo_config_get_property;
- gobject_class->dispose = ufo_config_dispose;
- gobject_class->finalize = ufo_config_finalize;
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ oclass->set_property = ufo_config_set_property;
+ oclass->get_property = ufo_config_get_property;
+ oclass->dispose = ufo_config_dispose;
+ oclass->finalize = ufo_config_finalize;
/**
* UfoConfig:paths:
@@ -223,7 +220,7 @@ ufo_config_class_init (UfoConfigClass *klass)
* An array of strings with paths pointing to possible filter and kernel
* file locations.
*/
- config_properties[PROP_PATHS] =
+ properties[PROP_PATHS] =
g_param_spec_value_array ("paths",
"Array with paths",
"Array with paths",
@@ -235,30 +232,24 @@ ufo_config_class_init (UfoConfigClass *klass)
G_PARAM_READWRITE);
/**
- * UfoConfig:profile-level:
+ * UfoConfig:device-class:
*
- * Controls the amount of profiling.
+ * Let the user select which device class to use for execution.
*
- * See: #UfoProfilerLevel for different levels of profiling.
+ * See: #UfoDeviceType for the device classes.
*/
- config_properties[PROP_PROFILE_LEVEL] =
- g_param_spec_flags ("profile-level",
- "Profiling level",
- "Profiling level",
- UFO_TYPE_PROFILER_LEVEL,
- UFO_PROFILER_LEVEL_NONE,
+ properties[PROP_DEVICE_TYPE] =
+ g_param_spec_flags ("device-type",
+ "Device type to use",
+ "Device type to use",
+ UFO_TYPE_DEVICE_TYPE,
+ UFO_DEVICE_ALL,
G_PARAM_READWRITE);
- config_properties[PROP_PROFILE_OUTPUT_PREFIX] =
- g_param_spec_string ("profile-output-prefix",
- "Filename prefix for profiling output",
- "Filename prefix for profiling output. If NULL, information is output to stdout.",
- NULL,
- G_PARAM_READWRITE);
-
- g_object_class_install_property (gobject_class, PROP_PATHS, config_properties[PROP_PATHS]);
- g_object_class_install_property (gobject_class, PROP_PROFILE_LEVEL, config_properties[PROP_PROFILE_LEVEL]);
- g_object_class_install_property (gobject_class, PROP_PROFILE_OUTPUT_PREFIX, config_properties[PROP_PROFILE_OUTPUT_PREFIX]);
+ g_object_class_install_property (oclass, PROP_PATHS,
+ properties[PROP_PATHS]);
+ g_object_class_install_property (oclass, PROP_DEVICE_TYPE,
+ properties[PROP_DEVICE_TYPE]);
g_type_class_add_private(klass, sizeof (UfoConfigPrivate));
}
@@ -270,8 +261,7 @@ ufo_config_init (UfoConfig *config)
config->priv = priv = UFO_CONFIG_GET_PRIVATE (config);
priv->path_array = g_value_array_new (0);
- priv->profile_level = UFO_PROFILER_LEVEL_NONE;
- priv->profile_output_prefix = NULL;
+ priv->device_type = UFO_DEVICE_ALL;
add_path ("/usr/local/lib64/ufo", priv);
add_path ("/usr/local/lib/ufo", priv);
diff --git a/ufo/ufo-config.h b/ufo/ufo-config.h
index 447350e..87b35ea 100644
--- a/ufo/ufo-config.h
+++ b/ufo/ufo-config.h
@@ -61,11 +61,27 @@ struct _UfoConfigClass {
GObjectClass parent_class;
};
-UfoConfig * ufo_config_new (void);
-void ufo_config_add_paths (UfoConfig *config,
- GList *paths);
-GList * ufo_config_get_paths (UfoConfig *config);
-GType ufo_config_get_type (void);
+/**
+ * UfoDeviceType:
+ * @UFO_DEVICE_ALL: All devices
+ * @UFO_DEVICE_CPU: Only CPU devices
+ * @UFO_DEVICE_GPU: Only GPU devices
+ *
+ * Types of OpenCL devices to query for. See UfoConfig:"device-type".
+ */
+typedef enum {
+ UFO_DEVICE_CPU = 1 << 0,
+ UFO_DEVICE_GPU = 1 << 1,
+ UFO_DEVICE_ALL = (1 << 1) | (1 << 0)
+} UfoDeviceType;
+
+
+UfoConfig * ufo_config_new (void);
+void ufo_config_add_paths (UfoConfig *config,
+ GList *paths);
+GList * ufo_config_get_paths (UfoConfig *config);
+UfoDeviceType ufo_config_get_device_type (UfoConfig *config);
+GType ufo_config_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-cpu-task-iface.c b/ufo/ufo-cpu-task-iface.c
index fe85176..28b406c 100644
--- a/ufo/ufo-cpu-task-iface.c
+++ b/ufo/ufo-cpu-task-iface.c
@@ -33,14 +33,6 @@ ufo_cpu_task_process (UfoCpuTask *task,
return UFO_CPU_TASK_GET_IFACE (task)->process (task, inputs, output, requisition);
}
-void
-ufo_cpu_task_reduce (UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition)
-{
- UFO_CPU_TASK_GET_IFACE (task)->reduce (task, output, requisition);
-}
-
gboolean
ufo_cpu_task_generate (UfoCpuTask *task,
UfoBuffer *output,
@@ -59,14 +51,6 @@ ufo_cpu_task_process_real (UfoCpuTask *task,
return FALSE;
}
-static void
-ufo_cpu_task_reduce_real (UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition)
-{
- g_warning ("`reduce' of UfoCpuTaskInterface not implemented");
-}
-
static gboolean
ufo_cpu_task_generate_real (UfoCpuTask *task,
UfoBuffer *output,
@@ -80,6 +64,5 @@ static void
ufo_cpu_task_default_init (UfoCpuTaskInterface *iface)
{
iface->process = ufo_cpu_task_process_real;
- iface->reduce = ufo_cpu_task_reduce_real;
iface->generate = ufo_cpu_task_generate_real;
}
diff --git a/ufo/ufo-cpu-task-iface.h b/ufo/ufo-cpu-task-iface.h
index 5cc2e64..a774e63 100644
--- a/ufo/ufo-cpu-task-iface.h
+++ b/ufo/ufo-cpu-task-iface.h
@@ -43,28 +43,22 @@ struct _UfoCpuTaskIface {
/*< private >*/
UfoTaskIface parent_iface;
- gboolean (*process) (UfoCpuTask *task,
- UfoBuffer **inputs,
- UfoBuffer *output,
- UfoRequisition *requisition);
- void (*reduce) (UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition);
- gboolean (*generate)(UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition);
+ gboolean (*process) (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+ gboolean (*generate) (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
};
-gboolean ufo_cpu_task_process (UfoCpuTask *task,
- UfoBuffer **inputs,
- UfoBuffer *output,
- UfoRequisition *requisition);
-void ufo_cpu_task_reduce (UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition);
-gboolean ufo_cpu_task_generate(UfoCpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition);
+gboolean ufo_cpu_task_process (UfoCpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+gboolean ufo_cpu_task_generate (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
GType ufo_cpu_task_get_type (void);
diff --git a/ufo/ufo-daemon.c b/ufo/ufo-daemon.c
new file mode 100644
index 0000000..eec9ce3
--- /dev/null
+++ b/ufo/ufo-daemon.c
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+
+#ifdef MPI
+#include <mpi.h>
+#include <ufo/ufo-mpi-messenger.h>
+#endif
+
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ufo/ufo-config.h>
+#include <ufo/ufo-daemon.h>
+#include <ufo/ufo-dummy-task.h>
+#include <ufo/ufo-input-task.h>
+#include <ufo/ufo-output-task.h>
+#include <ufo/ufo-plugin-manager.h>
+#include <ufo/ufo-scheduler.h>
+#include <ufo/ufo-task-graph.h>
+#include <ufo/ufo-zmq-messenger.h>
+#include <ufo/ufo-messenger-iface.h>
+
+G_DEFINE_TYPE (UfoDaemon, ufo_daemon, G_TYPE_OBJECT)
+
+#define UFO_DAEMON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_DAEMON, UfoDaemonPrivate))
+
+struct _UfoDaemonPrivate {
+ UfoConfig *config;
+ UfoPluginManager *manager;
+ UfoTaskGraph *task_graph;
+ UfoScheduler *scheduler;
+ GThread *scheduler_thread;
+ gpointer socket;
+ UfoNode *input_task;
+ UfoNode *output_task;
+ UfoBuffer *input;
+ gpointer context;
+ gchar *listen_address;
+ GThread *thread;
+ GMutex *startstop_lock;
+ GMutex *started_lock;
+ GMutex *stopped_lock;
+ gboolean has_started;
+ gboolean has_stopped;
+ GCond *started_cond;
+ GCond *stopped_cond;
+ UfoMessenger *msger;
+};
+
+static gpointer run_scheduler (UfoDaemon *daemon);
+
+UfoDaemon *
+ufo_daemon_new (UfoConfig *config, gchar *listen_address)
+{
+ UfoDaemon *daemon;
+
+ g_return_val_if_fail (listen_address != NULL, NULL);
+ g_return_val_if_fail (config != NULL, NULL);
+
+ daemon = UFO_DAEMON (g_object_new (UFO_TYPE_DAEMON, NULL));
+
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ priv->config = config;
+ priv->listen_address = listen_address;
+ priv->manager = ufo_plugin_manager_new (priv->config);
+ priv->scheduler = ufo_scheduler_new (priv->config, NULL);
+#ifdef MPI
+ priv->msger = UFO_MESSENGER (ufo_mpi_messenger_new ());
+#else
+ priv->msger = UFO_MESSENGER (ufo_zmq_messenger_new ());
+#endif
+ return daemon;
+}
+
+static void
+handle_get_num_devices (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ cl_context context;
+
+ UfoMessage *msg = ufo_message_new (UFO_MESSAGE_ACK, sizeof (guint16));
+ cl_uint *num_devices = g_malloc (sizeof (cl_uint));
+ context = ufo_scheduler_get_context (priv->scheduler);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetContextInfo (context,
+ CL_CONTEXT_NUM_DEVICES,
+ sizeof (cl_uint),
+ num_devices,
+ NULL));
+
+ *(guint16 *) msg->data = (guint16) *num_devices;
+
+ ufo_messenger_send_blocking (priv->msger, msg, 0);
+ ufo_message_free (msg);
+}
+
+static UfoNode *
+remove_dummy_if_present (UfoGraph *graph,
+ UfoNode *first)
+{
+ UfoNode *real = first;
+
+ if (UFO_IS_DUMMY_TASK (first)) {
+ UfoNode *dummy;
+ GList *successors;
+
+ dummy = first;
+ successors = ufo_graph_get_successors (graph, dummy);
+ g_assert (g_list_length (successors) == 1);
+ real = UFO_NODE (successors->data);
+ g_list_free (successors);
+ ufo_graph_remove_edge (graph, dummy, real);
+ }
+
+ return real;
+}
+
+static gchar *
+read_json (UfoDaemon *daemon, UfoMessage *msg)
+{
+ gchar *json;
+
+ json = g_malloc0 (msg->data_size + 1);
+ memcpy (json, msg->data, msg->data_size);
+
+ return json;
+}
+
+static void
+handle_replicate_json (UfoDaemon *daemon, UfoMessage *msg)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ gchar *json;
+ UfoTaskGraph *graph;
+ GError *error = NULL;
+
+ json = read_json (daemon, msg);
+
+ // send ack
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, 0);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+
+ graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+ ufo_task_graph_read_from_data (graph, priv->manager, json, &error);
+
+ if (error != NULL) {
+ g_printerr ("%s\n", error->message);
+ goto replicate_json_free;
+ }
+
+ ufo_scheduler_run (priv->scheduler, graph, NULL);
+ g_object_unref (priv->scheduler);
+
+ priv->scheduler = ufo_scheduler_new (priv->config, NULL);
+
+replicate_json_free:
+ g_object_unref (graph);
+ g_free (json);
+}
+
+static void
+handle_stream_json (UfoDaemon *daemon, UfoMessage *msg)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ gchar *json;
+ GList *roots;
+ GList *leaves;
+ UfoNode *first;
+ UfoNode *last;
+ GError *error = NULL;
+
+ json = read_json (daemon, msg);
+ // send ack
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, 0);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+
+ /* Setup local task graph */
+ priv->task_graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+ ufo_task_graph_read_from_data (priv->task_graph, priv->manager, json, &error);
+
+ if (error != NULL) {
+ g_printerr ("%s\n", error->message);
+ /* Send error to master */
+ return;
+ }
+
+ roots = ufo_graph_get_roots (UFO_GRAPH (priv->task_graph));
+ g_assert (g_list_length (roots) == 1);
+
+ leaves = ufo_graph_get_leaves (UFO_GRAPH (priv->task_graph));
+ g_assert (g_list_length (leaves) == 1);
+
+ first = UFO_NODE (g_list_nth_data (roots, 0));
+ last = UFO_NODE (g_list_nth_data (leaves, 0));
+
+ first = remove_dummy_if_present (UFO_GRAPH (priv->task_graph), first);
+
+ priv->input_task = ufo_input_task_new ();
+ priv->output_task = ufo_output_task_new (2);
+
+ ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
+ priv->input_task, first,
+ GINT_TO_POINTER (0));
+
+ ufo_graph_connect_nodes (UFO_GRAPH (priv->task_graph),
+ last, priv->output_task,
+ GINT_TO_POINTER (0));
+
+ priv->scheduler_thread = g_thread_create ((GThreadFunc) run_scheduler, daemon, TRUE, NULL);
+ g_free (json);
+}
+
+static void
+handle_get_structure (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ UfoMessage *response;
+
+ /* TODO move into .h and share between daemon and remote-node */
+ struct _Structure {
+ guint16 n_inputs;
+ guint16 n_dims;
+ } msg_data;
+
+ /* TODO don't hardcode these */
+ msg_data.n_inputs = 1;
+ msg_data.n_dims = 2;
+
+ response = ufo_message_new (UFO_MESSAGE_ACK, sizeof (struct _Structure));
+ *(struct _Structure *) (response->data) = msg_data;
+
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+}
+
+static void
+handle_send_inputs (UfoDaemon *daemon, UfoMessage *request)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ UfoRequisition requisition;
+ gpointer context;
+
+ context = ufo_scheduler_get_context (priv->scheduler);
+
+ struct _Header {
+ UfoRequisition requisition;
+ guint64 buffer_size;
+ };
+
+ char *base = request->data;
+ struct _Header *header = (struct _Header *) base;
+
+ /* Receive buffer size */
+ requisition = header->requisition;
+ if (priv->input == NULL) {
+ priv->input = ufo_buffer_new (&requisition, context);
+ }
+ else {
+ if (ufo_buffer_cmp_dimensions (priv->input, &requisition))
+ ufo_buffer_resize (priv->input, &requisition);
+ }
+ memcpy (ufo_buffer_get_host_array (priv->input, NULL),
+ base + sizeof (struct _Header),
+ ufo_buffer_get_size (priv->input));
+ ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task), priv->input);
+
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, 0);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+}
+
+static void
+handle_get_requisition (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ UfoRequisition requisition;
+
+ /* We need to get the requisition from the last node */
+ ufo_output_task_get_output_requisition (UFO_OUTPUT_TASK (priv->output_task),
+ &requisition);
+
+ UfoMessage *msg = ufo_message_new (UFO_MESSAGE_ACK, sizeof (UfoRequisition));
+ memcpy (msg->data, &requisition, msg->data_size);
+ ufo_messenger_send_blocking (priv->msger, msg, NULL);
+ ufo_message_free (msg);
+}
+
+static
+void handle_get_result (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ UfoBuffer *buffer;
+ gsize size;
+
+ buffer = ufo_output_task_get_output_buffer (UFO_OUTPUT_TASK (priv->output_task));
+ size = ufo_buffer_get_size (buffer);
+
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, size);
+ memcpy (response->data, ufo_buffer_get_host_array (buffer, NULL), size);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_output_task_release_output_buffer (UFO_OUTPUT_TASK (priv->output_task), buffer);
+}
+
+static void
+unref_and_free (GObject **object)
+{
+ if (*object) {
+ g_object_unref (*object);
+ *object = NULL;
+ }
+}
+
+static
+void handle_cleanup (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+
+ /*
+ * We send the ACK early on, because we don't want to let the host wait for
+ * actually cleaning up (and waiting some time to unref the input task).
+ */
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, 0);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+
+ // TODO check that we don't need to execture this branch wen priv->input is null
+ if (priv->input_task && priv->input) {
+ ufo_input_task_stop (UFO_INPUT_TASK (priv->input_task));
+
+ ufo_input_task_release_input_buffer (UFO_INPUT_TASK (priv->input_task),
+ priv->input);
+
+ g_usleep (1.5 * G_USEC_PER_SEC);
+ unref_and_free ((GObject **) &priv->input_task);
+ unref_and_free ((GObject **) &priv->input);
+ }
+
+ unref_and_free ((GObject **) &priv->output_task);
+ unref_and_free ((GObject **) &priv->task_graph);
+
+}
+
+static void
+handle_terminate (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ UfoMessage *response = ufo_message_new (UFO_MESSAGE_ACK, 0);
+ ufo_messenger_send_blocking (priv->msger, response, NULL);
+ ufo_message_free (response);
+
+ if(priv->scheduler_thread != NULL) {
+ g_message ("waiting for scheduler to finish");
+ g_thread_join (priv->scheduler_thread);
+ g_message ("scheduler finished!");
+ }
+
+ ufo_messenger_disconnect (priv->msger);
+}
+
+static gpointer
+run_scheduler (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ g_message ("Start scheduler");
+ ufo_scheduler_run (priv->scheduler, priv->task_graph, NULL);
+
+ g_message ("Done");
+ g_object_unref (priv->scheduler);
+
+ priv->scheduler = ufo_scheduler_new (priv->config, NULL);
+ return NULL;
+}
+
+static void
+ufo_daemon_start_impl (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ g_debug ("UfoDaemon started on address %s", priv->listen_address);
+
+ // tell the calling thread that we have started
+ g_mutex_lock (priv->started_lock);
+ priv->has_started = TRUE;
+ g_cond_signal (priv->started_cond);
+ g_mutex_unlock (priv->started_lock);
+
+ gboolean wait_for_messages = TRUE;
+ while (wait_for_messages) {
+
+ GError *err = NULL;
+ UfoMessage *msg = ufo_messenger_recv_blocking (priv->msger, &err);
+ if (err != NULL) {
+ /* if daemon is stopped, socket will be closed and msg_recv
+ * will yield an error - we stop
+ */
+ wait_for_messages = FALSE;
+ } else {
+ switch (msg->type) {
+ case UFO_MESSAGE_GET_NUM_DEVICES:
+ handle_get_num_devices (daemon);
+ break;
+ case UFO_MESSAGE_STREAM_JSON:
+ handle_stream_json (daemon, msg);
+ break;
+ case UFO_MESSAGE_REPLICATE_JSON:
+ handle_replicate_json (daemon, msg);
+ break;
+ case UFO_MESSAGE_GET_STRUCTURE:
+ handle_get_structure (daemon);
+ break;
+ case UFO_MESSAGE_SEND_INPUTS:
+ handle_send_inputs (daemon, msg);
+ break;
+ case UFO_MESSAGE_GET_REQUISITION:
+ handle_get_requisition (daemon);
+ break;
+ case UFO_MESSAGE_GET_RESULT:
+ handle_get_result (daemon);
+ break;
+ case UFO_MESSAGE_CLEANUP:
+ handle_cleanup (daemon);
+ break;
+ case UFO_MESSAGE_TERMINATE:
+ handle_terminate (daemon);
+ wait_for_messages = FALSE;
+ break;
+ default:
+ g_message ("Unknown message received\n");
+ }
+ }
+ ufo_message_free (msg);
+ }
+
+ // tell calling thread we have stopped
+ g_mutex_lock (priv->stopped_lock);
+ priv->has_stopped = TRUE;
+ g_cond_signal (priv->stopped_cond);
+ g_mutex_unlock (priv->stopped_lock);
+}
+
+void
+ufo_daemon_start (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+
+ g_mutex_lock (priv->startstop_lock);
+ if (priv->has_started) {
+ g_mutex_unlock (priv->startstop_lock);
+ return;
+ }
+
+ /* TODO handle error if unable to connect/bind */
+ ufo_messenger_connect (priv->msger, priv->listen_address, UFO_MESSENGER_SERVER);
+
+ priv->thread = g_thread_create ((GThreadFunc)ufo_daemon_start_impl, daemon, TRUE, NULL);
+ g_return_if_fail (priv->thread != NULL);
+
+ g_mutex_lock (priv->started_lock);
+ while (!priv->has_started)
+ g_cond_wait (priv->started_cond, priv->started_lock);
+ g_mutex_unlock (priv->started_lock);
+
+
+ g_mutex_unlock (priv->startstop_lock);
+}
+
+void
+ufo_daemon_stop (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+ g_mutex_lock (priv->startstop_lock);
+
+ /* HACK we can't call _disconnect() as this has to be run from the
+ * thread running the daemon which might be blocking on recv
+ * - we thus send a TERMINATE message to that thread
+ */
+
+ UfoMessenger *tmp_msger;
+#ifdef MPI
+ tmp_msger = UFO_MESSENGER (ufo_mpi_messenger_new ());
+#else
+ tmp_msger = UFO_MESSENGER (ufo_zmq_messenger_new ());
+#endif
+
+ ufo_messenger_connect (tmp_msger, priv->listen_address, UFO_MESSENGER_CLIENT);
+ UfoMessage *request = ufo_message_new (UFO_MESSAGE_TERMINATE, 0);
+ ufo_messenger_send_blocking (tmp_msger, request, NULL);
+
+ g_thread_join (priv->thread);
+
+ g_mutex_lock (priv->stopped_lock);
+ priv->has_stopped = TRUE;
+ g_cond_signal (priv->stopped_cond);
+ g_mutex_unlock (priv->stopped_lock);
+
+ g_mutex_unlock (priv->startstop_lock);
+}
+
+void ufo_daemon_wait_finish (UfoDaemon *daemon)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (daemon);
+
+ g_mutex_lock (priv->stopped_lock);
+ while (!priv->has_stopped)
+ g_cond_wait (priv->stopped_cond, priv->stopped_lock);
+ g_mutex_unlock (priv->stopped_lock);
+}
+
+static void
+ufo_daemon_dispose (GObject *object)
+{
+ UfoDaemonPrivate *priv;
+ priv = UFO_DAEMON_GET_PRIVATE (object);
+
+ if (priv->task_graph)
+ g_object_unref (priv->task_graph);
+ if (priv->config != NULL)
+ g_object_unref (priv->config);
+ if (priv->msger != NULL)
+ g_object_unref (priv->msger);
+ if (priv->manager != NULL)
+ g_object_unref (priv->manager);
+ if (priv->scheduler != NULL)
+ g_object_unref (priv->scheduler);
+
+ G_OBJECT_CLASS (ufo_daemon_parent_class)->dispose (object);
+}
+
+static void
+ufo_daemon_finalize (GObject *object)
+{
+ UfoDaemonPrivate *priv = UFO_DAEMON_GET_PRIVATE (object);
+ g_mutex_free (priv->startstop_lock);
+ g_cond_free (priv->started_cond);
+
+ G_OBJECT_CLASS (ufo_daemon_parent_class)->finalize (object);
+}
+
+static void
+ufo_daemon_class_init (UfoDaemonClass *klass)
+{
+ GObjectClass *oclass;
+
+ oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_daemon_dispose;
+ oclass->finalize = ufo_daemon_finalize;
+
+ g_type_class_add_private (klass, sizeof (UfoDaemonPrivate));
+}
+
+static void
+ufo_daemon_init (UfoDaemon *self)
+{
+ UfoDaemonPrivate *priv;
+ self->priv = priv = UFO_DAEMON_GET_PRIVATE (self);
+ priv->startstop_lock = g_mutex_new ();
+ priv->started_lock = g_mutex_new ();
+ priv->stopped_lock = g_mutex_new ();
+ priv->started_cond = g_cond_new ();
+ priv->stopped_cond = g_cond_new ();
+ priv->has_started = FALSE;
+ priv->has_stopped = FALSE;
+}
diff --git a/ufo/ufo-daemon.h b/ufo/ufo-daemon.h
new file mode 100644
index 0000000..3610310
--- /dev/null
+++ b/ufo/ufo-daemon.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_DAEMON_H
+#define __UFO_DAEMON_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_DAEMON (ufo_daemon_get_type())
+#define UFO_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_DAEMON, UfoDaemon))
+#define UFO_IS_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_DAEMON))
+#define UFO_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_DAEMON, UfoDaemonClass))
+#define UFO_IS_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_DAEMON))
+#define UFO_DAEMON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_DAEMON, UfoDaemonClass))
+
+typedef struct _UfoDaemon UfoDaemon;
+typedef struct _UfoDaemonClass UfoDaemonClass;
+typedef struct _UfoDaemonPrivate UfoDaemonPrivate;
+
+/**
+ * UfoDaemon:
+ *
+ * TODO: Add documentation
+ */
+struct _UfoDaemon {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoDaemonPrivate *priv;
+};
+
+/**
+ * UfoDaemonClass:
+ *
+ * #UfoDaemon class
+ */
+struct _UfoDaemonClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoDaemon * ufo_daemon_new (UfoConfig *config, gchar *listen_addr);
+void ufo_daemon_start (UfoDaemon *daemon);
+void ufo_daemon_stop (UfoDaemon *daemon);
+void ufo_daemon_wait_finish (UfoDaemon *daemon);
+GType ufo_daemon_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-gpu-task-iface.c b/ufo/ufo-gpu-task-iface.c
index bc33ff4..10415b2 100644
--- a/ufo/ufo-gpu-task-iface.c
+++ b/ufo/ufo-gpu-task-iface.c
@@ -27,55 +27,33 @@ gboolean
ufo_gpu_task_process (UfoGpuTask *task,
UfoBuffer **inputs,
UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
+ UfoRequisition *requisition)
{
- return UFO_GPU_TASK_GET_IFACE (task)->process (task, inputs, output, requisition, node);
-}
-
-void
-ufo_gpu_task_reduce (UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
-{
- UFO_GPU_TASK_GET_IFACE (task)->reduce (task, output, requisition, node);
+ return UFO_GPU_TASK_GET_IFACE (task)->process (task, inputs, output, requisition);
}
gboolean
ufo_gpu_task_generate (UfoGpuTask *task,
UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
+ UfoRequisition *requisition)
{
- return UFO_GPU_TASK_GET_IFACE (task)->generate (task, output, requisition, node);
+ return UFO_GPU_TASK_GET_IFACE (task)->generate (task, output, requisition);
}
static gboolean
ufo_gpu_task_process_real (UfoGpuTask *task,
UfoBuffer **inputs,
UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
+ UfoRequisition *requisition)
{
g_warning ("`process' of UfoGpuTaskInterface not implemented");
return FALSE;
}
-static void
-ufo_gpu_task_reduce_real (UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
-{
- g_warning ("`reduce' of UfoGpuTaskInterface not implemented");
-}
-
static gboolean
ufo_gpu_task_generate_real (UfoGpuTask *task,
UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node)
+ UfoRequisition *requisition)
{
g_warning ("`generate' of UfoGpuTaskInterface not implemented");
return FALSE;
@@ -85,6 +63,5 @@ static void
ufo_gpu_task_default_init (UfoGpuTaskInterface *iface)
{
iface->process = ufo_gpu_task_process_real;
- iface->reduce = ufo_gpu_task_reduce_real;
iface->generate = ufo_gpu_task_generate_real;
}
diff --git a/ufo/ufo-gpu-task-iface.h b/ufo/ufo-gpu-task-iface.h
index 1a78f74..4c1ff78 100644
--- a/ufo/ufo-gpu-task-iface.h
+++ b/ufo/ufo-gpu-task-iface.h
@@ -44,34 +44,22 @@ struct _UfoGpuTaskIface {
/*< private >*/
UfoTaskIface parent_iface;
- gboolean (*process) (UfoGpuTask *task,
- UfoBuffer **inputs,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
- void (*reduce) (UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
- gboolean (*generate)(UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
+ gboolean (*process) (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+ gboolean (*generate) (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
};
-gboolean ufo_gpu_task_process (UfoGpuTask *task,
- UfoBuffer **inputs,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
-void ufo_gpu_task_reduce (UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
-gboolean ufo_gpu_task_generate(UfoGpuTask *task,
- UfoBuffer *output,
- UfoRequisition *requisition,
- UfoGpuNode *node);
+gboolean ufo_gpu_task_process (UfoGpuTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+gboolean ufo_gpu_task_generate (UfoGpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
GType ufo_gpu_task_get_type (void);
diff --git a/ufo/ufo-graph.c b/ufo/ufo-graph.c
index 57c2e5b..62ef704 100644
--- a/ufo/ufo-graph.c
+++ b/ufo/ufo-graph.c
@@ -32,9 +32,9 @@ G_DEFINE_TYPE (UfoGraph, ufo_graph, G_TYPE_OBJECT)
#define UFO_GRAPH_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_GRAPH, UfoGraphPrivate))
struct _UfoGraphPrivate {
- GList *node_types;
GList *nodes;
GList *edges;
+ GList *copies;
};
enum {
@@ -62,45 +62,6 @@ ufo_graph_new (void)
}
/**
- * ufo_graph_register_node_type:
- * @graph: A #UfoGraph
- * @type: A #GType
- *
- * Registers @type to be a valid node type of this graph. If a type has not be
- * an added to @graph, any attempt to add such a node will fail.
- */
-void
-ufo_graph_register_node_type (UfoGraph *graph,
- GType type)
-{
- UfoGraphPrivate *priv;
-
- g_return_if_fail (UFO_IS_GRAPH (graph));
-
- /* Make sure type is at least a node type */
- g_return_if_fail (g_type_is_a (type, UFO_TYPE_NODE));
-
- priv = graph->priv;
- priv->node_types = g_list_append (priv->node_types, GINT_TO_POINTER (type));
-}
-
-/**
- * ufo_graph_get_registered_node_types:
- * @graph: A #UfoGraph
- *
- * Get all types of nodes that can be added to @graph.
- *
- * Returns: (element-type GType) (transfer container): A list of #GType
- * identifiers that can be added to @graph.
- */
-GList *
-ufo_graph_get_registered_node_types (UfoGraph *graph)
-{
- g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
- return g_list_copy (graph->priv->node_types);
-}
-
-/**
* ufo_graph_is_connected:
* @graph: A #UfoGraph
* @from: A source node
@@ -124,20 +85,6 @@ ufo_graph_is_connected (UfoGraph *graph,
return edge != NULL;
}
-static gboolean
-is_valid_node_type (UfoGraphPrivate *priv,
- UfoNode *node)
-{
- for (GList *it = g_list_first (priv->node_types); it != NULL; it = g_list_next (it)) {
- GType type = (GType) GPOINTER_TO_INT (it->data);
-
- if (G_TYPE_CHECK_INSTANCE_TYPE (node, type))
- return TRUE;
- }
-
- return FALSE;
-}
-
static void
add_node_if_not_found (UfoGraphPrivate *priv,
UfoNode *node)
@@ -170,7 +117,10 @@ ufo_graph_connect_nodes (UfoGraph *graph,
g_return_if_fail (UFO_IS_GRAPH (graph));
priv = graph->priv;
- g_return_if_fail (is_valid_node_type (priv, source) && is_valid_node_type (priv, target));
+ if (ufo_graph_is_connected (graph, source, target) &&
+ ufo_graph_get_edge_label (graph, source, target) == label) {
+ return;
+ }
edge = g_new0 (UfoEdge, 1);
edge->source = source;
@@ -219,7 +169,7 @@ ufo_graph_get_num_edges (UfoGraph *graph)
*
* Get all edges contained in @graph.
*
- * Returns: (element-type UfoEdge): a list of #UfoEdge elements or %NULL on
+ * Returns: (transfer full) (element-type UfoEdge): a list of #UfoEdge elements or %NULL on
* error. Release the list with g_list_free().
*/
GList *
@@ -395,6 +345,26 @@ ufo_graph_get_leaves (UfoGraph *graph)
return ufo_graph_get_nodes_filtered (graph, (UfoFilterPredicate) has_no_successor, graph);
}
+static GList *
+get_target_edges (GList *edges,
+ UfoNode *target)
+{
+ UfoEdge match;
+
+ match.target = target;
+ return g_list_find_all_data (edges, &match, cmp_edge_target);
+}
+
+static GList *
+get_source_edges (GList *edges,
+ UfoNode *source)
+{
+ UfoEdge match;
+
+ match.source = source;
+ return g_list_find_all_data (edges, &match, cmp_edge_source);
+}
+
/**
* ufo_graph_get_predecessors:
* @graph: A #UfoGraph
@@ -410,15 +380,12 @@ ufo_graph_get_predecessors (UfoGraph *graph,
UfoNode *node)
{
UfoGraphPrivate *priv;
- UfoEdge match;
GList *edges;
GList *result;
g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
priv = graph->priv;
-
- match.target = node;
- edges = g_list_find_all_data (priv->edges, &match, cmp_edge_target);
+ edges = get_target_edges (priv->edges, node);
result = NULL;
for (GList *it = g_list_first (edges); it != NULL; it = g_list_next (it)) {
@@ -430,6 +397,22 @@ ufo_graph_get_predecessors (UfoGraph *graph,
return result;
}
+guint
+ufo_graph_get_num_predecessors (UfoGraph *graph,
+ UfoNode *node)
+{
+ UfoGraphPrivate *priv;
+ GList *edges;
+ guint n_predecessors;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), 0);
+ priv = graph->priv;
+ edges = get_target_edges (priv->edges, node);
+ n_predecessors = g_list_length (edges);
+ g_list_free (edges);
+ return n_predecessors;
+}
+
/**
* ufo_graph_get_successors:
* @graph: A #UfoGraph
@@ -445,15 +428,12 @@ ufo_graph_get_successors (UfoGraph *graph,
UfoNode *node)
{
UfoGraphPrivate *priv;
- UfoEdge match;
GList *edges;
GList *result;
g_return_val_if_fail (UFO_IS_GRAPH (graph), NULL);
priv = graph->priv;
-
- match.source = node;
- edges = g_list_find_all_data (priv->edges, &match, cmp_edge_source);
+ edges = get_source_edges (priv->edges, node);
result = NULL;
for (GList *it = g_list_first (edges); it != NULL; it = g_list_next (it)) {
@@ -465,6 +445,164 @@ ufo_graph_get_successors (UfoGraph *graph,
return result;
}
+guint
+ufo_graph_get_num_successors (UfoGraph *graph,
+ UfoNode *node)
+{
+ UfoGraphPrivate *priv;
+ GList *edges;
+ guint n_successors;
+
+ g_return_val_if_fail (UFO_IS_GRAPH (graph), 0);
+ priv = graph->priv;
+ edges = get_source_edges (priv->edges, node);
+ n_successors = g_list_length (edges);
+ g_list_free (edges);
+ return n_successors;
+}
+
+static void
+copy_and_connect_successors (UfoGraph *graph,
+ UfoGraph *copy,
+ UfoNode *source,
+ GHashTable *map,
+ GError **error)
+{
+ GList *successors;
+ UfoNode *copied_source;
+
+ copied_source = g_hash_table_lookup (map, source);
+ successors = ufo_graph_get_successors (graph, source);
+
+ for (GList *jt = g_list_first (successors); jt != NULL; jt = g_list_next (jt)) {
+ UfoNode *target;
+ UfoNode *copied_target;
+ gpointer label;
+
+ target = UFO_NODE (jt->data);
+ copied_target = g_hash_table_lookup (map, target);
+
+ if (copied_target == NULL) {
+ copied_target = ufo_node_copy (target, error);
+
+ if (*error != NULL)
+ return;
+
+ g_hash_table_insert (map, target, copied_target);
+ }
+
+ label = ufo_graph_get_edge_label (graph, source, target);
+ ufo_graph_connect_nodes (copy, copied_source, copied_target, label);
+ copy_and_connect_successors (graph, copy, target, map, error);
+ }
+
+ g_list_free (successors);
+}
+
+/**
+ * ufo_graph_copy:
+ * @graph: A #UfoGraph
+ * @error: Location for an error or %NULL
+ *
+ * Deep-copies the structure of @graph by duplicating all nodes via
+ * ufo_node_copy(). This means the nodes will not be the same but have the same
+ * properties.
+ *
+ * Returns: (transfer full): A copy of @graph or %NULL on error.
+ */
+UfoGraph *
+ufo_graph_copy (UfoGraph *graph,
+ GError **error)
+{
+ UfoGraph *copy;
+ GList *roots;
+ GHashTable *map; /* maps from real node to copied node */
+ GError *tmp_error = NULL;
+
+ copy = UFO_GRAPH (g_object_new (G_OBJECT_TYPE (graph), NULL));
+ map = g_hash_table_new (NULL, NULL);
+ roots = ufo_graph_get_roots (graph);
+
+ for (GList *it = g_list_first (roots); it != NULL; it = g_list_next (it)) {
+ UfoNode *root;
+ UfoNode *copied_root;
+
+ root = UFO_NODE (it->data);
+ copied_root = ufo_node_copy (root, &tmp_error);
+
+ if (tmp_error != NULL)
+ break;
+
+ g_hash_table_insert (map, root, copied_root);
+ copy_and_connect_successors (graph, copy, root, map, &tmp_error);
+
+ if (tmp_error != NULL)
+ break;
+ }
+
+ g_hash_table_destroy (map);
+ g_list_free (roots);
+
+ if (tmp_error != NULL) {
+ g_warning ("Error: %s", tmp_error->message);
+ g_propagate_error (error, tmp_error);
+ g_object_unref (copy);
+ return NULL;
+ }
+
+ return copy;
+}
+
+static GList *
+append_level (UfoGraph *graph,
+ GList *current_level,
+ GList *result)
+{
+ GList *next_level = NULL;
+
+ result = g_list_append (result, current_level);
+
+ for (GList *it = g_list_first (current_level); it != NULL; it = g_list_next (it)) {
+ GList *successors;
+ UfoNode *node;
+
+ node = UFO_NODE (it->data);
+ successors = ufo_graph_get_successors (graph, node);
+
+ for (GList *jt = g_list_first (successors); jt != NULL; jt = g_list_next (jt)) {
+ UfoNode *succ;
+
+ succ = UFO_NODE (jt->data);
+
+ if (g_list_find (next_level, succ) == NULL)
+ next_level = g_list_append (next_level, succ);
+ }
+ }
+
+ if (next_level == NULL)
+ return result;
+
+ return append_level (graph, next_level, result);
+}
+
+/**
+ * ufo_graph_flatten:
+ * @graph: A #UfoGraph
+ *
+ * Flatten @graph to lists of lists.
+ *
+ * Returns: (transfer full) (element-type GList): a GList of GList, each containing nodes at the same height.
+ */
+GList *
+ufo_graph_flatten (UfoGraph *graph)
+{
+ GList *roots;
+ GList *result = NULL;
+
+ roots = ufo_graph_get_roots (graph);
+ return append_level (graph, roots, result);
+}
+
/**
* ufo_graph_expand:
* @graph: A #UfoGraph
@@ -501,10 +639,24 @@ ufo_graph_expand (UfoGraph *graph,
gpointer label;
next = UFO_NODE (it->data);
- copy = ufo_node_copy (next, &error);
- label = ufo_graph_get_edge_label (graph, orig, next);
- ufo_graph_connect_nodes (graph, current, copy, label);
- current = copy;
+
+ /*
+ * Do not copy node if it has more than one input because input data
+ * cannot be reliably associated
+ */
+ if (ufo_graph_get_num_predecessors (graph, next) <= 1) {
+ copy = ufo_node_copy (next, &error);
+ label = ufo_graph_get_edge_label (graph, orig, next);
+ ufo_graph_connect_nodes (graph, current, copy, label);
+ graph->priv->copies = g_list_append (graph->priv->copies, copy);
+ current = copy;
+ }
+ else {
+ label = ufo_graph_get_edge_label (graph, orig, next);
+ ufo_graph_connect_nodes (graph, current, next, label);
+ current = next;
+ }
+
orig = next;
}
@@ -708,18 +860,18 @@ ufo_graph_dispose (GObject *object)
priv->nodes = NULL;
}
+ if (priv->copies != NULL) {
+ g_list_foreach (priv->copies, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->copies);
+ priv->copies = NULL;
+ }
+
G_OBJECT_CLASS (ufo_graph_parent_class)->dispose (object);
}
static void
ufo_graph_finalize (GObject *object)
{
- UfoGraphPrivate *priv;
-
- priv = UFO_GRAPH_GET_PRIVATE (object);
- g_list_free (priv->node_types);
- priv->node_types = NULL;
-
G_OBJECT_CLASS (ufo_graph_parent_class)->finalize (object);
}
@@ -739,6 +891,6 @@ ufo_graph_init (UfoGraph *self)
{
UfoGraphPrivate *priv;
self->priv = priv = UFO_GRAPH_GET_PRIVATE (self);
- priv->node_types = NULL;
priv->nodes = NULL;
+ priv->copies = NULL;
}
diff --git a/ufo/ufo-graph.h b/ufo/ufo-graph.h
index 325a6f2..f1ff113 100644
--- a/ufo/ufo-graph.h
+++ b/ufo/ufo-graph.h
@@ -80,10 +80,6 @@ struct _UfoGraphClass {
};
UfoGraph *ufo_graph_new (void);
-void ufo_graph_register_node_type (UfoGraph *graph,
- GType type);
-GList *ufo_graph_get_registered_node_types
- (UfoGraph *graph);
void ufo_graph_connect_nodes (UfoGraph *graph,
UfoNode *source,
UfoNode *target,
@@ -106,14 +102,21 @@ guint ufo_graph_get_num_edges (UfoGraph *graph);
GList *ufo_graph_get_edges (UfoGraph *graph);
GList *ufo_graph_get_roots (UfoGraph *graph);
GList *ufo_graph_get_leaves (UfoGraph *graph);
+guint ufo_graph_get_num_predecessors (UfoGraph *graph,
+ UfoNode *node);
GList *ufo_graph_get_predecessors (UfoGraph *graph,
UfoNode *node);
+guint ufo_graph_get_num_successors (UfoGraph *graph,
+ UfoNode *node);
GList *ufo_graph_get_successors (UfoGraph *graph,
UfoNode *node);
GList *ufo_graph_get_paths (UfoGraph *graph,
UfoFilterPredicate pred);
+GList *ufo_graph_flatten (UfoGraph *graph);
void ufo_graph_expand (UfoGraph *graph,
GList *path);
+UfoGraph *ufo_graph_copy (UfoGraph *graph,
+ GError **error);
void ufo_graph_dump_dot (UfoGraph *graph,
const gchar *filename);
GType ufo_graph_get_type (void);
diff --git a/ufo/ufo-group.c b/ufo/ufo-group.c
index 0e5a694..2ce2643 100644
--- a/ufo/ufo-group.c
+++ b/ufo/ufo-group.c
@@ -95,6 +95,13 @@ ufo_group_new (GList *targets,
return group;
}
+guint
+ufo_group_get_num_targets (UfoGroup *group)
+{
+ g_return_val_if_fail (UFO_IS_GROUP (group), 0);
+ return group->priv->n_targets;
+}
+
static UfoBuffer *
pop_or_alloc_buffer (UfoGroupPrivate *priv,
guint pos,
@@ -102,7 +109,7 @@ pop_or_alloc_buffer (UfoGroupPrivate *priv,
{
UfoBuffer *buffer;
- if (ufo_queue_get_capacity (priv->queues[pos]) < priv->n_targets) {
+ if (ufo_queue_get_capacity (priv->queues[pos]) < (priv->n_targets + 1)) {
buffer = ufo_buffer_new (requisition, priv->context);
priv->buffers = g_list_append (priv->buffers, buffer);
ufo_queue_insert (priv->queues[pos], UFO_QUEUE_PRODUCER, buffer);
@@ -129,10 +136,12 @@ ufo_group_pop_output_buffer (UfoGroup *group,
UfoRequisition *requisition)
{
UfoGroupPrivate *priv;
- guint pos;
+ guint pos = 0;
priv = group->priv;
- pos = priv->pattern == UFO_SEND_SCATTER || UFO_SEND_SEQUENTIAL ? priv->current : 0;
+
+ if ((priv->pattern == UFO_SEND_SCATTER) || (priv->pattern == UFO_SEND_SEQUENTIAL))
+ pos = priv->current;
return pop_or_alloc_buffer (priv, pos, requisition);
}
@@ -230,6 +239,9 @@ ufo_group_push_input_buffer (UfoGroup *group,
UfoGroupPrivate *priv;
gint pos;
+ if (group == NULL) {
+ // G_BREAKPOINT();
+ }
priv = group->priv;
pos = g_list_index (priv->targets, target);
diff --git a/ufo/ufo-group.h b/ufo/ufo-group.h
index e4e7e32..cdb8061 100644
--- a/ufo/ufo-group.h
+++ b/ufo/ufo-group.h
@@ -83,6 +83,7 @@ struct _UfoGroupClass {
UfoGroup * ufo_group_new (GList *targets,
gpointer context,
UfoSendPattern pattern);
+guint ufo_group_get_num_targets (UfoGroup *group);
void ufo_group_set_num_expected (UfoGroup *group,
UfoTask *target,
gint n_expected);
diff --git a/ufo/ufo-input-task.c b/ufo/ufo-input-task.c
index 68f0cad..3064fa7 100644
--- a/ufo/ufo-input-task.c
+++ b/ufo/ufo-input-task.c
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
#ifdef __APPLE__
#include <OpenCL/cl.h>
@@ -25,8 +26,10 @@
#include <gmodule.h>
#include <ufo/ufo-input-task.h>
#include <ufo/ufo-cpu-task-iface.h>
-#include <ufo/ufo-gpu-task-iface.h>
-#include <ufo/ufo-gpu-node.h>
+
+#ifdef HAVE_PYTHON
+#include <Python.h>
+#endif
/**
* SECTION:ufo-input-task
@@ -63,18 +66,7 @@ enum {
UfoNode *
ufo_input_task_new (void)
{
- UfoInputTask *task;
- UfoInputTaskPrivate *priv;
-
- task = UFO_INPUT_TASK (g_object_new (UFO_TYPE_INPUT_TASK, NULL));
- priv = task->priv;
-
- /* TODO: free in_params and queues */
- priv->in_queue = g_async_queue_new ();
- priv->out_queue = g_async_queue_new ();
- priv->active = TRUE;
-
- return UFO_NODE (task);
+ return UFO_NODE (g_object_new (UFO_TYPE_INPUT_TASK, NULL));
}
void
@@ -99,13 +91,29 @@ ufo_input_task_release_input_buffer (UfoInputTask *task,
* Get the input buffer to which we write the data received from the master
* remote node.
*
- * Return value: (transfer full): A #UfoBuffer for writing input data.
+ * Return value: (transfer none): A #UfoBuffer for writing input data.
*/
UfoBuffer *
ufo_input_task_get_input_buffer (UfoInputTask *task)
{
+ UfoBuffer *buffer;
g_return_val_if_fail (UFO_IS_INPUT_TASK (task), NULL);
- return g_async_queue_pop (task->priv->out_queue);
+
+#ifdef HAVE_PYTHON
+ /*
+ * We have to let the Python interpreter run its threads, because this
+ * function here might block before Python code can insert any buffer.
+ */
+ Py_BEGIN_ALLOW_THREADS
+#endif
+
+ buffer = g_async_queue_pop (task->priv->out_queue);
+
+#ifdef HAVE_PYTHON
+ Py_END_ALLOW_THREADS
+#endif
+
+ return buffer;
}
static void
@@ -122,7 +130,7 @@ ufo_input_task_get_structure (UfoTask *task,
UfoTaskMode *mode)
{
*n_inputs = 0;
- *mode = UFO_TASK_MODE_SINGLE;
+ *mode = UFO_TASK_MODE_GENERATOR;
}
static void
@@ -134,32 +142,34 @@ ufo_input_task_get_requisition (UfoTask *task,
priv = UFO_INPUT_TASK_GET_PRIVATE (task);
- /* Pop input here but release later in ufo_input_task_process */
- priv->input = g_async_queue_pop (priv->in_queue);
- ufo_buffer_get_requisition (priv->input, requisition);
+ /* Pop input here but release later in ufo_input_task_generate */
+ if (priv->active) {
+ priv->input = g_async_queue_pop (priv->in_queue);
+ ufo_buffer_get_requisition (priv->input, requisition);
+ }
}
static gboolean
-ufo_input_task_process (UfoCpuTask *task,
- UfoBuffer **none,
- UfoBuffer *output,
- UfoRequisition *requisition)
+ufo_input_task_generate (UfoCpuTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition)
{
UfoInputTaskPrivate *priv;
g_return_val_if_fail (UFO_IS_INPUT_TASK (task), FALSE);
priv = UFO_INPUT_TASK_GET_PRIVATE (task);
- if (!priv->active)
+ if (!priv->active && priv->input == NULL)
return FALSE;
- ufo_buffer_discard_location (output, UFO_LOCATION_DEVICE);
+ ufo_buffer_discard_location (output);
ufo_buffer_copy (priv->input, output);
/* input was popped in ufo_input_task_get_requisition */
g_async_queue_push (priv->out_queue, priv->input);
+ priv->input = NULL;
- return priv->active;
+ return TRUE;
}
static void
@@ -183,7 +193,7 @@ ufo_task_interface_init (UfoTaskIface *iface)
static void
ufo_cpu_task_interface_init (UfoCpuTaskIface *iface)
{
- iface->process = ufo_input_task_process;
+ iface->generate = ufo_input_task_generate;
}
static void
@@ -201,4 +211,8 @@ ufo_input_task_init (UfoInputTask *task)
{
task->priv = UFO_INPUT_TASK_GET_PRIVATE (task);
ufo_task_node_set_plugin_name (UFO_TASK_NODE (task), "input-task");
+
+ task->priv->in_queue = g_async_queue_new ();
+ task->priv->out_queue = g_async_queue_new ();
+ task->priv->active = TRUE;
}
diff --git a/ufo/ufo-messenger-iface.c b/ufo/ufo-messenger-iface.c
new file mode 100644
index 0000000..d8495cc
--- /dev/null
+++ b/ufo/ufo-messenger-iface.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+ #include <ufo/ufo-messenger-iface.h>
+
+typedef UfoMessengerIface UfoMessengerInterface;
+
+void
+ufo_message_free (UfoMessage *msg)
+{
+ if (msg == NULL)
+ return;
+ g_free (msg->data);
+ g_free (msg);
+}
+
+UfoMessage *
+ufo_message_new (UfoMessageType type, guint64 data_size)
+{
+ UfoMessage *msg = g_malloc (sizeof (UfoMessage));
+ msg->type = type;
+ msg->data_size = data_size;
+ if (data_size == 0)
+ msg->data = NULL;
+ else
+ msg->data = g_malloc (data_size);
+ return msg;
+}
+
+G_DEFINE_INTERFACE (UfoMessenger, ufo_messenger, G_TYPE_OBJECT)
+
+/**
+ * UfoTaskError:
+ * @UFO_TASK_ERROR_SETUP: Error during setup of a task.
+ */
+GQuark
+ufo_messenger_error_quark ()
+{
+ return g_quark_from_static_string ("ufo-messenger-error-quark");
+}
+
+/**
+ * ufo_messenger_connect:
+ * @msger: The messenger object
+ * @addr: (transfer none) : The address to connect. This is implementation specific.
+ * @role: The role of the local endpoint (client or server).
+ *
+ * Connects a messenger to and endpoint.
+ */
+void
+ufo_messenger_connect (UfoMessenger *msger,
+ gchar *addr,
+ UfoMessengerRole role)
+{
+ UFO_MESSENGER_GET_IFACE (msger)->connect (msger, addr, role);
+}
+
+void
+ufo_messenger_disconnect (UfoMessenger *msger)
+{
+ UFO_MESSENGER_GET_IFACE (msger)->disconnect (msger);
+}
+
+/**
+ * ufo_messenger_send_blocking:
+ * @msger: The messenger object
+ * @request: (transfer none): The request #UfoMessage.
+ * @error: A #GError
+ * Returns: (allow-none) : A #UfoMessage response to the sent request.
+ *
+ * Sends a #UfoMessage request to the connected
+ * endpoint and blocks until the message want fully sent.
+ */
+UfoMessage *
+ufo_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request,
+ GError **error)
+{
+ return UFO_MESSENGER_GET_IFACE (msger)->send_blocking (msger, request, error);
+}
+
+/**
+ * ufo_messenger_recv_blocking:
+ * @msger: The messenger object.
+ * @error: The #GError object
+ *
+ * Returns: The received #UfoMessage.
+ *
+ * Receives a #UfoMessage from the connected endpoint and blocks until the
+ * message was fully received.
+ *
+ */
+UfoMessage *
+ufo_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error)
+{
+ return UFO_MESSENGER_GET_IFACE (msger)->recv_blocking (msger, error);
+}
+
+static void
+ufo_messenger_default_init (UfoMessengerInterface *iface)
+{
+}
diff --git a/ufo/ufo-messenger-iface.h b/ufo/ufo-messenger-iface.h
new file mode 100644
index 0000000..7d9308f
--- /dev/null
+++ b/ufo/ufo-messenger-iface.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef UFO_MESSENGER_H
+#define UFO_MESSENGER_H
+
+#if !defined (__UFO_H_INSIDE__) && !defined (UFO_COMPILATION)
+#error "Only <ufo/ufo.h> can be included directly."
+#endif
+
+#include <ufo/ufo-remote-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_MESSENGER (ufo_messenger_get_type())
+#define UFO_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_MESSENGER, UfoMessenger))
+#define UFO_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_MESSENGER, UfoMessengerIface))
+#define UFO_IS_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_MESSENGER))
+#define UFO_IS_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_MESSENGER))
+#define UFO_MESSENGER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), UFO_TYPE_MESSENGER, UfoMessengerIface))
+
+#define UFO_MESSENGER_ERROR ufo_messenger_error_quark()
+
+typedef struct _UfoMessenger UfoMessenger;
+typedef struct _UfoMessengerIface UfoMessengerIface;
+typedef struct _UfoMessage UfoMessage;
+
+
+/**
+ * UfoMessageType:
+ * @UFO_MESSAGE_STREAM_JSON: insert
+ * @UFO_MESSAGE_REPLICATE_JSON: insert
+ * @UFO_MESSAGE_GET_NUM_DEVICES: insert
+ * @UFO_MESSAGE_GET_STRUCTURE: insert
+ * @UFO_MESSAGE_STRUCTURE: insert
+ * @UFO_MESSAGE_GET_REQUISITION: insert
+ * @UFO_MESSAGE_REQUISITION: insert
+ * @UFO_MESSAGE_SEND_INPUTS: insert
+ * @UFO_MESSAGE_GET_RESULT: insert
+ * @UFO_MESSAGE_RESULT: insert
+ * @UFO_MESSAGE_CLEANUP: insert
+ * @UFO_MESSAGE_ACK: insert
+ * @UFO_MESSAGE_TERMINATE: insert
+ *
+ * The type of a message.
+ *
+ */
+typedef enum {
+ UFO_MESSAGE_STREAM_JSON = 0,
+ UFO_MESSAGE_REPLICATE_JSON,
+ UFO_MESSAGE_GET_NUM_DEVICES,
+ UFO_MESSAGE_GET_STRUCTURE,
+ UFO_MESSAGE_STRUCTURE,
+ UFO_MESSAGE_GET_REQUISITION,
+ UFO_MESSAGE_REQUISITION,
+ UFO_MESSAGE_SEND_INPUTS,
+ UFO_MESSAGE_GET_RESULT,
+ UFO_MESSAGE_RESULT,
+ UFO_MESSAGE_CLEANUP,
+ UFO_MESSAGE_TERMINATE,
+ UFO_MESSAGE_ACK
+} UfoMessageType;
+
+/**
+ * UfoMessage:
+ * @type: #UfoMessageType
+ * @data_size: The size of the data field.
+ * @data: A #gpointer to the transferred data
+ *
+ * A message transfered via IPC.
+ *
+ */
+struct _UfoMessage {
+ UfoMessageType type;
+ guint64 data_size;
+ gpointer data;
+};
+
+void ufo_message_free (UfoMessage *msg);
+UfoMessage * ufo_message_new (UfoMessageType type, guint64 data_size);
+
+typedef enum {
+ UFO_MESSENGER_BUFFER_FULL,
+ UFO_MESSENGER_SIZE_MISSMATCH
+} UfoMessengerError;
+
+/**
+ * UfoMessengerRole:
+ * @UFO_MESSENGER_CLIENT: (insert)
+ * @UFO_MESSENGER_SERVER: (insert)
+ *
+ * The role of an connection endpoint.
+ */
+typedef enum {
+ UFO_MESSENGER_CLIENT,
+ UFO_MESSENGER_SERVER
+} UfoMessengerRole;
+
+struct _UfoMessengerIface {
+ /*< private >*/
+ GTypeInterface parent_iface;
+
+ void (*connect) (UfoMessenger *msger,
+ gchar *addr,
+ UfoMessengerRole role);
+
+ void (*disconnect) (UfoMessenger *msger);
+
+ UfoMessage * (*send_blocking) (UfoMessenger *msger,
+ UfoMessage *request,
+ GError **error);
+
+ UfoMessage * (*recv_blocking) (UfoMessenger *msger,
+ GError **error);
+};
+
+
+void ufo_messenger_connect (UfoMessenger *msger,
+ gchar *addr,
+ UfoMessengerRole role);
+
+void ufo_messenger_disconnect (UfoMessenger *msger);
+
+UfoMessage *ufo_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request,
+ GError **error);
+
+UfoMessage *ufo_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error);
+
+GQuark ufo_messenger_error_quark (void);
+GType ufo_messenger_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-mpi-messenger.c b/ufo/ufo-mpi-messenger.c
new file mode 100644
index 0000000..2172dbb
--- /dev/null
+++ b/ufo/ufo-mpi-messenger.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-mpi-messenger.h>
+#include <mpi.h>
+#include <string.h>
+#include <unistd.h>
+
+static void ufo_messenger_interface_init (UfoMessengerIface *iface);
+
+#define UFO_MPI_MESSENGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_MPI_MESSENGER, UfoMpiMessengerPrivate))
+
+G_DEFINE_TYPE_WITH_CODE (UfoMpiMessenger, ufo_mpi_messenger, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_MESSENGER,
+ ufo_messenger_interface_init))
+
+
+struct _UfoMpiMessengerPrivate {
+ gint own_rank;
+ gint remote_rank;
+ gint pid;
+ gint global_size;
+ gboolean connected;
+ GMutex *mutex;
+ gboolean free_mutex;
+ UfoMessengerRole role;
+};
+
+/* C99 allows flexible length structs that we use to map
+* arbitrary frame lengths that are transferred via mpi.
+* Note: Sizes of datatypes should be fixed and equal on all plattforms
+* (i.e. don't use a gsize as it has different size on x86 & x86_64)
+*/
+typedef struct _DataFrame {
+ UfoMessageType type;
+ guint64 data_size;
+ // variable length data field
+ char data[];
+} DataFrame;
+
+/*
+ * In most MPI implementations, calls to MPI_Send/Recv are not thread safe.
+ * If a global_mutex != NULL is specified, we use this global lock to serialize
+ * the Send/Recv. If global_mutex is NULL, we don't synchronize (i.e. when
+ * calling from ufo-daemon since it only holds a single messaging thread).
+ * If MPI_THREADS_MULTIPLE is supported, we wouldn't need a global lock - however,
+ * on most InfiniBand systems, this is not the case.
+ */
+UfoMpiMessenger *
+ufo_mpi_messenger_new ()
+{
+ UfoMpiMessenger *msger;
+ msger = UFO_MPI_MESSENGER (g_object_new (UFO_TYPE_MPI_MESSENGER, NULL));
+
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+ MPI_Comm_rank (MPI_COMM_WORLD, &priv->own_rank);
+ MPI_Comm_size (MPI_COMM_WORLD, &priv->global_size);
+
+ gint provided_thread_level;
+ MPI_Query_thread (&provided_thread_level);
+ if (provided_thread_level >= MPI_THREAD_MULTIPLE) {
+ /* don't use global mutex, we rely on the MPI implementation to be thread
+ * safe. TODO: don't even use a per-thread lock in this case.
+ */
+ priv->mutex = g_mutex_new ();
+ priv->free_mutex = TRUE;
+ } else if (provided_thread_level == MPI_THREAD_SERIALIZED) {
+ g_message ("The MPI implementation does not support MPI_THREAD_MULTIPLE");
+ g_message ("Using global lock for MPI communication, performance may be degraded.");
+ static GStaticMutex static_mutex = G_STATIC_MUTEX_INIT;
+ priv->mutex = g_static_mutex_get_mutex (&static_mutex);
+ } else {
+ g_critical ("Required thread level MPI_THREAD_SERIALIZED not available in used MPI implementation");
+ }
+
+ return msger;
+}
+
+void
+ufo_mpi_messenger_connect (UfoMessenger *msger, gchar *addr, UfoMessengerRole role)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+ g_mutex_lock (priv->mutex);
+
+ if (role == UFO_MESSENGER_CLIENT) {
+ int remote_rank = g_ascii_strtoll (addr, NULL, 0);
+ priv->remote_rank = remote_rank;
+ g_debug ("[%d:%d]: CLIENT connected to: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ } else {
+ priv->remote_rank = 0;
+ g_debug ("[%d:%d]: SERVER connected to: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ }
+ priv->connected = TRUE;
+ g_mutex_unlock (priv->mutex);
+}
+
+void
+ufo_mpi_messenger_disconnect (UfoMessenger *msger)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+ g_mutex_lock (priv->mutex);
+ priv->connected = FALSE;
+ g_mutex_unlock (priv->mutex);
+}
+
+UfoMessage *
+ufo_mpi_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request_msg,
+ GError **error)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+
+ g_mutex_lock (priv->mutex);
+ g_assert (priv->connected == TRUE);
+
+ // we send in two phaess: first send the data frame of fixed size
+ // then the receiver knows how much bytes will follow in the second send
+ DataFrame *request_frame = g_malloc0 (sizeof (DataFrame));
+ request_frame->type = request_msg->type;
+ request_frame->data_size = request_msg->data_size;
+
+ // send preflight
+ // g_debug ("[%d:%d] SEND sending preflight to: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ MPI_Ssend (request_frame, sizeof (DataFrame), MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD);
+ // g_debug ("[%d:%d] SEND preflight done to: %d", priv->pid, priv->own_rank, priv->remote_rank);
+
+ // send payload
+ if (request_msg->data_size > 0) {
+ g_debug ("[%d:%d] SEND sending payload to: %d, size: %lu", priv->pid, priv->own_rank, priv->remote_rank, request_msg->data_size);
+ int err = MPI_Ssend (request_msg->data, request_msg->data_size, MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD);
+ if (err != MPI_SUCCESS) {
+ g_critical ("error on MPI_Ssend: %d", err);
+ }
+ g_debug ("[%d:%d] SEND payload done to: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ }
+
+ if (request_msg->type == UFO_MESSAGE_ACK) {
+ goto finalize;
+ }
+
+ // receive the response
+ MPI_Status status;
+ UfoMessage *response = g_malloc0 (sizeof (UfoMessage));
+
+ // reuse the memory buffer
+ DataFrame *response_frame = request_frame;
+ // g_debug ("[%d:%d] SEND waiting for response preflight from: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ // if (priv->own_rank == 2)
+ // G_BREAKPOINT();
+ MPI_Recv (response_frame, sizeof (DataFrame), MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD, &status);
+ // g_debug ("[%d:%d] SEND response preflight received from: %d SIZE:%lu", priv->pid, priv->own_rank, priv->remote_rank, response_frame->data_size);
+
+ response->type = response_frame->type;
+ response->data_size = response_frame->data_size;
+
+ if (response_frame->data_size > 0) {
+ gpointer buff = g_malloc0 (response_frame->data_size);
+ g_debug ("[%d:%d] SEND waiting for response payload from: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ MPI_Recv (buff, response_frame->data_size, MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD, &status);
+ g_debug ("[%d:%d] SEND payload received from: %d", priv->pid, priv->own_rank, priv->remote_rank);
+ response->data = buff;
+ }
+
+ goto finalize;
+
+ finalize:
+ g_mutex_unlock (priv->mutex);
+ return response;
+}
+
+UfoMessage *
+ufo_mpi_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+
+ g_mutex_lock (priv->mutex);
+ g_assert (priv->connected == TRUE);
+
+ UfoMessage *response = g_malloc0 (sizeof (DataFrame));
+ DataFrame *frame = g_malloc0 (sizeof (DataFrame));
+ MPI_Status status;
+
+ g_debug ("[%d:%d] RECV waiting for preflight from %d", priv->pid, priv->own_rank, priv->remote_rank);
+ int ret = MPI_Recv (frame, sizeof (DataFrame), MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD, &status);
+
+ if (ret != MPI_SUCCESS)
+ g_critical ("error on recv: %d", ret);
+
+ g_debug ("[%d:%d] RECV preflight received from %d, size: %lu", priv->pid, priv->own_rank, priv->remote_rank, frame->data_size);
+ response->type = frame->type;
+ response->data_size = frame->data_size;
+
+ if (frame->data_size > 0) {
+ gpointer buff = g_malloc0 (frame->data_size);
+ g_debug ("[%d:%d] RECV waiting for payload with size %lu from %d", priv->pid, priv->own_rank, frame->data_size, priv->remote_rank);
+ MPI_Recv (buff, frame->data_size, MPI_CHAR, priv->remote_rank, 0, MPI_COMM_WORLD, &status);
+ g_debug ("[%d:%d] RECV payload received from %d, size: %lu", priv->pid, priv->own_rank, priv->remote_rank, frame->data_size);
+ response->data = buff;
+ }
+ g_mutex_unlock (priv->mutex);
+ return response;
+}
+
+static void
+ufo_messenger_interface_init (UfoMessengerIface *iface)
+{
+ iface->connect = ufo_mpi_messenger_connect;
+ iface->disconnect = ufo_mpi_messenger_disconnect;
+ iface->send_blocking = ufo_mpi_messenger_send_blocking;
+ iface->recv_blocking = ufo_mpi_messenger_recv_blocking;
+}
+
+
+static void
+ufo_mpi_messenger_dispose (GObject *object)
+{
+ ufo_mpi_messenger_disconnect (UFO_MESSENGER (object));
+}
+
+static void
+ufo_mpi_messenger_finalize (GObject *object)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (object);
+
+ if (priv->free_mutex)
+ g_mutex_free (priv->mutex);
+}
+
+static void
+ufo_mpi_messenger_class_init (UfoMpiMessengerClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_mpi_messenger_dispose;
+ oclass->finalize = ufo_mpi_messenger_finalize;
+
+ g_type_class_add_private (klass, sizeof(UfoMpiMessengerPrivate));
+}
+
+static void
+ufo_mpi_messenger_init (UfoMpiMessenger *msger)
+{
+ UfoMpiMessengerPrivate *priv = UFO_MPI_MESSENGER_GET_PRIVATE (msger);
+ priv->connected = FALSE;
+}
diff --git a/ufo/ufo-mpi-messenger.h b/ufo/ufo-mpi-messenger.h
new file mode 100644
index 0000000..34235ce
--- /dev/null
+++ b/ufo/ufo-mpi-messenger.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_MPI_MESSENGER_H
+#define __UFO_MPI_MESSENGER_H
+
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-messenger-iface.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_MPI_MESSENGER (ufo_mpi_messenger_get_type())
+#define UFO_MPI_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_MPI_MESSENGER, UfoMpiMessenger))
+#define UFO_IS_MPI_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_MPI_MESSENGER))
+#define UFO_MPI_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_MPI_MESSENGER, UfoMpiMessengerClass))
+#define UFO_IS_MPI_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_MPI_MESSENGER))
+#define UFO_MPI_MESSENGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_MPI_MESSENGER, UfoMpiMessengerClass))
+
+typedef struct _UfoMpiMessenger UfoMpiMessenger;
+typedef struct _UfoMpiMessengerClass UfoMpiMessengerClass;
+typedef struct _UfoMpiMessengerPrivate UfoMpiMessengerPrivate;
+
+struct _UfoMpiMessenger {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoMpiMessengerPrivate *priv;
+};
+
+struct _UfoMpiMessengerClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoMpiMessenger *ufo_mpi_messenger_new (void);
+GType ufo_mpi_messenger_get_type (void);
+
+void ufo_mpi_messenger_connect (UfoMessenger *msger,
+ gchar *addr,
+ UfoMessengerRole role);
+
+void ufo_mpi_messenger_disconnect (UfoMessenger *msg);
+
+UfoMessage *ufo_mpi_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request,
+ GError **error);
+
+UfoMessage *ufo_mpi_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo-node.c b/ufo/ufo-node.c
index a60e690..2e9d941 100644
--- a/ufo/ufo-node.c
+++ b/ufo/ufo-node.c
@@ -31,6 +31,8 @@ G_DEFINE_TYPE (UfoNode, ufo_node, G_TYPE_OBJECT)
struct _UfoNodePrivate {
UfoNode *copied_from;
+ guint index;
+ guint total;
gpointer label;
};
@@ -64,26 +66,34 @@ ufo_node_get_label (UfoNode *node)
return node->priv->label;
}
-static UfoNode *
-ufo_node_copy_real (UfoNode *node,
- GError **error)
+static void
+copy_properties (GObject *dst,
+ GObject *src)
{
- GObject *copy;
GParamSpec **props;
guint n_props;
- copy = g_object_new (G_OBJECT_TYPE (node), NULL);
- props = g_object_class_list_properties (G_OBJECT_GET_CLASS (node), &n_props);
+ props = g_object_class_list_properties (G_OBJECT_GET_CLASS (src), &n_props);
for (guint i = 0; i < n_props; i++) {
GValue value = {0};
g_value_init (&value, props[i]->value_type);
- g_object_get_property (G_OBJECT (node), props[i]->name, &value);
- g_object_set_property (G_OBJECT (copy), props[i]->name, &value);
+ g_object_get_property (G_OBJECT (src), props[i]->name, &value);
+ g_object_set_property (G_OBJECT (dst), props[i]->name, &value);
}
g_free (props);
+}
+
+static UfoNode *
+ufo_node_copy_real (UfoNode *node,
+ GError **error)
+{
+ GObject *copy;
+
+ copy = g_object_new (G_OBJECT_TYPE (node), NULL);
+ copy_properties (copy, G_OBJECT (node));
return UFO_NODE (copy);
}
@@ -99,13 +109,25 @@ ufo_node_equal_real (UfoNode *n1,
n2->priv->copied_from == n1;
}
+static void
+update_total (UfoNode *node,
+ guint total)
+{
+ node->priv = UFO_NODE_GET_PRIVATE (node);
+ node->priv->total = total;
+
+ if (node->priv->copied_from != NULL)
+ update_total (node->priv->copied_from, total);
+}
+
/**
* ufo_node_copy:
* @node: A #UfoNode
* @error: Location for an error
*
* Get a copy of @node. How "deep" the copy is, depends on the inherited
- * implementation of @node.
+ * implementation of @node. The copy receives an new index and the total amount
+ * of nodes is increased by one.
*
* Returns: (transfer full): Copy of @node.
*/
@@ -116,10 +138,49 @@ ufo_node_copy (UfoNode *node,
UfoNode *offspring;
offspring = UFO_NODE_GET_CLASS (node)->copy (node, error);
+ offspring->priv->label = node->priv->label;
offspring->priv->copied_from = node;
+ offspring->priv->index = node->priv->total;
+ offspring->priv->total = offspring->priv->index + 1;
+
+ update_total (node, offspring->priv->total);
+
return offspring;
}
+/**
+ * ufo_node_get_index:
+ * @node: A #UfoNode
+ *
+ * Get the index of this node. When a graph is expanded, nodes are copied. The
+ * original node has index 1, all successive copies receive a monotonous
+ * increasing index. The total amount of copied nodes can be queried with
+ * ufo_node_get_total().
+ *
+ * Returns: The index of @node.
+ */
+guint
+ufo_node_get_index (UfoNode *node)
+{
+ g_return_val_if_fail (UFO_IS_NODE (node), 0);
+ return node->priv->index;
+}
+
+/**
+ * ufo_node_get_total:
+ * @node: A #UfoNode
+ *
+ * Get the total amount of copied nodes.
+ *
+ * Returns: The number of copied nodes.
+ */
+guint
+ufo_node_get_total (UfoNode *node)
+{
+ g_return_val_if_fail (UFO_IS_NODE (node), 0);
+ return node->priv->total;
+}
+
gboolean
ufo_node_equal (UfoNode *n1,
UfoNode *n2)
@@ -143,5 +204,7 @@ ufo_node_init (UfoNode *self)
self->priv = priv = UFO_NODE_GET_PRIVATE (self);
priv->copied_from = NULL;
+ priv->index = 0;
+ priv->total = 1;
priv->label = NULL;
}
diff --git a/ufo/ufo-node.h b/ufo/ufo-node.h
index 9d5eb18..f13b394 100644
--- a/ufo/ufo-node.h
+++ b/ufo/ufo-node.h
@@ -73,6 +73,8 @@ UfoNode *ufo_node_copy (UfoNode *node,
GError **error);
gboolean ufo_node_equal (UfoNode *n1,
UfoNode *n2);
+guint ufo_node_get_index (UfoNode *node);
+guint ufo_node_get_total (UfoNode *node);
GType ufo_node_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-output-task.c b/ufo/ufo-output-task.c
index a14f6c4..f2c7dc4 100644
--- a/ufo/ufo-output-task.c
+++ b/ufo/ufo-output-task.c
@@ -127,7 +127,7 @@ ufo_output_task_get_structure (UfoTask *task,
{
UfoOutputTaskPrivate *priv = UFO_OUTPUT_TASK_GET_PRIVATE (task);
- *mode = UFO_TASK_MODE_SINGLE;
+ *mode = UFO_TASK_MODE_PROCESSOR;
*n_inputs = 1;
*in_params = g_new0 (UfoInputParam, 1);
(*in_params)[0].n_dims = priv->n_dims;
diff --git a/ufo/ufo-plugin-manager.c b/ufo/ufo-plugin-manager.c
index d45ea6c..00a3936 100644
--- a/ufo/ufo-plugin-manager.c
+++ b/ufo/ufo-plugin-manager.c
@@ -32,9 +32,13 @@
*
* The plugin manager opens shared object modules searched for in locations
* specified with ufo_plugin_manager_add_paths(). An #UfoFilter can be
- * instantiated with ufo_plugin_manager_get_filter() with a one-to-one mapping
- * between filter name xyz and module name libfilterxyz.so. Any errors are
+ * instantiated with ufo_plugin_manager_get_task() with a one-to-one mapping
+ * between filter name xyz and module name libufofilterxyz.so. Any errors are
* reported as one of #UfoPluginManagerError codes.
+ *
+ * Apart from standard locations and paths passed through the #UfoConfig object,
+ * #UfoPluginManager also looks into the path that is specified in the
+ * UFO_PLUGIN_PATH environment variable.
*/
G_DEFINE_TYPE_WITH_CODE (UfoPluginManager, ufo_plugin_manager, G_TYPE_OBJECT,
@@ -123,59 +127,37 @@ ufo_plugin_manager_new (UfoConfig *config)
return manager;
}
-static gchar *
-transform_string (const gchar *pattern,
- const gchar *s,
- const gchar *separator)
-{
- gchar **sv;
- gchar *transformed;
- gchar *result;
-
- sv = g_strsplit_set (s, "-_ ", -1);
- transformed = g_strjoinv (separator, sv);
- result = g_strdup_printf (pattern, transformed);
-
- g_strfreev (sv);
- g_free (transformed);
- return result;
-}
/**
- * ufo_plugin_manager_get_task:
+ * ufo_plugin_manager_get_plugin:
* @manager: A #UfoPluginManager
- * @name: Name of the plugin.
+ * @func_name: Name of the constructor function.
+ * @module_name: Filename of the shared object.
* @error: return location for a GError or %NULL
*
- * Load a #UfoFilter module and return an instance. The shared object name must
- * be * constructed as "libfilter at name.so".
- *
- * Since: 0.2, the error parameter is available
+ * Load a module and return an instance.
*
- * Returns: (transfer none): (allow-none): #UfoFilter or %NULL if module cannot be found
+ * Returns: (transfer full): (allow-none): #gpointer or %NULL if module cannot be found
*/
-UfoNode *
-ufo_plugin_manager_get_task (UfoPluginManager *manager, const gchar *name, GError **error)
+gpointer
+ufo_plugin_manager_get_plugin (UfoPluginManager *manager,
+ const gchar *func_name,
+ const gchar *module_name,
+ GError **error)
{
- g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) && (name != NULL), NULL);
- UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
- UfoNode *node;
- NewFunc *func;
- GModule *module;
- gchar *func_name = NULL;
- gchar *module_name = NULL;
-
- g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) && name != NULL, NULL);
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) &&
+ func_name != NULL &&
+ module_name != NULL, NULL);
- if (!g_strcmp0 (name, "[dummy]"))
- return ufo_dummy_task_new ();
+ UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
+ gpointer plugin = NULL;
+ NewFunc *func = NULL;
+ GModule *module = NULL;
- func = g_hash_table_lookup (priv->new_funcs, name);
+ gchar *key = g_strjoin("@", func_name, module_name, NULL);
+ func = g_hash_table_lookup (priv->new_funcs, key);
if (func == NULL) {
- module_name = transform_string ("libufofilter%s.so", name, NULL);
- func_name = transform_string ("ufo_%s_task_new", name, "_");
-
gchar *path = plugin_manager_get_path (priv, module_name);
if (path == NULL) {
@@ -207,54 +189,51 @@ ufo_plugin_manager_get_task (UfoPluginManager *manager, const gchar *name, GErro
}
priv->modules = g_slist_append (priv->modules, module);
- g_hash_table_insert (priv->new_funcs, g_strdup (name), func);
-
- g_free (func_name);
- g_free (module_name);
+ g_hash_table_insert (priv->new_funcs, g_strdup (key), func);
+ g_free (key);
}
- node = (*func) ();
- ufo_task_node_set_plugin_name (UFO_TASK_NODE (node), name);
- g_message ("UfoPluginManager: Created %s-%p", name, (gpointer) node);
-
- return node;
+ plugin = (*func) ();
+ return plugin;
handle_error:
- g_free (module_name);
- g_free (func_name);
+ g_free (key);
return NULL;
}
/**
- * ufo_plugin_manager_get_all_task_names:
+ * ufo_plugin_get_all_plugin_names:
* @manager: A #UfoPluginManager
+ * @filename_regex: Regex for filenames
+ * @filename_pattern: Pattern according with the files will be searched
*
- * Return a list with potential filter names that match shared objects in all
+ * Return a list with potential plugin names that match shared objects in all
* search paths.
*
* Return value: (element-type utf8) (transfer full): List of strings with filter names
*/
-GList *
-ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager)
+GList*
+ufo_plugin_get_all_plugin_names (UfoPluginManager *manager,
+ const GRegex *filename_regex,
+ const gchar *filename_pattern)
{
g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager), NULL);
UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
GList *result = NULL;
- GRegex *regex = g_regex_new ("libufofilter([A-Za-z]+).so", 0, 0, NULL);
GMatchInfo *match_info = NULL;
for (GList *path = g_list_first (priv->search_paths); path != NULL; path = g_list_next (path)) {
glob_t glob_vector;
gchar *pattern;
- pattern = g_build_filename ((gchar *) path->data, "libufofilter*.so", NULL);
+ pattern = g_build_filename ((gchar *) path->data, filename_pattern, NULL);
glob (pattern, GLOB_MARK | GLOB_TILDE, NULL, &glob_vector);
g_free (pattern);
gsize i = 0;
while (i < glob_vector.gl_pathc) {
- g_regex_match (regex, glob_vector.gl_pathv[i], 0, &match_info);
+ g_regex_match (filename_regex, glob_vector.gl_pathv[i], 0, &match_info);
if (g_match_info_matches (match_info)) {
gchar *word = g_match_info_fetch (match_info, 1);
@@ -266,7 +245,6 @@ ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager)
}
g_match_info_free (match_info);
- g_regex_unref (regex);
return result;
}
@@ -330,8 +308,15 @@ ufo_plugin_manager_finalize (GObject *gobject)
UfoPluginManager *manager = UFO_PLUGIN_MANAGER (gobject);
UfoPluginManagerPrivate *priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
- g_slist_foreach (priv->modules, (GFunc) g_module_close, NULL);
- g_slist_free (priv->modules);
+ /* XXX: This is a necessary hack! We return a full reference for
+ * ufo_plugin_manager_get_task() so that the Python run-time can cleanup
+ * the tasks that are assigned. However, there is no relationship between
+ * graphs, tasks and the plugin manager and it might happen, that the plugin
+ * manager is destroy before the graph which in turn would unref invalid
+ * objects. So, we just don't close the modules and hope for the best.
+ */
+ /* g_slist_foreach (priv->modules, (GFunc) g_module_close, NULL); */
+ /* g_slist_free (priv->modules); */
g_list_foreach (priv->search_paths, (GFunc) g_free, NULL);
g_list_free (priv->search_paths);
@@ -359,6 +344,7 @@ ufo_plugin_manager_class_init (UfoPluginManagerClass *klass)
static void
ufo_plugin_manager_init (UfoPluginManager *manager)
{
+ static const gchar *PATH_VAR = "UFO_PLUGIN_PATH";
UfoPluginManagerPrivate *priv;
manager->priv = priv = UFO_PLUGIN_MANAGER_GET_PRIVATE (manager);
@@ -366,4 +352,90 @@ ufo_plugin_manager_init (UfoPluginManager *manager)
priv->search_paths = NULL;
priv->new_funcs = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
+
+ if (g_getenv (PATH_VAR)) {
+ priv->search_paths = g_list_append (priv->search_paths,
+ g_strdup (g_getenv (PATH_VAR)));
+ }
+}
+
+
+
+static gchar *
+transform_string (const gchar *pattern,
+ const gchar *s,
+ const gchar *separator)
+{
+ gchar **sv;
+ gchar *transformed;
+ gchar *result;
+
+ sv = g_strsplit_set (s, "-_ ", -1);
+ transformed = g_strjoinv (separator, sv);
+ result = g_strdup_printf (pattern, transformed);
+
+ g_strfreev (sv);
+ g_free (transformed);
+ return result;
+}
+
+/**
+ * ufo_plugin_manager_get_task:
+ * @manager: A #UfoPluginManager
+ * @name: Name of the plugin.
+ * @error: return location for a GError or %NULL
+ *
+ * Load a #UfoFilter module and return an instance. The shared object name must
+ * be * constructed as "libfilter at name.so".
+ *
+ * Since: 0.2, the error parameter is available
+ *
+ * Returns: (transfer full): (allow-none): #UfoFilter or %NULL if module cannot be found
+ */
+UfoTaskNode *
+ufo_plugin_manager_get_task (UfoPluginManager *manager, const gchar *name, GError **error)
+{
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager) && name != NULL, NULL);
+ UfoTaskNode *node;
+
+ if (!g_strcmp0 (name, "[dummy]"))
+ return UFO_TASK_NODE (ufo_dummy_task_new ());
+
+ gchar *module_name = transform_string ("libufofilter%s.so", name, NULL);
+ gchar *func_name = transform_string ("ufo_%s_task_new", name, "_");
+ node = UFO_TASK_NODE (ufo_plugin_manager_get_plugin (manager,
+ func_name,
+ module_name,
+ error));
+
+ ufo_task_node_set_plugin_name (node, name);
+
+ g_free (func_name);
+ g_free (module_name);
+
+ g_debug ("UfoPluginManager: Created %s-%p", name, (gpointer) node);
+ return node;
+}
+
+/**
+ * ufo_plugin_manager_get_all_task_names:
+ * @manager: A #UfoPluginManager
+ *
+ * Return a list with potential filter names that match shared objects in all
+ * search paths.
+ *
+ * Return value: (element-type utf8) (transfer full): List of strings with filter names
+ */
+GList *
+ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager)
+{
+ g_return_val_if_fail (UFO_IS_PLUGIN_MANAGER (manager), NULL);
+ GRegex *regex = g_regex_new ("libufofilter([A-Za-z]+).so", 0, 0, NULL);
+
+ GList *result = ufo_plugin_get_all_plugin_names(manager,
+ regex,
+ "libufofilter*.so");
+
+ g_regex_unref (regex);
+ return result;
}
diff --git a/ufo/ufo-plugin-manager.h b/ufo/ufo-plugin-manager.h
index 76c6570..e28c9bd 100644
--- a/ufo/ufo-plugin-manager.h
+++ b/ufo/ufo-plugin-manager.h
@@ -26,7 +26,7 @@
#include <ufo/ufo-configurable.h>
#include <ufo/ufo-config.h>
-#include <ufo/ufo-node.h>
+#include <ufo/ufo-task-node.h>
G_BEGIN_DECLS
@@ -75,11 +75,21 @@ struct _UfoPluginManagerClass {
};
UfoPluginManager * ufo_plugin_manager_new (UfoConfig *config);
-UfoNode * ufo_plugin_manager_get_task (UfoPluginManager *manager,
+gpointer ufo_plugin_manager_get_plugin (UfoPluginManager *manager,
+ const gchar *func_name,
+ const gchar *module_name,
+ GError **error);
+GList * ufo_plugin_get_all_plugin_names (UfoPluginManager *manager,
+ const GRegex *filename_regex,
+ const gchar *filename_pattern);
+GType ufo_plugin_manager_get_type (void);
+
+
+
+UfoTaskNode * ufo_plugin_manager_get_task (UfoPluginManager *manager,
const gchar *name,
GError **error);
GList * ufo_plugin_manager_get_all_task_names (UfoPluginManager *manager);
-GType ufo_plugin_manager_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-profiler.c b/ufo/ufo-profiler.c
index 3a9e73e..6cb6800 100644
--- a/ufo/ufo-profiler.c
+++ b/ufo/ufo-profiler.c
@@ -34,9 +34,7 @@
* @Title: UfoProfiler
*
* The #UfoProfiler provides a drop-in replacement for a manual
- * clEnqueueNDRangeKernel() call and tracks any associated events. The amount of
- * profiling can be controlled with an #UfoProfilerLevel when constructing the
- * profiler.
+ * clEnqueueNDRangeKernel() call and tracks any associated events.
*
* Each #UfoFilter is assigned a profiler with ufo_profiler_set_profiler() by
* the managing #UfoBaseScheduler. Filter implementations should call
@@ -54,13 +52,14 @@ G_DEFINE_TYPE(UfoProfiler, ufo_profiler, G_TYPE_OBJECT)
struct EventRow {
cl_event event;
cl_kernel kernel;
+ cl_command_queue queue;
};
struct _UfoProfilerPrivate {
- UfoProfilerLevel level;
-
GArray *event_array;
GTimer **timers;
+ GList *trace_events;
+ gboolean trace;
};
enum {
@@ -68,40 +67,18 @@ enum {
N_PROPERTIES
};
-/**
- * timer_level:
- *
- * Maps UfoProfilerTimer to a UfoProfilerLevel
- */
-static UfoProfilerLevel timer_level[] = {
- UFO_PROFILER_LEVEL_IO, /* TIMER_IO */
- UFO_PROFILER_LEVEL_CPU, /* TIMER_CPU */
- UFO_PROFILER_LEVEL_SYNC, /* TIMER_FETCH */
- UFO_PROFILER_LEVEL_SYNC /* TIMER_RELEASE */
-};
+static GTimer *global_clock = NULL;
-/**
- * UfoProfilerLevel:
- * @UFO_PROFILER_LEVEL_NONE: Do not track any profiling information
- * @UFO_PROFILER_LEVEL_IO: Track I/O events
- * @UFO_PROFILER_LEVEL_OPENCL: Track OpenCL events
- * @UFO_PROFILER_LEVEL_CPU: Track general CPU time
- * @UFO_PROFILER_LEVEL_SYNC: Track synchronization wait time
- *
- * Profiling levels that the profiler supports. To set the global profiling
- * level use the #UfoConfiguration:profile-level: property on a
- * #UfoConfiguration object set to the #UfoScheduler.
- */
/**
* UfoProfilerTimer:
* @UFO_PROFILER_TIMER_IO: Select I/O timer
* @UFO_PROFILER_TIMER_CPU: Select CPU timer
+ * @UFO_PROFILER_TIMER_GPU: Select GPU timer
* @UFO_PROFILER_TIMER_FETCH: Select timer that measures the synchronization
* time to fetch data from the queues.
* @UFO_PROFILER_TIMER_RELEASE: Select timer that measures the synchronization
* time to push data to the queues.
- * @UFO_PROFILER_TIMER_CPU: Select CPU timer
* @UFO_PROFILER_TIMER_LAST: Auxiliary value, do not use.
*
* Use these values to select a specific timer when calling
@@ -110,20 +87,15 @@ static UfoProfilerLevel timer_level[] = {
/**
* ufo_profiler_new:
- * @level: Amount of information that should be tracked by the profiler.
*
* Create a profiler object.
*
* Return value: A new profiler object.
*/
UfoProfiler *
-ufo_profiler_new (UfoProfilerLevel level)
+ufo_profiler_new (void)
{
- UfoProfiler *profiler;
-
- profiler = UFO_PROFILER (g_object_new (UFO_TYPE_PROFILER, NULL));
- profiler->priv->level = level;
- return profiler;
+ return UFO_PROFILER (g_object_new (UFO_TYPE_PROFILER, NULL));
}
/**
@@ -151,12 +123,11 @@ ufo_profiler_call (UfoProfiler *profiler,
{
UfoProfilerPrivate *priv;
cl_event event;
- cl_event *event_loc;
cl_int cl_err;
struct EventRow row;
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
priv = profiler->priv;
- event_loc = priv->level & UFO_PROFILER_LEVEL_OPENCL ? &event : NULL;
cl_err = clEnqueueNDRangeKernel (command_queue,
kernel,
@@ -164,14 +135,13 @@ ufo_profiler_call (UfoProfiler *profiler,
NULL,
global_work_size,
local_work_size,
- 0, NULL, event_loc);
+ 0, NULL, &event);
UFO_RESOURCES_CHECK_CLERR (cl_err);
- if (priv->level & UFO_PROFILER_LEVEL_OPENCL) {
- row.event = event;
- row.kernel = kernel;
- g_array_append_val (priv->event_array, row);
- }
+ row.event = event;
+ row.kernel = kernel;
+ row.queue = command_queue;
+ g_array_append_val (priv->event_array, row);
}
/**
@@ -187,9 +157,7 @@ ufo_profiler_start (UfoProfiler *profiler,
UfoProfilerTimer timer)
{
g_return_if_fail (UFO_IS_PROFILER (profiler));
-
- if (profiler->priv->level & timer_level[timer])
- g_timer_continue (profiler->priv->timers[timer]);
+ g_timer_continue (profiler->priv->timers[timer]);
}
/**
@@ -205,9 +173,93 @@ ufo_profiler_stop (UfoProfiler *profiler,
UfoProfilerTimer timer)
{
g_return_if_fail (UFO_IS_PROFILER (profiler));
+ g_timer_stop (profiler->priv->timers[timer]);
+}
+
+void
+ufo_profiler_trace_event (UfoProfiler *profiler,
+ const gchar *name,
+ const gchar *type)
+{
+ UfoTraceEvent *event;
+ gulong timestamp;
+
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
+ if (!profiler->priv->trace)
+ return;
+
+ g_timer_elapsed (global_clock, ×tamp);
+
+ event = g_malloc0 (sizeof(UfoTraceEvent));
+ event->name = name;
+ event->type = type;
+ event->thread_id = g_thread_self ();
+ event->timestamp = (gdouble) timestamp;
+ profiler->priv->trace_events = g_list_append (profiler->priv->trace_events, event);
+}
- if (profiler->priv->level & timer_level[timer])
- g_timer_stop (profiler->priv->timers[timer]);
+
+void
+ufo_profiler_enable_tracing (UfoProfiler *profiler,
+ gboolean enable)
+{
+ g_return_if_fail (UFO_IS_PROFILER (profiler));
+ profiler->priv->trace = enable;
+}
+
+/**
+ * ufo_profiler_get_trace_events: (skip)
+ * @profiler: A #UfoProfiler object.
+ *
+ * Get all events recorded with @profiler.
+ *
+ * Returns: (element-type UfoTraceEvent): A list with #UfoTraceEvent objects.
+ */
+GList *
+ufo_profiler_get_trace_events (UfoProfiler *profiler)
+{
+ g_return_val_if_fail (UFO_IS_PROFILER (profiler), NULL);
+ return profiler->priv->trace_events;
+}
+
+static void
+get_time_stamps (cl_event event, gulong *queued, gulong *submitted, gulong *start, gulong *end)
+{
+ UFO_RESOURCES_CHECK_CLERR (clWaitForEvents (1, &event));
+ UFO_RESOURCES_CHECK_CLERR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, sizeof (cl_ulong), queued, NULL));
+ UFO_RESOURCES_CHECK_CLERR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_SUBMIT, sizeof (cl_ulong), submitted, NULL));
+ UFO_RESOURCES_CHECK_CLERR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_START, sizeof (cl_ulong), start, NULL));
+ UFO_RESOURCES_CHECK_CLERR (clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END, sizeof (cl_ulong), end, NULL));
+}
+
+static gdouble
+gpu_elapsed (UfoProfilerPrivate *priv)
+{
+ struct EventRow *row;
+ gdouble elapsed = 0.0;
+ guint len = priv->event_array->len;
+
+ if (len == 0)
+ return 0.0;
+
+ for (guint i = 0; i < len; i++) {
+ gulong start, end;
+
+ row = &g_array_index (priv->event_array, struct EventRow, i);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetEventInfo (row->event, CL_EVENT_COMMAND_QUEUE,
+ sizeof (cl_command_queue), &row->queue,
+ NULL));
+
+ get_time_stamps (row->event, NULL, NULL, &start, &end);
+
+ if (end < start)
+ elapsed += (gdouble) ((G_MAXULONG - start) + end) * 1e-9;
+ else
+ elapsed += ((gdouble) (end - start)) * 1e-9;
+ }
+
+ return elapsed;
}
/**
@@ -224,6 +276,10 @@ ufo_profiler_elapsed (UfoProfiler *profiler,
UfoProfilerTimer timer)
{
g_return_val_if_fail (UFO_IS_PROFILER (profiler), 0.0);
+
+ if (timer == UFO_PROFILER_TIMER_GPU)
+ return gpu_elapsed (profiler->priv);
+
return g_timer_elapsed (profiler->priv->timers[timer], NULL);
}
@@ -239,15 +295,6 @@ get_kernel_name (cl_kernel kernel)
return s;
}
-static void
-get_time_stamps (cl_event event, gulong *queued, gulong *submitted, gulong *start, gulong *end)
-{
- clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, sizeof (cl_ulong), queued, NULL);
- clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_SUBMIT, sizeof (cl_ulong), submitted, NULL);
- clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_START, sizeof (cl_ulong), start, NULL);
- clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END, sizeof (cl_ulong), end, NULL);
-}
-
/**
* ufo_profiler_foreach:
* @profiler: A #UfoProfiler object.
@@ -268,9 +315,6 @@ ufo_profiler_foreach (UfoProfiler *profiler,
priv = profiler->priv;
- if (priv->level == UFO_PROFILER_LEVEL_NONE)
- return;
-
for (guint i = 0; i < priv->event_array->len; i++) {
cl_command_queue queue;
gulong queued, submitted, start, end;
@@ -298,25 +342,31 @@ static void
ufo_profiler_dispose (GObject *object)
{
G_OBJECT_CLASS (ufo_profiler_parent_class)->dispose (object);
- g_message ("UfoProfiler: disposed");
}
static void
ufo_profiler_finalize (GObject *object)
{
UfoProfilerPrivate *priv;
+ struct EventRow *row;
G_OBJECT_CLASS (ufo_profiler_parent_class)->finalize (object);
priv = UFO_PROFILER_GET_PRIVATE (object);
+ for (guint i = 0; i < priv->event_array->len; i++) {
+ row = &g_array_index (priv->event_array, struct EventRow, i);
+ clReleaseEvent (row->event);
+ }
+
g_array_free (priv->event_array, TRUE);
+ g_list_foreach (priv->trace_events, (GFunc) g_free, NULL);
+ g_list_free (priv->trace_events);
+
for (guint i = 0; i < UFO_PROFILER_TIMER_LAST; i++)
g_timer_destroy (priv->timers[i]);
g_free (priv->timers);
-
- g_message ("UfoProfiler: finalized");
}
static void
@@ -327,6 +377,9 @@ ufo_profiler_class_init (UfoProfilerClass *klass)
gobject_class->finalize = ufo_profiler_finalize;
g_type_class_add_private (klass, sizeof (UfoProfilerPrivate));
+
+ if (global_clock == NULL)
+ global_clock = g_timer_new ();
}
static void
@@ -336,6 +389,8 @@ ufo_profiler_init (UfoProfiler *manager)
manager->priv = priv = UFO_PROFILER_GET_PRIVATE (manager);
priv->event_array = g_array_sized_new (FALSE, TRUE, sizeof(struct EventRow), 2048);
+ priv->trace_events = NULL;
+ priv->trace = FALSE;
/* Setup timers for all events */
priv->timers = g_new0 (GTimer *, UFO_PROFILER_TIMER_LAST);
@@ -348,6 +403,4 @@ ufo_profiler_init (UfoProfiler *manager)
g_timer_reset (timer);
priv->timers[i] = timer;
}
-
- priv->level = UFO_PROFILER_LEVEL_NONE;
}
diff --git a/ufo/ufo-profiler.h b/ufo/ufo-profiler.h
index 050e251..99253d5 100644
--- a/ufo/ufo-profiler.h
+++ b/ufo/ufo-profiler.h
@@ -71,39 +71,54 @@ struct _UfoProfilerClass {
GObjectClass parent_class;
};
+/**
+ * UfoTraceEvent:
+ * @name: Name of the event
+ * @type: Type of the event
+ * @thread_id: ID of thread in which the event was issued
+ * @timestamp: Arbitrary timestamp of the event
+ */
+typedef struct {
+ const gchar *name;
+ const gchar *type;
+ gpointer thread_id;
+ gdouble timestamp;
+} UfoTraceEvent;
+
typedef enum {
UFO_PROFILER_TIMER_IO = 0,
UFO_PROFILER_TIMER_CPU,
+ UFO_PROFILER_TIMER_GPU,
UFO_PROFILER_TIMER_FETCH,
UFO_PROFILER_TIMER_RELEASE,
UFO_PROFILER_TIMER_LAST,
} UfoProfilerTimer;
-typedef enum {
- UFO_PROFILER_LEVEL_NONE = 0,
- UFO_PROFILER_LEVEL_CPU = 1 << 0,
- UFO_PROFILER_LEVEL_OPENCL = 1 << 1,
- UFO_PROFILER_LEVEL_IO = 1 << 2,
- UFO_PROFILER_LEVEL_SYNC = 1 << 3
-} UfoProfilerLevel;
-
-UfoProfiler *ufo_profiler_new (UfoProfilerLevel level);
-void ufo_profiler_call (UfoProfiler *profiler,
- gpointer command_queue,
- gpointer kernel,
- guint work_dim,
- const gsize *global_work_size,
- const gsize *local_work_size);
-void ufo_profiler_foreach (UfoProfiler *profiler,
- UfoProfilerFunc func,
- gpointer user_data);
-void ufo_profiler_start (UfoProfiler *profiler,
- UfoProfilerTimer timer);
-void ufo_profiler_stop (UfoProfiler *profiler,
- UfoProfilerTimer timer);
-gdouble ufo_profiler_elapsed (UfoProfiler *profiler,
- UfoProfilerTimer timer);
-GType ufo_profiler_get_type (void);
+UfoProfiler *ufo_profiler_new (void);
+void ufo_profiler_call (UfoProfiler *profiler,
+ gpointer command_queue,
+ gpointer kernel,
+ guint work_dim,
+ const gsize *global_work_size,
+ const gsize *local_work_size);
+void ufo_profiler_foreach (UfoProfiler *profiler,
+ UfoProfilerFunc func,
+ gpointer user_data);
+void ufo_profiler_start (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+void ufo_profiler_stop (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+void ufo_profiler_trace_event (UfoProfiler *profiler,
+ const gchar *name,
+ const gchar *type);
+void ufo_profiler_enable_tracing
+ (UfoProfiler *profiler,
+ gboolean enable);
+GList *ufo_profiler_get_trace_events
+ (UfoProfiler *profiler);
+gdouble ufo_profiler_elapsed (UfoProfiler *profiler,
+ UfoProfilerTimer timer);
+GType ufo_profiler_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-remote-node.c b/ufo/ufo-remote-node.c
index 21d367a..e2e40ab 100644
--- a/ufo/ufo-remote-node.c
+++ b/ufo/ufo-remote-node.c
@@ -17,123 +17,115 @@
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <zmq.h>
#include <string.h>
#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-messenger-iface.h>
+#include <ufo/ufo-zmq-messenger.h>
+
+#ifdef MPI
+#include <ufo/ufo-mpi-messenger.h>
+#endif
G_DEFINE_TYPE (UfoRemoteNode, ufo_remote_node, UFO_TYPE_NODE)
#define UFO_REMOTE_NODE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_REMOTE_NODE, UfoRemoteNodePrivate))
-static void ufo_msg_send (UfoMessage *msg, gpointer socket, gint flags);
-static void receive_ack (gpointer socket);
-
struct _UfoRemoteNodePrivate {
gpointer context;
- gpointer socket;
guint n_inputs;
- GMutex *mutex;
+ gboolean terminated;
+ UfoMessenger *msger;
};
UfoNode *
-ufo_remote_node_new (gpointer zmq_context,
- const gchar *address)
+ufo_remote_node_new (const gchar *address)
{
UfoRemoteNode *node;
UfoRemoteNodePrivate *priv;
- g_return_val_if_fail (zmq_context != NULL && address != NULL, NULL);
+ g_return_val_if_fail (address != NULL, NULL);
node = UFO_REMOTE_NODE (g_object_new (UFO_TYPE_REMOTE_NODE, NULL));
- priv = node->priv;
- priv->context = zmq_context;
- priv->socket = zmq_socket (zmq_context, ZMQ_REQ);
-
- if (zmq_connect (priv->socket, address) == 0) {
- g_message ("Connected remote node to `%s' via socket=%p",
- address,
- priv->socket);
- return UFO_NODE (node);
- }
- else {
- g_warning ("Could not connect to `%s': %s",
- address,
- zmq_strerror (errno));
- g_object_unref (node);
- return NULL;
- }
+ priv = UFO_REMOTE_NODE_GET_PRIVATE (node);
+
+#ifdef MPI
+ priv->msger = UFO_MESSENGER (ufo_mpi_messenger_new ());
+#else
+ priv->msger = UFO_MESSENGER (ufo_zmq_messenger_new ());
+#endif
+
+ gchar *addr = g_strdup (address);
+ ufo_messenger_connect (priv->msger, addr, UFO_MESSENGER_CLIENT);
+ g_free(addr);
+
+ return UFO_NODE (node);
}
guint
ufo_remote_node_get_num_gpus (UfoRemoteNode *node)
{
- UfoRemoteNodePrivate *priv;
- UfoMessage request;
- UfoMessage result;
- zmq_msg_t reply;
-
g_return_val_if_fail (UFO_IS_REMOTE_NODE (node), 0);
- priv = node->priv;
-
- g_mutex_lock (priv->mutex);
- request.type = UFO_MESSAGE_GET_NUM_DEVICES;
- ufo_msg_send (&request, priv->socket, 0);
+ UfoRemoteNodePrivate *priv;
+ UfoMessage *request = ufo_message_new (UFO_MESSAGE_GET_NUM_DEVICES, 0);
- zmq_msg_init (&reply);
- zmq_msg_recv (&reply, priv->socket, 0);
- memcpy (&result, zmq_msg_data (&reply), sizeof (UfoMessage));
- zmq_msg_close (&reply);
+ priv = node->priv;
- g_mutex_unlock (priv->mutex);
+ UfoMessage *result;
+ result = ufo_messenger_send_blocking (priv->msger, request, NULL);
+ guint n_devices = * (guint16 *) result->data;
- return result.d.n_devices;
+ ufo_message_free (request);
+ ufo_message_free (result);
+ g_assert (n_devices < 32);
+ return n_devices;
}
void
ufo_remote_node_request_setup (UfoRemoteNode *node)
{
- UfoRemoteNodePrivate *priv;
- UfoMessage request;
+ // TODO setup isn't in use, remove it
+ //g_assert (FALSE);
- g_return_if_fail (UFO_IS_REMOTE_NODE (node));
-
- priv = node->priv;
- request.type = UFO_MESSAGE_SETUP;
-
- g_mutex_lock (priv->mutex);
+ // g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+ // UfoRemoteNodePrivate *priv = UFO_REMOTE_NODE_GET_PRIVATE (node);
- ufo_msg_send (&request, priv->socket, 0);
- receive_ack (priv->socket);
-
- g_mutex_unlock (priv->mutex);
+ // UfoMessage *request;
+ // request = ufo_message_new (UFO_MESSAGE_SETUP, 0);
+ // ufo_message_send_blocking (request);
+ // ufo_message_free (request);
}
void
ufo_remote_node_send_json (UfoRemoteNode *node,
- const gchar *json,
- gsize size)
+ UfoRemoteMode mode,
+ const gchar *json)
{
UfoRemoteNodePrivate *priv;
- UfoMessage request;
- zmq_msg_t json_msg;
+ UfoMessage *request;
+ UfoMessageType type;
+ guint64 size;
g_return_if_fail (UFO_IS_REMOTE_NODE (node));
priv = node->priv;
- request.type = UFO_MESSAGE_TASK_JSON;
-
- g_mutex_lock (priv->mutex);
-
- ufo_msg_send (&request, priv->socket, ZMQ_SNDMORE);
- zmq_msg_init_size (&json_msg, size);
- memcpy (zmq_msg_data (&json_msg), json, size);
- zmq_msg_send (&json_msg, priv->socket, 0);
- zmq_msg_close (&json_msg);
+ switch (mode) {
+ case UFO_REMOTE_MODE_STREAM:
+ type = UFO_MESSAGE_STREAM_JSON;
+ break;
+ case UFO_REMOTE_MODE_REPLICATE:
+ type = UFO_MESSAGE_REPLICATE_JSON;
+ break;
+ default:
+ g_warning ("Don't understand UfoRemoteMode");
+ type = 0;
+ }
- receive_ack (priv->socket);
+ size = (guint64) strlen (json);
+ request = ufo_message_new (type, size);
- g_mutex_unlock (priv->mutex);
+ memcpy (request->data, json, size);
+ ufo_messenger_send_blocking (priv->msger, request, NULL);
}
void
@@ -143,41 +135,33 @@ ufo_remote_node_get_structure (UfoRemoteNode *node,
UfoTaskMode *mode)
{
UfoRemoteNodePrivate *priv;
- UfoMessage request;
- UfoMessage *header;
- zmq_msg_t header_msg;
- zmq_msg_t payload_msg;
- UfoInputParam *in_param;
-
- g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+ UfoMessage *request, *response;
priv = node->priv;
- *mode = UFO_TASK_MODE_SINGLE;
- request.type = UFO_MESSAGE_GET_STRUCTURE;
- g_mutex_lock (priv->mutex);
+ struct _Structure {
+ guint16 n_inputs;
+ guint16 n_dims;
+ } msg_data;
- ufo_msg_send (&request, priv->socket, 0);
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+ *mode = UFO_TASK_MODE_PROCESSOR;
- /* Receive header */
- zmq_msg_init (&header_msg);
- zmq_msg_recv (&header_msg, priv->socket, 0);
- header = (UfoMessage *) zmq_msg_data (&header_msg);
- /* Receive payload */
- zmq_msg_init (&payload_msg);
- zmq_msg_recv (&payload_msg, priv->socket, 0);
- in_param = (UfoInputParam *) zmq_msg_data (&payload_msg);
+ request = ufo_message_new (UFO_MESSAGE_GET_STRUCTURE, 0);
+ response = ufo_messenger_send_blocking (priv->msger, request, NULL);
+ g_assert (response->data_size == sizeof (struct _Structure));
- priv->n_inputs = header->d.n_inputs;
- *n_inputs = header->d.n_inputs;
- *in_params = g_new0 (UfoInputParam, 1);
- (*in_params)[0].n_dims = in_param->n_dims;
+ msg_data = *(struct _Structure *) response->data;
+
+ priv->n_inputs = msg_data.n_inputs;
+ *n_inputs = msg_data.n_inputs;
- zmq_msg_close (&header_msg);
- zmq_msg_close (&payload_msg);
+ *in_params = g_new0 (UfoInputParam, 1);
+ (*in_params)[0].n_dims = msg_data.n_dims;
- g_mutex_unlock (priv->mutex);
+ ufo_message_free (request);
+ ufo_message_free (response);
}
void
@@ -185,48 +169,51 @@ ufo_remote_node_send_inputs (UfoRemoteNode *node,
UfoBuffer **inputs)
{
UfoRemoteNodePrivate *priv;
- UfoMessage request;
+ UfoMessage *request;
g_return_if_fail (UFO_IS_REMOTE_NODE (node));
priv = node->priv;
- request.type = UFO_MESSAGE_SEND_INPUTS;
-
- g_mutex_lock (priv->mutex);
-
- ufo_msg_send (&request, priv->socket, ZMQ_SNDMORE);
/*
* For each of the input data items send two frames: the first one contains
* the size as an UfoRequisition struct and the second one the raw byte
* data.
*/
- for (guint i = 0; i < priv->n_inputs; i++) {
+ struct _Header {
UfoRequisition requisition;
- zmq_msg_t requisition_msg;
- zmq_msg_t data_msg;
- gsize size;
- gint flags;
+ guint64 buffer_size;
+ };
- ufo_buffer_get_requisition (inputs[i], &requisition);
- size = ufo_buffer_get_size (inputs[i]);
+ // determine our total message size
+ guint64 size = 0;
- zmq_msg_init_size (&requisition_msg, sizeof (UfoRequisition));
- zmq_msg_init_size (&data_msg, size);
+ for (guint i = 0; i < priv->n_inputs; i++) {
+ guint64 buffer_size = ufo_buffer_get_size (inputs[i]);
+ size += buffer_size;
+ }
- memcpy (zmq_msg_data (&requisition_msg), &requisition, sizeof (UfoRequisition));
- memcpy (zmq_msg_data (&data_msg), ufo_buffer_get_host_array (inputs[i], NULL), size);
+ gpointer buffer = g_malloc (priv->n_inputs * sizeof (struct _Header) + size);
- flags = i == priv->n_inputs - 1 ? 0 : ZMQ_SNDMORE;
- zmq_msg_send (&requisition_msg, priv->socket, ZMQ_SNDMORE);
- zmq_msg_send (&data_msg, priv->socket, flags);
+ char *base = buffer;
- zmq_msg_close (&requisition_msg);
- zmq_msg_close (&data_msg);
+ for (guint i = 0; i < priv->n_inputs; i++) {
+ struct _Header *header = g_new0 (struct _Header, 1);
+ ufo_buffer_get_requisition (inputs[i], &header->requisition);
+ header->buffer_size = (guint64) ufo_buffer_get_size (inputs[i]);
+
+ memcpy (base, header, sizeof (struct _Header));
+ base += sizeof (struct _Header);
+ memcpy (base, ufo_buffer_get_host_array (inputs[i], NULL), header->buffer_size);
+ base += header->buffer_size;
}
- receive_ack (priv->socket);
- g_mutex_unlock (priv->mutex);
+ request = ufo_message_new (UFO_MESSAGE_SEND_INPUTS, size);
+ g_free (request->data);
+ request->data = buffer;
+ // send as a single message
+ ufo_messenger_send_blocking (priv->msger, request, NULL);
+
}
void
@@ -234,31 +221,23 @@ ufo_remote_node_get_result (UfoRemoteNode *node,
UfoBuffer *buffer)
{
UfoRemoteNodePrivate *priv;
- UfoMessage request;
- zmq_msg_t reply_msg;
+ UfoMessage *request, *response;
gpointer host_array;
g_return_if_fail (UFO_IS_REMOTE_NODE (node));
priv = node->priv;
- request.type = UFO_MESSAGE_GET_RESULT;
-
- g_mutex_lock (priv->mutex);
+ request = ufo_message_new (UFO_MESSAGE_GET_RESULT, 0);
+ response = ufo_messenger_send_blocking (priv->msger, request, NULL);
- ufo_msg_send (&request, priv->socket, 0);
-
- /* Get the remote data and put it into our buffer */
- zmq_msg_init (&reply_msg);
- zmq_msg_recv (&reply_msg, priv->socket, 0);
-
- ufo_buffer_discard_location (buffer, UFO_LOCATION_DEVICE);
+ ufo_buffer_discard_location (buffer);
host_array = ufo_buffer_get_host_array (buffer, NULL);
- g_assert (ufo_buffer_get_size (buffer) == zmq_msg_size (&reply_msg));
- memcpy (host_array, zmq_msg_data (&reply_msg), ufo_buffer_get_size (buffer));
+ g_assert (ufo_buffer_get_size (buffer) == response->data_size);
- zmq_msg_close (&reply_msg);
+ memcpy (host_array, response->data, ufo_buffer_get_size (buffer));
- g_mutex_unlock (priv->mutex);
+ ufo_message_free (request);
+ ufo_message_free (response);
}
void
@@ -266,74 +245,57 @@ ufo_remote_node_get_requisition (UfoRemoteNode *node,
UfoRequisition *requisition)
{
UfoRemoteNodePrivate *priv;
- UfoMessage request;
- zmq_msg_t reply_msg;
+ UfoMessage *request, *response;
g_return_if_fail (UFO_IS_REMOTE_NODE (node));
priv = node->priv;
- request.type = UFO_MESSAGE_GET_REQUISITION;
-
- g_mutex_lock (priv->mutex);
-
- ufo_msg_send (&request, priv->socket, 0);
+ request = ufo_message_new (UFO_MESSAGE_GET_REQUISITION, 0);
+ response = ufo_messenger_send_blocking (priv->msger, request, NULL);
- zmq_msg_init (&reply_msg);
- zmq_msg_recv (&reply_msg, priv->socket, 0);
- g_assert (zmq_msg_size (&reply_msg) >= sizeof (UfoRequisition));
- memcpy (requisition, zmq_msg_data (&reply_msg), sizeof (UfoRequisition));
- zmq_msg_close (&reply_msg);
+ g_assert (response->data_size == sizeof (UfoRequisition));
+ memcpy (requisition, response->data, sizeof (UfoRequisition));
- g_mutex_unlock (priv->mutex);
+ ufo_message_free(request);
+ ufo_message_free(response);
}
static void
-cleanup_remote (gpointer socket)
+cleanup_remote (UfoRemoteNodePrivate *priv)
{
- UfoMessage request;
-
- request.type = UFO_MESSAGE_CLEANUP;
-
- ufo_msg_send (&request, socket, 0);
- receive_ack (socket);
+ UfoMessage *request = ufo_message_new (UFO_MESSAGE_CLEANUP, 0);
+ ufo_messenger_send_blocking (priv->msger, request, NULL);
+ ufo_message_free (request);
}
-static void
-ufo_msg_send (UfoMessage *msg,
- gpointer socket,
- gint flags)
+void
+ufo_remote_node_terminate (UfoRemoteNode *node)
{
- zmq_msg_t request;
+ UfoRemoteNodePrivate *priv = UFO_REMOTE_NODE_GET_PRIVATE (node);
- zmq_msg_init_size (&request, sizeof (UfoMessage));
- memcpy (zmq_msg_data (&request), msg, sizeof (UfoMessage));
- zmq_msg_send (&request, socket, flags);
- zmq_msg_close (&request);
-}
+ priv->terminated = TRUE;
+ cleanup_remote (priv);
-static void
-receive_ack (gpointer socket)
-{
- zmq_msg_t reply_msg;
+ UfoMessage *request;
+
+ g_return_if_fail (UFO_IS_REMOTE_NODE (node));
+
+ priv = node->priv;
+ request = ufo_message_new (UFO_MESSAGE_TERMINATE, 0);
+ ufo_messenger_send_blocking (priv->msger, request, NULL);
- zmq_msg_init (&reply_msg);
- zmq_msg_recv (&reply_msg, socket, 0);
- zmq_msg_close (&reply_msg);
+ ufo_messenger_disconnect (priv->msger);
+ return;
}
static void
ufo_remote_node_dispose (GObject *object)
{
- UfoRemoteNodePrivate *priv;
-
- priv = UFO_REMOTE_NODE_GET_PRIVATE (object);
-
- if (priv->socket != NULL) {
- cleanup_remote (priv->socket);
+ UfoRemoteNodePrivate *priv = UFO_REMOTE_NODE_GET_PRIVATE (object);
- g_debug ("Close socket=%p", priv->socket);
- zmq_close (priv->socket);
- priv->socket = NULL;
+ if (!priv->terminated) {
+ cleanup_remote (priv);
+ ufo_messenger_disconnect (priv->msger);
}
G_OBJECT_CLASS (ufo_remote_node_parent_class)->dispose (object);
@@ -342,11 +304,6 @@ ufo_remote_node_dispose (GObject *object)
static void
ufo_remote_node_finalize (GObject *object)
{
- UfoRemoteNodePrivate *priv;
-
- priv = UFO_REMOTE_NODE_GET_PRIVATE (object);
- g_mutex_free (priv->mutex);
-
G_OBJECT_CLASS (ufo_remote_node_parent_class)->finalize (object);
}
@@ -367,8 +324,6 @@ ufo_remote_node_init (UfoRemoteNode *self)
{
UfoRemoteNodePrivate *priv;
self->priv = priv = UFO_REMOTE_NODE_GET_PRIVATE (self);
- priv->context = NULL;
- priv->socket = NULL;
priv->n_inputs = 0;
- priv->mutex = g_mutex_new ();
+ priv->terminated = FALSE;
}
diff --git a/ufo/ufo-remote-node.h b/ufo/ufo-remote-node.h
index ad2bf63..22958af 100644
--- a/ufo/ufo-remote-node.h
+++ b/ufo/ufo-remote-node.h
@@ -27,6 +27,7 @@
#include <ufo/ufo-node.h>
#include <ufo/ufo-buffer.h>
#include <ufo/ufo-task-iface.h>
+#include <ufo/ufo-messenger-iface.h>
G_BEGIN_DECLS
@@ -40,7 +41,6 @@ G_BEGIN_DECLS
typedef struct _UfoRemoteNode UfoRemoteNode;
typedef struct _UfoRemoteNodeClass UfoRemoteNodeClass;
typedef struct _UfoRemoteNodePrivate UfoRemoteNodePrivate;
-typedef struct _UfoMessage UfoMessage;
/**
* UfoRemoteNode:
@@ -66,55 +66,25 @@ struct _UfoRemoteNodeClass {
};
/**
- * UfoMessageType: (skip)
- * @UFO_MESSAGE_TASK_JSON: insert
- * @UFO_MESSAGE_GET_NUM_DEVICES: insert
- * @UFO_MESSAGE_SETUP: insert
- * @UFO_MESSAGE_GET_STRUCTURE: insert
- * @UFO_MESSAGE_STRUCTURE: insert
- * @UFO_MESSAGE_GET_REQUISITION: insert
- * @UFO_MESSAGE_REQUISITION: insert
- * @UFO_MESSAGE_SEND_INPUTS: insert
- * @UFO_MESSAGE_GET_RESULT: insert
- * @UFO_MESSAGE_RESULT: insert
- * @UFO_MESSAGE_CLEANUP: insert
- * @UFO_MESSAGE_ACK: insert
+ * UfoRemoteMode:
+ * @UFO_REMOTE_MODE_STREAM: Expand task graph and execute only sub-branches
+ * remotely.
+ * @UFO_REMOTE_MODE_REPLICATE: Replicate the entire task graph and execute it
+ * remotely.
*/
typedef enum {
- UFO_MESSAGE_TASK_JSON = 0,
- UFO_MESSAGE_GET_NUM_DEVICES,
- UFO_MESSAGE_SETUP,
- UFO_MESSAGE_GET_STRUCTURE,
- UFO_MESSAGE_STRUCTURE,
- UFO_MESSAGE_GET_REQUISITION,
- UFO_MESSAGE_REQUISITION,
- UFO_MESSAGE_SEND_INPUTS,
- UFO_MESSAGE_GET_RESULT,
- UFO_MESSAGE_RESULT,
- UFO_MESSAGE_CLEANUP,
- UFO_MESSAGE_ACK
-} UfoMessageType;
+ UFO_REMOTE_MODE_STREAM,
+ UFO_REMOTE_MODE_REPLICATE
+} UfoRemoteMode;
-/**
- * UfoMessage: (skip)
- * @type: Type of the wire message
- */
-struct _UfoMessage {
- UfoMessageType type;
- union {
- guint16 n_inputs;
- guint16 n_devices;
- } d;
-};
-UfoNode *ufo_remote_node_new (gpointer zmq_context,
- const gchar *address);
+UfoNode *ufo_remote_node_new (const gchar *address);
guint ufo_remote_node_get_num_gpus (UfoRemoteNode *node);
void ufo_remote_node_request_setup (UfoRemoteNode *node);
void ufo_remote_node_send_json (UfoRemoteNode *node,
- const gchar *json,
- gsize size);
+ UfoRemoteMode mode,
+ const gchar *json);
void ufo_remote_node_get_structure (UfoRemoteNode *node,
guint *n_inputs,
UfoInputParam **in_params,
@@ -126,6 +96,7 @@ void ufo_remote_node_get_result (UfoRemoteNode *node,
void ufo_remote_node_get_requisition (UfoRemoteNode *node,
UfoRequisition *requisition);
void ufo_remote_node_cleanup (UfoRemoteNode *node);
+void ufo_remote_node_terminate (UfoRemoteNode *node);
GType ufo_remote_node_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-resources.c b/ufo/ufo-resources.c
index d8295e7..83f360f 100644
--- a/ufo/ufo-resources.c
+++ b/ufo/ufo-resources.c
@@ -20,6 +20,7 @@
#include "config.h"
#include <glib.h>
+#include <gio/gio.h>
#include <stdio.h>
#ifdef __APPLE__
#include <OpenCL/cl.h>
@@ -39,13 +40,18 @@
* kernels from text files.
*/
+static void ufo_resources_initable_iface_init (GInitableIface *iface);
+
G_DEFINE_TYPE_WITH_CODE (UfoResources, ufo_resources, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL))
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL)
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ ufo_resources_initable_iface_init))
#define UFO_RESOURCES_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_RESOURCES, UfoResourcesPrivate))
/**
* UfoResourcesError:
+ * @UFO_RESOURCES_ERROR_GENERAL: General resource problems
* @UFO_RESOURCES_ERROR_LOAD_PROGRAM: Could not load the OpenCL file
* @UFO_RESOURCES_ERROR_CREATE_PROGRAM: Could not create a program from
* the sources
@@ -62,20 +68,21 @@ ufo_resources_error_quark (void)
}
struct _UfoResourcesPrivate {
+ GError *construct_error;
UfoConfig *config;
- cl_uint num_platforms;
- cl_platform_id *opencl_platforms;
- cl_context opencl_context;
- cl_uint *num_devices; /**< Number of OpenCL devices per platform id */
- cl_device_id **opencl_devices; /**< Array of OpenCL devices per platform id */
- cl_command_queue *command_queues; /**< Array of command queues per device */
+ cl_platform_id platform;
+ cl_context context;
+ cl_uint n_devices; /**< Number of OpenCL devices per platform id */
+ cl_device_id *devices; /**< Array of OpenCL devices per platform id */
+ cl_command_queue *command_queues; /**< Array of command queues per device */
+ GList *include_paths; /**< List of include paths for kernel includes >*/
GList *kernel_paths; /**< Colon-separated string with paths to kernel files */
- GHashTable *opencl_programs; /**< Map from filename to cl_program */
- GList *opencl_kernels;
- GString *opencl_build_options;
- GString *include_paths; /**< List of include paths "-I/foo/bar" built from added paths */
+ GHashTable *kernel_cache;
+ GList *programs;
+ GList *kernels;
+ GString *build_opts;
};
enum {
@@ -162,7 +169,7 @@ ufo_resources_clerr (int error)
}
static gchar *
-resources_load_opencl_program (const gchar *filename)
+read_file (const gchar *filename)
{
FILE *fp = fopen (filename, "r");
@@ -191,19 +198,22 @@ resources_load_opencl_program (const gchar *filename)
}
static void
-resources_release_kernel (cl_kernel kernel)
+release_kernel (cl_kernel kernel)
{
+ g_debug ("Release kernel=%p", (gpointer) kernel);
UFO_RESOURCES_CHECK_CLERR (clReleaseKernel (kernel));
}
static void
-resources_release_program (cl_program program)
+release_program (cl_program program)
{
+ g_debug ("Release program=%p", (gpointer) program);
UFO_RESOURCES_CHECK_CLERR (clReleaseProgram (program));
}
static gchar *
-resources_find_path (UfoResourcesPrivate *priv, const gchar *filename)
+lookup_kernel_path (UfoResourcesPrivate *priv,
+ const gchar *filename)
{
/* Check first if filename is already a path */
if (g_path_is_absolute (filename)) {
@@ -213,43 +223,287 @@ resources_find_path (UfoResourcesPrivate *priv, const gchar *filename)
return NULL;
}
- /* If it is not a path, search in all paths that were added */
- GList *elem = g_list_first (priv->kernel_paths);
+ for (GList *it = g_list_first (priv->kernel_paths); it != NULL; it = g_list_next (it)) {
+ gchar *path;
- while (elem != NULL) {
- gchar *path = g_strdup_printf ("%s%c%s", (gchar *) elem->data, G_DIR_SEPARATOR, filename);
+ path = g_build_filename ((gchar *) it->data, filename, NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
return path;
g_free (path);
- elem = g_list_next (elem);
}
return NULL;
}
+static gboolean
+platform_has_gpus (cl_platform_id platform)
+{
+ cl_uint n_devices = 0;
+ cl_int err;
+
+ err = clGetDeviceIDs (platform,
+ CL_DEVICE_TYPE_GPU,
+ 0, NULL, &n_devices);
+
+ if (err != CL_DEVICE_NOT_FOUND)
+ UFO_RESOURCES_CHECK_CLERR (err);
+
+ return n_devices > 0;
+}
+
+static cl_platform_id
+get_preferably_gpu_based_platform (void)
+{
+ cl_platform_id *platforms;
+ cl_uint n_platforms;
+ cl_platform_id candidate = 0;
+
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (0, NULL, &n_platforms));
+ platforms = g_malloc0 (n_platforms * sizeof (cl_platform_id));
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (n_platforms, platforms, NULL));
+
+ if (n_platforms > 0)
+ candidate = platforms[0];
+
+ for (guint i = 0; i < n_platforms; i++) {
+ if (platform_has_gpus (platforms[i])) {
+ candidate = platforms[i];
+ break;
+ }
+ }
+
+ g_free (platforms);
+ return candidate;
+}
+
+static gboolean
+platform_vendor_has_prefix (cl_platform_id platform,
+ const gchar *prefix)
+{
+ gboolean has_prefix;
+ gchar *str;
+ gsize size;
+
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformInfo (platform, CL_PLATFORM_VENDOR, 0, NULL, &size));
+ str = g_malloc0 (size);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetPlatformInfo (platform, CL_PLATFORM_VENDOR, size, str, NULL));
+ has_prefix = g_str_has_prefix (str, prefix);
+
+ g_free (str);
+ return has_prefix;
+}
+
+static void
+add_vendor_to_build_opts (GString *opts,
+ cl_platform_id platform)
+{
+ if (platform_vendor_has_prefix (platform, "NVIDIA"))
+ g_string_append (opts, "-cl-nv-verbose -DVENDOR=NVIDIA");
+
+ if (platform_vendor_has_prefix (platform, "Advanced Micro Devices"))
+ g_string_append (opts, "-DVENDOR=AMD");
+}
+
+static cl_device_type
+get_device_type (UfoResourcesPrivate *priv)
+{
+ if (priv->config == NULL)
+ return CL_DEVICE_TYPE_ALL;
+
+ switch (ufo_config_get_device_type (priv->config)) {
+ case UFO_DEVICE_CPU:
+ return CL_DEVICE_TYPE_CPU;
+ case UFO_DEVICE_GPU:
+ return CL_DEVICE_TYPE_GPU;
+ case UFO_DEVICE_ALL:
+ return CL_DEVICE_TYPE_ALL;
+ }
+
+ return CL_DEVICE_TYPE_ALL;
+}
+
+static void
+restrict_to_gpu_subset (UfoResourcesPrivate *priv)
+{
+ /*
+ * Selects a single GPU which can be set via the UFO_USE_GPU
+ * environment variable, even if more GPUs are available. The specifc GPU
+ * is selected via the integer value of UFO_USE_GPU (index starts at 1).
+ * Used for debugging and evaluation.
+ */
+
+ const gchar* env_gpu = g_getenv ("UFO_USE_GPU");
+ if (env_gpu == NULL || g_strcmp0 (env_gpu, "") == 0)
+ return;
+
+ guint device_index = (guint) g_ascii_strtoull (env_gpu, NULL, 0);
+ if (device_index == 0) {
+ g_error ("Unrecognized format for env var UFO_USE_GPU");
+ return;
+ }
+ if (device_index > priv->n_devices) {
+ g_error ("Can't select UFO_USE_GPU=%d gpus as it exceeds number of available devices", device_index);
+ return;
+ }
+
+ // TODO allow restriction to real subset, like 1,3,5 etc.
+ cl_device_id *devices_subset = g_malloc0 (1 * sizeof (cl_device_id));
+ devices_subset[0] = priv->devices[device_index - 1];
+ g_free (priv->devices);
+ priv->devices = devices_subset;
+ priv->n_devices = 1;
+}
+
+static gboolean
+initialize_opencl (UfoResourcesPrivate *priv,
+ GError **error)
+{
+ cl_int errcode = CL_SUCCESS;
+ cl_device_type device_type;
+ cl_command_queue_properties queue_properties = CL_QUEUE_PROFILING_ENABLE;
+
+ priv->platform = get_preferably_gpu_based_platform ();
+ add_vendor_to_build_opts (priv->build_opts, priv->platform);
+ device_type = get_device_type (priv);
+
+ errcode = clGetDeviceIDs (priv->platform, device_type, 0, NULL, &priv->n_devices);
+ UFO_RESOURCES_CHECK_AND_SET (errcode, error);
+
+ if (errcode != CL_SUCCESS)
+ return FALSE;
+
+ priv->devices = g_malloc0 (priv->n_devices * sizeof (cl_device_id));
+
+ errcode = clGetDeviceIDs (priv->platform, device_type, priv->n_devices, priv->devices, NULL);
+ UFO_RESOURCES_CHECK_AND_SET (errcode, error);
+
+ if (errcode != CL_SUCCESS)
+ return FALSE;
+
+ restrict_to_gpu_subset (priv);
+
+ priv->context = clCreateContext (NULL,
+ priv->n_devices, priv->devices,
+ NULL, NULL, &errcode);
+
+ UFO_RESOURCES_CHECK_AND_SET (errcode, error);
+
+ if (errcode != CL_SUCCESS)
+ return FALSE;
+
+ priv->command_queues = g_malloc0 (priv->n_devices * sizeof (cl_command_queue));
+
+ for (guint i = 0; i < priv->n_devices; i++) {
+ priv->command_queues[i] = clCreateCommandQueue (priv->context,
+ priv->devices[i],
+ queue_properties, &errcode);
+ UFO_RESOURCES_CHECK_AND_SET (errcode, error);
+
+ if (errcode != CL_SUCCESS)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**
* ufo_resources_new:
* @config: A #UfoConfiguration object or %NULL
+ * @error: Location of a #GError or %NULL
*
* Create a new #UfoResources instance.
*
* Returns: (transfer none): A new #UfoResources
*/
UfoResources *
-ufo_resources_new (UfoConfig *config)
+ufo_resources_new (UfoConfig *config,
+ GError **error)
+{
+ return g_initable_new (UFO_TYPE_RESOURCES, NULL, error,
+ "config", config,
+ NULL);
+}
+
+static gchar *
+escape_device_name (gchar *name)
+{
+ gchar *tmp = name;
+
+ while (*tmp) {
+ gchar c = *tmp;
+
+ if (c == ' ')
+ *tmp = '_';
+ else
+ *tmp = g_ascii_toupper (c);
+
+ tmp++;
+ }
+
+ return name;
+}
+
+static void
+append_include_path (const gchar *path,
+ GString *str)
+{
+ g_string_append_printf (str, " -I%s", path);
+}
+
+static gchar *
+get_device_build_options (UfoResourcesPrivate *priv,
+ guint device_index,
+ const gchar *additional)
{
- return UFO_RESOURCES (g_object_new (UFO_TYPE_RESOURCES,
- "config", config,
- NULL));
+ GString *opts;
+ gsize size;
+ gchar *name;
+
+ g_assert (device_index < priv->n_devices);
+
+ opts = g_string_new (priv->build_opts->str);
+
+ if (additional != NULL)
+ g_string_append (opts, additional);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetDeviceInfo (priv->devices[device_index],
+ CL_DEVICE_NAME, 0, NULL, &size));
+ name = g_malloc0 (size);
+
+ UFO_RESOURCES_CHECK_CLERR (clGetDeviceInfo (priv->devices[device_index],
+ CL_DEVICE_NAME, size, name, NULL));
+
+ g_string_append_printf (opts, " -DDEVICE=%s", escape_device_name (name));
+ g_free (name);
+
+ g_list_foreach (priv->include_paths, (GFunc) append_include_path, opts);
+
+ return g_string_free (opts, FALSE);
}
static void
-append_include_path (gchar *path,
- GString *directive)
+handle_build_error (cl_program program,
+ cl_device_id device,
+ cl_int errcode,
+ GError **error)
{
- g_string_append_printf (directive, " -I%s", path);
+ const gsize LOG_SIZE = 4096;
+ gchar *log;
+
+ g_set_error (error,
+ UFO_RESOURCES_ERROR,
+ UFO_RESOURCES_ERROR_BUILD_PROGRAM,
+ "Failed to build OpenCL program: %s", ufo_resources_clerr (errcode));
+
+ log = g_malloc0 (LOG_SIZE * sizeof (char));
+
+ UFO_RESOURCES_CHECK_CLERR (clGetProgramBuildInfo (program, device, CL_PROGRAM_BUILD_LOG,
+ LOG_SIZE, log, NULL));
+ g_print ("\n=== Build log ===%s\n\n", log);
+ g_free (log);
}
static cl_program
@@ -259,10 +513,10 @@ add_program_from_source (UfoResourcesPrivate *priv,
GError **error)
{
cl_program program;
- gchar *build_options = NULL;
cl_int errcode = CL_SUCCESS;
+ gchar *build_options;
- program = clCreateProgramWithSource (priv->opencl_context,
+ program = clCreateProgramWithSource (priv->context,
1, &source, NULL, &errcode);
if (errcode != CL_SUCCESS) {
@@ -273,99 +527,75 @@ add_program_from_source (UfoResourcesPrivate *priv,
return NULL;
}
- if (options != NULL)
- build_options = g_strdup_printf ("%s %s %s", priv->opencl_build_options->str, priv->include_paths->str, options);
- else
- build_options = g_strdup_printf ("%s %s", priv->opencl_build_options->str, priv->include_paths->str);
+ build_options = get_device_build_options (priv, 0, options);
errcode = clBuildProgram (program,
- priv->num_devices[0],
- priv->opencl_devices[0],
+ priv->n_devices, priv->devices,
build_options,
NULL, NULL);
- g_free (build_options);
-
if (errcode != CL_SUCCESS) {
- g_set_error (error,
- UFO_RESOURCES_ERROR,
- UFO_RESOURCES_ERROR_BUILD_PROGRAM,
- "Failed to build OpenCL program: %s", ufo_resources_clerr (errcode));
-
- const gsize LOG_SIZE = 4096;
- gchar *log = (gchar *) g_malloc0(LOG_SIZE * sizeof (char));
- UFO_RESOURCES_CHECK_CLERR (clGetProgramBuildInfo (program,
- priv->opencl_devices[0][0],
- CL_PROGRAM_BUILD_LOG,
- LOG_SIZE, (void *) log, NULL));
- g_print ("\n=== Build log for s===%s\n\n", log);
- g_free (log);
+ handle_build_error (program, priv->devices[0], errcode, error);
return NULL;
}
+ priv->programs = g_list_append (priv->programs, program);
+
+ g_free (build_options);
return program;
}
-static cl_program
-resources_add_program (UfoResources *resources, const gchar *filename, const gchar *options, GError **error)
+static gchar *
+get_first_kernel_name (const gchar *source)
{
- g_return_val_if_fail (UFO_IS_RESOURCES (resources) || (filename != NULL), FALSE);
- UfoResourcesPrivate *priv = resources->priv;
-
- /* Programs might be added multiple times if this is not locked */
- static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
- g_static_mutex_lock (&mutex);
-
- /* Don't process the kernel file again, if already load */
- cl_program program = g_hash_table_lookup (priv->opencl_programs, filename);
+ GRegex *regex;
+ gchar *name = NULL;
+ GMatchInfo *match = NULL;
+ GError *error = NULL;
- if (program != NULL) {
- g_static_mutex_unlock (&mutex);
- return program;
- }
-
- gchar *path = resources_find_path (priv, filename);
+ regex = g_regex_new ("__kernel\\svoid\\s([A-Za-z][A-Za-z0-9_]+)",
+ G_REGEX_MULTILINE, 0, &error);
- if (path == NULL) {
- g_set_error (error,
- UFO_RESOURCES_ERROR,
- UFO_RESOURCES_ERROR_LOAD_PROGRAM,
- "Could not find `%s'. Maybe you forgot to pass a configuration?", filename);
- g_static_mutex_unlock (&mutex);
+ if (error != NULL) {
+ g_error ("%s", error->message);
+ g_error_free (error);
return NULL;
}
- gchar *buffer = resources_load_opencl_program (path);
- g_free (path);
+ if (g_regex_match (regex, source, 0, &match))
+ name = g_match_info_fetch (match, 1);
- if (buffer == NULL) {
- g_set_error (error,
- UFO_RESOURCES_ERROR,
- UFO_RESOURCES_ERROR_LOAD_PROGRAM,
- "Could not open `%s'", filename);
- g_static_mutex_unlock (&mutex);
- return NULL;
- }
-
- program = add_program_from_source (priv, buffer, options, error);
- g_message ("Added program %p from `%s`", (gpointer) program, filename);
-
- if (program != NULL)
- g_hash_table_insert (priv->opencl_programs, g_strdup (filename), program);
-
- g_static_mutex_unlock (&mutex);
- g_free (buffer);
- return program;
+ g_match_info_free (match);
+ g_regex_unref (regex);
+ return name;
}
static cl_kernel
-resources_get_kernel (UfoResourcesPrivate *priv,
- cl_program program,
- const gchar *kernel_name,
- GError **error)
+create_kernel (UfoResourcesPrivate *priv,
+ cl_program program,
+ const gchar *kernel_name,
+ GError **error)
{
+ cl_kernel kernel;
+ gchar *name;
cl_int errcode = CL_SUCCESS;
- cl_kernel kernel = clCreateKernel (program, kernel_name, &errcode);
+
+ if (kernel_name == NULL) {
+ gchar *source;
+ gsize size;
+
+ UFO_RESOURCES_CHECK_CLERR (clGetProgramInfo (program, CL_PROGRAM_SOURCE, 0, NULL, &size));
+ source = g_malloc0 (size);
+ UFO_RESOURCES_CHECK_CLERR (clGetProgramInfo (program, CL_PROGRAM_SOURCE, size, source, NULL));
+ name = get_first_kernel_name (source);
+ g_free (source);
+ }
+ else {
+ name = g_strdup (kernel_name);
+ }
+
+ kernel = clCreateKernel (program, name, &errcode);
+ g_free (name);
if (kernel == NULL || errcode != CL_SUCCESS) {
g_set_error (error,
@@ -375,56 +605,130 @@ resources_get_kernel (UfoResourcesPrivate *priv,
return NULL;
}
- priv->opencl_kernels = g_list_append (priv->opencl_kernels, kernel);
+ priv->kernels = g_list_append (priv->kernels, kernel);
return kernel;
}
+static gchar *
+create_cache_key (const gchar *filename,
+ const gchar *kernelname)
+{
+ return g_strdup_printf ("%s:%s", filename, kernelname);
+}
+
/**
* ufo_resources_get_kernel:
* @resources: A #UfoResources object
* @filename: Name of the .cl kernel file
- * @kernel: Name of a kernel
- * @error: Return location for a GError from #UfoResourcesError, or NULL
+ * @kernel: Name of a kernel, or %NULL
+ * @error: Return location for a GError from #UfoResourcesError, or %NULL
*
* Loads a and builds a kernel from a file. The file is searched in the current
- * working directory and all paths added through
- * ufo_resources_add_paths ().
+ * working directory and all paths added through ufo_resources_add_paths (). If
+ * @kernel is %NULL, the first encountered kernel is returned.
*
* Returns: (transfer none): a cl_kernel object that is load from @filename or %NULL on error
*/
gpointer
ufo_resources_get_kernel (UfoResources *resources,
const gchar *filename,
- const gchar *kernel,
+ const gchar *kernelname,
GError **error)
{
UfoResourcesPrivate *priv;
+ gchar *path;
+ gchar *buffer;
cl_program program;
- GError *tmp_error = NULL;
g_return_val_if_fail (UFO_IS_RESOURCES (resources) &&
- (filename != NULL) &&
- (kernel != NULL), NULL);
+ (filename != NULL), NULL);
priv = resources->priv;
- program = resources_add_program (resources, filename, "", &tmp_error);
+ path = lookup_kernel_path (priv, filename);
+
+ if (path == NULL) {
+ g_set_error (error, UFO_RESOURCES_ERROR, UFO_RESOURCES_ERROR_LOAD_PROGRAM,
+ "Could not find `%s'. Maybe you forgot to pass a configuration?", filename);
+ return NULL;
+ }
+
+ buffer = read_file (path);
+ g_free (path);
- if (program == NULL) {
- g_propagate_error (error, tmp_error);
+ if (buffer == NULL) {
+ g_set_error (error, UFO_RESOURCES_ERROR, UFO_RESOURCES_ERROR_LOAD_PROGRAM,
+ "Could not open `%s'", filename);
return NULL;
}
- return resources_get_kernel (priv, program, kernel, error);
+ program = add_program_from_source (priv, buffer, "", error);
+ g_debug ("Added program %p from `%s`", (gpointer) program, filename);
+ g_free (buffer);
+
+ return create_kernel (priv, program, kernelname, error);
+}
+
+/**
+ * ufo_resources_get_cached_kernel:
+ * @resources: A #UfoResources object
+ * @filename: Name of the .cl kernel file
+ * @kernel: Name of a kernel, or %NULL
+ * @error: Return location for a GError from #UfoResourcesError, or %NULL
+ *
+ * Loads a and builds a kernel from a file. The file is searched in the current
+ * working directory and all paths added through ufo_resources_add_paths (). If
+ * @kernel is %NULL, the first encountered kernel is returned. The kernel object
+ * is cached and should not be used by two threads concurrently.
+ *
+ * Returns: (transfer none): a cl_kernel object that is load from @filename or %NULL on error
+ */
+gpointer
+ufo_resources_get_cached_kernel (UfoResources *resources,
+ const gchar *filename,
+ const gchar *kernelname,
+ GError **error)
+{
+ UfoResourcesPrivate *priv;
+ cl_kernel kernel;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources) &&
+ (filename != NULL), NULL);
+
+ priv = resources->priv;
+
+ if (kernelname != NULL) {
+ gchar *cache_key;
+
+ cache_key = create_cache_key (filename, kernelname);
+ kernel = g_hash_table_lookup (priv->kernel_cache, cache_key);
+
+ if (kernel != NULL) {
+ g_free (cache_key);
+ return kernel;
+ }
+ }
+
+ kernel = ufo_resources_get_kernel (resources, filename, kernelname, error);
+
+ if (kernel != NULL && kernelname != NULL) {
+ gchar *cache_key;
+
+ cache_key = create_cache_key (filename, kernelname);
+ g_hash_table_insert (priv->kernel_cache, cache_key, kernel);
+ }
+
+ return kernel;
}
/**
* ufo_resources_get_kernel_from_source:
* @resources: A #UfoResources
* @source: OpenCL source string
- * @kernel: Name of a kernel
+ * @kernel: Name of a kernel or %NULL
* @error: Return location for a GError from #UfoResourcesError, or NULL
*
- * Loads and builds a kernel from a string.
+ * Loads and builds a kernel from a string. If @kernel is %NULL, the first
+ * kernel defined in @source is used.
*
* Returns: (transfer none): a cl_kernel object that is load from @filename
*/
@@ -438,23 +742,12 @@ ufo_resources_get_kernel_from_source (UfoResources *resources,
cl_program program;
g_return_val_if_fail (UFO_IS_RESOURCES (resources) &&
- (source != NULL) &&
- (kernel != NULL), NULL);
+ (source != NULL), NULL);
priv = UFO_RESOURCES_GET_PRIVATE (resources);
program = add_program_from_source (priv, source, NULL, error);
-
- /*
- * We add the program under a fake file name. This looks very brittle to me
- * (kernel name could be the same as a source filename) but it should work
- * in most cases.
- */
- if (program != NULL)
- g_hash_table_insert (priv->opencl_programs, g_strdup (kernel), program);
- else
- return NULL;
-
- return resources_get_kernel (priv, program, kernel, error);
+ g_debug ("Added program %p from source", (gpointer) program);
+ return create_kernel (priv, program, kernel, error);
}
/**
@@ -470,16 +763,16 @@ gpointer
ufo_resources_get_context (UfoResources *resources)
{
g_return_val_if_fail (UFO_IS_RESOURCES (resources), NULL);
- return resources->priv->opencl_context;
+ return resources->priv->context;
}
/**
- * ufo_resources_get_cmd_queues:
+ * ufo_resources_get_cmd_queues: (skip)
* @resources: A #UfoResources
*
* Get all command queues managed by @resources.
*
- * Return value: (element-type gpointer) (transfer container): List with
+ * Returns: (transfer container) (element-type gpointer): List with
* cl_command_queue objects. Free with g_list_free() but not its elements.
*/
GList *
@@ -491,12 +784,72 @@ ufo_resources_get_cmd_queues (UfoResources *resources)
g_return_val_if_fail (UFO_IS_RESOURCES (resources), NULL);
priv = resources->priv;
- for (guint i = 0; i < priv->num_devices[0]; i++)
+ for (guint i = 0; i < priv->n_devices; i++)
result = g_list_append (result, priv->command_queues[i]);
return result;
}
+/**
+ * ufo_resources_get_devices: (skip)
+ * @resources: A #UfoResources
+ *
+ * Get all devices queues managed by @resources.
+ *
+ * Returns: (element-type gpointer) (transfer container): List with
+ * cl_device_id objects. Free with g_list_free() but not its elements.
+ */
+GList *
+ufo_resources_get_devices (UfoResources *resources)
+{
+ UfoResourcesPrivate *priv;
+ GList *result = NULL;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES(resources), NULL);
+ priv = resources->priv;
+
+ for (guint i = 0; i < priv->n_devices; i++)
+ result = g_list_append (result, priv->devices[i]);
+
+ return result;
+}
+
+/**
+ * ufo_resources_get_mapped_cmd_queues:
+ * @resources: A #UfoResources
+ *
+ * Get all devices queues managed by @resources.
+ *
+ * Return value: (transfer container): Hash table with cl_device_id objects as key and
+ * cl_command_queue objects as value. Free with g_hash_table_destroy() but not
+ * its elements.
+ */
+GHashTable *
+ufo_resources_get_mapped_cmd_queues (UfoResources *resources)
+{
+ UfoResourcesPrivate *priv;
+ GHashTable *result = NULL;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (resources), NULL);
+ priv = resources->priv;
+ result = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) release_program);
+
+ for (guint i = 0; i < priv->n_devices; i++)
+ g_hash_table_insert (result, priv->devices[i], priv->command_queues[i]);
+
+ return result;
+}
+
+static GList *
+append_config_paths (GList *list, UfoConfig *config)
+{
+ GList *paths;
+
+ paths = ufo_config_get_paths (config);
+ return g_list_concat (list, paths);
+}
+
static void
ufo_resources_set_property (GObject *object,
guint property_id,
@@ -515,12 +868,11 @@ ufo_resources_set_property (GObject *object,
if (value_object != NULL) {
UfoConfig *config;
- GList *paths;
config = UFO_CONFIG (value_object);
- paths = ufo_config_get_paths (config);
- priv->kernel_paths = g_list_concat (priv->kernel_paths, paths);
- g_list_foreach (paths, (GFunc) append_include_path, priv->include_paths);
+ priv->kernel_paths = append_config_paths (priv->kernel_paths, config);
+ priv->include_paths = append_config_paths (priv->include_paths, config);
+
g_object_ref (config);
priv->config = config;
}
@@ -562,45 +914,83 @@ ufo_resources_dispose (GObject *object)
priv->config = NULL;
}
- G_OBJECT_CLASS (ufo_resources_parent_class)->finalize (object);
+ G_OBJECT_CLASS (ufo_resources_parent_class)->dispose (object);
+}
+
+static void
+list_free_full (GList **list,
+ GFunc free_func)
+{
+ g_assert (list != NULL);
+ g_list_foreach (*list, free_func, NULL);
+ g_list_free (*list);
+ *list = NULL;
}
static void
ufo_resources_finalize (GObject *object)
{
- UfoResourcesPrivate *priv = UFO_RESOURCES_GET_PRIVATE (object);
+ UfoResourcesPrivate *priv;
- g_hash_table_destroy (priv->opencl_programs);
- g_list_foreach (priv->kernel_paths, (GFunc) g_free, NULL);
- g_list_free (priv->kernel_paths);
- g_list_foreach (priv->opencl_kernels, (GFunc) resources_release_kernel, NULL);
- g_list_free (priv->opencl_kernels);
+ priv = UFO_RESOURCES_GET_PRIVATE (object);
- for (guint i = 0; i < priv->num_devices[0]; i++)
- UFO_RESOURCES_CHECK_CLERR (clReleaseCommandQueue (priv->command_queues[i]));
+ g_clear_error (&priv->construct_error);
+ g_hash_table_destroy (priv->kernel_cache);
+
+ list_free_full (&priv->kernel_paths, (GFunc) g_free);
+ list_free_full (&priv->include_paths, (GFunc) g_free);
+ list_free_full (&priv->kernels, (GFunc) release_kernel);
+ list_free_full (&priv->programs, (GFunc) release_program);
- UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->opencl_context));
+ for (guint i = 0; i < priv->n_devices; i++)
+ UFO_RESOURCES_CHECK_CLERR (clReleaseCommandQueue (priv->command_queues[i]));
- g_string_free (priv->opencl_build_options, TRUE);
- g_string_free (priv->include_paths, TRUE);
+ if (priv->context)
+ UFO_RESOURCES_CHECK_CLERR (clReleaseContext (priv->context));
- for (guint i = 0; i < priv->num_platforms; i ++)
- g_free (priv->opencl_devices[i]);
+ g_string_free (priv->build_opts, TRUE);
- g_free (priv->num_devices);
- g_free (priv->opencl_devices);
- g_free (priv->opencl_platforms);
+ g_free (priv->devices);
g_free (priv->command_queues);
- priv->num_devices = NULL;
- priv->opencl_kernels = NULL;
- priv->opencl_devices = NULL;
- priv->opencl_platforms = NULL;
+ priv->kernels = NULL;
+ priv->devices = NULL;
G_OBJECT_CLASS (ufo_resources_parent_class)->finalize (object);
g_debug ("UfoResources: finalized");
}
+static gboolean
+ufo_resources_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ UfoResources *resources;
+ UfoResourcesPrivate *priv;
+
+ g_return_val_if_fail (UFO_IS_RESOURCES (initable), FALSE);
+
+ if (cancellable != NULL) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Cancellable initialization not supported");
+ return FALSE;
+ }
+
+ resources = UFO_RESOURCES (initable);
+ priv = resources->priv;
+
+ if (!initialize_opencl (priv, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+ufo_resources_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = ufo_resources_initable_init;
+}
+
static void
ufo_resources_class_init (UfoResourcesClass *klass)
{
@@ -620,72 +1010,18 @@ static void
ufo_resources_init (UfoResources *self)
{
UfoResourcesPrivate *priv;
+
self->priv = priv = UFO_RESOURCES_GET_PRIVATE (self);
priv->config = NULL;
- priv->opencl_programs = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) resources_release_program);
- priv->opencl_kernels = NULL;
- priv->opencl_platforms = NULL;
- priv->opencl_build_options = g_string_new ("-cl-mad-enable ");
- priv->include_paths = g_string_new ("-I. ");
+ priv->programs = NULL;
+ priv->kernels = NULL;
+ priv->kernel_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ priv->build_opts = g_string_new ("-cl-mad-enable ");
+ priv->include_paths = g_list_append (NULL, g_strdup ("."));
priv->kernel_paths = g_list_append (NULL, g_strdup ("."));
priv->kernel_paths = g_list_append (priv->kernel_paths, g_strdup (UFO_PLUGIN_DIR));
-
- /* initialize OpenCL subsystem */
- int errcode = CL_SUCCESS;
- UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (0, NULL, &priv->num_platforms));
- priv->opencl_platforms = g_malloc0(priv->num_platforms * sizeof (cl_platform_id));
-
- UFO_RESOURCES_CHECK_CLERR (clGetPlatformIDs (priv->num_platforms, priv->opencl_platforms, NULL));
- priv->num_devices = g_malloc0(priv->num_platforms * sizeof (cl_uint));
- priv->opencl_devices = g_malloc0(priv->num_platforms * sizeof (cl_device_id *));
-
- /* Get devices for each available platform */
- gchar *info_buffer = g_malloc0 (256);
-
- for (guint i = 0; i < priv->num_platforms; i++) {
- cl_uint num_devices;
- cl_platform_id platform = priv->opencl_platforms[i];
-
- UFO_RESOURCES_CHECK_CLERR (clGetPlatformInfo (platform, CL_PLATFORM_VENDOR, 256, info_buffer, NULL));
-
- if (g_str_has_prefix (info_buffer, "NVIDIA"))
- g_string_append (priv->opencl_build_options, "-cl-nv-verbose -DVENDOR=NVIDIA");
- else if (g_str_has_prefix (info_buffer, "Advanced Micro Devices"))
- g_string_append (priv->opencl_build_options, "-DVENDOR=AMD");
-
- UFO_RESOURCES_CHECK_CLERR (clGetDeviceIDs (platform,
- CL_DEVICE_TYPE_ALL,
- 0, NULL,
- &num_devices));
- priv->opencl_devices[i] = g_malloc0 (num_devices * sizeof (cl_device_id));
-
- UFO_RESOURCES_CHECK_CLERR (clGetDeviceIDs (platform,
- CL_DEVICE_TYPE_ALL,
- num_devices, priv->opencl_devices[i],
- NULL));
- priv->num_devices[i] = num_devices;
- }
-
- g_free (info_buffer);
- cl_command_queue_properties queue_properties = CL_QUEUE_PROFILING_ENABLE;
-
- /* XXX: create context for each platform?! */
- if (priv->num_platforms > 0) {
- priv->opencl_context = clCreateContext (NULL,
- priv->num_devices[0],
- priv->opencl_devices[0],
- NULL, NULL, &errcode);
- UFO_RESOURCES_CHECK_CLERR (errcode);
- priv->command_queues = g_malloc0 (priv->num_devices[0] * sizeof (cl_command_queue));
-
- for (guint i = 0; i < priv->num_devices[0]; i++) {
- priv->command_queues[i] = clCreateCommandQueue (priv->opencl_context,
- priv->opencl_devices[0][i],
- queue_properties, &errcode);
- UFO_RESOURCES_CHECK_CLERR (errcode);
- }
- }
+ priv->kernel_paths = g_list_append (priv->kernel_paths, g_strdup ("/usr/lib/ufo"));
+ priv->kernel_paths = g_list_append (priv->kernel_paths, g_strdup ("/usr/local/lib/ufo"));
}
diff --git a/ufo/ufo-resources.h b/ufo/ufo-resources.h
index af465c8..2148939 100644
--- a/ufo/ufo-resources.h
+++ b/ufo/ufo-resources.h
@@ -44,6 +44,7 @@ typedef struct _UfoResourcesPrivate UfoResourcesPrivate;
typedef enum {
+ UFO_RESOURCES_ERROR_GENERAL,
UFO_RESOURCES_ERROR_LOAD_PROGRAM,
UFO_RESOURCES_ERROR_CREATE_PROGRAM,
UFO_RESOURCES_ERROR_BUILD_PROGRAM,
@@ -61,6 +62,20 @@ typedef enum {
if ((error) != CL_SUCCESS) g_log("ocl", G_LOG_LEVEL_CRITICAL, "Error <%s:%i>: %s", __FILE__, __LINE__, ufo_resources_clerr((error))); }
/**
+ * UFO_RESOURCES_CHECK_AND_SET:
+ * @error: OpenCL error code
+ * @g_error_loc: Return location for a GError or %NULL
+ *
+ * Check @error and set @g_error_loc accordingly.
+ *
+ * Returns: %TRUE if no error occurred, %FALSE otherwise.
+ */
+#define UFO_RESOURCES_CHECK_AND_SET(error, g_error_loc) { \
+ if ((error) != CL_SUCCESS) \
+ g_set_error (g_error_loc, UFO_RESOURCES_ERROR, UFO_RESOURCES_ERROR_GENERAL, \
+ "OpenCL Error: %s", ufo_resources_clerr((error))); }
+
+/**
* UfoResources:
*
* Manages OpenCL resources. The contents of the #UfoResources structure
@@ -83,17 +98,24 @@ struct _UfoResourcesClass {
GObjectClass parent_class;
};
-UfoResources * ufo_resources_new (UfoConfig *config);
+UfoResources * ufo_resources_new (UfoConfig *config,
+ GError **error);
gpointer ufo_resources_get_kernel (UfoResources *resources,
const gchar *filename,
const gchar *kernel,
GError **error);
+gpointer ufo_resources_get_cached_kernel (UfoResources *resources,
+ const gchar *filename,
+ const gchar *kernel,
+ GError **error);
gpointer ufo_resources_get_kernel_from_source (UfoResources *resources,
const gchar *source,
const gchar *kernel,
GError **error);
gpointer ufo_resources_get_context (UfoResources *resources);
GList * ufo_resources_get_cmd_queues (UfoResources *resources);
+GList * ufo_resources_get_devices (UfoResources *resources);
+GHashTable * ufo_resources_get_mapped_cmd_queues (UfoResources *resources);
const gchar * ufo_resources_clerr (int error);
GType ufo_resources_get_type (void);
GQuark ufo_resources_error_quark (void);
diff --git a/ufo/ufo-scheduler.c b/ufo/ufo-scheduler.c
index 4b39906..f7ca218 100644
--- a/ufo/ufo-scheduler.c
+++ b/ufo/ufo-scheduler.c
@@ -16,15 +16,21 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
#ifdef __APPLE__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
+#include <gio/gio.h>
#include <stdio.h>
#include <string.h>
+#ifdef HAVE_PYTHON
+#include <Python.h>
+#endif
+
#include <ufo/ufo-buffer.h>
#include <ufo/ufo-config.h>
#include <ufo/ufo-configurable.h>
@@ -46,8 +52,12 @@
* on CPU and GPU hardware.
*/
+static void ufo_scheduler_initable_iface_init (GInitableIface *iface);
+
G_DEFINE_TYPE_WITH_CODE (UfoScheduler, ufo_scheduler, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL))
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_CONFIGURABLE, NULL)
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ ufo_scheduler_initable_iface_init))
#define UFO_SCHEDULER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_SCHEDULER, UfoSchedulerPrivate))
@@ -60,16 +70,20 @@ typedef struct {
} TaskLocalData;
struct _UfoSchedulerPrivate {
+ GError *construct_error;
UfoConfig *config;
UfoResources *resources;
GList *remotes;
+ UfoRemoteMode mode;
gboolean expand;
+ gboolean trace;
};
enum {
PROP_0,
PROP_EXPAND,
PROP_REMOTES,
+ PROP_ENABLE_TRACING,
N_PROPERTIES,
/* Here come the overriden properties that we don't install ourselves. */
@@ -79,6 +93,17 @@ enum {
static GParamSpec *properties[N_PROPERTIES] = { NULL, };
/**
+ * UfoSchedulerError:
+ * @UFO_SCHEDULER_ERROR_SETUP: Could not start scheduler due to error
+ */
+GQuark
+ufo_scheduler_error_quark (void)
+{
+ return g_quark_from_static_string ("ufo-scheduler-error-quark");
+}
+
+
+/**
* ufo_scheduler_new:
* @config: A #UfoConfig or %NULL
* @remotes: (element-type utf8): A #GList with strings describing remote machines or %NULL
@@ -125,8 +150,8 @@ ufo_scheduler_get_context (UfoScheduler *scheduler)
* @scheduler: A #UfoScheduler
* @split: %TRUE if task graph should be split
*
- * Sets whether the task graph should be expanded before execution to increase
- * multi GPU performance.
+ * Sets whether the task graph should be expanded to accomodate for a multi GPU
+ * system. Each suitable branch will be run on another GPU.
*/
void
ufo_scheduler_set_task_expansion (UfoScheduler *scheduler,
@@ -136,6 +161,23 @@ ufo_scheduler_set_task_expansion (UfoScheduler *scheduler,
g_object_set (G_OBJECT (scheduler), "expand", expand, NULL);
}
+/**
+ * ufo_scheduler_set_remote_mode:
+ * @scheduler: A #UfoScheduler
+ * @mode: Mode of remote execution.
+ *
+ * Sets the mode of remote execution.
+ *
+ * See: #UfoRemoteMode.
+ */
+void
+ufo_scheduler_set_remote_mode (UfoScheduler *scheduler,
+ UfoRemoteMode mode)
+{
+ g_return_if_fail (UFO_IS_SCHEDULER (scheduler));
+ scheduler->priv->mode = mode;
+}
+
static gboolean
get_inputs (TaskLocalData *tld,
UfoBuffer **inputs)
@@ -181,77 +223,146 @@ release_inputs (TaskLocalData *tld,
}
}
-static void
-exchange_data (UfoBuffer *input,
- TaskLocalData *tld)
+static gboolean
+any (gboolean *values,
+ guint n_values)
{
- UfoRemoteNode *remote;
- UfoGroup *group;
- UfoBuffer *output;
- UfoRequisition requisition;
+ gboolean result = FALSE;
- remote = UFO_REMOTE_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (tld->task)));
- ufo_remote_node_send_inputs (remote, &input);
- release_inputs (tld, &input);
+ for (guint i = 0; i < n_values; i++)
+ result = result || values[i];
- ufo_remote_node_get_requisition (remote, &requisition);
- group = ufo_task_node_get_out_group (UFO_TASK_NODE (tld->task));
- output = ufo_group_pop_output_buffer (group, &requisition);
- ufo_remote_node_get_result (remote, output);
- ufo_group_push_output_buffer (group, output);
+ return result;
}
static void
run_remote_task (TaskLocalData *tld)
{
UfoRemoteNode *remote;
- UfoBuffer *input;
guint n_remote_gpus;
- GThreadPool *pool;
- GError *error = NULL;
+ gboolean *alive;
+ gboolean active = TRUE;
g_assert (tld->n_inputs == 1);
+
remote = UFO_REMOTE_NODE (ufo_task_node_get_proc_node (UFO_TASK_NODE (tld->task)));
n_remote_gpus = ufo_remote_node_get_num_gpus (remote);
- pool = g_thread_pool_new ((GFunc) exchange_data, tld, (gint) n_remote_gpus, TRUE, &error);
- g_assert_no_error (error);
+ alive = g_new0 (gboolean, n_remote_gpus);
/*
* We launch a new thread for each incoming input data set because then we
* can send as many items as we have remote GPUs available without waiting
* for processing to stop.
*/
- while (1) {
- if (get_inputs (tld, &input))
- g_thread_pool_push (pool, input, &error);
- else
- break;
+ while (active) {
+ for (guint i = 0; i < n_remote_gpus; i++) {
+ UfoBuffer *input;
+
+ if (get_inputs (tld, &input)) {
+ ufo_remote_node_send_inputs (remote, &input);
+ release_inputs (tld, &input);
+ alive[i] = TRUE;
+ }
+ else {
+ alive[i] = FALSE;
+ }
+ }
+
+ for (guint i = 0; i < n_remote_gpus; i++) {
+ UfoGroup *group;
+ UfoBuffer *output;
+ UfoRequisition requisition;
+
+ if (!alive[i])
+ continue;
+
+ ufo_remote_node_get_requisition (remote, &requisition);
+ group = ufo_task_node_get_out_group (UFO_TASK_NODE (tld->task));
+ output = ufo_group_pop_output_buffer (group, &requisition);
+ ufo_remote_node_get_result (remote, output);
+ ufo_group_push_output_buffer (group, output);
+ }
+
+ active = any (alive, n_remote_gpus);
}
- g_thread_pool_free (pool, FALSE, TRUE);
+ g_free (alive);
ufo_group_finish (ufo_task_node_get_out_group (UFO_TASK_NODE (tld->task)));
}
+static gboolean
+check_implementation (UfoTaskNode *node,
+ const gchar *func,
+ const gchar *type,
+ gboolean assertion)
+{
+ if (!assertion) {
+ g_error ("%s is not implemented, although %s is a %s",
+ func, ufo_task_node_get_plugin_name (node), type);
+ }
+
+ return assertion;
+}
+
+static gboolean
+is_correctly_implemented (UfoTaskNode *node,
+ UfoTaskMode mode,
+ UfoTaskProcessFunc process,
+ UfoTaskGenerateFunc generate)
+{
+ switch (mode) {
+ case UFO_TASK_MODE_GENERATOR:
+ return check_implementation (node, "generate", "generator", generate != NULL);
+
+ case UFO_TASK_MODE_PROCESSOR:
+ return check_implementation (node, "process", "processor", process != NULL);
+
+ case UFO_TASK_MODE_REDUCTOR:
+ return check_implementation (node, "process or generate", "reductor",
+ (process != NULL) && (generate != NULL));
+ default:
+ g_error ("Unknown mode");
+ return FALSE;
+ }
+}
+
static gpointer
run_task (TaskLocalData *tld)
{
UfoBuffer *inputs[tld->n_inputs];
UfoBuffer *output;
UfoTaskNode *node;
+ UfoProfiler *profiler;
+ UfoTaskProcessFunc process;
+ UfoTaskGenerateFunc generate;
UfoRequisition requisition;
gboolean active;
node = UFO_TASK_NODE (tld->task);
active = TRUE;
output = NULL;
+ profiler = g_object_ref (ufo_task_node_get_profiler (node));
if (UFO_IS_REMOTE_TASK (tld->task)) {
run_remote_task (tld);
return NULL;
}
+ if (UFO_IS_GPU_TASK (tld->task)) {
+ process = (UfoTaskProcessFunc) ufo_gpu_task_process;
+ generate = (UfoTaskGenerateFunc) ufo_gpu_task_generate;
+ }
+ else {
+ process = (UfoTaskProcessFunc) ufo_cpu_task_process;
+ generate = (UfoTaskGenerateFunc) ufo_cpu_task_generate;
+ }
+
+ if (!is_correctly_implemented (node, tld->mode, process, generate))
+ return NULL;
+
while (active) {
UfoGroup *group;
+ gboolean produces;
group = ufo_task_node_get_out_group (node);
@@ -265,122 +376,74 @@ run_task (TaskLocalData *tld)
/* Get output buffers */
ufo_task_get_requisition (tld->task, inputs, &requisition);
+ produces = requisition.n_dims > 0;
- if (requisition.n_dims > 0) {
+ if (produces) {
output = ufo_group_pop_output_buffer (group, &requisition);
g_assert (output != NULL);
}
- /* Process */
- if (UFO_IS_GPU_TASK (tld->task)) {
- UfoGpuNode *gpu_node;
-
- if (output != NULL)
- ufo_buffer_discard_location (output, UFO_LOCATION_HOST);
-
- gpu_node = UFO_GPU_NODE (ufo_task_node_get_proc_node (node));
-
- switch (tld->mode) {
- case UFO_TASK_MODE_SINGLE:
- active = ufo_gpu_task_process (UFO_GPU_TASK (tld->task),
- inputs, output,
- &requisition, gpu_node);
- break;
-
- case UFO_TASK_MODE_GENERATE:
- case UFO_TASK_MODE_REDUCE:
- do {
- ufo_gpu_task_process (UFO_GPU_TASK (tld->task),
- inputs, output,
- &requisition, gpu_node);
- release_inputs (tld, inputs);
- active = get_inputs (tld, inputs);
- } while (active);
- break;
- }
-
- if (tld->mode == UFO_TASK_MODE_REDUCE)
- ufo_gpu_task_reduce (UFO_GPU_TASK (tld->task),
- output,
- &requisition,
- gpu_node);
+ if (output != NULL)
+ ufo_buffer_discard_location (output);
+
+ switch (tld->mode) {
+ case UFO_TASK_MODE_PROCESSOR:
+ ufo_profiler_trace_event (profiler, "process", "B");
+ active = process (tld->task, inputs, output, &requisition);
+ ufo_profiler_trace_event (profiler, "process", "E");
+ break;
+
+ case UFO_TASK_MODE_REDUCTOR:
+ do {
+ ufo_profiler_trace_event (profiler, "process", "B");
+ process (tld->task, inputs, output, &requisition);
+ ufo_profiler_trace_event (profiler, "process", "E");
+
+ release_inputs (tld, inputs);
+ active = get_inputs (tld, inputs);
+ } while (active);
+ break;
+
+ case UFO_TASK_MODE_GENERATOR:
+ ufo_profiler_trace_event (profiler, "generate", "B");
+ active = generate (tld->task, output, &requisition);
+ ufo_profiler_trace_event (profiler, "generate", "E");
+ break;
}
- else if (UFO_IS_CPU_TASK (tld->task)) {
- if (output != NULL)
- ufo_buffer_discard_location (output, UFO_LOCATION_DEVICE);
-
- switch (tld->mode) {
- case UFO_TASK_MODE_SINGLE:
- active = ufo_cpu_task_process (UFO_CPU_TASK (tld->task), inputs, output, &requisition);
- break;
-
- case UFO_TASK_MODE_GENERATE:
- case UFO_TASK_MODE_REDUCE:
- do {
- ufo_cpu_task_process (UFO_CPU_TASK (tld->task),
- inputs,
- output,
- &requisition);
- release_inputs (tld, inputs);
- active = get_inputs (tld, inputs);
- } while (active);
- break;
- }
- if (tld->mode == UFO_TASK_MODE_REDUCE)
- ufo_cpu_task_reduce (UFO_CPU_TASK (tld->task), output, &requisition);
- }
+ if (active && produces && (tld->mode != UFO_TASK_MODE_REDUCTOR))
+ ufo_group_push_output_buffer (group, output);
/* Release buffers for further consumption */
- release_inputs (tld, inputs);
-
- if (requisition.n_dims > 0) {
- switch (tld->mode) {
- case UFO_TASK_MODE_SINGLE:
- if (active)
- ufo_group_push_output_buffer (group, output);
- else
- ufo_group_finish (group);
- break;
-
- case UFO_TASK_MODE_REDUCE:
+ if (active)
+ release_inputs (tld, inputs);
+
+ if (tld->mode == UFO_TASK_MODE_REDUCTOR) {
+ active = TRUE;
+
+ do {
+ ufo_profiler_trace_event (profiler, "generate", "B");
+ active = generate (tld->task, output, &requisition);
+ ufo_profiler_trace_event (profiler, "generate", "E");
+
+ if (active) {
ufo_group_push_output_buffer (group, output);
- ufo_group_finish (group);
- break;
-
- case UFO_TASK_MODE_GENERATE:
- {
- do {
- if (UFO_IS_GPU_TASK (tld->task)) {
- UfoGpuNode *gpu_node;
-
- ufo_buffer_discard_location (output, UFO_LOCATION_HOST);
- gpu_node = UFO_GPU_NODE (ufo_task_node_get_proc_node (node));
- active = ufo_gpu_task_generate (UFO_GPU_TASK (tld->task),
- output,
- &requisition, gpu_node);
- }
- else {
- active = ufo_cpu_task_generate (UFO_CPU_TASK (tld->task),
- output,
- &requisition);
- }
-
- if (active) {
- ufo_group_push_output_buffer (group, output);
- output = ufo_group_pop_output_buffer (group, &requisition);
- }
- } while (active);
-
- ufo_group_finish (group);
- }
- break;
- }
+ output = ufo_group_pop_output_buffer (group, &requisition);
+ }
+ } while (active);
}
+
+ if (!active)
+ ufo_group_finish (group);
}
- g_message ("`%s' finished", G_OBJECT_TYPE_NAME (tld->task));
+ // g_message ("`%s' finished: CPU: %3.5fs GPU: %3.5fs IO: %3.5fs",
+ // G_OBJECT_TYPE_NAME (tld->task),
+ // ufo_profiler_elapsed (profiler, UFO_PROFILER_TIMER_CPU),
+ // ufo_profiler_elapsed (profiler, UFO_PROFILER_TIMER_GPU),
+ // ufo_profiler_elapsed (profiler, UFO_PROFILER_TIMER_IO));
+ g_object_unref (profiler);
return NULL;
}
@@ -390,6 +453,7 @@ cleanup_task_local_data (TaskLocalData **tlds,
{
for (guint i = 0; i < n; i++) {
TaskLocalData *tld = tlds[i];
+
g_free (tld->in_params);
g_free (tld->finished);
g_free (tld);
@@ -414,6 +478,7 @@ setup_tasks (UfoSchedulerPrivate *priv,
for (guint i = 0; i < n_nodes; i++) {
UfoNode *node;
+ UfoProfiler *profiler;
TaskLocalData *tld;
node = g_list_nth_data (nodes, i);
@@ -424,6 +489,9 @@ setup_tasks (UfoSchedulerPrivate *priv,
ufo_task_setup (UFO_TASK (node), priv->resources, error);
ufo_task_get_structure (UFO_TASK (node), &tld->n_inputs, &tld->in_params, &tld->mode);
+ profiler = ufo_task_node_get_profiler (UFO_TASK_NODE (node));
+ ufo_profiler_enable_tracing (profiler, priv->trace);
+
tld->finished = g_new0 (gboolean, tld->n_inputs);
if (error && *error != NULL)
@@ -481,6 +549,177 @@ setup_groups (UfoSchedulerPrivate *priv,
return groups;
}
+static gboolean
+correct_connections (UfoTaskGraph *graph,
+ GError **error)
+{
+ GList *nodes;
+ gboolean result = TRUE;
+
+ nodes = ufo_graph_get_nodes (UFO_GRAPH (graph));
+
+ for (GList *it = g_list_first (nodes); it != NULL; it = g_list_next (it)) {
+ UfoTaskNode *node;
+ UfoInputParam *in_params;
+ guint n_inputs;
+ UfoTaskMode mode;
+ UfoGroup *group;
+
+ node = UFO_TASK_NODE (it->data);
+ ufo_task_get_structure (UFO_TASK (node), &n_inputs, &in_params, &mode);
+ group = ufo_task_node_get_out_group (node);
+
+ if (((mode == UFO_TASK_MODE_GENERATOR) || (mode == UFO_TASK_MODE_REDUCTOR)) &&
+ ufo_group_get_num_targets (group) < 1) {
+ g_set_error (error, UFO_SCHEDULER_ERROR, UFO_SCHEDULER_ERROR_SETUP,
+ "No outgoing node for `%s'",
+ ufo_task_node_get_unique_name (node));
+ result = FALSE;
+ break;
+ }
+ }
+
+ g_list_free (nodes);
+ return result;
+}
+
+static void
+replicate_task_graph (UfoTaskGraph *graph,
+ UfoArchGraph *arch)
+{
+ GList *remotes;
+ guint n_graphs;
+ guint index = 1;
+
+ remotes = ufo_arch_graph_get_remote_nodes (arch);
+ n_graphs = g_list_length (remotes) + 1;
+
+ for (GList *it = g_list_first (remotes); it != NULL; it = g_list_next (it)) {
+ UfoRemoteNode *node;
+ gchar *json;
+
+ /* Set partition index for the remote task graph */
+ ufo_task_graph_set_partition (graph, index++, n_graphs);
+ json = ufo_task_graph_get_json_data (graph, NULL);
+ node = UFO_REMOTE_NODE (it->data);
+ ufo_remote_node_send_json (node, UFO_REMOTE_MODE_REPLICATE, json);
+ g_free (json);
+ }
+
+ /* Set partition index for the local task graph */
+ ufo_task_graph_set_partition (graph, 0, n_graphs);
+ g_list_free (remotes);
+}
+
+static void
+propagate_partition (UfoTaskGraph *graph)
+{
+ GList *nodes;
+ guint index;
+ guint total;
+
+ ufo_task_graph_get_partition (graph, &index, &total);
+ nodes = ufo_graph_get_nodes (UFO_GRAPH (graph));
+
+ for (GList *it = g_list_first (nodes); it != NULL; it = g_list_next (it))
+ ufo_task_node_set_partition (UFO_TASK_NODE (it->data), index, total);
+
+ g_list_free (nodes);
+}
+
+typedef struct {
+ UfoTraceEvent *event;
+ UfoTaskNode *node;
+ gdouble timestamp;
+} SortedEvent;
+
+static gint
+compare_event (const SortedEvent *a,
+ const SortedEvent *b,
+ gpointer user_data)
+{
+ return (gint) (a->timestamp - b->timestamp);
+}
+
+static GList *
+get_sorted_event_trace (TaskLocalData **tlds,
+ guint n_nodes)
+{
+ GList *sorted = NULL;
+
+ for (guint i = 0; i < n_nodes; i++) {
+ UfoTaskNode *node;
+ UfoProfiler *profiler;
+ GList *events;
+
+ node = UFO_TASK_NODE (tlds[i]->task);
+ profiler = ufo_task_node_get_profiler (node);
+ events = ufo_profiler_get_trace_events (profiler);
+
+ for (GList *it = g_list_first (events); it != NULL; it = g_list_next (it)) {
+ UfoTraceEvent *event;
+ SortedEvent *new_event;
+
+ event = (UfoTraceEvent *) it->data;
+ new_event = g_new0 (SortedEvent, 1);
+ new_event->event = event;
+ new_event->timestamp = event->timestamp;
+ new_event->node = node;
+ sorted = g_list_insert_sorted_with_data (sorted, new_event,
+ (GCompareDataFunc) compare_event, NULL);
+ }
+ }
+
+ return sorted;
+}
+
+static void
+write_traces (TaskLocalData **tlds,
+ guint n_nodes)
+{
+ FILE *fp;
+ gchar *filename;
+ guint pid;
+ GList *sorted;
+
+ sorted = get_sorted_event_trace (tlds, n_nodes);
+ pid = (guint) getpid ();
+ filename = g_strdup_printf (".trace.%i.json", pid);
+ fp = fopen (filename, "w");
+ fprintf (fp, "{ \"traceEvents\": [");
+
+ for (GList *it = g_list_first (sorted); it != NULL; it = g_list_next (it)) {
+ SortedEvent *sorted_event;
+ UfoTraceEvent *event;
+ gchar *name;
+
+ sorted_event = (SortedEvent *) it->data;
+ event = sorted_event->event;
+ name = g_strdup_printf ("%s-%p", G_OBJECT_TYPE_NAME (sorted_event->node),
+ (gpointer) sorted_event->node);
+
+ fprintf (fp, "{\"cat\":\"f\",\"ph\": \"%s\", \"ts\": %.1f, \"pid\": %i, \"tid\": \"%s\",\"name\": \"%s\", \"args\": {}}\n",
+ event->type, event->timestamp, pid, name, event->name);
+ if (g_list_next (it) != NULL)
+ fprintf (fp, ",");
+
+ g_free (name);
+ }
+
+ fprintf (fp, "] }");
+ fclose (fp);
+
+ g_list_foreach (sorted, (GFunc) g_free, NULL);
+ g_list_free (sorted);
+}
+
+static void
+join_threads (GThread **threads, guint n_threads)
+{
+ for (guint i = 0; i < n_threads; i++)
+ g_thread_join (threads[i]);
+}
+
void
ufo_scheduler_run (UfoScheduler *scheduler,
UfoTaskGraph *task_graph,
@@ -497,12 +736,25 @@ ufo_scheduler_run (UfoScheduler *scheduler,
g_return_if_fail (UFO_IS_SCHEDULER (scheduler));
priv = scheduler->priv;
+ if (priv->construct_error != NULL) {
+ if (error)
+ *error = g_error_copy (priv->construct_error);
+ return;
+ }
+
arch_graph = UFO_ARCH_GRAPH (ufo_arch_graph_new (priv->resources,
priv->remotes));
- if (priv->expand)
- ufo_task_graph_expand (task_graph, arch_graph);
+ if (priv->mode == UFO_REMOTE_MODE_REPLICATE) {
+ replicate_task_graph (task_graph, arch_graph);
+ }
+
+ if (priv->expand) {
+ gboolean expand_remote = priv->mode == UFO_REMOTE_MODE_STREAM;
+ ufo_task_graph_expand (task_graph, arch_graph, expand_remote);
+ }
+ propagate_partition (task_graph);
ufo_task_graph_map (task_graph, arch_graph);
/* Prepare task structures */
@@ -512,6 +764,10 @@ ufo_scheduler_run (UfoScheduler *scheduler,
return;
groups = setup_groups (priv, task_graph);
+
+ if (!correct_connections (task_graph, error))
+ return;
+
n_nodes = ufo_graph_get_num_nodes (UFO_GRAPH (task_graph));
threads = g_new0 (GThread *, n_nodes);
timer = g_timer_new ();
@@ -524,14 +780,32 @@ ufo_scheduler_run (UfoScheduler *scheduler,
return;
}
- /* Wait for threads to finish */
- for (guint i = 0; i < n_nodes; i++)
- g_thread_join (threads[i]);
+#ifdef HAVE_PYTHON
+ if (Py_IsInitialized ()) {
+ Py_BEGIN_ALLOW_THREADS
+
+ join_threads (threads, n_nodes);
- g_print ("Processing finished after %3.5fs\n", g_timer_elapsed (timer, NULL));
+ Py_END_ALLOW_THREADS
+ }
+ else {
+ join_threads (threads, n_nodes);
+ }
+#else
+ join_threads (threads, n_nodes);
+#endif
+
+#ifdef HAVE_PYTHON
+ if (Py_IsInitialized ())
+#endif
+
+ g_message ("Processing finished after %3.5fs", g_timer_elapsed (timer, NULL));
g_timer_destroy (timer);
/* Cleanup */
+ if (priv->trace)
+ write_traces (tlds, n_nodes);
+
cleanup_task_local_data (tlds, n_nodes);
g_list_foreach (groups, (GFunc) g_object_unref, NULL);
g_list_free (groups);
@@ -587,6 +861,10 @@ ufo_scheduler_set_property (GObject *object,
priv->expand = g_value_get_boolean (value);
break;
+ case PROP_ENABLE_TRACING:
+ priv->trace = g_value_get_boolean (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
@@ -606,6 +884,10 @@ ufo_scheduler_get_property (GObject *object,
g_value_set_boolean (value, priv->expand);
break;
+ case PROP_ENABLE_TRACING:
+ g_value_set_boolean (value, priv->trace);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
@@ -618,7 +900,8 @@ ufo_scheduler_constructed (GObject *object)
UfoSchedulerPrivate *priv;
priv = UFO_SCHEDULER_GET_PRIVATE (object);
- priv->resources = ufo_resources_new (priv->config);
+ priv->resources = ufo_resources_new (priv->config,
+ &priv->construct_error);
}
static void
@@ -648,6 +931,7 @@ ufo_scheduler_finalize (GObject *object)
priv = UFO_SCHEDULER_GET_PRIVATE (object);
+ g_clear_error (&priv->construct_error);
g_list_foreach (priv->remotes, (GFunc) g_free, NULL);
g_list_free (priv->remotes);
priv->remotes = NULL;
@@ -655,6 +939,41 @@ ufo_scheduler_finalize (GObject *object)
G_OBJECT_CLASS (ufo_scheduler_parent_class)->finalize (object);
}
+static gboolean
+ufo_scheduler_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ UfoScheduler *scheduler;
+ UfoSchedulerPrivate *priv;
+
+ g_return_val_if_fail (UFO_IS_SCHEDULER (initable), FALSE);
+
+ if (cancellable != NULL) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Cancellable initialization not supported");
+ return FALSE;
+ }
+
+ scheduler = UFO_SCHEDULER (initable);
+ priv = scheduler->priv;
+
+ if (priv->construct_error != NULL) {
+ if (error)
+ *error = g_error_copy (priv->construct_error);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+ufo_scheduler_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = ufo_scheduler_initable_init;
+}
+
static void
ufo_scheduler_class_init (UfoSchedulerClass *klass)
{
@@ -672,6 +991,13 @@ ufo_scheduler_class_init (UfoSchedulerClass *klass)
TRUE,
G_PARAM_READWRITE);
+ properties[PROP_ENABLE_TRACING] =
+ g_param_spec_boolean ("enable-tracing",
+ "Enable and write profile traces",
+ "Enable and write profile traces",
+ FALSE,
+ G_PARAM_READWRITE);
+
properties[PROP_REMOTES] =
g_param_spec_value_array ("remotes",
"List containing remote addresses",
@@ -698,7 +1024,10 @@ ufo_scheduler_init (UfoScheduler *scheduler)
scheduler->priv = priv = UFO_SCHEDULER_GET_PRIVATE (scheduler);
priv->expand = TRUE;
+ priv->trace = FALSE;
priv->config = NULL;
priv->resources = NULL;
priv->remotes = NULL;
+ priv->construct_error = NULL;
+ priv->mode = UFO_REMOTE_MODE_STREAM;
}
diff --git a/ufo/ufo-scheduler.h b/ufo/ufo-scheduler.h
index f3ae564..562d054 100644
--- a/ufo/ufo-scheduler.h
+++ b/ufo/ufo-scheduler.h
@@ -26,6 +26,7 @@
#include <ufo/ufo-config.h>
#include <ufo/ufo-task-graph.h>
+#include <ufo/ufo-remote-node.h>
G_BEGIN_DECLS
@@ -36,10 +37,16 @@ G_BEGIN_DECLS
#define UFO_IS_SCHEDULER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_SCHEDULER))
#define UFO_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_SCHEDULER, UfoSchedulerClass))
+#define UFO_SCHEDULER_ERROR ufo_scheduler_error_quark()
+
typedef struct _UfoScheduler UfoScheduler;
typedef struct _UfoSchedulerClass UfoSchedulerClass;
typedef struct _UfoSchedulerPrivate UfoSchedulerPrivate;
+typedef enum {
+ UFO_SCHEDULER_ERROR_SETUP
+} UfoSchedulerError;
+
/**
* UfoScheduler:
*
@@ -64,16 +71,18 @@ struct _UfoSchedulerClass {
GObjectClass parent_class;
};
-UfoScheduler* ufo_scheduler_new (UfoConfig *config,
- GList *remotes);
-void ufo_scheduler_run (UfoScheduler *scheduler,
- UfoTaskGraph *task_graph,
- GError** error);
-gpointer ufo_scheduler_get_context (UfoScheduler *scheduler);
-void ufo_scheduler_set_task_expansion
- (UfoScheduler *scheduler,
- gboolean split);
-GType ufo_scheduler_get_type (void);
+UfoScheduler* ufo_scheduler_new (UfoConfig *config,
+ GList *remotes);
+void ufo_scheduler_run (UfoScheduler *scheduler,
+ UfoTaskGraph *task_graph,
+ GError** error);
+gpointer ufo_scheduler_get_context (UfoScheduler *scheduler);
+void ufo_scheduler_set_task_expansion (UfoScheduler *scheduler,
+ gboolean split);
+void ufo_scheduler_set_remote_mode (UfoScheduler *scheduler,
+ UfoRemoteMode mode);
+GType ufo_scheduler_get_type (void);
+GQuark ufo_scheduler_error_quark (void);
G_END_DECLS
diff --git a/ufo/ufo-task-graph.c b/ufo/ufo-task-graph.c
index 3fc0c79..b76c78f 100644
--- a/ufo/ufo-task-graph.c
+++ b/ufo/ufo-task-graph.c
@@ -43,6 +43,8 @@ struct _UfoTaskGraphPrivate {
GHashTable *prop_sets;
GHashTable *json_nodes;
GList *remote_tasks;
+ guint index;
+ guint total;
};
typedef enum {
@@ -55,10 +57,16 @@ static void handle_json_prop_set (JsonObject *, const gchar *, JsonNode *, gp
static void handle_json_single_prop (JsonObject *, const gchar *, JsonNode *, gpointer user);
static void handle_json_task_edge (JsonArray *, guint, JsonNode *, gpointer);
static gboolean handle_json_task_node (JsonNode *, UfoTaskGraphPrivate *priv, GError **error);
-static void add_task_node_to_json_array (UfoNode *, JsonArray *);
+static void add_task_node_to_json_array (UfoTaskNode *, JsonArray *);
static JsonObject *json_object_from_ufo_node (UfoNode *node);
static JsonNode *get_json_representation (UfoTaskGraph *, GError **);
+/*
+ * ChangeLog:
+ * - 1.1: Add "index" and "total" keys to the root object
+ */
+static const gchar *JSON_API_VERSION = "1.1";
+
/**
* UfoTaskGraphError:
* @UFO_TASK_GRAPH_ERROR_JSON_KEY: Key is not found in JSON
@@ -94,6 +102,8 @@ read_json (UfoTaskGraph *graph,
GError **error)
{
JsonParser *json_parser;
+ JsonNode *json_root;
+ JsonObject *object;
GError *tmp_error = NULL;
json_parser = json_parser_new ();
@@ -122,7 +132,20 @@ read_json (UfoTaskGraph *graph,
graph->priv->manager = manager;
g_object_ref (manager);
- add_nodes_from_json (graph, json_parser_get_root (json_parser), error);
+ json_root = json_parser_get_root (json_parser);
+ object = json_node_get_object (json_root);
+
+ if (json_object_has_member (object, "index") &&
+ json_object_has_member (object, "total")) {
+ guint index = (guint) json_object_get_int_member (object, "index");
+ guint total = (guint) json_object_get_int_member (object, "total");
+ ufo_task_graph_set_partition (graph, index, total);
+ }
+ else {
+ g_warning ("JSON does not define `index' and `total' keys");
+ }
+
+ add_nodes_from_json (graph, json_root, error);
g_object_unref (json_parser);
}
@@ -212,14 +235,37 @@ get_json_representation (UfoTaskGraph *graph,
g_list_free (successors);
}
+ json_object_set_string_member (root_object, "version", JSON_API_VERSION);
json_object_set_array_member (root_object, "nodes", nodes);
json_object_set_array_member (root_object, "edges", edges);
+ json_object_set_int_member (root_object, "index", graph->priv->index);
+ json_object_set_int_member (root_object, "total", graph->priv->total);
+
json_node_set_object (root_node, root_object);
g_list_free (task_nodes);
return root_node;
}
+static JsonGenerator *
+task_graph_to_generator (UfoTaskGraph *graph,
+ GError **error)
+{
+ JsonNode *root_node;
+ JsonGenerator *generator;
+
+ root_node = get_json_representation (graph, error);
+
+ if (error != NULL && *error != NULL)
+ return NULL;
+
+ generator = json_generator_new ();
+ json_generator_set_root (generator, root_node);
+ json_node_free (root_node);
+
+ return generator;
+}
+
/**
* ufo_task_graph_save_to_json:
* @graph: A #UfoTaskGraph.
@@ -233,20 +279,31 @@ ufo_task_graph_save_to_json (UfoTaskGraph *graph,
const gchar *filename,
GError **error)
{
- JsonNode *root_node;
JsonGenerator *generator;
- root_node = get_json_representation (graph, error);
+ generator = task_graph_to_generator (graph, error);
- if (error != NULL && *error != NULL)
- return;
+ if (generator != NULL) {
+ json_generator_to_file (generator, filename, error);
+ g_object_unref (generator);
+ }
+}
- generator = json_generator_new ();
- json_generator_set_root (generator, root_node);
- json_generator_to_file (generator, filename, error);
+gchar *
+ufo_task_graph_get_json_data (UfoTaskGraph *graph,
+ GError **error)
+{
+ JsonGenerator *generator;
+ gchar *json = NULL;
- json_node_free (root_node);
- g_object_unref (generator);
+ generator = task_graph_to_generator (graph, error);
+
+ if (generator != NULL) {
+ json = json_generator_to_data (generator, NULL);
+ g_object_unref (generator);
+ }
+
+ return json;
}
static gboolean
@@ -260,7 +317,7 @@ build_remote_graph (UfoTaskGraph *remote_graph,
GList *first,
GList *last)
{
- UfoTaskNode *node;
+ UfoTaskNode *node = NULL;
UfoTaskNode *predecessor = NULL;
for (GList *it = g_list_next (first); it != last; it = g_list_next (it)) {
@@ -272,6 +329,7 @@ build_remote_graph (UfoTaskGraph *remote_graph,
predecessor = node;
}
+ g_assert (node != NULL);
return node;
}
@@ -284,18 +342,11 @@ create_remote_tasks (UfoTaskGraph *task_graph,
{
UfoTaskGraphPrivate *priv;
UfoTaskNode *task;
- JsonNode *root;
- JsonGenerator *generator;
gchar *json;
- gsize size;
-
- root = get_json_representation (remote_graph, NULL);
- generator = json_generator_new ();
- json_generator_set_root (generator, root);
- json = json_generator_to_data (generator, &size);
priv = task_graph->priv;
- ufo_remote_node_send_json (remote, json, size);
+ json = ufo_task_graph_get_json_data (remote_graph, NULL);
+ ufo_remote_node_send_json (remote, UFO_REMOTE_MODE_STREAM, json);
task = UFO_TASK_NODE (ufo_remote_task_new ());
priv->remote_tasks = g_list_append (priv->remote_tasks, task);
@@ -305,8 +356,6 @@ create_remote_tasks (UfoTaskGraph *task_graph,
ufo_task_graph_connect_nodes (task_graph, task, last);
g_free (json);
- json_node_free (root);
- g_object_unref (generator);
}
static void
@@ -407,6 +456,7 @@ find_longest_path (GList *paths)
* ufo_task_graph_expand:
* @task_graph: A #UfoTaskGraph
* @arch_graph: A #UfoArchGraph
+ * @expand_remote: %TRUE if remote nodes should be inserted
*
* Expands @task_graph in a way that most of the resources in @arch_graph can be
* occupied. In the simple pipeline case, the longest possible GPU paths are
@@ -414,7 +464,8 @@ find_longest_path (GList *paths)
*/
void
ufo_task_graph_expand (UfoTaskGraph *task_graph,
- UfoArchGraph *arch_graph)
+ UfoArchGraph *arch_graph,
+ gboolean expand_remote)
{
GList *paths;
GList *path;
@@ -428,16 +479,21 @@ ufo_task_graph_expand (UfoTaskGraph *task_graph,
path = find_longest_path (paths);
if (path != NULL) {
- GList *remotes;
guint n_gpus;
- guint n_remotes;
- remotes = ufo_arch_graph_get_remote_nodes (arch_graph);
- n_remotes = g_list_length (remotes);
+ if (expand_remote) {
+ GList *remotes;
+ guint n_remotes;
+
+ remotes = ufo_arch_graph_get_remote_nodes (arch_graph);
+ n_remotes = g_list_length (remotes);
- if (n_remotes > 0) {
- g_debug ("Expand for %i remote nodes", n_remotes);
- expand_remotes (task_graph, remotes, path);
+ if (n_remotes > 0) {
+ g_debug ("Expand for %i remote nodes", n_remotes);
+ expand_remotes (task_graph, remotes, path);
+ }
+
+ g_list_free (remotes);
}
n_gpus = ufo_arch_graph_get_num_gpus (arch_graph);
@@ -445,8 +501,6 @@ ufo_task_graph_expand (UfoTaskGraph *task_graph,
for (guint i = 1; i < n_gpus; i++)
ufo_graph_expand (UFO_GRAPH (task_graph), path);
-
- g_list_free (remotes);
}
g_list_foreach (paths, (GFunc) g_list_free, NULL);
@@ -493,7 +547,9 @@ map_proc_node (UfoGraph *graph,
for (GList *it = g_list_first (successors); it != NULL; it = g_list_next (it)) {
map_proc_node (graph, UFO_NODE (it->data), proc_index, gpu_nodes);
- proc_index = (proc_index + 1) % n_gpus;
+
+ if (!UFO_IS_REMOTE_TASK (UFO_NODE (it->data)))
+ proc_index = (proc_index + 1) % n_gpus;
}
g_list_free (successors);
@@ -560,6 +616,27 @@ ufo_task_graph_connect_nodes_full (UfoTaskGraph *graph,
ufo_graph_connect_nodes (UFO_GRAPH (graph), UFO_NODE (n1), UFO_NODE (n2), GINT_TO_POINTER (input));
}
+void
+ufo_task_graph_set_partition (UfoTaskGraph *graph,
+ guint index,
+ guint total)
+{
+ g_return_if_fail (UFO_IS_TASK_GRAPH (graph));
+ g_assert (index < total);
+ graph->priv->index = index;
+ graph->priv->total = total;
+}
+
+void
+ufo_task_graph_get_partition (UfoTaskGraph *graph,
+ guint *index,
+ guint *total)
+{
+ g_return_if_fail (UFO_IS_TASK_GRAPH (graph));
+ *index = graph->priv->index;
+ *total = graph->priv->total;
+}
+
static void
add_nodes_from_json (UfoTaskGraph *graph,
JsonNode *root,
@@ -601,7 +678,7 @@ handle_json_task_node (JsonNode *element,
UfoTaskGraphPrivate *priv,
GError **error)
{
- UfoNode *plugin;
+ UfoTaskNode *plugin;
JsonObject *object;
GError *tmp_error = NULL;
const gchar *name;
@@ -618,6 +695,7 @@ handle_json_task_node (JsonNode *element,
plugin_name = json_object_get_string_member (object, "plugin");
plugin = ufo_plugin_manager_get_task (priv->manager, plugin_name, &tmp_error);
+ ufo_task_node_set_plugin_name (plugin, plugin_name);
if (tmp_error != NULL) {
g_propagate_error (error, tmp_error);
@@ -711,6 +789,12 @@ handle_json_task_edge (JsonArray *array,
from_node = g_hash_table_lookup (priv->json_nodes, from_name);
to_node = g_hash_table_lookup (priv->json_nodes, to_name);
+ if (from_node == NULL)
+ g_error ("No filter `%s' defined", from_name);
+
+ if (to_node == NULL)
+ g_error ("No filter `%s' defined", to_name);
+
ufo_task_graph_connect_nodes_full (graph, from_node, to_node, to_port);
if (error != NULL)
@@ -739,25 +823,26 @@ handle_json_single_prop (JsonObject *object,
gpointer user)
{
GValue val = {0,};
- json_node_get_value (node, &val);
- g_object_set_property (G_OBJECT(user), name, &val);
+ if (!JSON_NODE_HOLDS_NULL (node)) {
+ json_node_get_value (node, &val);
+ g_object_set_property (G_OBJECT(user), name, &val);
+ }
}
static void
-add_task_node_to_json_array (UfoNode *node, JsonArray *array)
+add_task_node_to_json_array (UfoTaskNode *node, JsonArray *array)
{
JsonObject *node_object;
JsonNode *prop_node;
node_object = json_object_new ();
-
- json_object_set_string_member (node_object,
- "plugin",
- ufo_task_node_get_plugin_name (UFO_TASK_NODE (node)));
-
- json_object_set_string_member (node_object,
- "name",
- ufo_task_node_get_unique_name (UFO_TASK_NODE (node)));
+ const gchar *plugin_name = ufo_task_node_get_plugin_name (node);
+ g_assert (plugin_name != NULL);
+ json_object_set_string_member (node_object, "plugin", plugin_name);
+
+ const gchar *name = ufo_task_node_get_unique_name (node);
+ g_assert (name != NULL);
+ json_object_set_string_member (node_object, "name", name);
prop_node = json_gobject_serialize (G_OBJECT (node));
json_object_set_member (node_object, "properties", prop_node);
@@ -770,13 +855,11 @@ json_object_from_ufo_node (UfoNode *node)
JsonObject *object;
object = json_object_new ();
- json_object_set_string_member (object,
- "name",
- ufo_task_node_get_unique_name (UFO_TASK_NODE (node)));
+ const gchar *unique_name = ufo_task_node_get_unique_name (UFO_TASK_NODE (node));
+ json_object_set_string_member (object, "name", unique_name);
return object;
}
-
static void
ufo_task_graph_dispose (GObject *object)
{
@@ -839,8 +922,6 @@ ufo_task_graph_init (UfoTaskGraph *self)
priv->prop_sets = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) json_object_unref);
-
- /* Maybe we should define a specific task node type from which all tasks
- * must inherit */
- ufo_graph_register_node_type (UFO_GRAPH (self), UFO_TYPE_NODE);
+ priv->index = 0;
+ priv->total = 1;
}
diff --git a/ufo/ufo-task-graph.h b/ufo/ufo-task-graph.h
index 10b9c1a..75cb1b3 100644
--- a/ufo/ufo-task-graph.h
+++ b/ufo/ufo-task-graph.h
@@ -84,10 +84,13 @@ void ufo_task_graph_read_from_data (UfoTaskGraph *graph,
void ufo_task_graph_save_to_json (UfoTaskGraph *graph,
const gchar *filename,
GError **error);
+gchar *ufo_task_graph_get_json_data (UfoTaskGraph *graph,
+ GError **error);
void ufo_task_graph_map (UfoTaskGraph *task_graph,
UfoArchGraph *arch_graph);
void ufo_task_graph_expand (UfoTaskGraph *task_graph,
- UfoArchGraph *arch_graph);
+ UfoArchGraph *arch_graph,
+ gboolean expand_remote);
void ufo_task_graph_connect_nodes (UfoTaskGraph *graph,
UfoTaskNode *n1,
UfoTaskNode *n2);
@@ -96,6 +99,12 @@ void ufo_task_graph_connect_nodes_full (UfoTaskGraph *graph,
UfoTaskNode *n2,
guint input);
void ufo_task_graph_fuse (UfoTaskGraph *task_graph);
+void ufo_task_graph_set_partition (UfoTaskGraph *task_graph,
+ guint index,
+ guint total);
+void ufo_task_graph_get_partition (UfoTaskGraph *task_graph,
+ guint *index,
+ guint *total);
GType ufo_task_graph_get_type (void);
GQuark ufo_task_graph_error_quark (void);
diff --git a/ufo/ufo-task-iface.h b/ufo/ufo-task-iface.h
index 1199627..314a9e5 100644
--- a/ufo/ufo-task-iface.h
+++ b/ufo/ufo-task-iface.h
@@ -48,18 +48,27 @@ typedef enum {
/**
* UfoTaskMode:
- * @UFO_TASK_MODE_SINGLE: one-by-one processing
- * @UFO_TASK_MODE_REDUCE: receive fininite stream and generate a reduced stream
- * @UFO_TASK_MODE_GENERATE: do not receive any data but produce a stream.
+ * @UFO_TASK_MODE_PROCESSOR: one-by-one processing
+ * @UFO_TASK_MODE_GENERATOR: do not receive any data but produce a stream.
+ * @UFO_TASK_MODE_REDUCTOR: receive fininite stream and generate a reduced stream
*
* Task modes describe how a task operates considering the input data.
*/
typedef enum {
- UFO_TASK_MODE_SINGLE,
- UFO_TASK_MODE_REDUCE,
- UFO_TASK_MODE_GENERATE
+ UFO_TASK_MODE_PROCESSOR,
+ UFO_TASK_MODE_GENERATOR,
+ UFO_TASK_MODE_REDUCTOR,
} UfoTaskMode;
+typedef gboolean (*UfoTaskProcessFunc) (UfoTask *task,
+ UfoBuffer **inputs,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+
+typedef gboolean (*UfoTaskGenerateFunc) (UfoTask *task,
+ UfoBuffer *output,
+ UfoRequisition *requisition);
+
/**
* UfoInputParam:
* @n_dims: Number of dimensions
diff --git a/ufo/ufo-task-node.c b/ufo/ufo-task-node.c
index 6f60db6..23f1fa4 100644
--- a/ufo/ufo-task-node.c
+++ b/ufo/ufo-task-node.c
@@ -32,9 +32,12 @@ struct _UfoTaskNodePrivate {
UfoSendPattern pattern;
UfoNode *proc_node;
UfoGroup *out_group;
+ UfoProfiler *profiler;
GList *in_groups[16];
GList *current[16];
gint n_expected[16];
+ guint index;
+ guint total;
};
void
@@ -56,14 +59,14 @@ ufo_task_node_set_plugin_name (UfoTaskNode *task_node,
const gchar *
ufo_task_node_get_plugin_name (UfoTaskNode *task_node)
{
- g_return_val_if_fail (UFO_IS_TASK_NODE (task_node), NULL);
+ g_assert (UFO_IS_TASK_NODE (task_node));
return task_node->priv->plugin;
}
const gchar *
ufo_task_node_get_unique_name (UfoTaskNode *task_node)
{
- g_return_val_if_fail (UFO_IS_TASK_NODE (task_node), NULL);
+ g_assert (UFO_IS_TASK_NODE (task_node));
return task_node->priv->unique;
}
@@ -177,6 +180,34 @@ ufo_task_node_set_proc_node (UfoTaskNode *task_node,
task_node->priv->proc_node = proc_node;
}
+void
+ufo_task_node_set_profiler (UfoTaskNode *node,
+ UfoProfiler *profiler)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+
+ if (node->priv->profiler)
+ g_object_unref (node->priv->profiler);
+
+ g_object_ref (profiler);
+ node->priv->profiler = profiler;
+}
+
+/**
+ * ufo_task_node_get_profiler:
+ * @node: A #UfoTaskNode
+ *
+ * Get the associated profiler of @node.
+ *
+ * Return value: (transfer full): A #UfoProfiler object.
+ */
+UfoProfiler *
+ufo_task_node_get_profiler (UfoTaskNode *node)
+{
+ g_return_val_if_fail (UFO_IS_TASK_NODE (node), NULL);
+ return node->priv->profiler;
+}
+
/**
* ufo_task_node_get_proc_node:
* @node: A #UfoTaskNode
@@ -192,9 +223,59 @@ ufo_task_node_get_proc_node (UfoTaskNode *node)
return node->priv->proc_node;
}
+void
+ufo_task_node_set_partition (UfoTaskNode *node,
+ guint index,
+ guint total)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ g_assert (index < total);
+ node->priv->index = index;
+ node->priv->total = total;
+}
+
+void
+ufo_task_node_get_partition (UfoTaskNode *node,
+ guint *index,
+ guint *total)
+{
+ g_return_if_fail (UFO_IS_TASK_NODE (node));
+ *index = node->priv->index;
+ *total = node->priv->total;
+}
+
+static UfoNode *
+ufo_task_node_copy (UfoNode *node,
+ GError **error)
+{
+ UfoTaskNode *orig;
+ UfoTaskNode *copy;
+
+ copy = UFO_TASK_NODE (UFO_NODE_CLASS (ufo_task_node_parent_class)->copy (node, error));
+ orig = UFO_TASK_NODE (node);
+
+ copy->priv->pattern = orig->priv->pattern;
+
+ for (guint i = 0; i < 16; i++)
+ copy->priv->n_expected[i] = orig->priv->n_expected[i];
+
+ ufo_task_node_set_plugin_name (copy, orig->priv->plugin);
+
+ return UFO_NODE (copy);
+}
+
static void
ufo_task_node_dispose (GObject *object)
{
+ UfoTaskNodePrivate *priv;
+
+ priv = UFO_TASK_NODE_GET_PRIVATE (object);
+
+ if (priv->profiler) {
+ g_object_unref (priv->profiler);
+ priv->profiler = NULL;
+ }
+
G_OBJECT_CLASS (ufo_task_node_parent_class)->dispose (object);
}
@@ -214,11 +295,15 @@ static void
ufo_task_node_class_init (UfoTaskNodeClass *klass)
{
GObjectClass *oclass;
+ UfoNodeClass *nclass;
oclass = G_OBJECT_CLASS (klass);
oclass->dispose = ufo_task_node_dispose;
oclass->finalize = ufo_task_node_finalize;
+ nclass = UFO_NODE_CLASS (klass);
+ nclass->copy = ufo_task_node_copy;
+
g_type_class_add_private (klass, sizeof(UfoTaskNodePrivate));
}
@@ -231,6 +316,9 @@ ufo_task_node_init (UfoTaskNode *self)
self->priv->pattern = UFO_SEND_SCATTER;
self->priv->proc_node = NULL;
self->priv->out_group = NULL;
+ self->priv->index = 0;
+ self->priv->total = 1;
+ self->priv->profiler = ufo_profiler_new ();
for (guint i = 0; i < 16; i++) {
self->priv->in_groups[i] = NULL;
diff --git a/ufo/ufo-task-node.h b/ufo/ufo-task-node.h
index 2e6df01..68c8228 100644
--- a/ufo/ufo-task-node.h
+++ b/ufo/ufo-task-node.h
@@ -26,6 +26,7 @@
#include <ufo/ufo-node.h>
#include <ufo/ufo-group.h>
+#include <ufo/ufo-profiler.h>
G_BEGIN_DECLS
@@ -89,6 +90,15 @@ void ufo_task_node_switch_in_group (UfoTaskNode *node,
void ufo_task_node_set_proc_node (UfoTaskNode *task_node,
UfoNode *proc_node);
UfoNode *ufo_task_node_get_proc_node (UfoTaskNode *node);
+void ufo_task_node_set_partition (UfoTaskNode *node,
+ guint index,
+ guint total);
+void ufo_task_node_get_partition (UfoTaskNode *node,
+ guint *index,
+ guint *total);
+void ufo_task_node_set_profiler (UfoTaskNode *node,
+ UfoProfiler *profiler);
+UfoProfiler *ufo_task_node_get_profiler (UfoTaskNode *node);
GType ufo_task_node_get_type (void);
G_END_DECLS
diff --git a/ufo/ufo-zmq-messenger.c b/ufo/ufo-zmq-messenger.c
new file mode 100644
index 0000000..32ba32e
--- /dev/null
+++ b/ufo/ufo-zmq-messenger.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ufo/ufo-zmq-messenger.h>
+#include <zmq.h>
+#include <string.h>
+
+#include "zmq-shim.h"
+
+static void ufo_messenger_interface_init (UfoMessengerIface *iface);
+
+#define UFO_ZMQ_MESSENGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ZMQ_MESSENGER, UfoZmqMessengerPrivate))
+
+G_DEFINE_TYPE_WITH_CODE (UfoZmqMessenger, ufo_zmq_messenger, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (UFO_TYPE_MESSENGER,
+ ufo_messenger_interface_init))
+
+
+struct _UfoZmqMessengerPrivate {
+ gchar *remote_addr;
+ GMutex *mutex;
+ gpointer zmq_socket;
+ gpointer zmq_ctx;
+ UfoMessengerRole role;
+};
+
+/* C99 allows flexible length structs that we use to map
+* arbitrary frame lengths that are transferred via zmq.
+* Note: Sizes of datatypes should be fixed and equal on all plattforms
+* (i.e. don't use a gsize as it has different size on x86 & x86_64)
+*/
+typedef struct _DataFrame {
+ UfoMessageType type;
+ guint64 data_size;
+ // variable length data field
+ char data[];
+} DataFrame;
+
+UfoZmqMessenger *
+ufo_zmq_messenger_new (void)
+{
+ UfoZmqMessenger *msger;
+ msger = UFO_ZMQ_MESSENGER (g_object_new (UFO_TYPE_ZMQ_MESSENGER, NULL));
+
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+ priv->zmq_ctx = zmq_ctx_new ();
+
+ return msger;
+}
+
+static void
+validate_zmq_listen_address (gchar *addr)
+{
+ if (!g_str_has_prefix (addr, "tcp://"))
+ g_critical ("address didn't start with tcp:// scheme, which is required currently");
+
+ /* Pitfall: zmq will silently accept hostnames like tcp://localhost:5555
+ * but not bind to it as it treats it like an interface name (like eth0).
+ * We have to use IP addresses instead of DNS names.
+ */
+ gchar *host = g_strdup (&addr[6]);
+ if (!g_ascii_isdigit (host[0]) && host[0] != '*')
+ g_message ("treating address %s as interface device name. Use IP address if supplying a host was intended.", host);
+ g_free (host);
+}
+
+void
+ufo_zmq_messenger_connect (UfoMessenger *msger, gchar *addr, UfoMessengerRole role)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+ g_mutex_lock (priv->mutex);
+
+ priv->remote_addr = g_strdup (addr);
+ priv->role = role;
+
+ if (role == UFO_MESSENGER_CLIENT) {
+ priv->zmq_socket = zmq_socket (priv->zmq_ctx, ZMQ_REQ);
+
+ if (zmq_connect (priv->zmq_socket, priv->remote_addr) == 0) {
+ g_message ("Connected to `%s' via socket=%p",
+ priv->remote_addr,
+ priv->zmq_socket);
+ }
+ else {
+ g_warning ("Could not connect to `%s': %s",
+ addr,
+ zmq_strerror (errno));
+ }
+ } else if (role == UFO_MESSENGER_SERVER) {
+ validate_zmq_listen_address (priv->remote_addr);
+ priv->zmq_socket = zmq_socket (priv->zmq_ctx, ZMQ_REP);
+
+ gint err = zmq_bind (priv->zmq_socket, priv->remote_addr);
+ if (err < 0)
+ g_critical ("could not bind to address %s", priv->remote_addr);
+ }
+
+ g_mutex_unlock (priv->mutex);
+ return;
+}
+
+void
+ufo_zmq_messenger_disconnect (UfoMessenger *msger)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+
+ g_mutex_lock (priv->mutex);
+
+ if (priv->zmq_socket != NULL) {
+ zmq_close (priv->zmq_socket);
+ priv->zmq_socket = NULL;
+
+ // waits for outstanding messages to be flushed
+ zmq_term (priv->zmq_ctx);
+ g_free (priv->remote_addr);
+ }
+
+ g_mutex_unlock (priv->mutex);
+ return;
+}
+
+UfoMessage *
+ufo_zmq_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request_msg,
+ GError **error)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+
+ if (request_msg->type == UFO_MESSAGE_ACK && priv->role == UFO_MESSENGER_CLIENT)
+ g_critical ("Clients can't send ACK messages");
+
+ g_mutex_lock (priv->mutex);
+
+ UfoMessage *result = NULL;
+ zmq_msg_t request;
+
+ gsize frame_size = sizeof (DataFrame) + request_msg->data_size;
+ zmq_msg_init_size (&request, frame_size);
+ DataFrame *frame = (DataFrame *) zmq_msg_data (&request);
+
+ frame->data_size = request_msg->data_size;
+ frame->type = request_msg->type;
+ //TODO eliminate extra copying
+ memcpy (frame->data, request_msg->data, request_msg->data_size);
+
+ gint err = zmq_msg_send (&request, priv->zmq_socket, 0);
+ zmq_msg_close (&request);
+
+ if (err < 0) {
+ g_set_error (error, ufo_messenger_error_quark (), zmq_errno (),
+ "Error sending message via %s: %s",
+ priv->remote_addr, zmq_strerror (zmq_errno ()));
+ goto finalize;
+ }
+
+ /* if this is an ACK message, don't expect a response
+ * (send_blocking is then most likely being called by the server)
+ */
+ if (request_msg->type == UFO_MESSAGE_ACK) {
+ goto finalize;
+ }
+
+ /* we always need to receive as response as ZMQ
+ * requires REQ/REP/REQ/REP/... scheme
+ */
+ zmq_msg_t reply;
+ zmq_msg_init (&reply);
+
+ err = zmq_msg_recv (&reply, priv->zmq_socket, 0);
+ gint size = zmq_msg_size (&reply);
+ if (err < 0) {
+ g_set_error (error, ufo_messenger_error_quark (), zmq_errno(),
+ "Could not receive from %s: %s ", priv->remote_addr,
+ zmq_strerror (zmq_errno ()));
+ goto finalize;
+ }
+
+ DataFrame *resp_frame = (DataFrame *) zmq_msg_data (&reply);
+
+ guint64 expected_size = (guint32) (sizeof (DataFrame) + resp_frame->data_size);
+ if ((guint64) size != expected_size) {
+ g_set_error (error, ufo_messenger_error_quark(),
+ UFO_MESSENGER_SIZE_MISSMATCH,
+ "Received unexpected frame size: %d", size);
+ goto finalize;
+ }
+
+ UfoMessage *reply_msg = ufo_message_new (resp_frame->type, resp_frame->data_size);
+ memcpy (reply_msg->data, resp_frame->data, resp_frame->data_size);
+
+ zmq_msg_close (&reply);
+ result = reply_msg;
+ goto finalize;
+
+ finalize:
+ g_mutex_unlock (priv->mutex);
+ return result;
+
+}
+
+UfoMessage *
+ufo_zmq_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+ g_assert (priv->role == UFO_MESSENGER_SERVER);
+
+ g_mutex_lock (priv->mutex);
+
+ UfoMessage *result = NULL;
+ zmq_msg_t reply;
+ zmq_msg_init (&reply);
+ gint err = zmq_msg_recv (&reply, priv->zmq_socket, 0);
+ gint size = zmq_msg_size (&reply);
+
+ if (err < 0) {
+ zmq_msg_close (&reply);
+ g_set_error (error, ufo_messenger_error_quark(), zmq_errno(),
+ "Could not receive from %s: %s ", priv->remote_addr,
+ zmq_strerror (zmq_errno ()));
+ goto finalize;
+ }
+
+ DataFrame *frame = zmq_msg_data (&reply);
+
+ guint expected_size = (guint) (sizeof (DataFrame) + frame->data_size);
+ if ((guint)size != expected_size) {
+ g_set_error (error, ufo_messenger_error_quark(),
+ UFO_MESSENGER_SIZE_MISSMATCH,
+ "Received unexpected frame size: %d, should be: %d",
+ size, expected_size);
+ goto finalize;
+ }
+
+ UfoMessage *msg = ufo_message_new (frame->type, frame->data_size);
+ memcpy (msg->data, frame->data, frame->data_size);
+
+ zmq_msg_close (&reply);
+ result = msg;
+ goto finalize;
+
+ finalize:
+ g_mutex_unlock (priv->mutex);
+ return result;
+}
+
+static void
+ufo_messenger_interface_init (UfoMessengerIface *iface)
+{
+ iface->connect = ufo_zmq_messenger_connect;
+ iface->disconnect = ufo_zmq_messenger_disconnect;
+ iface->send_blocking = ufo_zmq_messenger_send_blocking;
+ iface->recv_blocking = ufo_zmq_messenger_recv_blocking;
+}
+
+
+static void
+ufo_zmq_messenger_dispose (GObject *object)
+{
+ ufo_zmq_messenger_disconnect (UFO_MESSENGER (object));
+}
+
+static void
+ufo_zmq_messenger_finalize (GObject *object)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (object);
+
+ if (priv->zmq_ctx != NULL) {
+ zmq_ctx_destroy (priv->zmq_ctx);
+ priv->zmq_ctx = NULL;
+ }
+
+ g_mutex_free (priv->mutex);
+}
+
+static void
+ufo_zmq_messenger_class_init (UfoZmqMessengerClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ oclass->dispose = ufo_zmq_messenger_dispose;
+ oclass->finalize = ufo_zmq_messenger_finalize;
+
+ g_type_class_add_private (klass, sizeof(UfoZmqMessengerPrivate));
+}
+
+static void
+ufo_zmq_messenger_init (UfoZmqMessenger *msger)
+{
+ UfoZmqMessengerPrivate *priv = UFO_ZMQ_MESSENGER_GET_PRIVATE (msger);
+ priv->zmq_socket = NULL;
+ priv->zmq_ctx = NULL;
+ priv->mutex = g_mutex_new ();
+}
diff --git a/ufo/ufo-zmq-messenger.h b/ufo/ufo-zmq-messenger.h
new file mode 100644
index 0000000..19462cb
--- /dev/null
+++ b/ufo/ufo-zmq-messenger.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
+ *
+ * This file is part of Ufo.
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UFO_ZMQ_MESSENGER_H
+#define __UFO_ZMQ_MESSENGER_H
+
+#include <ufo/ufo-remote-node.h>
+#include <ufo/ufo-messenger-iface.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_ZMQ_MESSENGER (ufo_zmq_messenger_get_type())
+#define UFO_ZMQ_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_ZMQ_MESSENGER, UfoZmqMessenger))
+#define UFO_IS_ZMQ_MESSENGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_ZMQ_MESSENGER))
+#define UFO_ZMQ_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_ZMQ_MESSENGER, UfoZmqMessengerClass))
+#define UFO_IS_ZMQ_MESSENGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_ZMQ_MESSENGER))
+#define UFO_ZMQ_MESSENGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_ZMQ_MESSENGER, UfoZmqMessengerClass))
+
+typedef struct _UfoZmqMessenger UfoZmqMessenger;
+typedef struct _UfoZmqMessengerClass UfoZmqMessengerClass;
+typedef struct _UfoZmqMessengerPrivate UfoZmqMessengerPrivate;
+
+struct _UfoZmqMessenger {
+ /*< private >*/
+ GObject parent_instance;
+
+ UfoZmqMessengerPrivate *priv;
+};
+
+struct _UfoZmqMessengerClass {
+ /*< private >*/
+ GObjectClass parent_class;
+};
+
+UfoZmqMessenger *ufo_zmq_messenger_new (void);
+GType ufo_zmq_messenger_get_type (void);
+
+void ufo_zmq_messenger_connect (UfoMessenger *msger,
+ gchar *addr,
+ UfoMessengerRole role);
+
+void ufo_zmq_messenger_disconnect (UfoMessenger *msg);
+
+UfoMessage *ufo_zmq_messenger_send_blocking (UfoMessenger *msger,
+ UfoMessage *request,
+ GError **error);
+
+UfoMessage *ufo_zmq_messenger_recv_blocking (UfoMessenger *msger,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/ufo/ufo.h b/ufo/ufo.h
index b9b3d8e..e9d8617 100644
--- a/ufo/ufo.h
+++ b/ufo/ufo.h
@@ -29,6 +29,7 @@
#include <ufo/ufo-cpu-node.h>
#include <ufo/ufo-cpu-task-iface.h>
#include <ufo/ufo-dummy-task.h>
+#include <ufo/ufo-daemon.h>
#include <ufo/ufo-enums.h>
#include <ufo/ufo-gpu-node.h>
#include <ufo/ufo-gpu-task-iface.h>
@@ -46,6 +47,8 @@
#include <ufo/ufo-task-graph.h>
#include <ufo/ufo-task-iface.h>
#include <ufo/ufo-task-node.h>
+#include <ufo/ufo-basic-ops.h>
+#include <ufo/ufo-messenger-iface.h>
#undef __UFO_H_INSIDE__
diff --git a/ufo/ufo.pc.in b/ufo/ufo.pc.in
index 732f672..bc5c186 100644
--- a/ufo/ufo.pc.in
+++ b/ufo/ufo.pc.in
@@ -1,9 +1,9 @@
-prefix=@UFO_PKG_PREFIX@
-exec_prefix=@UFO_PKG_EXEC_PREFIX@
-libdir=@UFO_PKG_LIBDIR@
-includedir=@UFO_PKG_INCLUDEDIR@
-girdir=@UFO_PKG_GIRDIR@
-typelibdir=@UFO_PKG_TYPELIBDIR@
+prefix=@UFO_PREFIX@
+exec_prefix=@UFO_EPREFIX@
+libdir=@UFO_LIBDIR@
+includedir=@UFO_INCLUDEDIR@
+girdir=@UFO_GIRDIR@
+typelibdir=@UFO_TYPELIBDIR@
Name: @TARNAME@
Description: @UFO_DESCRIPTION_SUMMARY@
diff --git a/ufo/zmq-shim.h b/ufo/zmq-shim.h
new file mode 100644
index 0000000..7c19973
--- /dev/null
+++ b/ufo/zmq-shim.h
@@ -0,0 +1,22 @@
+#include <zmq.h>
+
+#ifndef ZMQ_DONTWAIT
+# define ZMQ_DONTWAIT ZMQ_NOBLOCK
+#endif
+#ifndef ZMQ_RCVHWM
+# define ZMQ_RCVHWM ZMQ_HWM
+#endif
+#ifndef ZMQ_SNDHWM
+# define ZMQ_SNDHWM ZMQ_HWM
+#endif
+#if ZMQ_VERSION_MAJOR == 2
+# define more_t int64_t
+# define zmq_ctx_new() zmq_init (1)
+# define zmq_ctx_destroy(context) zmq_term (context)
+# define zmq_msg_send(msg,sock,opt) zmq_send (sock, msg, opt)
+# define zmq_msg_recv(msg,sock,opt) zmq_recv (sock, msg, opt)
+# define ZMQ_POLL_MSEC 1000 /* zmq_poll is usec */
+#elif ZMQ_VERSION_MAJOR == 3
+# define more_t int
+# define ZMQ_POLL_MSEC 1 /* zmq_poll is msec */
+#endif
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ufo-core.git
More information about the debian-science-commits
mailing list