cjdrake / pyeda

Python EDA
BSD 2-Clause "Simplified" License
305 stars 55 forks source link

Memory leak when printing large funtions #131

Closed JoBaehr closed 7 years ago

JoBaehr commented 8 years ago

Hi, I am generating large boolean functions from circuit netlists using python3 (v 3.4.3, 64 bit, ubuntu v14.04), networkx and pyeda v 0.28.0. Once these functions are above a certain size, they are no longer printable. I have attached a copy of the code used to generate the functions, including three different circuit modules (round module, c432 and add_sub module). The add_sub module works fine. The c432 module very quickly exhaust 8 GB memory. When limiting my memory to approx 30 GB (using the round module, 24 input variables), after all the memory has been used, the following error occurs:

Traceback (most recent call last):
  File "pyeda_test.py", line 206, in <module>
    print(out_function)
  File "/usr/local/lib/python3.4/dist-packages/pyeda/boolalg/expr.py",
line 1122, in __str__
    return "{}({})".format(self.NAME, ', '.join(str(x) for x in self.xs))
  File "/usr/local/lib/python3.4/dist-packages/pyeda/boolalg/expr.py",
line 1122, in <genexpr>
    return "{}({})".format(self.NAME, ', '.join(str(x) for x in self.xs))
  File "/usr/local/lib/python3.4/dist-packages/pyeda/boolalg/expr.py",
line 1122, in __str__
    return "{}({})".format(self.NAME, ', '.join(str(x) for x in self.xs))
.... (repeated) ....
  File "/usr/local/lib/python3.4/dist-packages/pyeda/boolalg/expr.py",
line 1122, in __str__
    return "{}({})".format(self.NAME, ', '.join(str(x) for x in self.xs))
MemoryError

Without a set limit, the program will use all available memory and crash. I am able to work with the functions (ie Xnor several functions etc.), the problem only arises when I need to print them or write them to file.

pyeda_test.zip

cjdrake commented 8 years ago

I tried opening that zip file, but got this error:

Archive:  pyeda_test.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of pyeda_test.zip or
        pyeda_test.zip.zip, and cannot find pyeda_test.zip.ZIP, period.
cjdrake commented 8 years ago

That time the file unzipped fine, but the add_sub, c432, and round directories are empty. It looks like the pyeda_test.py script requires files from those directories.

JoBaehr commented 8 years ago

Sorry: pyeda_test.zip

cjdrake commented 8 years ago

I ran into some Python 2/3 problems while trying to run the modules in your zip file.

What makes you think this is a memory leak, and not just an expression that's too big to fit in a string? The string conversion is all done in Python, so if there's a memory "leak" it might be in CPython itself, which seems a bit unlikely.

But I have a theory. Take a look at line 1124 of expr.py:

@cached_property
def xs(self):
    """Return a tuple of this operator's arguments."""
    return tuple(_expr(node) for node in self.node.data())

Since it uses cached_property, it will store that value permanently.

Try changing cached_property to just property, and see if you can get the computation to fit in memory. In fact, try doing a search/replace of all cached_property invocations in that module.

Let me know what you find out.