提交 05f3bfcb authored 作者: Arnaud Bergeron's avatar Arnaud Bergeron

Add a basic GC to the CVM just like VM has.

上级 7527d285
......@@ -84,6 +84,8 @@ typedef struct {
int * var_computed; // 1 or 0 for every variable
PyObject ** var_computed_cells;
PyObject ** var_value_cells;
Py_ssize_t **dependencies; // list of vars dependencies for GC
Py_ssize_t *n_dependencies;
Py_ssize_t n_output_vars;
Py_ssize_t * output_vars; // variables that *must* be evaluated by call
......@@ -140,6 +142,16 @@ CLazyLinker_dealloc(PyObject* _self)
free(self->node_inputs);
free(self->node_outputs);
if (self->dependencies)
{
for (int i = 0; i < self->n_vars; ++i)
{
free(self->dependencies[i]);
}
free(self->dependencies);
free(self->n_dependencies);
}
free(self->var_owner);
free(self->var_has_owner);
free(self->var_computed);
......@@ -179,6 +191,8 @@ CLazyLinker_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->var_computed = NULL;
self->var_computed_cells = NULL;
self->var_value_cells = NULL;
self->dependencies = NULL;
self->n_dependencies = NULL;
self->n_output_vars = 0;
self->output_vars = NULL;
......@@ -234,6 +248,7 @@ CLazyLinker_init(CLazyLinker *self, PyObject *args, PyObject *kwds)
(char*)"node_prereqs",
(char*)"node_output_size",
(char*)"update_storage",
(char*)"dependencies",
NULL};
PyObject *compute_map_list=NULL,
......@@ -248,10 +263,11 @@ CLazyLinker_init(CLazyLinker *self, PyObject *args, PyObject *kwds)
*output_vars=NULL,
*node_prereqs=NULL,
*node_output_size=NULL,
*update_storage=NULL;
*update_storage=NULL,
*dependencies=NULL;
assert(!self->nodes);
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OOOiOOOOOOOOOOOOOOO", kwlist,
if (! PyArg_ParseTupleAndKeywords(args, kwds, "OOOiOOOOOOOOOOOOOOOO", kwlist,
&self->nodes,
&self->thunks,
&self->pre_call_clear,
......@@ -270,7 +286,8 @@ CLazyLinker_init(CLazyLinker *self, PyObject *args, PyObject *kwds)
&output_vars,
&node_prereqs,
&node_output_size,
&update_storage
&update_storage,
&dependencies
))
return -1;
Py_INCREF(self->nodes);
......@@ -423,6 +440,23 @@ CLazyLinker_init(CLazyLinker *self, PyObject *args, PyObject *kwds)
return -1;
}
if (dependencies != Py_None)
{
self->dependencies = (Py_ssize_t**)calloc(self->n_vars, sizeof(Py_ssize_t *));
self->n_dependencies = (Py_ssize_t*)calloc(self->n_vars, sizeof(Py_ssize_t));
assert(self->dependencies);
assert(self->n_dependencies);
for (int i = 0; i < self->n_vars; ++i)
{
PyObject *tmp = PyList_GetItem(dependencies, i);
// refcounting - tmp is borrowed
if (unpack_list_of_ssize_t(tmp, &self->dependencies[i], &self->n_dependencies[i],
"dependencies"))
return -1;
}
}
if (unpack_list_of_ssize_t(output_vars, &self->output_vars, &self->n_output_vars,
"output_vars"))
return -1;
......@@ -705,6 +739,42 @@ int lazy_rec_eval(CLazyLinker * self, Py_ssize_t var_idx, PyObject*one, PyObject
self->var_computed[self->node_outputs[owner_idx][i]] = 1;
}
// Free vars that are not needed anymore
if (self->allow_gc)
{
for (int i = 0; i < self->node_n_inputs[owner_idx]; ++i)
{
int cleanup = 1;
Py_ssize_t i_idx = self->node_inputs[owner_idx][i];
if (!self->var_has_owner[i_idx])
continue;
for (int j = 0; j < self->n_output_vars; ++j)
{
if (i_idx == self->output_vars[j])
{
cleanup = 0;
break;
}
}
if (!cleanup) continue;
for (int j = 0; j < self->n_dependencies[i_idx]; ++j)
{
if (!self->var_computed[self->dependencies[i_idx][j]])
{
cleanup = 0;
break;
}
}
if (!cleanup) continue;
Py_INCREF(Py_None);
err = PyList_SetItem(self->var_value_cells[i_idx], 0, Py_None);
if (err) goto fail;
}
}
return 0;
pyfail:
Py_DECREF(rval);
......@@ -791,6 +861,17 @@ CLazyLinker_call(PyObject *_self, PyObject *args, PyObject *kwds)
Py_INCREF(tmp);
PyList_SetItem(self->var_value_cells[dst], 0, tmp);
}
// Free all intermediate values (outputs and updates have
// already been copied above).
if (self->allow_gc)
{
for (int i = 0; i < self->n_vars; ++i)
{
Py_INCREF(Py_None);
PyList_SetItem(self->var_value_cells[i], 0, Py_None);
}
}
}
}
Py_DECREF(one);
......@@ -874,7 +955,7 @@ static PyTypeObject lazylinker_ext_CLazyLinkerType = {
static PyObject * get_version(PyObject *dummy, PyObject *args)
{
PyObject *result = PyFloat_FromDouble(0.13);
PyObject *result = PyFloat_FromDouble(0.14);
return result;
}
......
......@@ -13,7 +13,7 @@ if config.compiledir not in sys.path:
sys.path.append(config.compiledir)
force_compile = False
version = 0.13 # must match constant returned in function get_version()
version = 0.14 # must match constant returned in function get_version()
try:
......
......@@ -184,9 +184,8 @@ class Stack(VM):
"""
def __init__(self, nodes, thunks, pre_call_clear,
storage_map, compute_map,
env, allow_gc,
callback=None):
storage_map, compute_map, env, allow_gc,
dependencies=None, callback=None):
super(Stack, self).__init__(nodes, thunks, pre_call_clear)
self.allow_gc = allow_gc
......@@ -211,16 +210,11 @@ class Stack(VM):
for prereq in ords[node]:
node.destroy_dependencies += prereq.outputs
dependencies = self.dependencies = {}
for k in storage_map:
dependencies[k] = []
if k.owner and k.clients:
ls = []
is_output = 0
for cl in k.clients:
if cl[0] is not 'output':
ls += cl[0].outputs
dependencies[k] += ls
self.dependencies = dependencies
if self.allow_gc and self.dependencies is None:
raise ValueError("Must set dependencies when using GC")
if config.profile:
self.memory_size_map = {"nt8": 1, "t16": 2, "t32": 4,
"t64": 8, "128": 16}
......@@ -454,6 +448,19 @@ class VM_Linker(link.LocalLinker):
# admittedly confusing, and it could use some cleaning up. The base
# Linker object should probably go away completely.
def compute_gc_dependencies(self, smap):
dependencies = {}
for k in smap:
dependencies[k] = []
if k.owner and k.clients:
ls = []
is_output = 0
for cl in k.clients:
if cl[0] is not 'output':
ls += cl[0].outputs
dependencies[k] += ls
return dependencies
def make_vm(self, nodes, thunks,
input_storage, output_storage, storage_map,
post_thunk_clear,
......@@ -467,10 +474,14 @@ class VM_Linker(link.LocalLinker):
if self.callback is not None:
if self.use_cloop:
logger.warn('CLoop does not support callback, using Stack VM.')
deps = None
if self.allow_gc:
deps = self.compute_gc_dependencies(storage_map)
vm = Stack(
nodes, thunks, pre_call_clear,
storage_map, compute_map,
self.env, self.allow_gc,
dependencies=deps,
callback=self.callback)
elif self.use_cloop:
# create a map from nodes to ints and vars to ints
......@@ -500,6 +511,14 @@ class VM_Linker(link.LocalLinker):
assert type(storage_map_list[0]) is list
assert type(compute_map_list[0]) is list
if self.allow_gc:
dependency_map=self.compute_gc_dependencies(storage_map)
dependency_map_list = [
[vars_idx[d] for d in dependency_map[vars_idx_inv[i]]]
for i in xrange(len(vars_idx_inv))]
else:
dependency_map_list = None
# build the pointers to node inputs and offsets
base_input_output_list = []
node_n_inputs = []
......@@ -566,6 +585,7 @@ class VM_Linker(link.LocalLinker):
node_prereqs=node_prereqs,
node_output_size=node_output_size,
update_storage=update_storage,
dependencies=dependency_map_list,
)
assert c0 == sys.getrefcount(node_n_inputs)
else:
......@@ -583,10 +603,14 @@ class VM_Linker(link.LocalLinker):
thunks,
pre_call_clear)
else:
deps = None
if self.allow_gc:
deps = self.compute_gc_dependencies(storage_map)
vm = Stack(
nodes, thunks, pre_call_clear,
storage_map, compute_map,
self.env, self.allow_gc
self.env, self.allow_gc,
dependencies=deps
)
return vm
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论