[+] Initial commit
This commit is contained in:
Executable
+2909
File diff suppressed because it is too large
Load Diff
Executable
+251
@@ -0,0 +1,251 @@
|
||||
// Copyright 2018 Intel Corporation.
|
||||
//
|
||||
// This is the PlaidML base library interface, handling functionality common across the Vertex.AI libraries.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#ifdef VAI_DLL
|
||||
#define VAI_API __declspec(dllexport)
|
||||
#else
|
||||
#define VAI_API __declspec(dllimport)
|
||||
#endif
|
||||
#elif __GNUC__ >= 4
|
||||
#define VAI_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define VAI_API
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
// Error handling.
|
||||
//
|
||||
// In the Vertex.AI C APIs, functions that can fail return either a pointer or a
|
||||
// boolean; success is represented as a non-NULL or true value, and failure is
|
||||
// represented as a NULL or false value.
|
||||
//
|
||||
// When a call fails, the callee is responsible for recording additional
|
||||
// information in thread-local storage. This information can be retrieved by
|
||||
// calling vai_last_status(). Otherwise (if a call is successful), no
|
||||
// guarantees are made; the callee may clobber existing thread-local error
|
||||
// information, leaving it in an undefined state.
|
||||
//
|
||||
// Note that errors may occur asynchronously. Asynchronous errors are reported
|
||||
// to the various callback functions used to collect the results of
|
||||
// asynchronous, operations, again via a NULL or false value. In this case,
|
||||
// the last error can be retrieved from thread-local-storage within the
|
||||
// callback function.
|
||||
//
|
||||
// Failed calls always propagate errors, poisoning the state of any objects
|
||||
// being updated. Additionally, NULL inputs are valid for all calls, causing
|
||||
// them to fail (on the assumption that a NULL input indicates an earlier
|
||||
// out-of-memory condition). Callers may take advantage of this by performing
|
||||
// a sequence of calls without checking for errors, and then checking the last
|
||||
// dependent call for errors; this obscures the exact call that produced an
|
||||
// error, but in most cases the caller is more interested in the fact that the
|
||||
// overall computation failed, and less interested in exactly which call
|
||||
// failed.
|
||||
|
||||
// These are the various status codes the application may observe.
|
||||
// Note that additional status codes may be added in subsquent releases.
|
||||
//
|
||||
// The set of status codes attempts to provide enough information for software components to determine the appropriate
|
||||
// recovery action to take. For diagnostics, the human-readable string associated with the status is typically more
|
||||
// useful.
|
||||
typedef enum {
|
||||
// A status representing "No error".
|
||||
VAI_STATUS_OK = 0,
|
||||
|
||||
// Indicates that an asynchronous operations was cancelled.
|
||||
VAI_STATUS_CANCELLED = 1,
|
||||
|
||||
// A generic catch-all error, used when an error condition must be signalled but
|
||||
// there is no appropriate API-level status code.
|
||||
VAI_STATUS_UNKNOWN = 2,
|
||||
|
||||
// Indicates that at least one invalid argument was passed to a function.
|
||||
VAI_STATUS_INVALID_ARGUMENT = 3,
|
||||
|
||||
// The operation deadline was exceeded.
|
||||
VAI_STATUS_DEADLINE_EXCEEDED = 4,
|
||||
|
||||
// The requested object was not found.
|
||||
VAI_STATUS_NOT_FOUND = 5,
|
||||
|
||||
// The requested object already exists.
|
||||
VAI_STATUS_ALREADY_EXISTS = 6,
|
||||
|
||||
// The caller does not have permission to access a resource required by the operation.
|
||||
VAI_STATUS_PERMISSION_DENIED = 7,
|
||||
|
||||
// A resource required by the operation is exhausted. (For example, this is returned when the implementation is
|
||||
// unable to allocate sufficient memory.)
|
||||
VAI_STATUS_RESOURCE_EXHAUSTED = 8,
|
||||
|
||||
// A precondition required by the operation is unmet. (For example, this is returned when an object supplied to a
|
||||
// call is not in the correct state for the call to take place).
|
||||
VAI_STATUS_FAILED_PRECONDITION = 9,
|
||||
|
||||
// A transactional operation was aborted by the system. Generally, this is a transient condition.
|
||||
VAI_STATUS_ABORTED = 10,
|
||||
|
||||
// A call parameter is out of the range accepted by the implementation.
|
||||
VAI_STATUS_OUT_OF_RANGE = 11,
|
||||
|
||||
// The requested functionality is not implemented.
|
||||
VAI_STATUS_UNIMPLEMENTED = 12,
|
||||
|
||||
// An internal error occurred. Typically, this indicates that the implementation has detected that its internal state
|
||||
// is inconsistent.
|
||||
VAI_STATUS_INTERNAL = 13,
|
||||
|
||||
// A resource required by the operation (such as a hardware device) is unavailable for use.
|
||||
VAI_STATUS_UNAVAILABLE = 14,
|
||||
|
||||
// The system has lost data required by the operation, typically due to hardware failure.
|
||||
VAI_STATUS_DATA_LOSS = 15,
|
||||
|
||||
// The caller is unauthenticated, but authenticated access is required to access some resource.
|
||||
VAI_STATUS_UNAUTHENTICATED = 16,
|
||||
} vai_status;
|
||||
|
||||
// Returns the last status recorded in the current thread's thread-local storage,
|
||||
// or VAI_STATUS_OK if no status has been recorded.
|
||||
VAI_API vai_status vai_last_status();
|
||||
|
||||
// Resets the current thread's thread-local status storage to VAI_STATUS_OK.
|
||||
VAI_API void vai_clear_status();
|
||||
|
||||
// Returns a NUL-terminated UTF-8 message describing the status of the call
|
||||
// errors recorded by the current thread's thread-local storage. If no error has
|
||||
// been recorded, an empty string will be returned.
|
||||
//
|
||||
// The returned string will remain alive until vai_clear_error is called, another Vertex.AI
|
||||
// call is made, or until the current thread exits.
|
||||
//
|
||||
// The error string may be dependent on the locale installed when the error occurred.
|
||||
VAI_API const char* vai_last_status_str();
|
||||
|
||||
// Logger configuration.
|
||||
typedef enum {
|
||||
VAI_LOG_SEVERITY_TRACE = 2,
|
||||
VAI_LOG_SEVERITY_DEBUG = 4,
|
||||
VAI_LOG_SEVERITY_FATAL = 8,
|
||||
VAI_LOG_SEVERITY_ERROR = 16,
|
||||
VAI_LOG_SEVERITY_WARNING = 32,
|
||||
VAI_LOG_SEVERITY_VERBOSE = 64,
|
||||
VAI_LOG_SEVERITY_INFO = 128,
|
||||
} vai_log_severity;
|
||||
|
||||
// Sets the process-global logging callback.
|
||||
VAI_API void vai_set_logger(void (*logger)(void*, vai_log_severity, const char*), void* arg);
|
||||
|
||||
// Dynamic feature detection.
|
||||
//
|
||||
// Invoking this API with an unknown / unsupported feature ID will return NULL.
|
||||
// Invoking it with a supported feature ID will return a pointer to a static
|
||||
// feature-specific value.
|
||||
typedef enum {
|
||||
VAI_FEATURE_ID_RESERVED = 0,
|
||||
} vai_feature_id;
|
||||
|
||||
VAI_API void* vai_query_feature(vai_feature_id id);
|
||||
|
||||
// A Vertex.AI context provides a scope for Vertex.AI library operations. In
|
||||
// particular, it provides an asynchronous execution context, allowing callers
|
||||
// to correctly synchronize with asynchronous callbacks during shutdown.
|
||||
//
|
||||
// NULL semantically points to a valid, but cancelled, context.
|
||||
|
||||
#ifdef __cplusplus
|
||||
struct vai_ctx;
|
||||
#else
|
||||
typedef struct vai_ctx vai_ctx;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocate and returns a context, or returns NULL if the library
|
||||
// cannot allocate sufficient memory.
|
||||
VAI_API vai_ctx* vai_alloc_ctx();
|
||||
|
||||
// Frees a context. After this call, the context should not be used for
|
||||
// any subsequent calls. Freeing a NULL context is a no-op.
|
||||
//
|
||||
// Freeing a context will block until pending asynchronous operations are complete.
|
||||
VAI_API void vai_free_ctx(vai_ctx* ctx);
|
||||
|
||||
// Cancels outstanding asynchronous operations associated with the context
|
||||
// (ensuring that callbacks are completed before returning to the caller), and
|
||||
// causes future callbacks issued using the context to synchronously fail.
|
||||
//
|
||||
// Note that there is no call to go from "cancelled" back to "uncancelled".
|
||||
//
|
||||
// This does not block waiting for asynchronous operations to complete.
|
||||
VAI_API void vai_cancel_ctx(vai_ctx* ctx);
|
||||
|
||||
// Sets the context to log events according to the specified
|
||||
// configuration. For instance, to point the context's event log at
|
||||
// "eventlog.gz", use the JSON string:
|
||||
//
|
||||
// "@type": "type.vertex.ai/vertexai.eventing.file.proto.EventLog",
|
||||
// "filename": "eventlog.gz"
|
||||
//
|
||||
// If the context already has an associated eventlog, that eventlog
|
||||
// will be finalized and closed asynchronously, once all asynchronous
|
||||
// activity using that eventlog has completed.
|
||||
//
|
||||
// A NULL config sets the context to not use the event logging
|
||||
// subsystem for future calls.
|
||||
VAI_API bool vai_set_eventlog(vai_ctx* ctx, const char* config);
|
||||
|
||||
// Gets the current value of a performance counter based on the name.
|
||||
// If there is no performance counter with that name, returns -1.
|
||||
VAI_API int64_t vai_get_perf_counter(const char* name);
|
||||
|
||||
// Sets the current value of a performance counter based on the name.
|
||||
// If there is no performance counter with that name, no action is taken.
|
||||
VAI_API void vai_set_perf_counter(const char* name, int64_t value);
|
||||
|
||||
// A PlaidML datatype indicates the type of data stored within a buffer, as
|
||||
// observed by a program.
|
||||
typedef enum {
|
||||
PLAIDML_DATA_INVALID = 0,
|
||||
PLAIDML_DATA_BOOLEAN = 0x02,
|
||||
PLAIDML_DATA_INT8 = 0x10,
|
||||
PLAIDML_DATA_INT16 = 0x11,
|
||||
PLAIDML_DATA_INT32 = 0x12,
|
||||
PLAIDML_DATA_INT64 = 0x13,
|
||||
PLAIDML_DATA_INT128 = 0x14,
|
||||
PLAIDML_DATA_UINT8 = 0x20,
|
||||
PLAIDML_DATA_UINT16 = 0x21,
|
||||
PLAIDML_DATA_UINT32 = 0x22,
|
||||
PLAIDML_DATA_UINT64 = 0x23,
|
||||
PLAIDML_DATA_FLOAT16 = 0x31,
|
||||
PLAIDML_DATA_FLOAT32 = 0x32,
|
||||
PLAIDML_DATA_FLOAT64 = 0x33,
|
||||
PLAIDML_DATA_BFLOAT16 = 0x38,
|
||||
PLAIDML_DATA_PRNG = 0x40,
|
||||
} plaidml_datatype;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct default_delete<::vai_ctx> {
|
||||
void operator()(::vai_ctx* ctx) const noexcept { ::vai_free_ctx(ctx); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // __cplusplus
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright 2018 Intel Corporation.
|
||||
//
|
||||
// This is the Vertex.AI common C++ interface, which provides a higher level object
|
||||
// oriented wrapper on top of the Vertex.AI common C API.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "plaidml/base/base.h"
|
||||
|
||||
namespace vertexai {
|
||||
|
||||
class vai_exception : public std::runtime_error {
|
||||
public:
|
||||
vai_exception(vai_status status, const std::string& what) : std::runtime_error(what), status_(status) {}
|
||||
vai_status status() { return status_; }
|
||||
|
||||
template <typename T>
|
||||
static void check_and_throw(const T& good) {
|
||||
if (good) {
|
||||
return;
|
||||
}
|
||||
vai_status status = vai_last_status();
|
||||
std::string err = vai_last_status_str();
|
||||
vai_clear_status();
|
||||
throw vai_exception{status, err.c_str()};
|
||||
}
|
||||
|
||||
static std::exception_ptr current() noexcept {
|
||||
try {
|
||||
vai_status status = vai_last_status();
|
||||
std::string err = vai_last_status_str();
|
||||
vai_clear_status();
|
||||
return std::make_exception_ptr(vai_exception{status, err.c_str()});
|
||||
} catch (...) {
|
||||
return std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
vai_status status_;
|
||||
};
|
||||
|
||||
class ctx final {
|
||||
public:
|
||||
ctx() : ctx_{vai_alloc_ctx()} {
|
||||
if (!ctx_) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
explicit ctx(std::unique_ptr<vai_ctx> ctx) : ctx_{std::move(ctx)} {
|
||||
if (!ctx_) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
vai_ctx* get_ctx() const { return ctx_.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<vai_ctx> ctx_;
|
||||
};
|
||||
|
||||
} // namespace vertexai
|
||||
Executable
+826
@@ -0,0 +1,826 @@
|
||||
// Copyright 2018 Intel Corporation.
|
||||
//
|
||||
// This is the PlaidML C++ interface, which provides a higher level object
|
||||
// oriented wrapper on top of the PlaidML C API.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <half.hpp>
|
||||
|
||||
#include "plaidml/base/base_cpp.h"
|
||||
#include "plaidml/plaidml.h"
|
||||
|
||||
using half_float::half;
|
||||
|
||||
namespace vertexai {
|
||||
namespace plaidml {
|
||||
|
||||
// Import plaidml_datatype into the namespace
|
||||
typedef plaidml_datatype datatype;
|
||||
|
||||
// Make a map for c++ types to PlaidML types
|
||||
template <typename T>
|
||||
struct to_plaidml_datatype {};
|
||||
template <>
|
||||
struct to_plaidml_datatype<int8_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_INT8;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<int16_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_INT16;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<int32_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_INT32;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<int64_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_INT64;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<uint8_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_UINT8;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<uint16_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_UINT16;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<uint32_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_UINT32;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<uint64_t> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_UINT64;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<half> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_FLOAT16;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<float> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_FLOAT32;
|
||||
};
|
||||
template <>
|
||||
struct to_plaidml_datatype<double> {
|
||||
static constexpr plaidml_datatype value = PLAIDML_DATA_FLOAT64;
|
||||
};
|
||||
|
||||
// Predeclare classes
|
||||
class application;
|
||||
class base_shape;
|
||||
class base_tensor;
|
||||
class buffer;
|
||||
class compose;
|
||||
class device;
|
||||
class device_config;
|
||||
class function;
|
||||
class gradient;
|
||||
class invoker;
|
||||
template <typename T>
|
||||
class mapping;
|
||||
class placeholder;
|
||||
template <typename T>
|
||||
class shape;
|
||||
template <typename T>
|
||||
class tensor;
|
||||
class variable;
|
||||
|
||||
// A dimension containing both size + stride
|
||||
struct dimension {
|
||||
uint64_t size;
|
||||
int64_t stride;
|
||||
};
|
||||
|
||||
inline std::vector<device_config> _enumerate_devices(const std::shared_ptr<ctx>& ctx,
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum);
|
||||
inline std::vector<device_config> enumerate_devices(const std::shared_ptr<ctx>& ctx);
|
||||
inline std::vector<device_config> enumerate_devices(const std::shared_ptr<ctx>& ctx, const std::string& config);
|
||||
|
||||
class base_shape {
|
||||
friend class base_tensor;
|
||||
friend class invoker;
|
||||
|
||||
public:
|
||||
// Construct an empty shape with a specific data type
|
||||
explicit base_shape(const std::shared_ptr<ctx>& ctx, datatype dtype = PLAIDML_DATA_FLOAT32)
|
||||
: ctx_{ctx}, ptr_(plaidml_alloc_shape(ctx->get_ctx(), dtype), plaidml_free_shape) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
// Simple passthrough of C api for setup
|
||||
void add_dimension(size_t size, ptrdiff_t stride) {
|
||||
bool r = plaidml_add_dimension(ctx_->get_ctx(), ptr_.get(), size, stride);
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
void set_offset(size_t offset) {
|
||||
bool r = plaidml_set_shape_offset(ctx_->get_ctx(), ptr_.get(), offset);
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
|
||||
// Add a dimension
|
||||
void push_back(const dimension& d) { add_dimension(d.size, d.stride); }
|
||||
|
||||
// Add multiple dimensions
|
||||
template <typename L>
|
||||
void add_dimensions(const L& dims, ptrdiff_t initial_stride = 1) {
|
||||
ptrdiff_t stride = initial_stride;
|
||||
for (const auto& sz : dims) {
|
||||
stride *= sz;
|
||||
}
|
||||
for (const auto& sz : dims) {
|
||||
stride /= sz;
|
||||
add_dimension(sz, stride);
|
||||
}
|
||||
}
|
||||
|
||||
// Make a simple shape with packed strides, last dimension lowest stride
|
||||
base_shape(const std::shared_ptr<ctx>& ctx, datatype dtype, const std::initializer_list<size_t>& il,
|
||||
uint64_t offset = 0)
|
||||
: base_shape(ctx, dtype) {
|
||||
add_dimensions(il);
|
||||
}
|
||||
|
||||
// Get information about a shape
|
||||
datatype type() const { return plaidml_get_shape_type(ptr_.get()); }
|
||||
size_t dimensions() const { return plaidml_get_shape_dimension_count(ptr_.get()); }
|
||||
dimension operator[](size_t i) const { return dimension{size(i), stride(i)}; }
|
||||
uint64_t size(size_t i) const { return plaidml_get_shape_dimension_size(ptr_.get(), i); }
|
||||
int64_t stride(size_t i) const { return plaidml_get_shape_dimension_stride(ptr_.get(), i); }
|
||||
uint64_t buffer_size() const { return plaidml_get_shape_buffer_size(ptr_.get()); }
|
||||
|
||||
const std::shared_ptr<ctx>& get_context() const { return ctx_; }
|
||||
|
||||
protected:
|
||||
explicit base_shape(const std::shared_ptr<ctx>& ctx, const std::shared_ptr<plaidml_shape>& ptr)
|
||||
: ctx_{ctx}, ptr_{ptr} {}
|
||||
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_shape> ptr_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class shape : public base_shape {
|
||||
public:
|
||||
explicit shape(const std::shared_ptr<ctx>& ctx, datatype dt = to_plaidml_datatype<T>::value) : base_shape(ctx, dt) {}
|
||||
|
||||
explicit shape(const base_shape& base, datatype dt = to_plaidml_datatype<T>::value) : base_shape(base) {
|
||||
if (dt != base.type()) {
|
||||
throw vai_exception(VAI_STATUS_INVALID_ARGUMENT, "Mismatched shape");
|
||||
}
|
||||
}
|
||||
|
||||
shape(const std::shared_ptr<ctx>& ctx, const std::initializer_list<size_t>& il, uint64_t offset = 0)
|
||||
: base_shape(ctx, to_plaidml_datatype<T>::value, il, offset) {}
|
||||
};
|
||||
|
||||
class buffer {
|
||||
friend class device;
|
||||
friend class base_tensor;
|
||||
|
||||
public:
|
||||
buffer() {}
|
||||
|
||||
void copy_into(const std::shared_ptr<ctx>& ctx, void* dst) {
|
||||
plaidml_mapping* mapping = plaidml_map_buffer_discard(ctx->get_ctx(), ptr_.get());
|
||||
char* src = plaidml_get_mapping_base(ctx->get_ctx(), mapping);
|
||||
size_t size = plaidml_get_mapping_size(ctx->get_ctx(), mapping);
|
||||
memcpy(dst, src, size);
|
||||
plaidml_free_mapping(mapping);
|
||||
}
|
||||
|
||||
void copy_from(const std::shared_ptr<ctx>& ctx, const void* src) {
|
||||
plaidml_mapping* mapping = plaidml_map_buffer_current(ptr_.get(), nullptr, nullptr);
|
||||
char* dst = plaidml_get_mapping_base(ctx->get_ctx(), mapping);
|
||||
size_t size = plaidml_get_mapping_size(ctx->get_ctx(), mapping);
|
||||
memcpy(dst, src, size);
|
||||
plaidml_writeback_mapping(ctx->get_ctx(), mapping);
|
||||
plaidml_free_mapping(mapping);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_buffer> ptr_;
|
||||
explicit buffer(const std::shared_ptr<plaidml_buffer>& ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
class base_tensor {
|
||||
friend class variable;
|
||||
|
||||
public:
|
||||
base_tensor() {}
|
||||
base_tensor(const std::shared_ptr<ctx>& ctx, const buffer& buf, const base_shape& shape)
|
||||
: ctx_(ctx), buf_(buf.ptr_), shape_(shape.ptr_) {}
|
||||
|
||||
base_shape get_shape() { return base_shape(ctx_, shape_); }
|
||||
buffer get_buffer() { return buffer(buf_); }
|
||||
std::shared_ptr<ctx> get_context() { return ctx_; }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_buffer> buf_;
|
||||
std::shared_ptr<plaidml_shape> shape_;
|
||||
};
|
||||
// Indicates that the mapping will be used for reading the buffer. The mapping
|
||||
// will reflect the buffer's current contents. By default, the implementation
|
||||
// is free to either discard the mapping's contents or to write them back to
|
||||
// the underlying buffer.
|
||||
struct map_for_read_t {};
|
||||
static constexpr map_for_read_t map_for_read = {};
|
||||
|
||||
// Indicates that the mapping will be used for writing to the buffer. The
|
||||
// mapping may not reflect the buffer's current contents; the implementation is
|
||||
// free to construct the mapping with garbage data. By default, the mapping's
|
||||
// contents will be written back to the buffer when the mapping is deleted
|
||||
// unless the deletion is due to an exceptional condition.
|
||||
struct map_for_write_t {};
|
||||
static constexpr map_for_write_t map_for_write = {};
|
||||
|
||||
// Indicates that the mapping will be used for read-write access to the buffer.
|
||||
// The mapping will reflect the buffer's current contents. By default, the
|
||||
// mapping's contents will be written back to the buffer when the mapping is
|
||||
// deleted unless the deletion is due to an exceptional condition.
|
||||
struct map_for_update_t {};
|
||||
static constexpr map_for_update_t map_for_update = {};
|
||||
|
||||
enum class mapping_destructor_behavior {
|
||||
writeback_if_normal, // Write the contents on normal exits
|
||||
writeback_always, // Always write the contents (including on exceptions)
|
||||
discard // The implementation may discard the contents
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class mapping {
|
||||
public:
|
||||
// Construct an uninitialized mapping.
|
||||
mapping() {}
|
||||
|
||||
~mapping() { release(); }
|
||||
|
||||
// Disallow copy + default construction
|
||||
mapping(const mapping& rhs) = delete;
|
||||
mapping& operator=(const mapping& rhs) = delete;
|
||||
|
||||
// Allow moves
|
||||
mapping(mapping&& rhs)
|
||||
: ctx_{std::move(rhs.ctx_)},
|
||||
buf_{std::move(rhs.buf_)},
|
||||
sizes_{std::move(rhs.sizes_)},
|
||||
strides_{std::move(rhs.strides_)},
|
||||
map_{std::move(rhs.map_)},
|
||||
behavior_{std::move(rhs.behavior_)},
|
||||
mapped_{rhs.mapped_} {
|
||||
rhs.mapped_ = nullptr;
|
||||
}
|
||||
|
||||
mapping& operator=(mapping&& rhs) {
|
||||
release();
|
||||
ctx_ = std::move(rhs.ctx_);
|
||||
buf_ = std::move(rhs.buf_);
|
||||
sizes_ = std::move(rhs.sizes_);
|
||||
strides_ = std::move(rhs.strides_);
|
||||
map_ = std::move(rhs.map_);
|
||||
behavior_ = std::move(rhs.behavior_);
|
||||
mapped_ = rhs.mapped_;
|
||||
rhs.mapped_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Provide access to raw buffer
|
||||
T* raw() { return mapped_; }
|
||||
|
||||
// Explicitly set the destruction behavior.
|
||||
void set_destructor_behavior(mapping_destructor_behavior behavior) { behavior_ = behavior; }
|
||||
|
||||
// Compute location of index, also do bounds check. Note: this is a convience function;
|
||||
// it is not designed to be performant.
|
||||
T& at(const std::initializer_list<size_t>& idx) {
|
||||
if (idx.size() != sizes_.size()) {
|
||||
throw vai_exception(VAI_STATUS_OUT_OF_RANGE, "Invalid number of indexes in mapping access");
|
||||
}
|
||||
ptrdiff_t off = 0;
|
||||
for (size_t i = 0; i < sizes_.size(); i++) {
|
||||
if (*(idx.begin() + i) >= sizes_[i]) {
|
||||
throw vai_exception(VAI_STATUS_OUT_OF_RANGE, "Index out of bound on mapping access");
|
||||
}
|
||||
off += strides_[i] * *(idx.begin() + i);
|
||||
}
|
||||
return mapped_[off];
|
||||
}
|
||||
|
||||
// Syntactic sugar
|
||||
template <typename... Args>
|
||||
T& operator()(Args... args) {
|
||||
return at({args...});
|
||||
}
|
||||
|
||||
private:
|
||||
friend class tensor<T>;
|
||||
|
||||
mapping(std::shared_ptr<ctx> ctx, std::shared_ptr<plaidml_buffer> buf, const std::shared_ptr<plaidml_shape>& shape,
|
||||
std::unique_ptr<plaidml_mapping> map, mapping_destructor_behavior behavior)
|
||||
: ctx_{std::move(ctx)}, buf_{std::move(buf)}, map_{std::move(map)}, behavior_{behavior} {
|
||||
sizes_.resize(plaidml_get_shape_dimension_count(shape.get()));
|
||||
strides_.resize(plaidml_get_shape_dimension_count(shape.get()));
|
||||
for (size_t i = 0; i < strides_.size(); i++) {
|
||||
sizes_[i] = plaidml_get_shape_dimension_size(shape.get(), i);
|
||||
strides_[i] = plaidml_get_shape_dimension_stride(shape.get(), i);
|
||||
}
|
||||
mapped_ = reinterpret_cast<T*>(plaidml_get_mapping_base(ctx_->get_ctx(), map_.get()));
|
||||
vai_exception::check_and_throw(mapped_);
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (!mapped_) {
|
||||
return;
|
||||
}
|
||||
switch (behavior_) {
|
||||
case mapping_destructor_behavior::writeback_if_normal:
|
||||
#ifdef __cpp_lib_uncaught_exceptions
|
||||
if (std::uncaught_exceptions()) {
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (std::uncaught_exception()) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// fallthrough
|
||||
case mapping_destructor_behavior::writeback_always:
|
||||
plaidml_writeback_mapping(ctx_->get_ctx(), map_.get());
|
||||
break;
|
||||
case mapping_destructor_behavior::discard:
|
||||
break;
|
||||
}
|
||||
mapped_ = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_buffer> buf_;
|
||||
std::vector<size_t> sizes_;
|
||||
std::vector<ptrdiff_t> strides_;
|
||||
std::unique_ptr<plaidml_mapping> map_;
|
||||
mapping_destructor_behavior behavior_;
|
||||
T* mapped_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class tensor : public base_tensor {
|
||||
friend class mapping<T>;
|
||||
|
||||
public:
|
||||
tensor() {}
|
||||
tensor(const std::shared_ptr<ctx>& ctx, const buffer& buf, const shape<T>& shape) : base_tensor(ctx, buf, shape) {}
|
||||
|
||||
mapping<T> map(map_for_read_t) const {
|
||||
std::unique_ptr<plaidml_mapping> m{plaidml_map_buffer_current(buf_.get(), NULL, NULL)};
|
||||
return mapping<T>{ctx_, buf_, shape_, std::move(m), mapping_destructor_behavior::discard};
|
||||
}
|
||||
|
||||
// Asynchronously creates a readable mapping. The completion function should take a std::future<mapping<T>>,
|
||||
// which will be a ready future for the result of the mapping call.
|
||||
template <typename C>
|
||||
void map(map_for_read_t, vai_ctx* ctx, C&& on_complete) const {
|
||||
std::unique_ptr<completion> comp{
|
||||
static_cast<completion*>(new typed_completion<C>(ctx_, buf_, shape_, std::forward<C>(on_complete)))};
|
||||
plaidml_map_buffer_current(buf_.get(), &OnMapped, comp.release());
|
||||
}
|
||||
|
||||
mapping<T> map(map_for_write_t) {
|
||||
std::unique_ptr<plaidml_mapping> m{plaidml_map_buffer_discard(ctx_->get_ctx(), buf_.get())};
|
||||
return mapping<T>{ctx_, buf_, shape_, std::move(m), mapping_destructor_behavior::writeback_if_normal};
|
||||
}
|
||||
|
||||
mapping<T> map(map_for_update_t) {
|
||||
std::unique_ptr<plaidml_mapping> m{plaidml_map_buffer_current(buf_.get(), NULL, NULL)};
|
||||
return mapping<T>{ctx_, buf_, shape_, std::move(m), mapping_destructor_behavior::writeback_if_normal};
|
||||
}
|
||||
|
||||
private:
|
||||
class completion {
|
||||
public:
|
||||
virtual ~completion() {}
|
||||
virtual void complete(plaidml_mapping* result) = 0;
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
class typed_completion final : public completion {
|
||||
public:
|
||||
typed_completion(std::shared_ptr<ctx> ctx, std::shared_ptr<plaidml_buffer> buf,
|
||||
std::shared_ptr<plaidml_shape> shape, C&& on_complete)
|
||||
: ctx_{std::move(ctx)},
|
||||
buf_{std::move(buf)},
|
||||
shape_{std::move(shape)},
|
||||
on_complete_{std::forward<C>(on_complete)} {}
|
||||
|
||||
void complete(plaidml_mapping* result) final {
|
||||
if (!result) {
|
||||
prom_.set_exception(vai_exception::current());
|
||||
} else {
|
||||
std::unique_ptr<plaidml_mapping> mp{result};
|
||||
prom_.set_value(mapping<T>{ctx_, std::move(buf_), shape_, std::move(mp), mapping_destructor_behavior::discard});
|
||||
}
|
||||
on_complete_(prom_.get_future());
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_buffer> buf_;
|
||||
std::shared_ptr<plaidml_shape> shape_;
|
||||
std::promise<mapping<T>> prom_;
|
||||
C on_complete_;
|
||||
};
|
||||
|
||||
static void OnMapped(void* arg, plaidml_mapping* result) noexcept {
|
||||
std::unique_ptr<completion> comp{static_cast<completion*>(arg)};
|
||||
comp->complete(result);
|
||||
}
|
||||
};
|
||||
|
||||
class placeholder {
|
||||
friend class variable;
|
||||
friend class compose;
|
||||
|
||||
public:
|
||||
placeholder() {}
|
||||
explicit placeholder(size_t ndims) : ptr_(plaidml_alloc_placeholder(ndims), plaidml_free_var) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_var> ptr_;
|
||||
};
|
||||
|
||||
class variable {
|
||||
friend class application;
|
||||
friend class compose;
|
||||
friend class function;
|
||||
friend class gradient;
|
||||
friend class invoker;
|
||||
|
||||
public:
|
||||
variable() {}
|
||||
variable(const int64_t& val) : ptr_(plaidml_alloc_int64(val), plaidml_free_var) { // NOLINT(runtime/explicit)
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
variable(const double& val) : ptr_(plaidml_alloc_real(val), plaidml_free_var) { // NOLINT(runtime/explicit)
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
variable(const placeholder& val) : ptr_(val.ptr_) {} // NOLINT(runtime/explicit)
|
||||
variable(const base_tensor& val) // NOLINT(runtime/explicit)
|
||||
: ptr_(plaidml_alloc_tensor(val.ctx_->get_ctx(), val.buf_.get(), val.shape_.get()), plaidml_free_var) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_var> ptr_;
|
||||
};
|
||||
|
||||
class application {
|
||||
friend class function;
|
||||
friend class compose;
|
||||
|
||||
public:
|
||||
application() {}
|
||||
|
||||
operator variable() {
|
||||
if (plaidml_get_function_output_count(func_.get()) != 1) {
|
||||
throw std::runtime_error("Function application with non-unique return used in variable context");
|
||||
}
|
||||
return get_output(0);
|
||||
}
|
||||
|
||||
variable get_output(size_t i) {
|
||||
if (i >= plaidml_get_function_output_count(func_.get())) {
|
||||
throw std::runtime_error("Attempting to get an invalid output index");
|
||||
}
|
||||
std::string oname = plaidml_get_function_output(func_.get(), i);
|
||||
return get_output(oname);
|
||||
}
|
||||
|
||||
variable get_output(const std::string& name) {
|
||||
variable r;
|
||||
std::shared_ptr<plaidml_var> out(plaidml_apply_alloc_output(ptr_.get(), name.c_str()), plaidml_free_var);
|
||||
vai_exception::check_and_throw(out);
|
||||
r.ptr_ = out;
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_function> func_;
|
||||
std::shared_ptr<plaidml_applier> ptr_;
|
||||
application(const std::shared_ptr<plaidml_function> func, const std::shared_ptr<plaidml_applier>& ptr)
|
||||
: func_(func), ptr_(ptr) {}
|
||||
};
|
||||
|
||||
class function {
|
||||
friend class compose;
|
||||
friend class invoker;
|
||||
|
||||
public:
|
||||
typedef std::vector<std::pair<std::string, variable>> parameters_t;
|
||||
typedef std::vector<variable> positional_t;
|
||||
|
||||
// Invalid function
|
||||
function() {}
|
||||
|
||||
// Make a function from code
|
||||
explicit function(const std::string& str, const std::string& id = "")
|
||||
: ptr_(plaidml_build_coded_function(str.c_str(), id.c_str()), plaidml_free_function) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
// Load and save function
|
||||
inline void load(const std::shared_ptr<ctx>& ctx, const device& dev,
|
||||
const std::string& file); // Later, after dev is defined
|
||||
void save(const std::string& file) {
|
||||
vai_exception::check_and_throw(plaidml_save_function(ptr_.get(), file.c_str()));
|
||||
}
|
||||
|
||||
// Get information
|
||||
size_t num_inputs() { return plaidml_get_function_input_count(ptr_.get()); }
|
||||
size_t num_outputs() { return plaidml_get_function_output_count(ptr_.get()); }
|
||||
std::string input_name(size_t i) {
|
||||
const char* name = plaidml_get_function_input(ptr_.get(), i);
|
||||
return (name == NULL ? "" : name);
|
||||
}
|
||||
std::string output_name(size_t i) {
|
||||
const char* name = plaidml_get_function_output(ptr_.get(), i);
|
||||
return (name == NULL ? "" : name);
|
||||
}
|
||||
|
||||
// Apply a function to values, produce new values, named parameters
|
||||
application apply(const parameters_t& inputs, const std::vector<application> prev = {}) {
|
||||
std::shared_ptr<plaidml_applier> app(plaidml_alloc_applier(ptr_.get()), plaidml_free_applier);
|
||||
vai_exception::check_and_throw(app);
|
||||
for (const auto& papp : prev) {
|
||||
bool r = plaidml_apply_add_dependency(app.get(), papp.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
for (const auto& arg : inputs) {
|
||||
bool r = plaidml_apply_add_input(app.get(), arg.first.c_str(), arg.second.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
return application(ptr_, app);
|
||||
}
|
||||
|
||||
application apply(const positional_t& inputs, const std::vector<application> prev = {}) {
|
||||
if (inputs.size() != num_inputs()) {
|
||||
throw std::runtime_error("Mismatched number of input in application: " + std::to_string(inputs.size()) + " vs " +
|
||||
std::to_string(num_inputs()));
|
||||
}
|
||||
std::shared_ptr<plaidml_applier> app(plaidml_alloc_applier(ptr_.get()), plaidml_free_applier);
|
||||
vai_exception::check_and_throw(app);
|
||||
for (const auto& papp : prev) {
|
||||
bool r = plaidml_apply_add_dependency(app.get(), papp.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
for (size_t idx = 0; idx < inputs.size(); ++idx) {
|
||||
bool r = plaidml_apply_add_input(app.get(), input_name(idx).c_str(), inputs[idx].ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
}
|
||||
return application(ptr_, app);
|
||||
}
|
||||
|
||||
// Operator() for ease of use in apply
|
||||
template <typename... Params>
|
||||
application operator()(Params... params) {
|
||||
return apply(std::vector<variable>{params...});
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_function> ptr_;
|
||||
explicit function(const std::shared_ptr<plaidml_function>& ptr) : ptr_(ptr) {}
|
||||
};
|
||||
|
||||
class compose {
|
||||
public:
|
||||
explicit compose(const std::string name = "") : ptr_(plaidml_alloc_composer(), plaidml_free_composer) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
compose& input(const std::string& name, const placeholder& p) {
|
||||
bool r = plaidml_add_composer_input(ptr_.get(), name.c_str(), p.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
compose& output(const std::string& name, const variable& p) {
|
||||
bool r = plaidml_add_composer_output(ptr_.get(), name.c_str(), p.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
compose& dependency(const application& prev) {
|
||||
bool r = plaidml_add_composer_dependency(ptr_.get(), prev.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
compose& update(const base_tensor& lhs, const variable& rhs) {
|
||||
variable tvar = lhs;
|
||||
bool r = plaidml_add_composer_update(ptr_.get(), tvar.ptr_.get(), rhs.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator function() {
|
||||
std::shared_ptr<plaidml_function> func(plaidml_build_composed_function(ptr_.get()), plaidml_free_function);
|
||||
vai_exception::check_and_throw(func);
|
||||
return function(func);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_composer> ptr_;
|
||||
};
|
||||
|
||||
class invoker {
|
||||
public:
|
||||
invoker() {}
|
||||
invoker(const invoker&) = delete;
|
||||
invoker(invoker&&) = default;
|
||||
invoker& operator=(const invoker&) = delete;
|
||||
invoker& operator=(invoker&&) = default;
|
||||
|
||||
invoker(const std::shared_ptr<ctx>& ctx, const function& func)
|
||||
: ctx_{ctx}, invoker_{plaidml_alloc_invoker(ctx_->get_ctx(), func.ptr_.get())} {
|
||||
vai_exception::check_and_throw(invoker_);
|
||||
}
|
||||
|
||||
invoker& set_input(const std::string& name, const variable& var) {
|
||||
auto r = plaidml_set_invoker_input(invoker_.get(), name.c_str(), var.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
invoker& set_output(const std::string& name, const variable& var) {
|
||||
auto r = plaidml_set_invoker_output(invoker_.get(), name.c_str(), var.ptr_.get());
|
||||
vai_exception::check_and_throw(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_shape output_shape(const std::string& name) {
|
||||
std::shared_ptr<plaidml_shape> shp{plaidml_alloc_invoker_output_shape(invoker_.get(), name.c_str()),
|
||||
plaidml_free_shape};
|
||||
vai_exception::check_and_throw(shp);
|
||||
return base_shape{ctx_, std::move(shp)};
|
||||
}
|
||||
|
||||
void save(const std::string& file, plaidml_file_format format) {
|
||||
vai_exception::check_and_throw(plaidml_save_invoker(invoker_.get(), file.c_str(), format));
|
||||
}
|
||||
|
||||
void set_const() { vai_exception::check_and_throw(plaidml_set_invoker_const(invoker_.get())); }
|
||||
|
||||
std::unique_ptr<plaidml_invocation> invoke() {
|
||||
std::unique_ptr<plaidml_invocation> invocation{plaidml_schedule_invocation(ctx_->get_ctx(), invoker_.get())};
|
||||
vai_exception::check_and_throw(invocation);
|
||||
return invocation;
|
||||
}
|
||||
|
||||
std::unique_ptr<plaidml_invocation> invoke(const std::shared_ptr<ctx>& ctx) {
|
||||
std::unique_ptr<plaidml_invocation> invocation{plaidml_schedule_invocation(ctx->get_ctx(), invoker_.get())};
|
||||
vai_exception::check_and_throw(invocation);
|
||||
return invocation;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::unique_ptr<plaidml_invoker> invoker_;
|
||||
};
|
||||
|
||||
// TODO: Fix this!
|
||||
class gradient {
|
||||
public:
|
||||
explicit gradient(const variable& var) : ptr_(plaidml_alloc_gradient(var.ptr_.get()), plaidml_free_gradient) {
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
variable operator()(const variable& v) {
|
||||
variable r;
|
||||
plaidml_var* var = plaidml_compute_grad_wrt(ptr_.get(), v.ptr_.get());
|
||||
vai_exception::check_and_throw(var);
|
||||
r.ptr_ = std::shared_ptr<plaidml_var>(var, plaidml_free_var);
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<plaidml_gradient> ptr_;
|
||||
};
|
||||
|
||||
class device {
|
||||
friend class function;
|
||||
friend class device_config;
|
||||
|
||||
public:
|
||||
device() = default;
|
||||
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
buffer allocate(uint64_t size) const {
|
||||
buffer r;
|
||||
|
||||
r.ptr_ =
|
||||
std::shared_ptr<plaidml_buffer>(plaidml_alloc_buffer(ctx_->get_ctx(), ptr_.get(), size), plaidml_free_buffer);
|
||||
vai_exception::check_and_throw(r.ptr_);
|
||||
return r;
|
||||
}
|
||||
|
||||
base_tensor allocate(const base_shape& s) const { return base_tensor(s.get_context(), allocate(s.buffer_size()), s); }
|
||||
|
||||
template <class T>
|
||||
tensor<T> allocate(const shape<T>& s) const {
|
||||
return tensor<T>(s.get_context(), allocate(s.buffer_size()), s);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit device(const std::shared_ptr<ctx>& ctx, plaidml_device* raw) : ctx_{ctx}, ptr_(raw, plaidml_close_device) {}
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_device> ptr_;
|
||||
const std::shared_ptr<ctx>& get_context() const { return ctx_; }
|
||||
};
|
||||
|
||||
class device_config {
|
||||
friend std::vector<device_config> _enumerate_devices(const std::shared_ptr<ctx>& ctx,
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum);
|
||||
|
||||
public:
|
||||
// Get any string based property
|
||||
std::string get_string_prop(plaidml_device_property prop) const {
|
||||
size_t out_size;
|
||||
bool r = plaidml_query_devconf(ctx_->get_ctx(), config_, prop, NULL, 0, &out_size);
|
||||
vai_exception::check_and_throw(r);
|
||||
std::string str(out_size, '\0');
|
||||
r = plaidml_query_devconf(ctx_->get_ctx(), config_, prop, &str[0], str.size(), NULL);
|
||||
str.pop_back();
|
||||
vai_exception::check_and_throw(r);
|
||||
return str;
|
||||
}
|
||||
|
||||
// Convenience functions for current properties
|
||||
std::string id() const { return get_string_prop(PLAIDML_DEVICE_ID); }
|
||||
std::string config() const { return get_string_prop(PLAIDML_DEVICE_CONFIG); }
|
||||
std::string description() const { return get_string_prop(PLAIDML_DEVICE_DESCRIPTION); }
|
||||
std::string details() const { return get_string_prop(PLAIDML_DEVICE_DETAILS); }
|
||||
|
||||
// Open the device
|
||||
device open() const {
|
||||
device dev(ctx_, plaidml_open_device(ctx_->get_ctx(), config_));
|
||||
vai_exception::check_and_throw(dev.ptr_);
|
||||
return dev;
|
||||
}
|
||||
|
||||
private:
|
||||
device_config(const std::shared_ptr<ctx>& ctx, const std::shared_ptr<plaidml_device_enumerator>& dev_enum,
|
||||
plaidml_devconf* config)
|
||||
: ctx_(ctx), dev_enum_(dev_enum), config_(config) {}
|
||||
|
||||
std::shared_ptr<ctx> ctx_;
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum_;
|
||||
plaidml_devconf* config_;
|
||||
};
|
||||
|
||||
std::vector<device_config> _enumerate_devices(const std::shared_ptr<ctx>& ctx,
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum) {
|
||||
std::vector<device_config> out;
|
||||
size_t i = 0;
|
||||
while (true) {
|
||||
plaidml_devconf* conf = plaidml_get_devconf(ctx->get_ctx(), dev_enum.get(), i);
|
||||
if (conf == NULL) break;
|
||||
i++;
|
||||
out.push_back(device_config(ctx, dev_enum, conf));
|
||||
}
|
||||
vai_clear_status(); // Since we always walk off the list, clear errors
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<device_config> enumerate_devices(const std::shared_ptr<ctx>& ctx) {
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum(plaidml_alloc_device_enumerator(ctx->get_ctx(), NULL, NULL),
|
||||
plaidml_free_device_enumerator);
|
||||
vai_exception::check_and_throw(dev_enum);
|
||||
return _enumerate_devices(ctx, dev_enum);
|
||||
}
|
||||
|
||||
std::vector<device_config> enumerate_devices(const std::shared_ptr<ctx>& ctx, const std::string& config) {
|
||||
std::vector<device_config> out;
|
||||
std::shared_ptr<plaidml_device_enumerator> dev_enum(
|
||||
plaidml_alloc_device_enumerator_with_config(ctx->get_ctx(), config.c_str(), NULL, NULL),
|
||||
plaidml_free_device_enumerator);
|
||||
vai_exception::check_and_throw(dev_enum);
|
||||
return _enumerate_devices(ctx, dev_enum);
|
||||
}
|
||||
|
||||
// Actually needs definitions of both classes
|
||||
void function::load(const std::shared_ptr<ctx>& ctx, const device& dev, const std::string& file) {
|
||||
ptr_ = std::shared_ptr<plaidml_function>(plaidml_load_function(ctx->get_ctx(), dev.ptr_.get(), file.c_str()),
|
||||
plaidml_free_function);
|
||||
vai_exception::check_and_throw(ptr_);
|
||||
}
|
||||
|
||||
} // namespace plaidml
|
||||
} // namespace vertexai
|
||||
Executable
+637
@@ -0,0 +1,637 @@
|
||||
// Copyright 2018 Intel Corporation.
|
||||
//
|
||||
// This is the PlaidML library interface, used to construct and manipulate
|
||||
// programs defined as a sequence of operations over tensors.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "plaidml/base/base.h"
|
||||
|
||||
#define PLAIDML_API VAI_API
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// PlaidML devconf objects represent device configurations. Devconf objects are
|
||||
// contained by PlaidML device enumerators, examined and potentially modified by
|
||||
// PlaidML library consumers, and then used to open PlaidML devices for compute
|
||||
// access.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_devconf;
|
||||
#else
|
||||
typedef struct plaidml_devconf plaidml_devconf;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Platform configuration properties. This set may be extended in the future.
|
||||
typedef enum {
|
||||
// Platform names are NUL-terminated strings.
|
||||
PLAIDML_DEVICE_ID = 1,
|
||||
|
||||
// Platform configs are NUL-terminated prototxt.
|
||||
PLAIDML_DEVICE_CONFIG = 2,
|
||||
|
||||
// Platform descriptions are NUL-terminated prototxt.
|
||||
PLAIDML_DEVICE_DESCRIPTION = 3,
|
||||
|
||||
// Platform descriptions are NUL-terminated prototxt.
|
||||
PLAIDML_DEVICE_DETAILS = 4
|
||||
} plaidml_device_property;
|
||||
|
||||
// Returns the version of plaidml
|
||||
PLAIDML_API const char* plaidml_get_version();
|
||||
|
||||
// Queries the supplied device configuration property.
|
||||
//
|
||||
// The supplied output buffer pointer should point to a property-specific value
|
||||
// to be filled in with the requested information; the output size is used for
|
||||
// property versioning and buffer overflow protection. Fields in the output
|
||||
// buffer not supported by the property implementation will be zero-filled
|
||||
// (i.e. zero is the default value for all properties, including unsupported
|
||||
// properties).
|
||||
//
|
||||
// The value pointed to by output_buffer_size_required, if provided, will be
|
||||
// filled in with the size required for the output buffer. This is most useful
|
||||
// with queries that return string values or arrays of values; a common pattern
|
||||
// is to make a call with a NULL output buffer and zero size, allocate a buffer
|
||||
// of the indicated output size required, and then to re-issue the query.
|
||||
PLAIDML_API bool plaidml_query_devconf(vai_ctx* ctx, plaidml_devconf* devconf, plaidml_device_property property,
|
||||
void* output_buffer, size_t output_buffer_size,
|
||||
size_t* output_buffer_size_required);
|
||||
|
||||
// PlaidML devices are used to supply resources that might be backed by a
|
||||
// variety of hardware.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_device;
|
||||
#else
|
||||
typedef struct plaidml_device plaidml_device;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Opens a device, using the supplied device configuration. A NULL
|
||||
// configuration is permitted; this will use the system default PlaidML compute
|
||||
// device.
|
||||
PLAIDML_API plaidml_device* plaidml_open_device(vai_ctx* ctx, plaidml_devconf* devconf);
|
||||
|
||||
// Closes a device. After this call, the device should not be used for any
|
||||
// subsequent calls. The device may share resources with other objects (such
|
||||
// as buffers and functions); those resources will only be released when they
|
||||
// are no longer needed by those other objects. Closing a NULL device is a
|
||||
// no-op.
|
||||
PLAIDML_API void plaidml_close_device(plaidml_device* device);
|
||||
|
||||
// PlaidML device enumerators offer access to sets of compute devices. Enumerators may
|
||||
// supply devices that are in-process, machine-local, or cross-network, depending on
|
||||
// the deployment configuration.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_device_enumerator;
|
||||
#else
|
||||
typedef struct plaidml_device_enumerator plaidml_device_enumerator;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocates a device enumerator and initializes it using automatic configuration.
|
||||
//
|
||||
// If the supplied callback is NULL, the call will block until the enumerator
|
||||
// is fully initialized, and then will return a pointer to the enumerator
|
||||
// (unless an error occurs).
|
||||
//
|
||||
// If the supplied callback is non-NULL, the call will immediately return NULL,
|
||||
// and will arrange for the callback to be invoked with the enumerator once the
|
||||
// enumerator becomes available (calling it with a NULL enumerator on error). The
|
||||
// library guarantees to invoke the callback exactly once.
|
||||
//
|
||||
// If the library returns an enumerator, there will be at least one
|
||||
// configured device available; otherwise, the call will fail with
|
||||
// VAI_STATUS_NOT_FOUND.
|
||||
//
|
||||
// The library may invoke the callback synchronously if the enumerator is
|
||||
// immediately available or in error conditions.
|
||||
PLAIDML_API plaidml_device_enumerator* plaidml_alloc_device_enumerator(
|
||||
vai_ctx* ctx, void (*callback)(void* arg, plaidml_device_enumerator* enumerator), void* arg);
|
||||
|
||||
// Allocates a device enumerator and initializes it using the supplied
|
||||
// configuration. Otherwise identical to the version that uses system
|
||||
// config.
|
||||
PLAIDML_API plaidml_device_enumerator* plaidml_alloc_device_enumerator_with_config(
|
||||
vai_ctx* ctx, const char* configuration, void (*callback)(void* arg, plaidml_device_enumerator* enumerator),
|
||||
void* arg);
|
||||
|
||||
// Frees a device enumerator. After this call, the enumerator should not be
|
||||
// used for any subsequent calls. The enumerator may share resources with
|
||||
// other objects (such as devices, buffers, and functions); those resources
|
||||
// will only be released when they are no longer needed by those other objects.
|
||||
// Freeing a NULL enumerator is a no-op.
|
||||
PLAIDML_API void plaidml_free_device_enumerator(plaidml_device_enumerator* enumerator);
|
||||
|
||||
// Gets the configuration file that was used to initialize devices.
|
||||
PLAIDML_API const char* plaidml_get_enumerator_config_source(plaidml_device_enumerator* enumerator);
|
||||
|
||||
// Gets the number of device valid or invalid configurations available.
|
||||
PLAIDML_API size_t plaidml_get_devconf_count(vai_ctx* ctx, plaidml_device_enumerator* enumerator, bool valid_devices);
|
||||
|
||||
// Gets one device configuration from a device enumerator. The lifetime of the
|
||||
// device configuration is bounded by the device enumerator; there's no need to
|
||||
// separately free the configuration. If the requested configuration index is
|
||||
// out of range, or if the enumerator is NULL, this call will return NULL.
|
||||
PLAIDML_API plaidml_devconf* plaidml_get_devconf(vai_ctx* ctx, plaidml_device_enumerator* enumerator, size_t index);
|
||||
|
||||
// Same as above, only returns invalid devices
|
||||
PLAIDML_API plaidml_devconf* plaidml_get_invalid_devconf(vai_ctx* ctx, plaidml_device_enumerator* enumerator,
|
||||
size_t index);
|
||||
|
||||
// PlaidML buffers are used to create bindings between actual data and the data
|
||||
// elements in PlaidML programs.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_buffer;
|
||||
#else
|
||||
typedef struct plaidml_buffer plaidml_buffer;
|
||||
#endif // __cplusplus
|
||||
|
||||
// PlaidML mappings are used to view and manipulate the contents of buffers.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_mapping;
|
||||
#else
|
||||
typedef struct plaidml_mapping plaidml_mapping;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocates a buffer of the supplied raw memory size, or returns NULL if the
|
||||
// library cannot allocate sufficient memory, or if the supplied device is
|
||||
// NULL.
|
||||
PLAIDML_API plaidml_buffer* plaidml_alloc_buffer(vai_ctx* ctx, plaidml_device* device, uint64_t size);
|
||||
|
||||
// Frees a buffer. After this call, the buffer should not be used for any
|
||||
// subsequent calls. Freeing a NULL buffer is a no-op.
|
||||
PLAIDML_API void plaidml_free_buffer(plaidml_buffer* buffer);
|
||||
|
||||
// Maps a buffer's current contents into memory.
|
||||
//
|
||||
// If the supplied callback is NULL, the call will block until the buffer is
|
||||
// available, and then will return a pointer to a mapping for the buffer
|
||||
// (unless an error occurs).
|
||||
//
|
||||
// If the supplied callback is non-NULL, the call will immediately return NULL,
|
||||
// and will arrange for the callback to be invoked with the mapping once the
|
||||
// buffer's data becomes available (calling it with a NULL mapping on error).
|
||||
//
|
||||
// The library may invoke the callback synchronously if the buffer's data is
|
||||
// already available or in error conditions.
|
||||
//
|
||||
// A NULL buffer may be supplied; this will always result in a NULL address,
|
||||
// and an out-of-memory error in the current thread's thread-local storage.
|
||||
PLAIDML_API plaidml_mapping* plaidml_map_buffer_current(plaidml_buffer* buffer,
|
||||
void (*callback)(void* arg, plaidml_mapping* mapping),
|
||||
void* arg);
|
||||
|
||||
// Maps a buffer into memory, possibly discarding its current contents.
|
||||
//
|
||||
// The implementation may preserve or discard the buffer's contents when
|
||||
// constructing the mapping; callers should not assume that the buffer has been
|
||||
// initialized.
|
||||
//
|
||||
// The implementation may construct a non-coherent mapping: reads from the
|
||||
// buffer may return arbitrary values, even after writing the same memory from
|
||||
// the same processor.
|
||||
//
|
||||
// A NULL buffer may be supplied; this will always result in a NULL address,
|
||||
// and an out-of-memory error in the current thread's thread-local storage.
|
||||
PLAIDML_API plaidml_mapping* plaidml_map_buffer_discard(vai_ctx* ctx, plaidml_buffer* buffer);
|
||||
|
||||
// Gets the base address of a mapping's mapped memory region. If the mapping
|
||||
// has been written back to the buffer, this call will return NULL. A NULL
|
||||
// mapping may be supplied; this will always return NULL.
|
||||
PLAIDML_API char* plaidml_get_mapping_base(vai_ctx* ctx, plaidml_mapping* mapping);
|
||||
|
||||
// Gets the size of a mapping's mapped memory region. If the mapping has been
|
||||
// written back to the buffer, this call will return 0. A NULL mapping may be
|
||||
// supplied; this will always return 0.
|
||||
PLAIDML_API size_t plaidml_get_mapping_size(vai_ctx* ctx, plaidml_mapping* mapping);
|
||||
|
||||
// Synchronizes a mapping with its backing store (if required by the underlying
|
||||
// device implementation), possibly removing the mapping from the current
|
||||
// virtual address space.
|
||||
//
|
||||
// After this call, callers must not access the mapping's previous virtual
|
||||
// memory region.
|
||||
//
|
||||
// Callers are allowed to free the mapping and use the buffer as a program input
|
||||
// immediately after this call.
|
||||
//
|
||||
// A NULL mapping may be supplied; this will always result in a false result
|
||||
// and an out-of-memory error in the current thread's thread-local storage.
|
||||
PLAIDML_API bool plaidml_writeback_mapping(vai_ctx* ctx, plaidml_mapping* mapping);
|
||||
|
||||
// Removes a mapping that's no longer required by the caller.
|
||||
//
|
||||
// After this call, callers must not access the mapping's previous virtual
|
||||
// memory region.
|
||||
//
|
||||
// Freeing a NULL mapping is a no-op.
|
||||
PLAIDML_API void plaidml_free_mapping(plaidml_mapping* mapping);
|
||||
|
||||
// PlaidML shapes describe the layout of the data within a buffer as observed by a
|
||||
// program.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_shape;
|
||||
#else
|
||||
typedef struct plaidml_shape plaidml_shape;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Set the default datatype for floating-point computations.
|
||||
PLAIDML_API void plaidml_set_floatx(plaidml_datatype datatype);
|
||||
|
||||
// Allocates a shape, or returns NULL if the library cannot allocate sufficient
|
||||
// memory. Note that shapes must have dimensions added before use.
|
||||
PLAIDML_API plaidml_shape* plaidml_alloc_shape(vai_ctx* ctx, plaidml_datatype datatype);
|
||||
|
||||
// Frees a shape. After this call, the shape should not be used for any
|
||||
// subsequent calls. Freeing a NULL shape is a no-op.
|
||||
PLAIDML_API void plaidml_free_shape(plaidml_shape* shape);
|
||||
|
||||
// Sets a shape's offset, in elements, from the beginning of the data.
|
||||
PLAIDML_API bool plaidml_set_shape_offset(vai_ctx* ctx, plaidml_shape* shape, uint64_t offset_in_elements);
|
||||
|
||||
// Set a shape's layout
|
||||
PLAIDML_API bool plaidml_shape_set_layout(vai_ctx* ctx, plaidml_shape* shape, const char* layout);
|
||||
|
||||
// Adds a dimension to a shape. Dimension sizes and strides are measured in
|
||||
// elements of the shape's datatype, not by local buffer byte counts.
|
||||
PLAIDML_API bool plaidml_add_dimension(vai_ctx* ctx, plaidml_shape* shape, uint64_t size_in_elements,
|
||||
int64_t stride_in_elements);
|
||||
|
||||
// Gets a shape's type.
|
||||
PLAIDML_API plaidml_datatype plaidml_get_shape_type(plaidml_shape* shape);
|
||||
|
||||
// Gets a shape's offset.
|
||||
PLAIDML_API uint64_t plaidml_get_shape_offset(plaidml_shape* shape);
|
||||
|
||||
// Get the number of dimensions for a shape.
|
||||
PLAIDML_API size_t plaidml_get_shape_dimension_count(plaidml_shape* shape);
|
||||
|
||||
// Gets the size in elements for a given shape dimension.
|
||||
// If the dimension is out of range, zero will be returned.
|
||||
PLAIDML_API uint64_t plaidml_get_shape_dimension_size(plaidml_shape* shape, size_t dim);
|
||||
|
||||
// Gets the stride in elements for a given shape dimension.
|
||||
// If the dimension is out of range, zero will be returned.
|
||||
PLAIDML_API int64_t plaidml_get_shape_dimension_stride(plaidml_shape* shape, size_t dim);
|
||||
|
||||
// Gets the byte size required for a buffer to hold the given shape.
|
||||
PLAIDML_API uint64_t plaidml_get_shape_buffer_size(plaidml_shape* shape);
|
||||
|
||||
// Gets the underlying element count described by the given shape.
|
||||
PLAIDML_API uint64_t plaidml_get_shape_element_count(plaidml_shape* shape);
|
||||
|
||||
// A PlaidML function defines a transformation from some set of inputs to
|
||||
// some set of outputs.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_function;
|
||||
#else
|
||||
typedef struct plaidml_function plaidml_function;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Frees a function. After this call, the function should not be used for any
|
||||
// subsequent calls. Freeing a NULL function is a no-op.
|
||||
PLAIDML_API void plaidml_free_function(plaidml_function* function);
|
||||
|
||||
// Return the number of inputs to a function, 0 if function is NULL
|
||||
PLAIDML_API size_t plaidml_get_function_input_count(plaidml_function* function);
|
||||
|
||||
// Return the name of input i for a function, or NULL if function is NULL or out of bounds
|
||||
PLAIDML_API const char* plaidml_get_function_input(plaidml_function* function, size_t i);
|
||||
|
||||
// Return the number of outpus from function, 0 if function is NULL
|
||||
PLAIDML_API size_t plaidml_get_function_output_count(plaidml_function* function);
|
||||
|
||||
// Return the name of output i for a function, or NULL if function is NULL or out of bounds
|
||||
PLAIDML_API const char* plaidml_get_function_output(plaidml_function* function, size_t i);
|
||||
|
||||
// A PlaidML var is an input to or an output from a PlaidML function.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_var;
|
||||
#else
|
||||
typedef struct plaidml_var plaidml_var;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Frees a var. After this call, the var should not be used for any
|
||||
// subsequent calls. Freeing a NULL var is a no-op.
|
||||
PLAIDML_API void plaidml_free_var(plaidml_var* var);
|
||||
|
||||
// Allocate a placeholder var.
|
||||
//
|
||||
// A placeholder can be used during function application: used as the output of
|
||||
// one function application and the the input of another function application,
|
||||
// the placeholder defines an information flow between the functions. A
|
||||
// placeholder can also during function composition: the placeholder can be
|
||||
// bound to the inputs or outputs of the composed function.
|
||||
//
|
||||
// num_dimensions specifies the placeholder dimension count: PlaidML functions are
|
||||
// polymorphic with respect to tensor sizes and datatypes, but not to the
|
||||
// actual dimension count of their inputs and outputs, so placeholders need to
|
||||
// indicate the number of dimensions of the variables they will eventually be
|
||||
// bound to. For scalar placeholders, specify zero for the dimension count.
|
||||
PLAIDML_API plaidml_var* plaidml_alloc_placeholder(size_t num_dimensions);
|
||||
|
||||
// Allocates a var representing a signed integer constant.
|
||||
PLAIDML_API plaidml_var* plaidml_alloc_int64(int64_t value);
|
||||
|
||||
// Allocates a var representing a floating point constant.
|
||||
PLAIDML_API plaidml_var* plaidml_alloc_real(double value);
|
||||
|
||||
// Allocates a var representing a tensor, bound to the given shape and buffer.
|
||||
PLAIDML_API plaidml_var* plaidml_alloc_tensor(vai_ctx* ctx, plaidml_buffer* buffer, plaidml_shape* shape);
|
||||
|
||||
// Attaches quantization parameters to a weights tensor
|
||||
PLAIDML_API bool plaidml_tensor_attach_qparams(plaidml_var* tensor, plaidml_var* qparams);
|
||||
|
||||
// Builds a function from the supplied code written in the PlaidML operation
|
||||
// description language. If 'id' is not NULL, attach the id to the function
|
||||
// for tracking purposes.
|
||||
PLAIDML_API plaidml_function* plaidml_build_coded_function(const char* code, const char* id);
|
||||
|
||||
// TODO: Make more general method to serialize things.
|
||||
|
||||
// Load a function (possibly with bound tensors) from a file
|
||||
PLAIDML_API plaidml_function* plaidml_load_function(vai_ctx* ctx, plaidml_device* dev, const char* filename);
|
||||
|
||||
// Store a function (possibly with bound tensors) from to a file
|
||||
PLAIDML_API bool plaidml_save_function(plaidml_function* func, const char* filename);
|
||||
|
||||
// Predeclare applier
|
||||
// A PlaidML applier describes the application of a PlaidML function to some
|
||||
// particular set of inputs, yielding some particular set of outputs. (For
|
||||
// example, you can think of "+" as a function; applying it to "2" and "3"
|
||||
// yields a particular output, "5".)
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_applier;
|
||||
#else
|
||||
typedef struct plaidml_applier plaidml_applier;
|
||||
#endif // __cplusplus
|
||||
|
||||
// A PlaidML composer builds a new function out of a set of vars, where the values
|
||||
// of the output vars have been previously defined (by using an applier),
|
||||
// either in terms of placeholders (which become the new function inputs), or
|
||||
// in terms of mutable tensors (which will be mutated each time the function is
|
||||
// run).
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_composer;
|
||||
#else
|
||||
typedef struct plaidml_composer plaidml_composer;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocates a composer, or returns NULL if the library cannot allocate sufficient memory.
|
||||
PLAIDML_API plaidml_composer* plaidml_alloc_composer();
|
||||
|
||||
// Binds a placeholder var to a named input of a composed function.
|
||||
PLAIDML_API bool plaidml_add_composer_input(plaidml_composer* composer, const char* name, plaidml_var* var);
|
||||
|
||||
// Binds a computed value var to a named output of a composed function.
|
||||
PLAIDML_API bool plaidml_add_composer_output(plaidml_composer* composer, const char* name, plaidml_var* var);
|
||||
|
||||
// Adds a dependency to the composed function. Any updates induced by the function
|
||||
// application will be updates of the newly generated function (in addition to any
|
||||
// explicit updates, which will superseed them).
|
||||
PLAIDML_API bool plaidml_add_composer_dependency(plaidml_composer* composer, plaidml_applier* must_run_before);
|
||||
|
||||
// Adds a tensor update to a composed function. This allows the composed
|
||||
// function to have externally visible side effects when run: the source tensor
|
||||
// (which should be a placeholder bound to an output of some function) will be
|
||||
// assigned to the destination tensor (either a placeholder or a tensor var)
|
||||
// each time the composed function is run.
|
||||
PLAIDML_API bool plaidml_add_composer_update(plaidml_composer* composer, plaidml_var* dest_tensor,
|
||||
plaidml_var* src_tensor);
|
||||
|
||||
// Builds the function described by the composer. This should be called at
|
||||
// most once per composer; after this call, the only valid operation on the
|
||||
// composer is plaidml_free_composer().
|
||||
PLAIDML_API plaidml_function* plaidml_build_composed_function(plaidml_composer* composer);
|
||||
|
||||
// Frees a composer. After this call, the composer should not be used for any
|
||||
// subsequent calls. Freeing a NULL composer is a no-op.
|
||||
PLAIDML_API void plaidml_free_composer(plaidml_composer* composer);
|
||||
|
||||
// Allocates an applier describing the application of the given function to some
|
||||
// number of inputs, or returns NULL if the library cannot allocate sufficient memory.
|
||||
PLAIDML_API plaidml_applier* plaidml_alloc_applier(plaidml_function* function);
|
||||
|
||||
// Adds a dependency to the applied function. This is used to sequence tensor
|
||||
// updates: if a sub-function of the applied function uses a mutable tensor as
|
||||
// an input, the value it will observe for that tensor will be the value after
|
||||
// the indicated function has run (presumably updating the tensor). In addition
|
||||
// the new function application will carry the updates forward.
|
||||
PLAIDML_API bool plaidml_apply_add_dependency(plaidml_applier* applier, plaidml_applier* must_run_before);
|
||||
|
||||
// Adds a named input to a function application. Note that the input variable
|
||||
// is not consumed; the caller remains responsible for calling plaidml_free_var()
|
||||
// when the supplied var is no longer needed.
|
||||
PLAIDML_API bool plaidml_apply_add_input(plaidml_applier* applier, const char* name, plaidml_var* var);
|
||||
|
||||
// Allocates a var corresponding to the output of a function application. The
|
||||
// caller is responsible for calling plaidml_free_var() on the result when the
|
||||
// variable is no longer needed.
|
||||
//
|
||||
// At the time when the output is allocated, all inputs to the function
|
||||
// application must already be added (either as concrete values or as
|
||||
// placeholders).
|
||||
PLAIDML_API plaidml_var* plaidml_apply_alloc_output(plaidml_applier* applier, const char* name);
|
||||
|
||||
// Frees an applier. After this call, the applier should not be used for any
|
||||
// subsequent calls. Freeing a NULL applier is a no-op.
|
||||
PLAIDML_API void plaidml_free_applier(plaidml_applier* applier);
|
||||
|
||||
// A PlaidML invoker provides a mechanism for scheduling runs of a
|
||||
// PlaidML function.
|
||||
//
|
||||
// The function need not be completely bound when supplied to the
|
||||
// invoker; the invoker may be mutated to set the function inputs and
|
||||
// outputs. The input and output bindings must be fully specified,
|
||||
// and must be dimensionally consistent with each other, at the time
|
||||
// the invoker is used to invoke the supplied function.
|
||||
//
|
||||
// Invokers are not threadsafe, and they are stateful; callers are
|
||||
// advised to synchronize concurrent access from the time the
|
||||
// invoker's inputs are set through to when the function has completed
|
||||
// running.
|
||||
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_invoker;
|
||||
#else
|
||||
typedef struct plaidml_invoker plaidml_invoker;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocates an invoker for the supplied function, or returns NULL if
|
||||
// the library cannot allocate sufficient memory, or if the supplied
|
||||
// context or function is NULL.
|
||||
PLAIDML_API plaidml_invoker* plaidml_alloc_invoker(vai_ctx* ctx, plaidml_function* function);
|
||||
|
||||
// Frees an invoker. After this call, the invoker should not be used for any
|
||||
// subsequent calls. Freeing a NULL invoker is a no-op.
|
||||
PLAIDML_API void plaidml_free_invoker(plaidml_invoker* invoker);
|
||||
|
||||
// Sets a named input for an invocation. The variable must be NULL or
|
||||
// a concrete object; placeholders are not permitted. Note that the
|
||||
// input variable is not consumed; the caller remains responsible for
|
||||
// calling plaidml_free_var() when the supplied var is no longer
|
||||
// needed.
|
||||
PLAIDML_API bool plaidml_set_invoker_input(plaidml_invoker* invoker, const char* name, plaidml_var* var);
|
||||
|
||||
// Allocates a shape corresponding to the output of an invocation.
|
||||
// The caller is responsible for calling plaidml_free_shape() on the
|
||||
// result when the shape is no longer needed.
|
||||
//
|
||||
// At the time when the shape is allocated, all inputs to the
|
||||
// invocation must already be set to concrete values that are
|
||||
// consistent in size.
|
||||
PLAIDML_API plaidml_shape* plaidml_alloc_invoker_output_shape(plaidml_invoker* invoker, const char* name);
|
||||
|
||||
// Sets a named output for an invocation. The variable must be NULL
|
||||
// or a concrete tensor; placeholders are not permitted. Note that
|
||||
// the output variable is not consumed; the caller remains responsible
|
||||
// for calling plaidml_free_var() when the supplied var is no longer
|
||||
// needed.
|
||||
PLAIDML_API bool plaidml_set_invoker_output(plaidml_invoker* invoker, const char* name, plaidml_var* var);
|
||||
|
||||
// PlaidML Stripe file formats.
|
||||
typedef enum {
|
||||
PLAIDML_FILE_FORMAT_TILE = 1,
|
||||
PLAIDML_FILE_FORMAT_STRIPE_HUMAN = 2,
|
||||
PLAIDML_FILE_FORMAT_STRIPE_PROTOTXT = 3,
|
||||
PLAIDML_FILE_FORMAT_STRIPE_BINARY = 4,
|
||||
} plaidml_file_format;
|
||||
|
||||
// Mark a functions inputs as 'const', that is, subject to constant folding
|
||||
// and other operations that assume they will no longer be changed
|
||||
PLAIDML_API bool plaidml_set_invoker_const(plaidml_invoker* invoker);
|
||||
|
||||
// Serializes an invoker to a file. All inputs to the invoker must
|
||||
// already be set to concrete values that are consistent in size.
|
||||
PLAIDML_API bool plaidml_save_invoker(plaidml_invoker* invoker, const char* filename, plaidml_file_format format);
|
||||
|
||||
// A PlaidML invocation describes one particular run of a function.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_invocation;
|
||||
#else
|
||||
typedef struct plaidml_invocation plaidml_invocation;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Schedules a run of an invoker's function with the invoker's current
|
||||
// input and output bindings.
|
||||
//
|
||||
// The invocation must be fully specified: all function inputs and
|
||||
// outputs must have corresponding inputs and outputs set in the
|
||||
// invoker. Furthermore, all inputs and outputs must be consistently
|
||||
// sized relative to each other and the function.
|
||||
//
|
||||
// All buffers used to back tensors that will be updated by the
|
||||
// invocation should already be unmapped. When this call returns,
|
||||
// those buffers logically contain the updated values, and may be
|
||||
// remapped; remapping requests will complete once the underlying
|
||||
// invocation is complete.
|
||||
//
|
||||
// Note that this call may return before the computation described by
|
||||
// the function has actually completed; the computation is scheduled,
|
||||
// not complete. Errors that occur asynchronously will be reported
|
||||
// when the buffers updated by running the function are remapped.
|
||||
//
|
||||
// Once this call returns, the invoker's inputs and outputs may be set
|
||||
// by the caller, and the invoker may be used for another run of the
|
||||
// invoker's function, even if the first run has not yet completed.
|
||||
PLAIDML_API plaidml_invocation* plaidml_schedule_invocation(vai_ctx* ctx, plaidml_invoker* invoker);
|
||||
|
||||
// Frees an invocation. After this call, the invocation should not be
|
||||
// used for any subsequent calls. Freeing a NULL invocation is a no-op.
|
||||
PLAIDML_API void plaidml_free_invocation(plaidml_invocation* invocation);
|
||||
|
||||
// A PlaidML gradient computes gradient data for a given scalar.
|
||||
#ifdef __cplusplus
|
||||
struct plaidml_gradient;
|
||||
#else
|
||||
typedef struct plaidml_gradient plaidml_gradient;
|
||||
#endif // __cplusplus
|
||||
|
||||
// Allocate and returns a gradient computer for a given scalar or NULL if error
|
||||
PLAIDML_API plaidml_gradient* plaidml_alloc_gradient(plaidml_var* var);
|
||||
|
||||
// Frees a gradient computer. After this call, the context should not be used for
|
||||
// any subsequent calls. Freeing a NULL context is a no-op.
|
||||
PLAIDML_API void plaidml_free_gradient(plaidml_gradient* grad);
|
||||
|
||||
// Determines the gradient of with respect to some value
|
||||
PLAIDML_API plaidml_var* plaidml_compute_grad_wrt(plaidml_gradient* grad, plaidml_var* wrt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_device> {
|
||||
void operator()(::plaidml_device* device) const noexcept { ::plaidml_close_device(device); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_device_enumerator> {
|
||||
void operator()(::plaidml_device_enumerator* enumerator) const noexcept {
|
||||
::plaidml_free_device_enumerator(enumerator);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_buffer> {
|
||||
void operator()(::plaidml_buffer* buffer) const noexcept { ::plaidml_free_buffer(buffer); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_mapping> {
|
||||
void operator()(::plaidml_mapping* mapping) const noexcept { ::plaidml_free_mapping(mapping); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_shape> {
|
||||
void operator()(::plaidml_shape* shape) const noexcept { ::plaidml_free_shape(shape); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_function> {
|
||||
void operator()(::plaidml_function* function) const noexcept { ::plaidml_free_function(function); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_var> {
|
||||
void operator()(::plaidml_var* var) const noexcept { ::plaidml_free_var(var); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_composer> {
|
||||
void operator()(::plaidml_composer* composer) const noexcept { ::plaidml_free_composer(composer); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_applier> {
|
||||
void operator()(::plaidml_applier* applier) const noexcept { ::plaidml_free_applier(applier); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_invoker> {
|
||||
void operator()(::plaidml_invoker* invoker) const noexcept { ::plaidml_free_invoker(invoker); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_invocation> {
|
||||
void operator()(::plaidml_invocation* invocation) const noexcept { ::plaidml_free_invocation(invocation); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct default_delete<::plaidml_gradient> {
|
||||
void operator()(::plaidml_gradient* gradient) const noexcept { ::plaidml_free_gradient(gradient); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // __cplusplus
|
||||
Reference in New Issue
Block a user