-
Notifications
You must be signed in to change notification settings - Fork 284
Fix for cbmc running out of memory while printing traces using json_ui / target: develop #1814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for cbmc running out of memory while printing traces using json_ui / target: develop #1814
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit message isn't very useful.
src/util/ui_message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is in the wrong commit.
src/cbmc/all_properties.cpp
Outdated
| { | ||
| jsont &json_trace=result["trace"]; | ||
| convert(bmc.ns, g.second.goto_trace, json_trace, bmc.trace_options()); | ||
| json_stream_arrayt &json_trace=result.push_back_stream_array("trace"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(commit for entire commit) This commit should come after the json_goto_trace refactoring.
src/util/json.cpp
Outdated
| } | ||
| } | ||
|
|
||
| void jsont::output_object(std::ostream &out, const objectt &object, unsigned indent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some doxygen would be good (sorry that I threw that over to you without docs).
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should go into the commit where this file was introduced
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these changes should go into the first commit
src/util/ui_message.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems still necessary as XML output hasn't been moved an xml_stream yet.
src/util/ui_message.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This include should come first.
src/util/ui_message.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unclear why this file is modified in this commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(comment for entire commit) These changes should be squashed with the previous commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to improve the commit message.
4dc26ce to
c3790b8
Compare
0086ac0 to
0a83f06
Compare
src/util/json.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unclear why this line is removed
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be some doxygen for all this
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes to this file should be in the previous commit.
src/util/message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a json_stream_arrayt variant, but no json_stream_objectt one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this include should be the first
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these changes should go into the first commit
src/goto-programs/json_goto_trace.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this non-const?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen missing throughout these files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this non-const?
|
@NlightNFotis, there's a compiliation error: https://travis-ci.org/diffblue/cbmc/jobs/339128397#L1550 |
|
Also, cpplint and clang-format are complaining. Be careful to reformat the changes in each commit separately. |
src/goto-programs/json_goto_trace.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a couple of header files that can be put into the cpp file.
268a8f5 to
7c8ea18
Compare
|
This should be ready to review, this only needs the clang format changes to be squashed to their appropriate commits. |
tautschnig
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR talks about fixing an out-of-memory problem, but then in the middle of the PR suddenly there is a refactoring commit as well. Lots of seemingly unnecessary whitespace changes. All of that makes reviewing extremely hard.
My main concern, however, is the core API that is not at all self-documenting. I get the problem that it is trying to solve, but it's very hard to tell whether that solution is actually fit for purpose. See details in my comments.
src/util/json.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the newline also be conditional on o_it!=object.beginn()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because an object always starts with an opening brace, after which we put a newline (code snippet factored out from lines 69-85 above).
src/util/json.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal, but out << "\": "; would also do the trick, wouldn't it?
src/util/json.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remote friends are bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary to have them.
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, that's a very strange piece of code. It seems to be extremely context-dependent and far from side-effect free.
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor does out << '[' so I'd expect this to be done in a destructor (otherwise the constructor shouldn't be doing the opening bracket).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what it is doing (by calling close() which, in turn, calls output_finalizer).
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit pick: no comma before "that"
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public operation is close - that's truly weird. Please create a meaningful API, which might have virtual ...(...) = 0; members - but at least it would explain how to use this thingy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public facility that this base class provides is close().
output_current and output_finalizer should be made abstract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this has happened? Maybe it has, but they are all protected so I have no idea what is the public interface of (children of) json_streamt.
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this fit in a "stream" class?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It allows mixing streamed and non-streamed json elements. The API enforces that the parent of a streamed element must always be a streamed element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it even make sense to mix them? Or is my above thought that a json_streamt is actually also some form of jsont that actually holds data?!
src/cbmc/all_properties.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These whitespace changes are unnecessary.
src/goto-programs/json_goto_trace.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be a template argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be able to use both the streaming and the object version.
8bb7f83 to
6544980
Compare
src/goto-programs/json_goto_trace.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be able to use both the streaming and the object version.
src/cbmc/all_properties.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These whitespace changes are unnecessary.
src/cbmc/bmc_cover.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this file are unnecessary.
src/util/json.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because an object always starts with an opening brace, after which we put a newline (code snippet factored out from lines 69-85 above).
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. There is some doxygen work to be done to explain how things fit together.
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This "new class" will soon be an "old class" ;)
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public facility that this base class provides is close().
output_current and output_finalizer should be made abstract.
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It allows mixing streamed and non-streamed json elements. The API enforces that the parent of a streamed element must always be a streamed element.
src/util/message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change seems unnecessary.
3e9a845 to
fdb4576
Compare
4e39f6d to
e74cdf6
Compare
3cedf1d to
8049ef1
Compare
|
I have added one last commit that attempts to fix the I will write a lengthier report about what was happening and why this is necessary later. |
8049ef1 to
63140dd
Compare
peterschrammel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @NlightNFotis, this looks good now. Please update the TG bump.
tautschnig
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Various comments below, with the definitive blocker of using std::cout (and thus iostream) in a header file.
I'm still not sure I'm on the right track: do we now have multiple classes that serve one and the same purpose, but differ in how output is implemented? Does this mix data representation and behaviour? Are you solving an original design deficiency in that a jsont took care of its own output by adding a variant that takes care of its own output in a different way? Shouldn't output just never have been a member function of jsont? Isn't this one of the prototypical situations to use the visitor pattern? Even more so as jsont is the root of a nice family of classes, and also a very much bounded one so that it wouldn't be necessary to add more members to a visitor (as is sort of the case for anything based on irept)?
src/util/message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain why this isn't get_json_stream() = 0; or marked protected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change it to get_json_stream() = 0; then I get compilation errors that some variables, such as message_handler in line 189 of graphml.cpp can not be initialised to an abstract type. I understand that this happens because other members of the hierarchy, like null_message_handlert are not redefining get_json_stream(), a now pure virtual function.
If it's marked protected, that creates problems with the interaction with the class mstreamt in the same file (message.h, line 184), particularly with the method json_stream() in line 244, which contains the statement return message.message_handler->get_json_stream();, which can not work with get_json_stream() being protected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change it to
get_json_stream() = 0;then I get compilation errors that some variables, such asmessage_handlerin line 189 ofgraphml.cppcan not be initialised to an abstract type. I understand that this happens because other members of the hierarchy, likenull_message_handlertare not redefiningget_json_stream(), a now pure virtual function.
To me, this looks like a prime example of why compile-time errors are preferable over runtime errors: in my opinion, that just means that null_message_handlert needs to be fixed.
src/util/message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe a forward declaration class json_stream_arrayt; would suffice.
src/util/json.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you remove this, then also the public in line 123 is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, this shouldn't be removed. Only move the function that is required to the public section.
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this prone to attempts of closing a closed file? child_stream is not reset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closing closed files is not a practical issue here because json_streamt only wraps the actual stream (that could be a file). json_streamt never closes that stream - that's in the realm of the user of json_streamt. However, to avoid confusion, I would assign child_stream = nullptr here and put appropriate PRECONDITIONS to make sure that there is no double-close (which is indeed a sign of a programming error).
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of all these push_back_stream* functions ("Add a JSON ..." -- to what?) as none of them are invoked anywhere in this commit, and why aren't they just a single one in the parent class? I understand that they have different return types, but is that actually necessary (as anything done to those return values can be resolved to the right child class via virtual tables)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be very inconvenient to let the user cast to json_stream_arrayt and json_stream_objectt in order to use their respective interfaces (objects and arrays are quite different things).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this fits with my overall comment: there seems to be a strong case for re-architecting here to use a visitor rather than this proposed design of inheritance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tautschnig, could you please explain how 'use a visitor' would contribute to a solution in this context?
Inheritance is used here because json_stream_arrayt and json_stream_objectt are both json streams, which share common functionality, namely flushing the data. If this is considered too little to justify a base class the common code can be duplicated in the respective derived classes at the cost of complicating the logic to flush the stream and to enforce the single-stream-at-a-time invariant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, there should be one class that knows how to stream jsont. That class would be the visitor. It has methods that know how to stream a json_arrayt or json_objectt (and json_numbert, json_stringt, etc.).
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need compatibility with jsont? Are you saying that this some sort of replacement for jsont? Please tell me that I'm wrong.
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it even make sense to mix them? Or is my above thought that a json_streamt is actually also some form of jsont that actually holds data?!
src/util/message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a json_stream_arrayt variant, but no json_stream_objectt one?
src/util/ui_message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. Not in a header file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, the implementation of the constructor must go into the .cpp file.
src/util/ui_message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, there seems to be no point of even having a std::ostream member as there is a single function that relies on it, and no way to setting it to any other value. Second, this has no place in a header file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, out is used many, many times in the .cpp file. Eventually, assigning out should be the only use of std::cout in the codebase.
The implementation of the constructor must be moved back into the cpp file.
src/util/json.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, this shouldn't be removed. Only move the function that is required to the public section.
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are actually quite similar. The only difference is that array elements don't have keys.
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closing closed files is not a practical issue here because json_streamt only wraps the actual stream (that could be a file). json_streamt never closes that stream - that's in the realm of the user of json_streamt. However, to avoid confusion, I would assign child_stream = nullptr here and put appropriate PRECONDITIONS to make sure that there is no double-close (which is indeed a sign of a programming error).
src/util/json_stream.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be very inconvenient to let the user cast to json_stream_arrayt and json_stream_objectt in order to use their respective interfaces (objects and arrays are quite different things).
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. open is the state of this not child_stream. You can create and close many child streams sequentially (timewise), e.g. for each element in an array or each property in an object). The invariant is that there can only be at most child stream at a time.
src/util/json_stream.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, it seems that open requires explanation.
src/util/ui_message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, the implementation of the constructor must go into the .cpp file.
src/util/ui_message.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, out is used many, many times in the .cpp file. Eventually, assigning out should be the only use of std::cout in the codebase.
The implementation of the constructor must be moved back into the cpp file.
63140dd to
4cf7dfc
Compare
|
Hi @tautschnig. I think your concerns have been addressed. Is it possible that you take another look and let me know if there's anything more you want to be done, else give it the green light? Thanks for your time, |
|
To what extent has #1814 (comment):
been addressed? Anyone is free to override my non-approval, but I do maintain that the architecture here is flawed and that implementing a different form of output by inheriting and overriding the data representation is wrong. |
|
@tautschnig As the person who had the initial problem -- would it help if I had a review? |
|
@martin-cs Your reviews are always welcome! It may very well be the case that an urgent solution is required and I thus invite overrides to my non-approval. Any maybe my suggested architecture is also flawed. I'm always open to input. |
4cf7dfc to
496476a
Compare
Introduce a new json object class that streams the object immediately to an output instead of building the object in memory and then output it to the stream.
Refactor the templated convert function with switch statements that handle different instructions to dispatch to functions that are specialised per instruction.
496476a to
123be20
Compare
|
@tautschnig @peterschrammel I have been made aware that there have been offline discussions regarding the architectural changes in this PR, and the disagreements have been resolved. Can you both take a look to let me know if everything is alright, and if yes, possibly merge it as well? @peterschrammel The associated testgen PR is also passing with no problems |
|
My apologies for having been dense and not fully understanding the problem this was trying to solve. It took an out-of-band chat with @peterschrammel to get me on track: it was not clear to me that constructing the Here is what I would have done: make |
This is a port of #1767 to
develop(instead ofgoto-analyzer-developas requested by @peterschrammel and @martin-cs . Below is the message of the original PR:There has been a bug reported to us where cbmc would run out of memory while creating a huge json object in memory to report the traces with. This is changing the tracing report facility to use a new json class that streams the objects immediately as created, and therefore fixes the issue.