提交 d8835a5f authored 作者: Iban Harlouchet's avatar Iban Harlouchet

numpydoc for theano/gof/cc.py

上级 0a7415d7
""" """
Defines Linkers that deal with C implementations. Defines Linkers that deal with C implementations.
""" """
from __future__ import print_function from __future__ import print_function
...@@ -45,8 +46,13 @@ run_cthunk = None # Will be imported only when needed. ...@@ -45,8 +46,13 @@ run_cthunk = None # Will be imported only when needed.
def get_module_cache(init_args=None): def get_module_cache(init_args=None):
""" """
:param init_args: If not None, the (k, v) pairs in this dictionary will
be forwarded to the ModuleCache constructor as keyword arguments. Parameters
----------
init_args
If not None, the (k, v) pairs in this dictionary will be forwarded to
the ModuleCache constructor as keyword arguments.
""" """
return cmodule.get_module_cache(config.compiledir, init_args=init_args) return cmodule.get_module_cache(config.compiledir, init_args=init_args)
...@@ -63,25 +69,31 @@ def get_persistent_module_cache(): ...@@ -63,25 +69,31 @@ def get_persistent_module_cache():
class CodeBlock: class CodeBlock:
"""WRITEME """
WRITEME
Represents a computation unit composed of declare, behavior, and cleanup. Represents a computation unit composed of declare, behavior, and cleanup.
@ivar declare: C code that declares variables for use by the computation
@ivar behavior: C code that performs the computation The constructor initializes a L{CodeBlock} with templatized declare,
@ivar cleanup: C code that cleans up things allocated or incref-ed behavior and cleanup. The sub parameter will be used in the other
in behavior arguments' templates. sub should contain a key called 'id' that maps to an
identifier for this block. The identifier will be used to determine the
failure code and a label to jump to. It should also contain a key called
'failure_var' that contains the name of the variable that contains the error
code.
Parameters
----------
declare
C code that declares variables for use by the computation.
behavior
C code that performs the computation.
cleanup
C code that cleans up things allocated or incref-ed in behavior.
""" """
def __init__(self, declare, behavior, cleanup, sub): def __init__(self, declare, behavior, cleanup, sub):
"""
Initialize a L{CodeBlock} with templatized declare, behavior
and cleanup. The sub parameter will be used in the other
arguments' templates. sub should contain a key called 'id'
that maps to an identifier for this block.
The identifier will be used to determine the failure code and
a label to jump to. It should also contain a key called
'failure_var' that contains the name of the variable that
contains the error code.
"""
self.declare = declare self.declare = declare
self.behavior = behavior self.behavior = behavior
# the dummy is because gcc throws an error when a label's # the dummy is because gcc throws an error when a label's
...@@ -94,10 +106,12 @@ class CodeBlock: ...@@ -94,10 +106,12 @@ class CodeBlock:
def failure_code(sub): def failure_code(sub):
"""Code contained in sub['fail'], usually substituted for %(fail)s. """
Code contained in sub['fail'], usually substituted for %(fail)s.
It sets information about current error, then goto the code It sets information about current error, then goto the code
actually handling the failure, which is defined in struct_gen(). actually handling the failure, which is defined in struct_gen().
""" """
return '''{ return '''{
%(failure_var)s = %(id)s; %(failure_var)s = %(id)s;
...@@ -110,7 +124,10 @@ def failure_code(sub): ...@@ -110,7 +124,10 @@ def failure_code(sub):
def failure_code_init(sub): def failure_code_init(sub):
"Code for failure in the struct init." """
Code for failure in the struct init.
"""
return '''{ return '''{
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
...@@ -122,10 +139,13 @@ def failure_code_init(sub): ...@@ -122,10 +139,13 @@ def failure_code_init(sub):
def code_gen(blocks): def code_gen(blocks):
"""WRITEME From a list of L{CodeBlock} instances, returns a string """
WRITEME
From a list of L{CodeBlock} instances, returns a string
that executes them all in sequence. eg for C{(decl1, task1, that executes them all in sequence. eg for C{(decl1, task1,
cleanup1)} and C{(decl2, task2, cleanup2)} the returned string cleanup1)} and C{(decl2, task2, cleanup2)} the returned string
will be of the form:: will be of the form:
decl1 decl1
decl2 decl2
...@@ -137,8 +157,8 @@ def code_gen(blocks): ...@@ -137,8 +157,8 @@ def code_gen(blocks):
} }
cleanup1 cleanup1
} }
"""
"""
decl = "" decl = ""
head = "" head = ""
tail = "" tail = ""
...@@ -150,27 +170,39 @@ def code_gen(blocks): ...@@ -150,27 +170,39 @@ def code_gen(blocks):
def struct_gen(args, struct_builders, blocks, sub): def struct_gen(args, struct_builders, blocks, sub):
"""WRITEME """
WRITEME
Generates a struct conforming to the following specifications: Generates a struct conforming to the following specifications:
* args -> all of the PyObject* type, stored in the struct
Parameters
----------
args
All of the PyObject* type, stored in the struct
they represent the storage and must be length 1 python lists. they represent the storage and must be length 1 python lists.
* struct_builders -> list of L{CodeBlock} instances such that struct_builders
List of L{CodeBlock} instances such that
* declarations are in the struct * declarations are in the struct
* behavior is in the constructor * behavior is in the constructor
* cleanup is in the destructor * cleanup is in the destructor
* blocks -> list of CodeBlock instances such that blocks
List of CodeBlock instances such that
* declarations, behavior and cleanup are in the run() * declarations, behavior and cleanup are in the run()
method of the struct method of the struct
* sub -> dictionary used to template the struct. sub
Dictionary used to template the struct.
* failure_var -> must contain a variable name to use for * failure_var -> must contain a variable name to use for
the failure code. the failure code.
Returns
-------
object
In a nutshell, this returns code for a struct that represents In a nutshell, this returns code for a struct that represents
a function with state. The state's initialization and destruction a function with state. The state's initialization and destruction
are handled by struct_builders and the actual behavior of the are handled by struct_builders and the actual behavior of the
function is handled by blocks. function is handled by blocks.
"""
"""
struct_decl = "" struct_decl = ""
struct_init_head = "" struct_init_head = ""
struct_init_tail = "" struct_init_tail = ""
...@@ -276,12 +308,18 @@ def struct_gen(args, struct_builders, blocks, sub): ...@@ -276,12 +308,18 @@ def struct_gen(args, struct_builders, blocks, sub):
# with handling of the py_<name> variable. # with handling of the py_<name> variable.
def get_nothing(r, name, sub): def get_nothing(r, name, sub):
"""WRITEME""" """
WRITEME
"""
return "" return ""
def get_c_declare(r, name, sub): def get_c_declare(r, name, sub):
"""Wrapper around c_declare that declares py_name""" """
Wrapper around c_declare that declares py_name.
"""
# The declaration will be used by the Apply node that # The declaration will be used by the Apply node that
# is computing it (`r.owner`), and by each of the clients. # is computing it (`r.owner`), and by each of the clients.
# If some of these have `check_input=True` in their `.op`, # If some of these have `check_input=True` in their `.op`,
...@@ -302,7 +340,10 @@ def get_c_declare(r, name, sub): ...@@ -302,7 +340,10 @@ def get_c_declare(r, name, sub):
def get_c_init(r, name, sub): def get_c_init(r, name, sub):
"""Wrapper around c_init that initializes py_name to Py_None""" """
Wrapper around c_init that initializes py_name to Py_None.
"""
pre = "" """ pre = "" """
py_%(name)s = Py_None; py_%(name)s = Py_None;
{Py_XINCREF(py_%(name)s);} {Py_XINCREF(py_%(name)s);}
...@@ -311,7 +352,10 @@ def get_c_init(r, name, sub): ...@@ -311,7 +352,10 @@ def get_c_init(r, name, sub):
def get_c_extract(r, name, sub): def get_c_extract(r, name, sub):
"""Wrapper around c_extract that initializes py_name from storage.""" """
Wrapper around c_extract that initializes py_name from storage.
"""
# `c_extract` is called when getting the value of an apply node's # `c_extract` is called when getting the value of an apply node's
# input from the compute map, before being used by its clients. # input from the compute map, before being used by its clients.
# If one of the clients has `check_input=True`, we need to perform # If one of the clients has `check_input=True`, we need to perform
...@@ -346,7 +390,10 @@ def get_c_extract(r, name, sub): ...@@ -346,7 +390,10 @@ def get_c_extract(r, name, sub):
def get_c_extract_out(r, name, sub): def get_c_extract_out(r, name, sub):
"""Wrapper around c_extract_out that initializes py_name from storage.""" """
Wrapper around c_extract_out that initializes py_name from storage.
"""
# `c_extract_out` is used to extract an output variable from # `c_extract_out` is used to extract an output variable from
# the compute map, to be used as pre-allocated memory for `r` # the compute map, to be used as pre-allocated memory for `r`
# before its value gets computed. # before its value gets computed.
...@@ -376,7 +423,10 @@ def get_c_extract_out(r, name, sub): ...@@ -376,7 +423,10 @@ def get_c_extract_out(r, name, sub):
def get_c_cleanup(r, name, sub): def get_c_cleanup(r, name, sub):
"""Wrapper around c_cleanup that decrefs py_name""" """
Wrapper around c_cleanup that decrefs py_name.
"""
post = """ post = """
{Py_XDECREF(py_%(name)s);} {Py_XDECREF(py_%(name)s);}
""" % locals() """ % locals()
...@@ -384,7 +434,10 @@ def get_c_cleanup(r, name, sub): ...@@ -384,7 +434,10 @@ def get_c_cleanup(r, name, sub):
def get_c_sync(r, name, sub): def get_c_sync(r, name, sub):
"""Wrapper around c_sync that syncs py_name with storage.""" """
Wrapper around c_sync that syncs py_name with storage.
"""
return """ return """
if (!%(failure_var)s) { if (!%(failure_var)s) {
%(sync)s %(sync)s
...@@ -397,11 +450,21 @@ def get_c_sync(r, name, sub): ...@@ -397,11 +450,21 @@ def get_c_sync(r, name, sub):
def apply_policy(policy, r, name, sub): def apply_policy(policy, r, name, sub):
"""WRITEME """
@param policy: list of functions that map a L{Variable} to a string, WRITEME
or a single such function
@type r: L{Variable} Parameters
@return: C{policy[0](r) + policy[1](r) + ...} ----------
policy
List of functions that map a L{Variable} to a string,
or a single such function.
r: L{Variable}
Returns
-------
object
C{policy[0](r) + policy[1](r) + ...}.
""" """
if isinstance(policy, (list, tuple)): if isinstance(policy, (list, tuple)):
ret = "" ret = ""
...@@ -412,22 +475,27 @@ def apply_policy(policy, r, name, sub): ...@@ -412,22 +475,27 @@ def apply_policy(policy, r, name, sub):
def struct_variable_codeblocks(variable, policies, id, symbol_table, sub): def struct_variable_codeblocks(variable, policies, id, symbol_table, sub):
"""WRITEME """
variable -> a Variable WRITEME
policies -> a pair of tuples ((declare_policy, behavior_policy,
cleanup_policy), -- at construction Parameters
(declare_policy, behavior_policy, ----------
cleanup_policy)) -- at execution variable : a Variable
the first list will produce an element of the policies : a pair of tuples
'struct_builders' argument in struct_gen the second (declare_policy, behavior_policy, cleanup_policy) -- at construction.
list will produce an element of the 'blocks' argument (declare_policy, behavior_policy, cleanup_policy)) -- at execution.
in struct_gen The first list will produce an element of the 'struct_builders' argument
in struct_gen. The second list will produce an element of the 'blocks'
id -> the id assigned to this variable's task in the computation argument in struct_gen.
symbol_table -> a dict that maps variables to variable names. It id
is not read by this function but a variable name for the The id assigned to this variable's task in the computation.
variable is computed and added to the table. symbol_table
sub -> dictionary for use by L{CodeBlock}. A dict that maps variables to variable names. It is not read by this
function but a variable name for the variable is computed and added to
the table.
sub
Dictionary for use by L{CodeBlock}.
""" """
name = "V%i" % id name = "V%i" % id
...@@ -453,7 +521,8 @@ def struct_variable_codeblocks(variable, policies, id, symbol_table, sub): ...@@ -453,7 +521,8 @@ def struct_variable_codeblocks(variable, policies, id, symbol_table, sub):
class CLinker(link.Linker): class CLinker(link.Linker):
"""WRITEME """
WRITEME
Creates C code for an fgraph, compiles it and returns callables Creates C code for an fgraph, compiles it and returns callables
through make_thunk and make_function that make use of the compiled through make_thunk and make_function that make use of the compiled
...@@ -462,6 +531,7 @@ class CLinker(link.Linker): ...@@ -462,6 +531,7 @@ class CLinker(link.Linker):
no_recycling can contain a list of Variables that belong to the fgraph. no_recycling can contain a list of Variables that belong to the fgraph.
If a Variable is in no_recycling, CLinker will clear the output storage If a Variable is in no_recycling, CLinker will clear the output storage
associated to it during the computation (to avoid reusing it). associated to it during the computation (to avoid reusing it).
""" """
def __init__(self, schedule=None): def __init__(self, schedule=None):
...@@ -470,7 +540,10 @@ class CLinker(link.Linker): ...@@ -470,7 +540,10 @@ class CLinker(link.Linker):
self.schedule = schedule self.schedule = schedule
def accept(self, fgraph, no_recycling=None): def accept(self, fgraph, no_recycling=None):
"""WRITEME""" """
WRITEME
"""
if no_recycling is None: if no_recycling is None:
no_recycling = [] no_recycling = []
if self.fgraph is not None and self.fgraph is not fgraph: if self.fgraph is not None and self.fgraph is not fgraph:
...@@ -483,9 +556,12 @@ class CLinker(link.Linker): ...@@ -483,9 +556,12 @@ class CLinker(link.Linker):
return self return self
def fetch_variables(self): def fetch_variables(self):
"""WRITEME """
Fills the inputs, outputs, variables, orphans, WRITEME
temps and node_order fields.
Fills the inputs, outputs, variables, orphans, temps and node_order
fields.
""" """
fgraph = self.fgraph fgraph = self.fgraph
self.inputs = fgraph.inputs self.inputs = fgraph.inputs
...@@ -527,7 +603,9 @@ class CLinker(link.Linker): ...@@ -527,7 +603,9 @@ class CLinker(link.Linker):
self.consts = [] self.consts = []
def code_gen(self): def code_gen(self):
"""WRITEME """
WRITEME
Generates code for a struct that does the computation of the fgraph and Generates code for a struct that does the computation of the fgraph and
stores it in the struct_code field of the instance. stores it in the struct_code field of the instance.
...@@ -538,6 +616,7 @@ class CLinker(link.Linker): ...@@ -538,6 +616,7 @@ class CLinker(link.Linker):
is avoided. is avoided.
This method caches its computations. This method caches its computations.
""" """
if getattr(self, 'struct_code', False): if getattr(self, 'struct_code', False):
...@@ -804,12 +883,15 @@ class CLinker(link.Linker): ...@@ -804,12 +883,15 @@ class CLinker(link.Linker):
return self.struct_code return self.struct_code
def support_code(self): def support_code(self):
"""WRITEME """
WRITEME
Returns a list of support code strings that are needed by Returns a list of support code strings that are needed by
one or more Variables or Ops. The support code from Variables is one or more Variables or Ops. The support code from Variables is
added before the support code from Ops. added before the support code from Ops.
This might contain duplicates. This might contain duplicates.
""" """
ret = [] ret = []
# generic support code # generic support code
...@@ -822,11 +904,14 @@ class CLinker(link.Linker): ...@@ -822,11 +904,14 @@ class CLinker(link.Linker):
return ret return ret
def compile_args(self): def compile_args(self):
"""WRITEME """
WRITEME
Returns a list of compile args that are needed by one Returns a list of compile args that are needed by one
or more Variables or Ops. or more Variables or Ops.
This might contain duplicates. This might contain duplicates.
""" """
ret = ["-O3"] ret = ["-O3"]
# this is the param the -ffast-math activate. I put the explicitly as # this is the param the -ffast-math activate. I put the explicitly as
...@@ -871,11 +956,14 @@ class CLinker(link.Linker): ...@@ -871,11 +956,14 @@ class CLinker(link.Linker):
return ret return ret
def headers(self): def headers(self):
"""WRITEME """
WRITEME
Returns a list of headers that are needed by one Returns a list of headers that are needed by one
or more Types or Ops. or more Types or Ops.
The return value will not contain duplicates. The return value will not contain duplicates.
""" """
ret = [] ret = []
for x in [y.type for y in self.variables] + [ for x in [y.type for y in self.variables] + [
...@@ -890,7 +978,9 @@ class CLinker(link.Linker): ...@@ -890,7 +978,9 @@ class CLinker(link.Linker):
""" """
Return a list of code snippets that have to be inserted Return a list of code snippets that have to be inserted
in the module initialization code. in the module initialization code.
The return value will not contain duplicates. The return value will not contain duplicates.
""" """
ret = [] ret = []
for x in [y.type for y in self.variables] + [ for x in [y.type for y in self.variables] + [
...@@ -923,11 +1013,14 @@ class CLinker(link.Linker): ...@@ -923,11 +1013,14 @@ class CLinker(link.Linker):
return c_compiler return c_compiler
def header_dirs(self): def header_dirs(self):
"""WRITEME """
WRITEME
Returns a list of lib directories that are needed by one Returns a list of lib directories that are needed by one
or more Types or Ops. or more Types or Ops.
The return value will not contain duplicates. The return value will not contain duplicates.
""" """
ret = [] ret = []
for x in [y.type for y in self.variables] + [ for x in [y.type for y in self.variables] + [
...@@ -939,11 +1032,14 @@ class CLinker(link.Linker): ...@@ -939,11 +1032,14 @@ class CLinker(link.Linker):
return utils.uniq(ret) return utils.uniq(ret)
def libraries(self): def libraries(self):
"""WRITEME """
WRITEME
Returns a list of libraries that are needed by one Returns a list of libraries that are needed by one
or more Types or Ops. or more Types or Ops.
The return value will not contain duplicates. The return value will not contain duplicates.
""" """
ret = [] ret = []
for x in [y.type for y in self.variables] + [ for x in [y.type for y in self.variables] + [
...@@ -955,11 +1051,14 @@ class CLinker(link.Linker): ...@@ -955,11 +1051,14 @@ class CLinker(link.Linker):
return utils.uniq(ret) return utils.uniq(ret)
def lib_dirs(self): def lib_dirs(self):
"""WRITEME """
WRITEME
Returns a list of lib directories that are needed by one Returns a list of lib directories that are needed by one
or more Types or Ops. or more Types or Ops.
The return value will not contain duplicates. The return value will not contain duplicates.
""" """
ret = [] ret = []
for x in [y.type for y in self.variables] + [ for x in [y.type for y in self.variables] + [
...@@ -972,18 +1071,26 @@ class CLinker(link.Linker): ...@@ -972,18 +1071,26 @@ class CLinker(link.Linker):
def __compile__(self, input_storage=None, def __compile__(self, input_storage=None,
output_storage=None, keep_lock=False): output_storage=None, keep_lock=False):
"""WRITEME """
WRITEME
Compiles this linker's fgraph. Compiles this linker's fgraph.
@type input_storage: list or None Parameters
@param input_storage: list of lists of length 1. In order to use ----------
the thunk returned by __compile__, the inputs must be put in input_storage: list or None
that storage. If None, storage will be allocated. List of lists of length 1. In order to use the thunk returned
@param output_storage: list of lists of length 1. The thunk returned by __compile__, the inputs must be put in that storage.
by __compile__ will put the variables of the computation in these If None, storage will be allocated.
lists. If None, storage will be allocated. output_storage: list of lists of length 1
The thunk returned by __compile__ will put the variables of the
computation in these lists. If None, storage will be allocated.
Returns
-------
object
Thunk, input_storage, output_storage, error_storage.
Returns: thunk, input_storage, output_storage, error_storage
""" """
error_storage = [None, None, None] error_storage = [None, None, None]
if input_storage is None: if input_storage is None:
...@@ -1037,27 +1144,34 @@ class CLinker(link.Linker): ...@@ -1037,27 +1144,34 @@ class CLinker(link.Linker):
def make_thunk(self, input_storage=None, output_storage=None, def make_thunk(self, input_storage=None, output_storage=None,
keep_lock=False): keep_lock=False):
"""WRITEME """
WRITEME
Compiles this linker's fgraph and returns a function to perform the Compiles this linker's fgraph and returns a function to perform the
computations, as well as lists of storage cells for both the computations, as well as lists of storage cells for both the inputs
inputs and outputs. and outputs.
@type input_storage: list or None Parameters
@param input_storage: list of lists of length 1. In order to use ----------
input_storage: list or None
List of lists of length 1. In order to use
the thunk returned by __compile__, the inputs must be put in the thunk returned by __compile__, the inputs must be put in
that storage. If None, storage will be allocated. that storage. If None, storage will be allocated.
@param output_storage: list of lists of length 1. The thunk returned output_storage: list of lists of length 1
by __compile__ will put the variables of the computation in these The thunk returned by __compile__ will put the variables of the
lists. If None, storage will be allocated. computation in these lists. If None, storage will be allocated.
Returns: thunk, input_storage, output_storage Returns
-------
object
Thunk, input_storage, output_storage.
The return values can be used as follows: The return values can be used as follows:
f, istor, ostor = clinker.make_thunk() f, istor, ostor = clinker.make_thunk()
istor[0].data = first_input istor[0].data = first_input
istor[1].data = second_input istor[1].data = second_input
f() f()
first_output = ostor[0].data first_output = ostor[0].data
""" """
init_tasks, tasks = self.get_init_tasks() init_tasks, tasks = self.get_init_tasks()
cthunk, in_storage, out_storage, error_storage = self.__compile__( cthunk, in_storage, out_storage, error_storage = self.__compile__(
...@@ -1069,7 +1183,8 @@ class CLinker(link.Linker): ...@@ -1069,7 +1183,8 @@ class CLinker(link.Linker):
return res, in_storage, out_storage return res, in_storage, out_storage
def cmodule_key(self): def cmodule_key(self):
"""Return a complete hashable signature of the module we compiled. """
Return a complete hashable signature of the module we compiled.
This function must have the property that no two programs that This function must have the property that no two programs that
compute different things yield the same key. compute different things yield the same key.
...@@ -1090,8 +1205,8 @@ class CLinker(link.Linker): ...@@ -1090,8 +1205,8 @@ class CLinker(link.Linker):
The outer tuple has a brief header, containing the compilation options The outer tuple has a brief header, containing the compilation options
passed to the compiler, the libraries to link against, an md5 hash passed to the compiler, the libraries to link against, an md5 hash
of theano.config (for all config options where "in_c_key" is True). of theano.config (for all config options where "in_c_key" is True).
It is followed by elements for every node in the It is followed by elements for every node in the topological ordering
topological ordering of `self.fgraph`. of `self.fgraph`.
If the Op of any Apply in the FunctionGraph does not have If the Op of any Apply in the FunctionGraph does not have
c_code_cache_ok()==True, then this function raises a KeyError c_code_cache_ok()==True, then this function raises a KeyError
...@@ -1116,7 +1231,6 @@ class CLinker(link.Linker): ...@@ -1116,7 +1231,6 @@ class CLinker(link.Linker):
If a variable is also a graph output, then its position in the If a variable is also a graph output, then its position in the
outputs list is also bundled with this tuple (after the b). outputs list is also bundled with this tuple (after the b).
The nature of a Constant instance is defined as its signature, The nature of a Constant instance is defined as its signature,
together with two integers: the topological position of the together with two integers: the topological position of the
first Apply using that Constant instance, and the lowest index first Apply using that Constant instance, and the lowest index
...@@ -1141,6 +1255,7 @@ class CLinker(link.Linker): ...@@ -1141,6 +1255,7 @@ class CLinker(link.Linker):
booleans, indicating whether each output is in the booleans, indicating whether each output is in the
no_recycling set. Older versions of compiled modules only have the no_recycling set. Older versions of compiled modules only have the
no_recycle list. no_recycle list.
""" """
return self.cmodule_key_(self.fgraph, self.no_recycling, return self.cmodule_key_(self.fgraph, self.no_recycling,
compile_args=self.compile_args(), compile_args=self.compile_args(),
...@@ -1154,7 +1269,8 @@ class CLinker(link.Linker): ...@@ -1154,7 +1269,8 @@ class CLinker(link.Linker):
c_compiler=None): c_compiler=None):
""" """
Do the actual computation of cmodule_key in a static method Do the actual computation of cmodule_key in a static method
to allow it to be reused in scalar.Composite.__eq__ to allow it to be reused in scalar.Composite.__eq__.
""" """
if compile_args is None: if compile_args is None:
compile_args = [] compile_args = []
...@@ -1311,6 +1427,7 @@ class CLinker(link.Linker): ...@@ -1311,6 +1427,7 @@ class CLinker(link.Linker):
""" """
This compiles the source code for this linker and returns a This compiles the source code for this linker and returns a
loaded module. loaded module.
""" """
if location is None: if location is None:
location = cmodule.dlimport_workdir(config.compiledir) location = cmodule.dlimport_workdir(config.compiledir)
...@@ -1353,11 +1470,12 @@ class CLinker(link.Linker): ...@@ -1353,11 +1470,12 @@ class CLinker(link.Linker):
return module return module
def get_dynamic_module(self): def get_dynamic_module(self):
"""Return a cmodule.DynamicModule instance full of the code """
for our fgraph. Return a cmodule.DynamicModule instance full of the code for our fgraph.
This method is cached on the first call so it can be called This method is cached on the first call so it can be called
multiple times without penalty. multiple times without penalty.
""" """
if not hasattr(self, '_mod'): if not hasattr(self, '_mod'):
self.code_gen() self.code_gen()
...@@ -1412,16 +1530,24 @@ class CLinker(link.Linker): ...@@ -1412,16 +1530,24 @@ class CLinker(link.Linker):
def cthunk_factory(self, error_storage, in_storage, out_storage, def cthunk_factory(self, error_storage, in_storage, out_storage,
keep_lock=False): keep_lock=False):
"""WRITEME """
error_storage -> list of length 3 WRITEME
in_storage -> list of lists of length 1, one per input
out_storage -> list of lists of length 1, one per output
Returns a thunk that points to an instance of a C struct that Parameters
----------
error_storage : list of length 3
in_storage : list of lists of length 1, one per input
out_storage : list of lists of length 1, one per output
Returns
-------
object
A thunk that points to an instance of a C struct that
can carry on the computation of this linker's fgraph. That thunk, can carry on the computation of this linker's fgraph. That thunk,
when executed, will fetch its inputs from in_storage, put its when executed, will fetch its inputs from in_storage, put its
outputs in out_storage and if an error occurs will put the outputs in out_storage and if an error occurs will put the
type, value and traceback of the exception in error_storage. type, value and traceback of the exception in error_storage.
""" """
try: try:
key = self.cmodule_key() key = self.cmodule_key()
...@@ -1481,18 +1607,22 @@ class CLinker(link.Linker): ...@@ -1481,18 +1607,22 @@ class CLinker(link.Linker):
class _CThunk(object): class _CThunk(object):
""" """
A thunk with a C implementation A thunk with a C implementation.
"""
def __init__(self, cthunk, init_tasks, tasks, error_storage):
"""
Parameters Parameters
---------- ----------
cthunk: the CObject pointer used by run_cthunk cthunk
init_tasks: WRITEME The CObject pointer used by run_cthunk.
tasks: WRITEME init_tasks
error_storage: WRITEME WRITEME
tasks
WRITEME
error_storage
WRITEME
""" """
def __init__(self, cthunk, init_tasks, tasks, error_storage):
global run_cthunk global run_cthunk
if run_cthunk is None: if run_cthunk is None:
# Lazy import to avoid compilation when importing theano. # Lazy import to avoid compilation when importing theano.
...@@ -1505,6 +1635,7 @@ class _CThunk(object): ...@@ -1505,6 +1635,7 @@ class _CThunk(object):
def find_task(self, failure_code): def find_task(self, failure_code):
""" """
Maps a failure code to the task that is associated to it. Maps a failure code to the task that is associated to it.
""" """
failure_code -= 1 failure_code -= 1
n = len(self.init_tasks) n = len(self.init_tasks)
...@@ -1540,7 +1671,9 @@ class _CThunk(object): ...@@ -1540,7 +1671,9 @@ class _CThunk(object):
class OpWiseCLinker(link.LocalLinker): class OpWiseCLinker(link.LocalLinker):
"""WRITEME """
WRITEME
Uses CLinker on the individual Ops that comprise an fgraph and loops Uses CLinker on the individual Ops that comprise an fgraph and loops
over them in Python. The variable is slower than a compiled version of over them in Python. The variable is slower than a compiled version of
the whole fgraph, but saves on compilation time because small changes the whole fgraph, but saves on compilation time because small changes
...@@ -1554,10 +1687,12 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1554,10 +1687,12 @@ class OpWiseCLinker(link.LocalLinker):
If a Variable is in no_recycling, CLinker will clear the output storage If a Variable is in no_recycling, CLinker will clear the output storage
associated to it prior to computation (to avoid reusing it). associated to it prior to computation (to avoid reusing it).
:note: This is in a sense the 'default' linker for Theano. The Notes
-----
This is in a sense the 'default' linker for Theano. The
overhead of using the OpWiseCLinker as compared with the CLinker overhead of using the OpWiseCLinker as compared with the CLinker
is only noticeable for graphs of very small tensors (such as 20 is only noticeable for graphs of very small tensors (such as 20
elements or less) elements or less).
""" """
...@@ -1676,9 +1811,12 @@ class OpWiseCLinker(link.LocalLinker): ...@@ -1676,9 +1811,12 @@ class OpWiseCLinker(link.LocalLinker):
def _default_checker(x, y): def _default_checker(x, y):
"""WRITEME """
WRITEME
Default checker for DualLinker. This checks that the Default checker for DualLinker. This checks that the
variables contain the same data using ==. variables contain the same data using ==.
""" """
if x[0] != y[0]: if x[0] != y[0]:
raise Exception("Output mismatch.", raise Exception("Output mismatch.",
...@@ -1686,7 +1824,9 @@ def _default_checker(x, y): ...@@ -1686,7 +1824,9 @@ def _default_checker(x, y):
class DualLinker(link.Linker): class DualLinker(link.Linker):
"""WRITEME """
WRITEME
Runs the fgraph in parallel using PerformLinker and CLinker. Runs the fgraph in parallel using PerformLinker and CLinker.
The thunk/function produced by DualLinker uses PerformLinker as the The thunk/function produced by DualLinker uses PerformLinker as the
...@@ -1695,6 +1835,7 @@ class DualLinker(link.Linker): ...@@ -1695,6 +1835,7 @@ class DualLinker(link.Linker):
the fgraph on which it runs OpWiseCLinker. At each step, the variables the fgraph on which it runs OpWiseCLinker. At each step, the variables
of perform and of the C implementation are verified using a checker of perform and of the C implementation are verified using a checker
function. function.
""" """
def __init__(self, checker=_default_checker, schedule=None): def __init__(self, checker=_default_checker, schedule=None):
...@@ -1719,6 +1860,7 @@ class DualLinker(link.Linker): ...@@ -1719,6 +1860,7 @@ class DualLinker(link.Linker):
no_recycling can contain a list of Variables that belong to the fgraph. no_recycling can contain a list of Variables that belong to the fgraph.
If a Variable is in no_recycling, CLinker will clear the output storage If a Variable is in no_recycling, CLinker will clear the output storage
associated to it during the computation (to avoid reusing it). associated to it during the computation (to avoid reusing it).
""" """
self.fgraph = None self.fgraph = None
self.checker = checker self.checker = checker
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论