https://redmine.ruby-lang.org/https://redmine.ruby-lang.org/favicon.ico?17113305112019-12-04T00:48:39ZRuby Issue Tracking SystemRuby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=829522019-12-04T00:48:39Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul><li><strong>File</strong> <a href="/attachments/8197">tracepoint-attr-16383.patch</a> <a class="icon-only icon-download" title="Download" href="/attachments/download/8197/tracepoint-attr-16383.patch">tracepoint-attr-16383.patch</a> added</li></ul><p>I'm not sure if skipping tracing for these methods is on purpose for performance reasons or not, but I agree it would be useful to be able to trace such method calls. Attached is a patch that implements tracing for <code>attr_reader</code>/<code>attr_writer</code> method calls. I'm not sure it is correct, but with the following code:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Person</span>
<span class="nb">attr_accessor</span> <span class="ss">:first_name</span>
<span class="nb">attr_accessor</span> <span class="ss">:last_name</span>
<span class="k">def</span> <span class="nf">name</span>
<span class="s2">"</span><span class="si">#{</span><span class="nb">self</span><span class="p">.</span><span class="nf">last_name</span><span class="si">}</span><span class="s2">, </span><span class="si">#{</span><span class="nb">self</span><span class="p">.</span><span class="nf">first_name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">person</span> <span class="o">=</span> <span class="no">Person</span><span class="p">.</span><span class="nf">new</span>
<span class="n">trace</span> <span class="o">=</span> <span class="no">TracePoint</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">:c_call</span><span class="p">,</span> <span class="ss">:call</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">tp</span><span class="o">|</span>
<span class="nb">p</span> <span class="p">[</span><span class="n">tp</span><span class="p">.</span><span class="nf">path</span><span class="p">,</span> <span class="n">tp</span><span class="p">.</span><span class="nf">lineno</span><span class="p">,</span> <span class="n">tp</span><span class="p">.</span><span class="nf">defined_class</span><span class="p">,</span> <span class="n">tp</span><span class="p">.</span><span class="nf">event</span><span class="p">,</span> <span class="n">tp</span><span class="p">.</span><span class="nf">callee_id</span><span class="p">]</span>
<span class="k">end</span>
<span class="n">trace</span><span class="p">.</span><span class="nf">enable</span>
<span class="n">person</span><span class="p">.</span><span class="nf">first_name</span> <span class="o">=</span> <span class="s1">'Josh'</span>
<span class="n">person</span><span class="p">.</span><span class="nf">last_name</span> <span class="o">=</span> <span class="s1">'McGibbon'</span>
<span class="n">person</span><span class="p">.</span><span class="nf">name</span>
<span class="n">trace</span><span class="p">.</span><span class="nf">disable</span>
</code></pre>
<p>I get the following output:</p>
<pre><code>["t.rb", 14, Person, :c_call, :first_name=]
["t.rb", 15, Person, :c_call, :last_name=]
["t.rb", 4, Person, :call, :name]
["t.rb", 5, Person, :c_call, :last_name]
["t.rb", 5, Person, :c_call, :first_name]
["<internal:trace_point>", 231, TracePoint, :call, :disable]
</code></pre>
<p>Note that because <code>attr_reader</code>/<code>attr_writer</code> are implemented in C, I choose <code>:c_call</code> and <code>:c_return</code> instead of <code>:call</code> and <code>:return</code>. There is at least a bug in that <code>method_id</code> is incorrect, showing the instance variable symbol instead of the method symbol.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=838322020-01-14T03:40:15Zmame (Yusuke Endoh)mame@ruby-lang.org
<ul><li><strong>Related to</strong> <i><a class="issue tracker-1 status-5 priority-4 priority-default closed" href="/issues/10470">Bug #10470</a>: TracePoint cannot trace attr_accessor/reader/writer method</i> added</li></ul> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=838682020-01-14T18:35:54Zko1 (Koichi Sasada)
<ul></ul><p>miniruby.modif is patch applied version.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Benchmark</span><span class="p">.</span><span class="nf">driver</span><span class="p">(</span><span class="ss">repeat_count: </span><span class="mi">10</span><span class="p">){</span><span class="o">|</span><span class="n">x</span><span class="o">|</span>
<span class="n">x</span><span class="p">.</span><span class="nf">executable</span> <span class="ss">name: </span><span class="s1">'clean'</span><span class="p">,</span> <span class="ss">command: </span><span class="sx">%w'./miniruby'</span>
<span class="n">x</span><span class="p">.</span><span class="nf">executable</span> <span class="ss">name: </span><span class="s1">'modif'</span><span class="p">,</span> <span class="ss">command: </span><span class="sx">%w'./miniruby.modif'</span>
<span class="n">x</span><span class="p">.</span><span class="nf">prelude</span> <span class="sx">%q{
class C
attr_reader :x
def initialize
@x = nil
end
end
obj = C.new
}</span>
<span class="n">x</span><span class="p">.</span><span class="nf">report</span> <span class="s1">'obj.x*64'</span><span class="p">,</span> <span class="s2">"obj.x; "</span> <span class="o">*</span> <span class="mi">64</span>
<span class="p">}</span>
</code></pre>
<pre><code>Warming up --------------------------------------
obj.x*64 1.697M i/s - 1.712M times in 1.008554s (589.26ns/i)
Calculating -------------------------------------
clean modif
obj.x*64 1.773M 1.364M i/s - 5.091M times in 2.870868s 3.731838s
Comparison:
obj.x*64
clean: 1773371.7 i/s
modif: 1364238.2 i/s - 1.30x slower
</code></pre>
<p>On microbenchmark, it is 30% slower, so we need to invent a hack to support it.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=839102020-01-16T07:28:51Zko1 (Koichi Sasada)
<ul></ul><ul>
<li>matz: good to have, but not a showstopper</li>
</ul> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=844972020-03-05T21:51:11ZEregon (Benoit Daloze)
<ul></ul><p>Are there plans to implement this in master, any timeline?</p>
<p>Andy Maleh wants to add specs for this in <a href="https://github.com/ruby/spec/pull/761" class="external">https://github.com/ruby/spec/pull/761</a> which is nice but we would need an expected fix version.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=844982020-03-06T00:09:41Zheadius (Charles Nutter)headius@headius.com
<ul></ul><blockquote>
<p>On microbenchmark, it is 30% slower, so we need to invent a hack to support it.</p>
</blockquote>
<p>In JRuby, that hack is called the <code>--debug</code> flag, which enables the full set of traces. At some point CRuby's probably going to have to do something similar, or else every operation in Ruby's going to pay the price of traces whether they're used or not.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=894902020-12-24T03:48:19ZAndyMaleh (Andy Maleh)
<ul></ul><p>Hi,</p>
<p>I compensated for lack of this feature by implementing <strong>manually-configured</strong> computed data-binding in <a href="https://github.com/AndyObtiva/glimmer-dsl-tk#hello-computed" class="external">Glimmer DSL for Tk</a> (Ruby Desktop Development GUI Library), <a href="https://github.com/AndyObtiva/glimmer-dsl-swt#hello-computed" class="external">Glimmer DSL for SWT</a> (JRuby Desktop Development GUI Library), and <a href="https://github.com/AndyObtiva/glimmer-dsl-opal#hello-computed" class="external">Glimmer DSL for Opal</a> (Pure Ruby Web GUI and Auto-Webifier of Desktop Apps via Opal on Rails).</p>
<p>Example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">label</span> <span class="p">{</span>
<span class="n">text</span> <span class="n">bind</span><span class="p">(</span><span class="vi">@contact</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">computed_by: </span><span class="p">[</span><span class="ss">:first_name</span><span class="p">,</span> <span class="ss">:last_name</span><span class="p">])</span>
<span class="p">}</span>
</code></pre>
<p>Alternatively, the <code>#first_name</code> and <code>#last_name</code> attributes could be implemented in the model as methods that notify observers of <code>#name</code> that it changed when called.</p>
<p>Still, I'd like to go a step further and implement <strong>automatic</strong> computed data-binding with simpler syntax:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">label</span> <span class="p">{</span>
<span class="n">text</span> <span class="n">bind</span><span class="p">(</span><span class="vi">@contact</span><span class="p">,</span> <span class="ss">:name</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>That way, Glimmer could automatically figure out through calling the <code>Contact#name</code> method that it calls the <code>first_name</code> and <code>last_name</code> attributes, and then hook observers to them for change notifications to update the GUI.</p>
<p>I was wondering if there is any chance to have this missing feature (tracing attribute calls) supported in Ruby 3.0 via an extra <code>ruby</code> command option (e.g. --trace-func) as per Charles Nutter's suggestion to avoid slowing down general app performance when this feature is not needed. Perhaps even make it configurable (e.g. --trace-func=attr_accessor for attribute-tracing only, or a comma separated list like --trace-func=methods,attr_reader) to ensure further that the performance hit is limited when the feature is needed.</p>
<p>I realize this feature (automatic computed data-binding) is very new and has not been proven as feasible for practical application development, but I have not seen it implemented anywhere else (e.g. Java/JavaScript) with this level of automation (knowing which variables to observe without manual configuration), and I believe Ruby is the language to make that happen if any, so I'd really like to give it a go.</p>
<p>Cheers,</p>
<p>Andy Maleh</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=918882021-05-09T06:57:59Zst0012 (Stan Lo)stan001212@gmail.com
<ul></ul><p>This may be a long shot, but would it be possible to make a c extension and apply a patch <a href="https://bugs.ruby-lang.org/attachments/8197" class="external">similar to this</a> from a gem?</p>
<p>I also think the <code>--debug</code> flag mentioned by Charles is an excellent idea. If we can hide debugging features behind a flag, they'll be easier to implement and have a faster development cycle.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=926012021-06-18T22:10:18Zjeremyevans0 (Jeremy Evans)merch-redmine@jeremyevans.net
<ul></ul><p>After thinking more regarding this issue, if we want no overhead by default, and only overhead if this feature is enabled via a command line flag (similar to JRuby's <code>--debug</code> flag), one possibility is to just use BMETHOD (or ISEQ) methods instead of IVAR/ATTRSET methods for attributes. A proof of concept for this can be implemented by adding the following to the top of <code>prelude.rb</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">if</span> <span class="vg">$DEBUG</span>
<span class="k">class</span> <span class="nc">Module</span>
<span class="n">remove_method</span><span class="p">(</span><span class="ss">:attr_accessor</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">attr_accessor</span><span class="p">(</span><span class="o">*</span><span class="n">meths</span><span class="p">)</span>
<span class="nb">attr_reader</span><span class="p">(</span><span class="o">*</span><span class="n">meths</span><span class="p">)</span>
<span class="nb">attr_writer</span><span class="p">(</span><span class="o">*</span><span class="n">meths</span><span class="p">)</span>
<span class="n">meths</span>
<span class="k">end</span>
<span class="n">remove_method</span><span class="p">(</span><span class="ss">:attr_reader</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">attr_reader</span><span class="p">(</span><span class="o">*</span><span class="n">meths</span><span class="p">)</span>
<span class="n">module_exec</span> <span class="k">do</span>
<span class="n">meths</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">meth</span><span class="o">|</span>
<span class="nb">instance_variable_get</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">meth</span><span class="si">}</span><span class="ss">"</span><span class="p">)</span> <span class="c1"># check valid</span>
<span class="n">define_method</span><span class="p">(</span><span class="n">meth</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">instance_variable_get</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">meth</span><span class="si">}</span><span class="ss">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">meths</span>
<span class="k">end</span>
<span class="n">remove_method</span><span class="p">(</span><span class="ss">:attr_writer</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">attr_writer</span><span class="p">(</span><span class="o">*</span><span class="n">meths</span><span class="p">)</span>
<span class="n">module_exec</span> <span class="k">do</span>
<span class="n">meths</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">meth</span><span class="o">|</span>
<span class="nb">instance_variable_get</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">meth</span><span class="si">}</span><span class="ss">"</span><span class="p">)</span> <span class="c1"># check valid</span>
<span class="n">define_method</span><span class="p">(</span><span class="ss">:"</span><span class="si">#{</span><span class="n">meth</span><span class="si">}</span><span class="ss">="</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">v</span><span class="o">|</span>
<span class="nb">instance_variable_set</span><span class="p">(</span><span class="ss">:"@</span><span class="si">#{</span><span class="n">meth</span><span class="si">}</span><span class="ss">"</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">meths</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Then you can run ruby with the <code>--debug</code> flag to enable tracing of attribute methods. As this approach uses BMETHOD instead of ISEQ, it needs the fix for <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: TracePoint return event location is incorrect for methods defined with define_method (Closed)" href="https://redmine.ruby-lang.org/issues/13392">#13392</a> to be committed for it to make sense.</p>
<p>This approach doesn't handle direct <code>rb_attr</code> use by C-extensions, though that could theoretically be fixed by making <code>rb_attr</code> use <code>rb_funcall</code>, at least for IDs that are valid instance variable names.</p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=934922021-08-29T14:24:18Zjeremyevans (Jeremy Evans)code@jeremyevans.net
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Closed</i></li></ul><p>Applied in changeset <a class="changeset" title="Support tracing of attr_reader and attr_writer In vm_call_method_each_type, check for c_call and..." href="https://redmine.ruby-lang.org/projects/ruby-master/repository/git/revisions/2d98593bf54a37397c6e4886ccc7e3654c2eaf85">git|2d98593bf54a37397c6e4886ccc7e3654c2eaf85</a>.</p>
<hr>
<p>Support tracing of attr_reader and attr_writer</p>
<p>In vm_call_method_each_type, check for c_call and c_return events before<br>
dispatching to vm_call_ivar and vm_call_attrset. With this approach, the<br>
call cache will still dispatch directly to those functions, so this<br>
change will only decrease performance for the first (uncached) call, and<br>
even then, the performance decrease is very minimal.</p>
<p>This approach requires that we clear the call caches when tracing is<br>
enabled or disabled. The approach currently switches all vm_call_ivar<br>
and vm_call_attrset call caches to vm_call_general any time tracing is<br>
enabled or disabled. So it could theoretically result in a slowdown for<br>
code that constantly enables or disables tracing.</p>
<p>This approach does not handle targeted tracepoints, but from my testing,<br>
c_call and c_return events are not supported for targeted tracepoints,<br>
so that shouldn't matter.</p>
<p>This includes a benchmark showing the performance decrease is minimal<br>
if detectable at all.</p>
<p>Fixes [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: TracePoint does not report calls to attribute reader methods (Closed)" href="https://redmine.ruby-lang.org/issues/16383">#16383</a>]<br>
Fixes [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: TracePoint cannot trace attr_accessor/reader/writer method (Closed)" href="https://redmine.ruby-lang.org/issues/10470">#10470</a>]</p>
<p>Co-authored-by: Takashi Kokubun <a href="mailto:takashikkbn@gmail.com" class="email">takashikkbn@gmail.com</a></p> Ruby master - Bug #16383: TracePoint does not report calls to attribute reader methodshttps://redmine.ruby-lang.org/issues/16383?journal_id=982382022-06-29T09:42:53ZEregon (Benoit Daloze)
<ul><li><strong>Related to</strong> <i><a class="issue tracker-1 status-5 priority-4 priority-default closed" href="/issues/18886">Bug #18886</a>: Struct aref and aset don't trigger any tracepoints.</i> added</li></ul>