-
Notifications
You must be signed in to change notification settings - Fork 82
inspect memory limit fix #100
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
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.
Some (mostly) code style problems must be addressed before merging
bin/rdebug-ide
Outdated
@@ -45,6 +51,7 @@ EOB | |||
options.evaluation_timeout = timeout | |||
end | |||
opts.on('--stop', 'stop when the script is loaded') {options.stop = true} | |||
|
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.
Is this change needed here?
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.
fixed
bin/rdebug-ide
Outdated
@@ -154,4 +161,4 @@ if options.attach_mode | |||
end | |||
else | |||
Debugger.debug_program(options) | |||
end |
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.
formatting
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -380,9 +384,37 @@ def max_compact_name_size | |||
50 | |||
end | |||
|
|||
def inspect_with_allocation_control(slice, memory_limit) | |||
x = Thread.current |
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.
Can we conceive a better name for this variable? Like current_thread
, start_thread
or alike
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
trace = TracePoint.new(:c_call, :call) do |tp| | ||
curr_alloc_size = ObjectSpace.memsize_of_all | ||
|
||
if(curr_alloc_size - start_alloc_size > 1e6*memory_limit) |
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.
spacing
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
end | ||
end | ||
|
||
trace.enable |
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 it's better to use TracePoint#enable( &block)
here
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.
TracePoint#enable( &block) works differently
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.
Could you please elaborate more?
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 a block is given, the trace will only be enabled within the scope of the block.
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 implementation, the checks are carried out more often, which means that the probability of detecting an overflow increases
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.
Yes, so I suggest changing these three lines with
trace.enable { slice.inspect }
In my implementation, the checks are carried out more often, which means that the probability of detecting an overflow increases
Sorry, did not get what overflow you're talking about.
lib/ruby-debug-ide/xml_printer.rb
Outdated
slice.inspect | ||
trace.disable | ||
rescue MemoryLimitError | ||
return nil |
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.
Do you think it makes sense to add some logging for such cases? Or return something very special
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.
Added logging
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 printing also a stacktrace of an exception may help investigating the problems in inspect
calls for users.
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 backtrack will end with the calls of our debase and r-d-i methods. I think that this is not very useful.
lib/ruby-debug-ide/xml_printer.rb
Outdated
def compact_array_str(value) | ||
slice = value[0..10] | ||
compact = slice.inspect | ||
|
||
if (defined?(JRUBY_VERSION) || ENV['DEBUGGER_MEMORY_LIMIT'].to_i <= 0) |
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 could be replaced with compact = if (...)
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 do not think that this is applicable in this case
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 so? Please see https://github.com/bbatsov/ruby-style-guide#use-if-case-returns
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -425,4 +457,4 @@ def build_value_attr(escaped_value_str) | |||
|
|||
end | |||
|
|||
end | |||
end |
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.
formatting
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.
fixed
a6dff63
to
9665253
Compare
lib/ruby-debug-ide/command.rb
Outdated
@@ -118,7 +118,7 @@ def timeout(sec) | |||
def debug_eval(str, b = get_binding) | |||
begin | |||
str = str.to_s | |||
str.force_encoding('UTF-8') if(RUBY_VERSION > 2.0) | |||
str.force_encoding('UTF-8') if(RUBY_VERSION > '2.0') |
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.
does this relate to the logging changes?
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -45,6 +45,7 @@ def initialize(interface) | |||
end | |||
|
|||
def print_msg(*args) | |||
puts 'def print_msg(*args)' |
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.
Is this puts
needed?
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -413,7 +415,7 @@ def compact_array_str(value) | |||
compact = if (defined?(JRUBY_VERSION) || ENV['DEBUGGER_MEMORY_LIMIT'].to_i <= 0) | |||
slice.inspect | |||
else | |||
compact = inspect_with_allocation_control(slice, ENV['DEBUGGER_MEMORY_LIMIT'].to_i) | |||
compact = inspect_with_allocation_control(slice, ENV['DEBUGGER_MEMORY_LIMIT'].to_i, value.object_id.to_s) |
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 am not sure object_id
us really useful for logging purposes: it does not tell anything about the object. I think the previous message already a good start.
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -404,6 +405,7 @@ def inspect_with_allocation_control(slice, memory_limit) | |||
trace.disable | |||
result | |||
rescue MemoryLimitError => e | |||
print_msg(e.message) |
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 one may make use of --debug
option here:
opts.on("-d", "--debug", "Debug self - prints information for debugging ruby-debug itself") do
Debugger.cli_debug = true
options.cli_debug = true
end
bin/rdebug-ide
Outdated
@@ -37,8 +37,8 @@ EOB | |||
opts.separator "" | |||
opts.separator "Options:" | |||
|
|||
ENV['DEBUGGER_MEMORY_LIMIT'] = '10' | |||
opts.on("-m", "--memory-limit LIMIT", Integer, "evaluation memory limit in mb (default: 10)") do |limit| | |||
ENV['DEBUGGER_MEMORY_LIMIT'] = '1' |
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 stands behind such defaults change? Could you please reason it?
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.
With 10 you have to wait for a pretty long time
lib/ruby-debug-ide/xml_printer.rb
Outdated
curr_thread.raise MemoryLimitError, "Out of memory: evaluation of inspect took more than #{memory_limit}mb." if curr_thread.alive? | ||
end | ||
if Thread.respond_to?(:critical) and Thread.critical | ||
raise ThreadError, "memory_limit within critical session" |
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.
AFAIU the execution of that line does not mean memory limit is exceeded. What does this check?
lib/ruby-debug-ide/xml_printer.rb
Outdated
start_alloc_size = ObjectSpace.memsize_of_all | ||
trace = TracePoint.new(:c_call, :call) do |tp| | ||
curr_alloc_size = ObjectSpace.memsize_of_all | ||
start_alloc_size = curr_alloc_size if (curr_alloc_size < start_alloc_size) |
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 case of GC?
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.
exactly
lib/ruby-debug-ide/xml_printer.rb
Outdated
result = nil | ||
inspect_thread = DebugThread.start { | ||
start_alloc_size = ObjectSpace.memsize_of_all | ||
trace = TracePoint.new(:c_call, :call) do |tp| |
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.
Do you need trace
variable? I don't see any usages..
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'll disable it through 'trace'
lib/ruby-debug-ide/xml_printer.rb
Outdated
|
||
if(curr_alloc_size - start_alloc_size > 1e6 * memory_limit) | ||
curr_thread.raise MemoryLimitError, "Out of memory: evaluation of inspect took more than #{memory_limit}mb. \n#{caller.map{|l| "\t#{l}"}.join("\n")}" | ||
inspect_thread.kill |
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'd rather move this kill to line 410, after join. It seems strange to me to kill the thread from this thread itself.
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -389,9 +392,19 @@ def inspect_with_allocation_control(slice, memory_limit) | |||
result = nil | |||
inspect_thread = DebugThread.start { | |||
start_alloc_size = ObjectSpace.memsize_of_all |
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.
Overall looks nice. One last question: do you think such checks on every call will slow down the execution?
The possible solution there is to make these checks only in 10% of calls (like Math.random > 0.9
) or alike
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.
Most often 'inspect' works fast and requires little memory, so in general the performance should not slow down. And in case of heavy inspect-s, when using probability, everything can crush with a high probability. Then why was this fix at all?)
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.
Perhaps, it is worth running a :call and :c_call handler a little less often. Every fifth, for example.
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.
Perhaps, it is worth running a :call and :c_call handler a little less often. Every fifth, for example.
That's what I'm talking about.
inspect
often works fast, but
- We add constant overhead on each call which may slow execution down in dozens of times;
- There are many
inspects
during variables collection so in total this matters
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 still getting an INTERNAL ERROR (pipe or something) when using probabilistic scheme. Apparently, it is better to abandon this proposal.
https://pastebin.com/SL8R1DGc
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.
Can you show the snippet you're using to achieve the result?
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.
fixed
lib/ruby-debug-ide/xml_printer.rb
Outdated
inspect_thread = DebugThread.start { | ||
start_alloc_size = ObjectSpace.memsize_of_all | ||
start_time = Time.now | ||
max_time = Debugger.evaluation_timeout |
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 10s evaluation timeout is too much for this place. The reason is that evaluation is an explicit user action so it's OK to try to wait for a possibly long evaluation. In the case of convenience infos calculated dozens of times per breakpoint, 10s does not make much sense to me. I'd say we should make it somewhere between 100 and 500ms.
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.
Minor changes still needed
lib/ruby-debug-ide/xml_printer.rb
Outdated
@@ -144,7 +158,46 @@ def print_string(string) | |||
print_variable('encoding', string.encoding, 'instance') if string.respond_to?('encoding') | |||
end | |||
end | |||
|
|||
|
|||
def exec_with_allocation_control(value, memory_limit, time_limit, exec_method, flag) |
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 does flag
mean? Not a helpful name for a parameter
lib/ruby-debug-ide/xml_printer.rb
Outdated
attr_reader :message | ||
attr_reader :backtrace | ||
|
||
def initialize(message, backtrace) |
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 one does not provide default backtrace
value and the one below does. Is that intentional?
lib/ruby-debug-ide/xml_printer.rb
Outdated
rescue MemoryLimitError, TimeLimitError => e | ||
print_debug(e.message + "\n" + e.backtrace) | ||
|
||
return nil if flag |
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.
ternary
Squashed and merged into master. |
Sets a memory limit for execution of inspect (default 10mb)