Bug #7556

test error on refinement

Added by Usaku NAKAMURA over 1 year ago. Updated over 1 year ago.

[ruby-core:50867]
Status:Closed
Priority:Normal
Assignee:Koichi Sasada
Category:ext
Target version:2.0.0
ruby -v:ruby -v: ruby 2.0.0dev (2012-12-13 trunk 38354) [x64-mswin64_100] Backport:

Description

1) Error:
testrefinerecursion(TestRefinement):
NoMethodError: undefined method recursive_length' for "oo":String
C:/Users/usa/ruby/test/ruby/test_refinement.rb:567:in
recursivelength'
:in <main>'
C:/Users/usa/ruby/test/ruby/test_refinement.rb:806:in
eval'
C:/Users/usa/ruby/test/ruby/test
refinement.rb:806:in eval_using'
C:/Users/usa/ruby/test/ruby/test_refinement.rb:574:in
testrefinerecursion'

On my box this error is 100% reproducible, but I also know that RubyCI and
RubyInstaller CI don't report this error.
I've heard that nobu reproduced this bug on x86_64-dawrin, but I don't know
the detail of his environment.

Once I wrote the detail of my debuggin, but it is lost by accidenal reboot

of my PC.

I have no energy to rewrite it, because writing long English sentences

irritates me, especially after seeing mails which reproach our native

language.

Associated revisions

Revision 38377
Added by Shugo Maeda over 1 year ago

  • vminsnhelper.c (vmcallsupermethod): remove volatile introduced
    in r38365.

  • vminsnhelper.c (vmcallmethod): use _forceinline to prevent
    VC to make vmcallgeneral and vmcallsuper_method as the same
    method. Thanks, Heesob Park. [Bug #7556]

History

#1 Updated by Martin Dürst over 1 year ago

On 2012/12/13 20:13, usa (Usaku NAKAMURA) wrote:

Issue #7556 has been reported by usa (Usaku NAKAMURA).

Once I wrote the detail of my debuggin, but it is lost by accidenal reboot

of my PC.

I have no energy to rewrite it, because writing long English sentences

irritates me, especially after seeing mails which reproach our native

language.

Two solutions:

1) Write short English sentences.
2) Write in Japanese. (If somebody thinks they really need to know what
you wrote, they can ask on the list.)

But I know that for creative people, it is much harder to do the same
work again than to do it the first time. I once worked on Devanagari
rendering, but lost that work in a reboot. I didn't want to redo it, so
I worked on Tamil instead. (I just wanted to see whether my architecture
was able to handle Indic rendering issues.)

Regards, Martin.

#2 Updated by Shugo Maeda over 1 year ago

  • Assignee changed from Shugo Maeda to Koichi Sasada

usa (Usaku NAKAMURA) wrote:

1) Error:
testrefinerecursion(TestRefinement):
NoMethodError: undefined method recursive_length' for "oo":String
C:/Users/usa/ruby/test/ruby/test_refinement.rb:567:in
recursivelength'
:in <main>'
C:/Users/usa/ruby/test/ruby/test_refinement.rb:806:in
eval'
C:/Users/usa/ruby/test/ruby/test
refinement.rb:806:in eval_using'
C:/Users/usa/ruby/test/ruby/test_refinement.rb:574:in
testrefinerecursion'

To avoid an infinite loop by super in a refinement, ci->call is used to distinguish super calls from normal calls,
and if it's a super call, skip the same method.
However, VC++ optimizes vmcallgeneral and vmcallsuper_method into the same method because they have the same definition, so ci->call cannot be used to distinguish super calls from normal calls. How intelligent VC++ is!

I've found that the following hack fixes the problem:

static VALUE
vmcallsupermethod(rbthreadt *th, rbcontrolframet regcfp, rbcallinfot *ci)
{
#ifdef _WIN32
volatile int x = 0; /
to avoid VC++ optimization which makes
vmcallsupermethod as an alias of
vm
callgeneral! */
#endif
return vm
callmethod(th, regcfp, ci);
}

Sasada-san, do you accept this ugly hack, or do you come up with a neat solution?

#3 Updated by Koichi Sasada over 1 year ago

(2012/12/13 22:32), shugo (Shugo Maeda) wrote:

Sasada-san, do you accept this ugly hack, or do you come up with a neat solution?

To answer your question, I need to learn how refinement is implemented.
Please wait a moment.
(or please commit it ahead and left this ticket open)

--
// SASADA Koichi at atdot dot net

#4 Updated by Shugo Maeda over 1 year ago

Hi,

2012/12/13 SASADA Koichi ko1@atdot.net:

Sasada-san, do you accept this ugly hack, or do you come up with a neat solution?

To answer your question, I need to learn how refinement is implemented.
Please wait a moment.
(or please commit it ahead and left this ticket open)

Thanks for your quick response.
I've commited the workaround, and have left the ticket open.

--
Shugo Maeda

#5 Updated by Heesob Park over 1 year ago

Here is another workaround:

#ifdef MSCVER
#pragma optimize( "", off )
#endif
static VALUE
vmcallsupermethod(rbthreadt *th, rbcontrolframet *regcfp, rbcallinfot *ci)
{
return vmcallmethod(th, regcfp, ci);
}
#ifdef _MSC
VER
#pragma optimize( "", on )
#endif

#6 Updated by Shugo Maeda over 1 year ago

Hello,

phasis68 (Heesob Park) wrote:

Here is another workaround:

#ifdef MSCVER
#pragma optimize( "", off )
#endif

Thanks for your suggestion.

But it seems that the #pragma optimize( "", off ) version is slightly slower than the volatile int x = 0 version.

with volatile int x = 0:

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.778000 0.000000 1.778000 ( 1.783227)
-------------------------------- total: 1.778000sec

        user     system      total        real

super 1.810000 0.000000 1.810000 ( 1.806230)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.747000 0.000000 1.747000 ( 1.789727)
-------------------------------- total: 1.747000sec

        user     system      total        real

super 1.763000 0.000000 1.763000 ( 1.760224)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.763000 0.000000 1.763000 ( 1.804229)
-------------------------------- total: 1.763000sec

        user     system      total        real

super 1.809000 0.000000 1.809000 ( 1.841734)

with #pragma optimize( "", off ):

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.825000 0.000000 1.825000 ( 1.859236)
-------------------------------- total: 1.825000sec

        user     system      total        real

super 1.872000 0.000000 1.872000 ( 1.864237)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.919000 0.000000 1.919000 ( 1.920744)
-------------------------------- total: 1.919000sec

        user     system      total        real

super 1.794000 0.000000 1.794000 ( 1.820232)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.872000 0.000000 1.872000 ( 1.913243)
-------------------------------- total: 1.872000sec

        user     system      total        real

super 1.810000 0.000000 1.810000 ( 1.817231)

I guess #pragma optimize( "", off ) disables function inlining of vmcallmethod.

#7 Updated by Heesob Park over 1 year ago

Here is a modified version which does not disable function inline expansion.

#ifdef MSCVER
#pragma optimize("g",off)
#endif
static VALUE
vmcallsupermethod(rbthreadt *th, rbcontrolframet *regcfp, rbcallinfot *ci)
{
return vmcallmethod(th, regcfp, ci);
}
#ifdef _MSC
VER
#pragma optimize("g",on)
#endif

#8 Updated by Shugo Maeda over 1 year ago

phasis68 (Heesob Park) wrote:

Here is a modified version which does not disable function inline expansion.

#ifdef MSCVER
#pragma optimize("g",off)
#endif

I also tried it, but couldn't see improvement:

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.856000 0.000000 1.856000 ( 1.868237)
-------------------------------- total: 1.856000sec

        user     system      total        real

super 1.872000 0.000000 1.872000 ( 1.910743)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.841000 0.000000 1.841000 ( 1.860736)
-------------------------------- total: 1.841000sec

        user     system      total        real

super 1.903000 0.016000 1.919000 ( 1.956249)

C:\Users\shugo\Documents\Source\ruby>\ruby\bin\ruby bmvm2super.rb
Rehearsal -----------------------------------------
super 1.872000 0.000000 1.872000 ( 1.927244)
-------------------------------- total: 1.872000sec

        user     system      total        real

super 1.841000 0.000000 1.841000 ( 1.868237)

And, other options of the optimize pragma such as "p" don't fix the problem.

#9 Updated by Heesob Park over 1 year ago

Here is a different workaround using _forceinline on vmcall_method function.

static
#ifdef MSCVER
_forceinline
#else
inline
#endif
VALUE
vm
callmethod(rbthreadt *th, rbcontrolframet *cfp, rbcallinfo_t *ci)
{
...
}

#10 Updated by Shugo Maeda over 1 year ago

phasis68 (Heesob Park) wrote:

Here is a different workaround using _forceinline on vmcall_method function.

static
#ifdef MSCVER
_forceinline
#else
inline
#endif
VALUE
vm
callmethod(rbthreadt *th, rbcontrolframet *cfp, rbcallinfo_t *ci)

Thanks, it solves the problem without the optimize progma for rbcallsuper_method, and performance decrease hasn't been observed.

Could you tell me why _forceinline for vmcallmethod prevent VC++ to make vmcallgeneral and vmcallsupermethod as the same function?
I couldn't find the reason at URL:http://msdn.microsoft.com/library/vstudio/z8y1yy88.

#11 Updated by Shugo Maeda over 1 year ago

  • Status changed from Assigned to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r38377.
Usaku, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • vminsnhelper.c (vmcallsupermethod): remove volatile introduced
    in r38365.

  • vminsnhelper.c (vmcallmethod): use _forceinline to prevent
    VC to make vmcallgeneral and vmcallsuper_method as the same
    method. Thanks, Heesob Park. [Bug #7556]

#12 Updated by Heesob Park over 1 year ago

It seems that inline or __inline is not respected by the compiler (ignored by compiler cost/benefit analyzer)

Refer to http://en.wikipedia.org/wiki/Inline_function

#13 Updated by Shugo Maeda over 1 year ago

phasis68 (Heesob Park) wrote:

It seems that inline or __inline is not respected by the compiler (ignored by compiler cost/benefit analyzer)

Refer to http://en.wikipedia.org/wiki/Inline_function

I know it, but I don't know why _forceinline prevent user functions (in this case, vmcallgeneral and vmcallsupermethod) to be optimized into a single function.

#14 Updated by Heesob Park over 1 year ago

2012/12/14 shugo (Shugo Maeda) redmine@ruby-lang.org

Issue #7556 has been updated by shugo (Shugo Maeda).

phasis68 (Heesob Park) wrote:

It seems that inline or __inline is not respected by the compiler
(ignored by compiler cost/benefit analyzer)

Refer to http://en.wikipedia.org/wiki/Inline_function

I know it, but I don't know why _forceinline prevent user functions (in
this case, vm
callgeneral and vmcallsupermethod) to be optimized into a
single function.

The _forceinline keyword overrides the cost/benefit analysis and
relies on the judgment of the programmer instead.
Using _
forceinline insures that all functions which call
vmcallmethod function have the inline expanded code instead of
vmcallmethod function call.
Thus, vmcallgeneral and vmcallsuper_method are separated function.

Also available in: Atom PDF