K.Sasada's Home Page

Diary - 2012 December

�������L

�t��

_25(Tue)

���A���F�{�� 25 ���܂ő�����ꂽ Ruby VM �A�h�x���g�J�����_�[�́C���E�̏I���̂��߁C�ۑ����Ă��Ȃ����������������Ă��܂��܂����D����C�������������Ă��������Ǝv���܂��D�����f���������v���܂��D


���A���F���E�̏I���ɂ���Ď���ꂽ�L���𐏎����������Ă��܂����C�����‚��̋L���̂����炪�F���I�ȉ����̂��߂Ɍ������Ă��܂��Ă���悤�ł��D�s�ӁC�����������Ă��������Ǝv���Ă���܂��D


�ꗗ�F


�Ƃ����킯�ŁC Ruby VM �A�h�x���g�J�����_�[�� 25 ���ځC�ŏI���ł��D

�r������ Ruby 2.0.0 �̏Љ�L���݂����ɂȂ��Ă��܂������CVM �܂��̋@�\���Ȃ�ƂȂ��Љ�o�����񂶂�Ȃ����Ǝv���܂��D

���āC2.0 �ł��c�������Ƃ͂��邩�ƌ�����ƁC���ꂪ��R����̂ł��D������ƍׂ������Ƃ�������Ă����Ƒ�ςȂ̂ŁC����l�ɂ�������Ȃ����C����l�Ȃ�ċ���̂��Ȃ��C�Ǝv���悤�ȉӏ������ł܂Ƃ߂Ă݂����Ǝv���܂��D

  • ���\�b�h�Ăяo���̍�����
    • �R���g���[���t���[���̃T�C�Y�������ƃX����������
    • �L���b�V���������ƃA�O���b�V�u�Ɍ�������
    • simple CFUNC ����邽�߂̃t���[�����[�N��������ƍ��
    • yield ���Ȃ�Ƃ�����i�L���b�V�����������铙�j
    • �C�����C�����\�b�h�L���b�V���̃A���S���Y������������
    • refinement ������������ƍl����
    • keyword �����������ɏ�������
  • VM �\��
    • ep �ŗ�O�����̃A���J�[�ɂ��Ă���̂� cfp �ɂ���
    • iseq ���� Object ��r��
    • �N�������������ƃV���v���ɂ���
    • �A�v���P�[�V�����g���݂������Ƃ��₷������C�h�L�������g������
  • ���� / Compiler
    • ���W�X�^�}�V��������������
    • ����������Ɩ��߂𐮗�����
    • optimizer ������������Ƃ����Ď�������
    • tailcall �����H
    • super ���Ȃ�Ƃ�����i���� Module �̋��j
    • �����t�@�C�����܂Ƃ߂���@�����i�ėp require �t���[�����[�N�j�� VFS �v��H
  • �������E�I�u�W�F�N�g�Ǘ� / GC
    • �^�ʂ̃q�[�v
    • mmap �ł܂Ƃ߂Ċm�ہC������ bitmap marking
    • Reference counting String storage
    • Symbol GC ����������
    • ����� GC ������
  • ���̑�
    • �x���`�}�[�N������������ƂȂ�Ƃ�����
    • �V�O�i����������������ƂȂ�Ƃ�����
    • C �g���̋K�i���Ȃ�Ƃ�����
    • �f�o�b�K�C�v���t�@�C���T�|�[�g������������ƂȂ�Ƃ�����

��R�����Ă����܂����D�v���‚����炠�ƂŒlj����Ă����܂��ˁD

�������Ă݂�ƁCRuby 2.0.0 �͖{���ɕێ�I�ŁC�\�z�����͂��������ǃh���X�e�B�b�N�ȋ@�\�͂���܂�����ĂȂ��ł��ˁD

Ruby 2.1 �܂łɂȂ�Ƃ��������Ȃ��D

�ł́C�܂����N�D�ǂ����N���D

_24(Mon)

Ruby VM �A�h�x���g�J�����_�[�� 24 ���ڂł��D

�����̓N���X�}�X�C�u�ł��ˁD�����܂ł�����Ƒ����Ă����ĂƂĂ��ǂ������Ǝv���܂��D

���āC�����͂���܂ł̍������̘b�i���͂͂����œr�؂�Ă���j

_23(Sun)

Ruby VM �A�h�x���g�J�����_�[�� 23 ���ڂł��D

����� VM �̍������̘b�i���͂͂����œr�؂�Ă���j

_22(Sat)

Ruby VM �A�h�x���g�J�����_�[�� 22 ���ڂł��D

�����́CVM �̍������̘b���i���͂͂����œr�؂�Ă���j

_21(Fri)

Ruby VM �A�h�x���g�J�����_�[�� 21 ���ڂł��D

�X�^�b�N�I�[�o�[�t���[���Ă���܂���ˁD�p�ӂ��ꂽ�X�^�b�N���g���؂��Ă��܂��Əo��G���[�ł��D�v���O�����ɂ���ĕK�v�ȃX�^�b�N�̃T�C�Y�͈Ⴄ���̂ł����CRuby 1.9 �܂ł̓X�^�b�N�̃T�C�Y���w�肷����@������܂���ł����D

�����ŁCRuby 2.0 �ł͎��� 4 �‚̊‹��ϐ��ɂ���āC�X�^�b�N�̐[����ς��邱�Ƃ��o����悤�ɂȂ�܂����D

  • RUBY_THREAD_VM_STACK_SIZE: �X���b�h����鎞�ɍ쐬���� VM �X�^�b�N�T�C�Y�i�f�t�H���g: 128KB (32bit CPU) or 256KB (64bit CPU)�j
  • RUBY_THREAD_MACHINE_STACK_SIZE: �X���b�h����鎞�ɍ쐬����}�V���X�^�b�N�T�C�Y�i�f�t�H���g�F512KB or 1024KB�j
  • RUBY_FIBER_VM_STACK_SIZE: �t�@�C�o����鎞�ɍ쐬���� VM �X�^�b�N�T�C�Y�i�f�t�H���g�F64KB or 128KB�j
  • RUBY_FIBER_MACHINE_STACK_SIZE: �t�@�C�o����鎞�ɍ쐬����}�V���X�^�b�N�T�C�Y�i�f�t�H���g�F256KB or 512KB�j

���ꂼ��X���b�h�ƃt�@�C�o�p�́CVM �̃X�^�b�N�ƃ}�V���X�^�b�N�̃T�C�Y���w��ł��܂��D

�������C�����̒l�͂����܂Ńq���g���ɂȂ��Ă��܂��D�������l���w�肵�Ă��C���̒l�����̃T�C�Y���w�肷�邱�Ƃ͂ł��܂��񂵁C�K���Ȑ��ŃA���C������܂��D�������� OS �ɂ���ẮC�X���b�h�̃}�V���X�^�b�N�T�C�Y��ύX���邱�Ƃ��o���Ȃ��ꍇ������܂��D

�����̒l�̓C���^�v���^�N�����ɂ̂ݗL���ł��D�C���^�v���^���N����Ɋ‹��ϐ��̒l��ω������Ă��C�C���^�v���^�͕ύX�𖳎����܂��D

���Ȃ݂ɁC1.9 �̎�������X�^�b�N�T�C�Y���傫���Ȃ��Ă��܂��D����́C�X�^�b�N�T�C�Y���傫���Ă܂����v���O�����͂���܂薳�����炾�낤�C�Ƃ������f�ł��D�����C32bit CPU ���g���Ă���CFiber�i�� Thread�j���ʂɍ쐬����悤�ȃv���O�����̏ꍇ�C���̊‹��ϐ��𗘗p���ă`���[�j���O���邱�Ƃ��������Ă݂ĉ������D


�����̐ݒ�����s���ɒm�邽�߂ɁC�V�����萔 RubyVM::DEFAULT_PARAMS ����������t�������܂����D

puts RubyVM::DEFAULT_PARAMS
#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
{:thread_vm_stack_size=>131072, :thread_machine_stack_size=>524288, :fiber_vm_stack_size=>65536, :fiber_machine_stack_size=>262144}

����Ȋ����Ŋe�l���i�[���ꂽ�n�b�V���I�u�W�F�N�g�����܂��D����C��������l���lj�����邩������܂���i����Ȃ���������܂���j�D�Ȃ��C�����܂ŎQ�l���Ȃ̂ŁC���̒l�����������Ă��C�C���^�v���^�̋����ɂ͈�؉e����^���܂���D

�ł́C�����͂��̕ӂŁD

_20(Thu)

Ruby VM �A�h�x���g�J�����_�[�� 20 ���ڂł��D

����� Module#prepend ���Љ�܂����Dinclude �ł̓��\�b�h�T���̏����Ō��ɒlj����Ă������̂��C�O�ɒlj�������̂ł����D

���K�̂��߂ɁC����̃v���O�������Čf���Ă݂܂��D

class C0
  def m; p :C0; end
end

module M
  def m; p :M; super; end
end

class C < C0
  prepend M                # include �������̂� prepend �ɂ��Ă���
  def m; p :C; super; end
end

obj = C.new
obj.m

#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
:M
:C
:C0

C �̃I�u�W�F�N�g�Ƀ��\�b�h m �����s�����Ƃ��CM#m ����ɌĂ΂�Ă��邱�Ƃ��킩��܂��D

����́uModule#prepend �ŁC����܂ŏo���Ȃ������悤�Ȃ��Ƃ��ł���悤�ɂȂ�܂��D�����Ă݂ĉ������D�v�ƌ��񂾂̂ł����C������������C�ǂ�Ȏ��Ɏg����ł��傤���D

��Ԃ��肻���Ȏg�����Ƃ��ẮC���郁�\�b�h�̊J�n�ƏI�����ɓ���̏��������������ꍇ�ł��D�Ⴆ�΁CArray#each ���Ă΂ꂽ�Ƃ��C���O���o�͂���悤�ȗ���L�q���Ă݂܂��D

module EachLogger
  def each(*args, &block)
    puts "Enter `each'"
    super
    puts "Leave `each'"
  end
end

class Array
  prepend EachLogger
end


p :each
[1, 2, 3].each{}
p :find
[1, 2, 3].find(1)
p :find_all
[1, 2, 3].find_all{|e| (e % 2) == 1}

#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
:each
Enter `each'
Leave `each'
:find
:find_all
Enter `each'
Leave `each'

�͂��C���̂悤�� each ���\�b�h�����s���ꂽ�Ƃ��CEachLogger �ɂ���ă��O���o�͂���邱�Ƃ��킩��܂����D

���Ȃ݂ɁCfind ���\�b�h�ł� each �͎g���Ă��Ȃ����Ƃ��킩��܂��D�t�� find_all ���\�b�h�ł͎g���Ă��܂����C����� Enumerable#find_all ���\�b�h�� each ���\�b�h���Ăяo���Ă��邩��ł��D

���̂悤�ɁC���\�b�h�̊J�n�ƏI�����ɉ�������̏������s���Ƃ������Ƃ� around �ƌ������肵�܂��D�������C�J�n�������C�I���������C�Ƃ������Ƃ��o���܂��D


���āC��قǂ� EachLogger �Ƃ��� each ���\�b�h�����M���O���郂�W���[�������܂������C�ǂ����Ȃ炠��N���X�̂��ׂẴ��\�b�h�̃��O���o�͂�����̂�����Ă݂܂��傤�D

def prepend_method_logger klass
  mod = Module.new
  klass.instance_methods(false).each{|m|
    mod.module_eval %Q{
      def #{m}(*args)
        puts "Enter `#{m}'"
        super
        puts "Leave `#{m}'"
      end
    }
  }
  klass.module_eval{
    prepend mod
  }
end

class C
  def m; puts "C#m"; end
  def n; puts "C#n"; end
end

prepend_analyse_module C

obj = C.new
obj.m
obj.n

#=>
Enter `m'
C#m
Leave `m'
Enter `n'
C#n
Leave `n'

prepend_method_logger �͎w�肳�ꂽ�N���X�ɒ�`����Ă��郁�\�b�h���ׂĂɑ΂��� EachLogger#each �̂悤�ɁC���O���o�͂��郁�\�b�h���`���Ă��܂��Dmodule_eval �𗘗p���Ă���̂������p�I�ł��ˁD

���s���ʂŁCC#m�CC#n �̎��s���ɁC������ƃ��O���o�͂���Ă��邱�Ƃ��킩��Ǝv���܂��D


���āC����𗘗p���āC����������ƕ֗���������Ȃ��c�[��������Ă݂܂��傤�D

����N���X�̃��\�b�h���C�ǂ̂悤�Ȉ������󂯕t���C�����ĕԒl�ɉ���Ԃ��Ă���̂����v���Ƃ��Ă݂܂��D�������邱�ƂŁC�Ӑ}���Ȃ��������󂯕t���Ă��邩�ǂ������킩��܂��D

def prepend_analyse_module klass
  $analyse_result = {} unless defined?($analyse_result)
  stat = $analyse_result[klass] = {}

  mod = Module.new
  klass.instance_methods(false).each{|m|
    stat[m] = [Hash.new{|h, k| h[k] = Hash.new(0)}, # args
               Hash.new(0)]                         # return
    src = %Q{
      def #{m}(*args)
        args.each.with_index{|e, i|
          $analyse_result[#{klass.name}][:#{m}][0][i][e.class] += 1
        }
        result = super
        $analyse_result[#{klass.name}][:#{m}][1][result.class] += 1
      end
    }
    mod.module_eval src
  }
  klass.module_eval{
    prepend mod
  }
end

class C
  def m foo, bar; puts "C#m"; end
  def n baz; puts "C#n"; end
end

prepend_analyse_module C

obj = C.new
obj.m 'a', 1
obj.m :sym, 1.2
obj.n /x/

require 'pp'
pp $analyse_result

#=>
C#m
C#m
C#n
{C=>
  {:m=>[{0=>{String=>1, Symbol=>1}, 1=>{Fixnum=>1, Float=>1}}, {NilClass=>2}],
   :n=>[{0=>{Regexp=>1}}, {NilClass=>1}]}}

�F�X�ʓ|�����������̂ŁC$analyse_result �Ƃ����O���[�o���ϐ��ɏ���S���l�ߍ��ނ悤�ɂ��Ă݂܂����D

���ʂ�����ƁCC#m �� 0 �Ԗڂ̈����� String ����� Symbol �� 1 �‚��C1 �Ԗڂ̈����ɁC... �Ƃ�����񂪂킩��܂��D

�����L���ɂ��āC�e�X�g�P�[�X�𑖂点�Ă݂�ƁC�Ӑ}���Ȃ��^�����Ă��邩�ǂ����C�`�F�b�N�ł��邩������܂���D

�ł́C�����͂��̕ӂŁD

_19(Wed)

Ruby VM �A�h�x���g�J�����_�[�� 19 ���ڂł��D

�����́CRuby 2.0 �œ������ꂽ Module#prepend �ɂ‚��Ă��Љ�܂��D

�������̒ʂ�CRuby �ł� Module �� include ���邱�ƂŁC���\�b�h��`���g�����邱�Ƃ��o���܂��D

module M
  def m; p :M; end
end

class C
  include M
end

���̂Ƃ��CC �I�u�W�F�N�g�̓��\�b�h m �������Ă��邱�ƂɂȂ�܂��D

���Ă����ŁCC �����\�b�h m �������Ă���Ƃ��C�ǂ��Ȃ邩�m���Ă��܂����H

module M
  def m; p :M; end
end

class C
  include M
  def m; p :C; end
end

C.new.m #=> :C

C#m �� M#m �ł́CC#m ���g���Ă��邱�Ƃ��킩��܂����D���́Cancestors ������Ƃ킩��܂��D

# ��̃R�[�h�̑������Ǝv���ĉ������D
p C.ancestors #=> [C, M, Object, Kernel, BasicObject]

Class#ancestors �̓N���X�̊K�w�\���������܂����C����͂��̂܂܃��\�b�h�̒T�������ɂ��Ȃ��Ă��܂��DC �� M �ł� C �̂ق�����ɗ���̂ŁCC#m ����Ƀq�b�g����̂ł����炪�g����C�Ƃ������Ƃł��ˁD

���߉����ɁCC#m �� super ���Ă݂܂��傤�D

module M
  def m; p :M; end
end

class C
  include M
  def m; p :C; super; end
end

C.new.m

#=>
:C
:M

C#m �� super ���� M#m ���Ă΂�Ă��邱�Ƃ��킩��܂��D


���āCC �� M �� include �����Ƃ��CC -> M �̏��Ƀ��\�b�h����������邱�Ƃ��킩��܂����D�����āCC#m ������΁C���ꂪ���p����܂��D

�������CC#m ������� M#m ���Ă�ŗ~�����C�Ƃ����ꍇ�͂ǂ�����΂����ł��傤���D���� 1 �•��@������܂��DObject#extend ���g���܂��D

class C0
  def m; p :C0; end
end

module M
  def m; p :M; super; end
end

class C < C0
  def m; p :C; super; end
end

obj = C.new
obj.extend M
obj.m

#=>
:M
:C
:C0

C �I�u�W�F�N�g�ł��� obj �� extend ���\�b�h�ɂ���� M ���g���������߁C������ M�CC�i������ C0�j�̏��Ƀ��\�b�h���Ă΂�Ă��邱�Ƃ��킩��܂��D�悩�����悩�����D

���C���ꂾ�� C.new �ō쐬�����I�u�W�F�N�g���ׂĂɑ΂��� Object#extend ���Ă΂˂΂Ȃ炸�s�ւł��i�����āC�I�u�W�F�N�g�̐������x���Ȃ�܂��j�D


������ Ruby 2.0 ����� Module#prepend �Ƃ����@�\���lj�����܂����DModule#include �ł� include ����N���X�̌��ɉ����Ă����̂��C���x�� prepend �ɂ���� �O�ɒlj�����C�Ƃ����@�\�ł��D

�ł͎��ۂɎg���Ă݂܂��傤�D

class C0
  def m; p :C0; end
end

module M
  def m; p :M; super; end
end

class C < C0
  prepend M                # include �������̂� prepend �ɂ��Ă���
  def m; p :C; super; end
end

obj = C.new
obj.m

#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
:M
:C
:C0

�����Cobj.m �� M#m�CC#m�i������ C0#m�j�̏��ɒT�������悤�ɂȂ�܂����D�ꉞ�Cancestors �����Ă����܂��傤���D

# �O�q�̃N���X��`������Ǝv���ĉ�����
p C.ancestors
#=> [M, C, C0, Object, Kernel, BasicObject]

�Ƃ����킯�ŁCC �̑O�� M �����邱�Ƃ��m�F�ł���Ǝv���܂��D

Module#prepend �ŁC����܂ŏo���Ȃ������悤�Ȃ��Ƃ��ł���悤�ɂȂ�܂��D�����Ă݂ĉ������D

�ł́C�����͂��̕ӂŁD

_18(Tue)

Ruby VM �A�h�x���g�J�����_�[�� 18 ���ڂł��D

����� 2.0 ���玎���I�ɓ������ꂽ Debug Inspector API �̂��Љ�����悤�Ǝv���܂��D�Ȃ��C���̋@�\����ɂ���Ď������ł��̂ŁC���Ƃŕς�邩������܂��񂵁C�����Ȃ邩������܂���D�t�B�[�h�o�b�N�C���҂����Ă���܂��D

���āCDebug Inspector API �Ƃ͉����Ƃ����ƁC���΂�X�^�b�N�t���[���̏������o�����Ƃł��D���Ă����ƁCcaller_locations �ł��������C�Ƃ����C�����܂����C����̓X�^�b�N�t���[���̔C�ӂ̃t���[���� Binding �I�u�W�F�N�g�����o���܂��D�‚܂�C���̃��\�b�h Binding of caller ���ēz�ł��D�����C���p���@�͂�����ƕ��G�ɂȂ��Ă��܂��D�܂��C�p�t�H�[�}���X�������x���̂ŁC���ʂ̃v���O�����̎��s�ł͎g���Ȃ��񂶂�Ȃ����Ǝv���܂��D�Ƃ������C�g��Ȃ��ʼn������D�����܂ŁC�f�o�b�K�p�ł��D���p���ցD

Debug Inspector API �Ɗ֌W����錾�� include/ruby/debug.h ������p���܂��D

/* debug inspector APIs */
typedef struct rb_debug_inspector_struct rb_debug_inspector_t;
typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *);

VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data);
VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index);
VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);

�܂��C���p����Ƃ��� rb_debug_inspector_open() ���C�֐��|�C���^ func �Ƌ��ɌĂяo���܂��Drb_debug_inspector_open() �́C���݂̃R���e�L�X�g�ɑΉ����� rb_debug_inspector_t �I�u�W�F�N�g�i�����ł́C�f�o�b�O�R���e�L�X�g�ƌĂт܂��j���쐬���Cfunc �͐������ꂽ�f�o�b�O�R���e�L�X�g�ւ̃|�C���^�ƁCrb_debug_inspector_open() �̑����� data �Ƌ��ɌĂ΂�܂��D

���������C����Ȋ����ɂȂ�܂��D

VALUE
func(const rb_debug_inspector_t *dc, void *data)
{
  ...
}


  ... /* �f�o�b�O�������ӏ��� */
  rb_debug_inspector_open(func, some_data_ptr);
  ...

�f�o�b�O�R���e�L�X�g�ւ̃|�C���^ dc �ɂ���āC���݂̃t���[���̏��ɃA�N�Z�X�ł��܂��D�Ȃ��Cdc �� func ���Ăяo����Ă���Ԃ̂ݗL���ł���Cfunc ����Ԃ������ dc �͉������Ă��܂��܂��̂ł����Ӊ������D

�܂��́Ccaller_locations �����o���܂��傤�Drb_debug_inspector_backtrace_locations(dc) �Ƃ���Ύ��o���܂��D��������o�����ƂŁC�X�^�b�N�t���[���̐[�����킩��܂��i���v���΁C�T�C�Y��Ԃ� API ��p�ӂ��Ă����΂悩�����D���߂�j�D����ŁC�X�^�b�N�̐[���� `depth' �ł��邱�Ƃ��킩�����Ƃ��܂��D

n �t���[���ځi�������C0 <= n < depth�j�̃t���[���̏������o�������Ƃ��́Crb_debug_inspector_frame_???_get(dc, n) �Ƃ��Ď��o���܂��D??? �ɁC���o�����������������݂܂��D����ɂ͎��̎�ނ�����܂��D

  • self - ���̃t���[���� self
  • class - ���̃t���[�������s���Ă��郁�\�b�h�̒�`����Ă���N���X�i���W���[���j
  • binding - ���̃t���[���� binding
  • iseq - ���̃t���[���� RubyVM::InstructionSequence �I�u�W�F�N�g

�������Cbinding �� iseq �� C ���\�b�h�Ȃǂ� nil �ł���”\��������܂��Dclass �� TracePoint#defined_class �Ŏ��o���N���X�i���W���[���j�Ɠ��l�ɓ��ك��\�b�h�̏ꍇ�C���كN���X��Ԃ��܂��D

���āC���ꂪ����ƐF�X�Ƃ���炵�����Ƃ��ł���C�����܂��񂩁D�ł�����܂藔�p���Ȃ��ʼn������ˁD�厖�Ȃ��ƂȂ̂ŌJ��Ԃ��Ă����܂����C���̋@�\����ɂ���Ď������ł��̂ŁC���Ƃŕς�邩������܂��񂵁C�����Ȃ邩������܂���D�t�B�[�h�o�b�N�C���҂����Ă���܂��D

�ł́C�����͂��̕ӂŁD

_17(Mon)

Ruby VM �A�h�x���g�J�����_�[�� 17 ���ڂł��D

DTrace ���o����悤�ɂȂ�܂����DAaron �����̂������ł��D�Љ�L�������x�������\��Ȃ̂ŁC�ڍׂ͂��������Q�Ƃ��ĉ������i�������Ă��Ȃ��̂ł悭�m��Ȃ��j�D

DTrace �̓����̎d�g�݂ɂ͂��܂�[�����Ă��Ȃ����C���̃g���[�X�̏�񂪐������Ƃ͎v���Ă��Ȃ��̂Łi�����C������ƒx���Ȃ邵�C�Ȃ񂩃R�[�h�������j�C�C�͂�����Ƃ��ɁC���̕ӂ͂����������ւ������Ǝv���Ă��܂��D

�ł́C�����͂��̕ӂŁi�蔲���j�D

_16(Sun)

Ruby VM �A�h�x���g�J�����_�[�� 16 ���ڂł��D

���������N�����Ȃ��悤�ȃR�A�Șb������ꏊ�Ȃ̂ŁC�N�������Ȃ������� TracePoint �̎����ɂ‚��ďq�ׂ܂��D

vm_trace.c �ɂ���܂��D�����ɂ� set_trace_func ���s�� rb_add_event_hook() �Ȃǂ��܂���������Ă���C���̂��Ƃ�����g���� set_trace_func ����������C����ƕ��s�� TracePoint API ����������Ă���C�Ƃ��������ł��D

Trace �����S�ɖ����ɂ��鏈���ɁC������ƍH�v������܂����C������������Y��ɂȂ�񂶂�Ȃ����Ǝv���Ă��܂��D

�܂��C���Ƃ͓ǂ߂Δ���܂��D�ȒP�ł��D�����킩��Ȃ��C�Ƃ����ꏊ������܂�����R�����g�������D

�ł́C�����͂��̕ӂŁi�蔲���j�D

_15(Sat)

Ruby VM �A�h�x���g�J�����_�[�� 15 ���ڂł��D

����܂ŁC3 ��ɓn���� TracePoint �̏Љ�����Ă��܂����D�����́CTracePoint �̋@�\�� C �g�����痘�p���邽�߂� C API �ɂ‚��Ă��Љ�܂��D

include/ruby/debug.h �Ƃ����t�@�C���������������D�u/* TracePoint APIs */�v�Ƃ����R�����g����n�܂�ӏ�������ɓ�����܂��D

�Z���ł��̂ŁC�S�����p���Ă݂܂��傤�D

VALUE rb_tracepoint_new(VALUE target_thread_not_supported_yet,
                        rb_event_flag_t events, 
                        void (*func)(VALUE, void *), void *data);
VALUE rb_tracepoint_enable(VALUE tpval);
VALUE rb_tracepoint_disable(VALUE tpval);
VALUE rb_tracepoint_enabled_p(VALUE tpval);

typedef struct rb_trace_arg_struct rb_trace_arg_t;
rb_trace_arg_t *rb_tracearg_from_tracepoint(VALUE tpval);

VALUE rb_tracearg_event(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_lineno(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_path(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_method_id(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_defined_class(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_binding(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_self(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_return_value(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg);

TracePoint.new �ɑ�������̂� rb_tracepoint_new() �ł��D�����Ɂu�g���[�X��L���ɂ���X���b�h�v�C�u�g���[�X�������C�x���g�v�C�u�g���[�X�ɑ������� C �֐��̃|�C���^ func�v����сufunc ���ĂԂƂ��ɓn���|�C���^�v���Ӗ����܂��D�Ԓl�� TracePoint �I�u�W�F�N�g�ɂȂ�܂��D�܂��C�킩��܂���ˁD

�X���b�h�̎w�肷��ׂ��p�����[�^���� target_thread_not_supported_yet �ƂȂ��Ă��܂����C�e�X�g���Ă��Ȃ��̂Ŗ��T�|�[�g�Ƃ������Ƃɂ��Ă��܂��D�N���e�X�g���ĉ������D�C�x���g�w��� events �́C�C�x���g��\�����l�̘_���a�ɂȂ�܂��D

���݂� trunk �ł́C�w��ł���C�x���g�� include/ruby/ruby.h �ɉ��L�̂悤�ɒ�`����Ă��܂��D���ꂼ��C���O������Ή����Ӗ����邩�킩��܂���ˁD

/* traditional set_trace_func events */
#define RUBY_EVENT_NONE      0x0000
#define RUBY_EVENT_LINE      0x0001
#define RUBY_EVENT_CLASS     0x0002
#define RUBY_EVENT_END       0x0004
#define RUBY_EVENT_CALL      0x0008
#define RUBY_EVENT_RETURN    0x0010
#define RUBY_EVENT_C_CALL    0x0020
#define RUBY_EVENT_C_RETURN  0x0040
#define RUBY_EVENT_RAISE     0x0080
#define RUBY_EVENT_ALL       0x00ff

/* for TracePoint extended events */
#define RUBY_EVENT_B_CALL          0x0100
#define RUBY_EVENT_B_RETURN        0x0200
#define RUBY_EVENT_THREAD_BEGIN    0x0400
#define RUBY_EVENT_THREAD_END      0x0800
#define RUBY_EVENT_TRACEPOINT_ALL  0xFFFF

/* special events */
#define RUBY_EVENT_SPECIFIED_LINE 0x10000
#define RUBY_EVENT_SWITCH         0x20000
#define RUBY_EVENT_COVERAGE       0x40000

func �� data �����ł킩��񂶂�Ȃ����Ǝv���܂��D���Ȃ݂ɁCfunc �̑������́C�������� TracePoint �I�u�W�F�N�g�ɂȂ�܂��D������CTracePoint.new �ɓn���u���b�N�Ɠ����ł��ˁD

���āC�쐬�����g���[�X�͂܂��L���ɂȂ��Ă��Ȃ��̂� rb_tracepoint_enable() �ɂ���ėL���ɂ��܂��D�����ɂ���ɂ� rb_tracepoint_disable() �ł��ˁD

���āC�w�肵���C�x���g����������ƁCfunc �� TracePoint �I�u�W�F�N�g�� data �ƂƂ��ɌĂ΂�܂��DTracePoint#event �Ȃǂ����s�������킯�ł����C�����ň��ԏ�����K�v������܂��Drb_tracearg_from_tracepoint() �� TracePoint �I�u�W�F�N�g��n���� rb_trace_arg_t �ւ̃|�C���^���擾���ĉ������D�����œ���ꂽ�|�C���^���g���� rb_tracearg_event() �Ȃǂ��Ăяo�����ƂŁC�����擾���邱�Ƃ��o���܂��D

��̓I�ɂ́C���̂悤�ɂȂ�񂶂�Ȃ����Ǝv���܂��D

void
func(VALUE tpobj, void *data)
{
  rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpobj);
  VALUE event_sym = rb_tracearg_event(trace_arg);
  ...
}

���Ƃ́C�g�����킩��܂���ˁC���ŁD

�Ƃ����킯�ŁC�삯���ł����CTrcaePoint �� C �g������g�����߂� C API �����Љ�܂����D����ō����ȃv���t�@�C���Ƃ��N������āD

�����ƁC�厖�Ȃ��Ƃ������Y��Ă��܂����Ddebug.h �̐擪������Ə����Ă���

/* Note: This file contains experimental APIs. */
/* APIs can be replaced at Ruby 2.0.1 or later */

�ɒ��ӂ��ĉ������D���̕ӂ� C API �́C�܂��C������΂���Ȃ̂ŁC�F��Ȃ܂����_������񂶂�Ȃ����Ǝv���Ă����ł����C���ۂ����‚����łɌ��‚����Ă��܂��D�Ȃ̂ŁC�����l�͂��Ƃŕς�����Ƃ��ɒǏ]����o��Ŏg���Ă���ĉ������D�S�����ˁD�܂��C�Ȃ񂩓s���̈������������‚��܂�����R�b�\�������ĉ������D

�ł́C�����͂��̕ӂŁD

_14(Fri)

Ruby VM �A�h�x���g�J�����_�[�� 14 ���ڂł��D

�����́C�ŋߏЉ�Ă��� TracePoint �ׂ̍����g�����̏Љ�����悤�Ǝv���܂��D

����̋L���ł� TracePoint.trace ���g���܂����Dset_trace_func �Ɠ��l�ɁC���̃��\�b�h�I��������ݒ肵���g���[�X���L���ɂȂ�܂��D�������C���ʂ̃I�u�W�F�N�g�̂悤�ɁCTracePoint.new �ɂ���� TracePoint �I�u�W�F�N�g���쐬���邱�Ƃ��o���܂��D�쐬��́C�܂��L���ł͂Ȃ��̂ŁCTracePoint#enable �Ƃ��ăg���[�X��L���ɂ��܂��D���Ȃ݂ɁCTracePoint.new �̈����� TracePoint.trace �Ɠ����ł��D

trace = TracePoint.new(events...){|tp| ... trace ... }
... # �܂��g���[�X�͗L������Ȃ�
trace.enable
... # ���͈̔͂̂݃g���[�X�͗L��
trace.disable

�‚܂�CTracePoint.trace �Ƃ����̂́CTracePoint.new ���āC����� enable ����Ƃ�����ꑧ�ōs���֗����\�b�h�Ƃ����킯�ł��D

���Ȃ݂� TracePoint#enable �̓u���b�N��^���邱�Ƃ��ł��C���̃u���b�N�����s���̂݃g���[�X��L���ɂ���C�Ƃ����g�������o���܂��D

trace = TracePoint.new(events...){|tp| ... trace ... }
... # �܂��g���[�X�͗L������Ȃ�
trace.enable{
  ... # ���͈̔͂̂݃g���[�X�͗L��
}

TracePoint#disable ���C���l�Ƀu���b�N��^���邱�Ƃ��ł��C���̃u���b�N�͈̔͂����g���[�X�𖳌��ɂ��邱�Ƃ��ł��܂��D


���āC�ł͂ǂ̃C�x���g���g���[�X�ł��邩�C�ł�����{�I�ɂ� set_trace_func �łł����g���[�X�{���ƂȂ��Ă��܂��DTracePoint �� rdoc ������p���܂��D

  • :line - execute code on a new line
  • :class - start a class or module definition
  • :end - finish a class or module definition
  • :call - call a Ruby method
  • :return - return from a Ruby method
  • :c_call - call a C-language routine
  • :c_return - return from a C-language routine
  • :raise - raise an exception

�����܂ł� set_trace_func �Ɠ����ŁC

  • :b_call - event hook at block entry
  • :b_return - event hook at block ending
  • :thread_begin - event hook at thread beginning
  • :thread_end - event hook at thread ending

����炪 TracePoint ����V���ɉ”\�ɂȂ����g���[�X�ł���C�x���g�ɂȂ�܂��D�܂��C�Ӗ��͓ǂ߂΂킩��܂���ˁD

�V���{���œn����悤�ɂ����s����C"c-call" �̂悤�ȃC�x���g���� :c_call �ɂ悤�ɂȂ��Ă��܂��D


���āC���� TracePoint.new �̃u���b�N�ɓn���Ă���u���b�N�p�����[�^�͈�̂Ȃ�Ȃ̂��C�Ƃ������Ƃ𒲂ׂĂ݂܂��D�܂��C�N���X�����Ă݂܂��D

trace = TracePoint.trace{|tp|
  p tp.class
  exit
}
#=> TracePoint

�ǂ����C����� TracePoint �I�u�W�F�N�g�̂悤�ł��D

inspect ���Ē��ׂĂ݂܂��傤�D

trace = TracePoint.trace{|tp|
  p [:tp, tp.object_id, tp]
}
p [:trace, trace.object_id, trace]
#=>
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
[:tp, 1476430, #<TracePoint:c_return `trace'@t.rb:1>]
[:tp, 1476430, #<TracePoint:[email protected]:4>]
[:tp, 1476430, #<TracePoint:c_call `object_id'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `object_id'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `p'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `hash'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `hash'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_call `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:tp, 1476430, #<TracePoint:c_return `inspect'@t.rb:4>]
[:trace, 1476430, #<TracePoint:enabled>]
[:tp, 1476430, #<TracePoint:c_return `p'@t.rb:4>]

������Ƃ킩��Â炭�Ȃ�������Ă܂����C���� TracePoint.new �ō쐬�����I�u�W�F�N�g�ƃu���b�N�p�����[�^�i�����ł� tp�j�͓����I�u�W�F�N�g�ł��iobject_id �������Ȃ̂��킩��Ǝv���܂��j�D�g���[�X���s���Ƃɏ��փA�N�Z�X���邽�߂����̃I�u�W�F�N�g���쐬����̂͌����Ȃ��C�Ǝv���Ă��������݌v�ɂ��Ă��܂��D

�����I�u�W�F�N�g�ł���Ȃ���Cinspect �̌��ʂ��C�g���[�X���s���ƁC�g���[�X�����s���Ă��Ȃ����ňႤ�̂��킩��܂��D�g���[�X���s���́CTracePoint#inspect �͉��̃C�x���g�Ńg���[�X���ł��邩�C�킩��₷���\�����Ă��܂��D�g���[�X���s���łȂ��Ƃ��́C���� TracePoint �I�u�W�F�N�g�Ŏw�肳���g���[�X���L���ł��邩�ǂ����������Ă��܂��i���̏ꍇ�Cenable �ƕ\�����Ă��܂��ˁj�D

�Ȃ��CTracePoint#enabled? ���\�b�h�ɂ���āC���̃g���[�X���L���ł��邩�ǂ����������Ă��܂��D


�Ō�ɁC�g���[�X���ɂǂ�ȏ�񂪎��邩���Љ�܂��D

  • TracePoint#event - �Ȃ�̃C�x���g�������������Ԃ��܂�
  • TracePoint#lineno - �C�x���g�����������s�ԍ���Ԃ��܂�
  • TracePoint#path - �C�x���g�����������p�X����Ԃ��܂�
  • TracePoint#defined_class - �C�x���g�������������\�b�h����`����Ă���N���X�i���W���[���j��Ԃ��܂�
  • TracePoint#method_id - �C�x���g�������������\�b�h����Ԃ��܂�
  • TracePoint#binding - �C�x���g�����������ӏ��� Binding �I�u�W�F�N�g��Ԃ��܂�
  • TracePoint#return_value - �C�x���g�������������̕Ԓl��Ԃ��܂�
  • TracePoint#raised_exception - �C�x���g�������������̗�O�I�u�W�F�N�g��Ԃ��܂�

event ���� binding �܂ł́Cset_trace_func �Ŏ�ꂽ���Ƃقړ����ł��D

TracePoint#return_value �́C:return, :c_return, :b_return �C�x���g�̎��̂ݗ��p�ł��郁�\�b�h�ŁCreturn �����������Ƃ��̕Ԓl��n���܂��D���̑��̃C�x���g�������ɂ��̃��\�b�h���Ă�ł���O���������܂��D

TracePoint#raised_exception �́C:raise �C�x���g�̎��̂ݗ��p�ł��郁�\�b�h�ŁC�ǂ̗�O�����������̂���Ԃ��܂��DTracePoint#return_value �Ɠ��l�ɁC���̑��̃C�x���g�������ɂ��̃��\�b�h���Ă�ł���O���������܂��D

���āCTracePoint#defined_class �́Cset_trace_func �ŗ��p�ł��� klass ���Ƃ͎኱�Ⴂ�܂��i��L�Łu�قځv�ƌ������̂͂��̓_���قȂ邽�߂ł��j�Dset_trace_func �ł́C���ك��\�b�h���Ă΂ꂽ�Ƃ��� klass �ɂ̓I���W�i���̃N���X���n���Ă��܂������CTracePoint#defined_class �ł͓��كN���X���Ԃ�悤�ɂȂ��Ă��܂��D����ɂ���āC���̃��\�b�h�����كN���X���ǂ����킩��悤�ɂȂ��Ă��܂��D

���āCtrace = TracePoint.trace{|tp| ...} �Ƃ����Ƃ��Ctrace �� tp ���C���͓����Ƃ������Ƃł������C�ł� �g���[�X�����s���Ă��Ȃ��Ƃ��ɁCtrace.event �ȂǂƂ���Ƃǂ��Ȃ�ł��傤���D�����͗�O����������C�ł����D

���āC3 ��Ńg���[�X�|�C���g���Љ�܂����D�F�X�Ɩʔ����g�������ł���V�@�\���Ǝv���܂��̂ŁC��������g���Ă݂ĉ������D

�ł́C�����͂��̕ӂŁD

_13(Thu)

Ruby VM �A�h�x���g�J�����_�[�� 13 ���ڂł��D

����� TracePoint �̗��p�Ⴞ���Љ�܂����D�R�[�h���Čf���܂��i�Ƃ����čs���҂��j�D

def m
  p :hello
  p :world
end

set_trace_func(proc{|event, file, line, id, binding, klass|
  puts "#{file}:#{line} #{id}" if event == 'line'
})

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

����� TracePoint �ŏ����������ł͎��ɁD

def m
  p :hello
  p :world
end

trace = TracePoint.trace(:line){|tp|
  puts "#{tp.path}:#{tp.lineno} #{tp.method_id}"
}

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

�g���[�X��ݒ肵�Ă���Ƃ���͎��̉ӏ��ł��ˁD

set_trace_func(proc{|event, file, line, id, binding, klass|
  puts "#{file}:#{line} #{id}" if event == 'line'
})

trace = TracePoint.trace(:line){|tp|
  puts "#{tp.path}:#{tp.lineno} #{tp.method_id}"
}

���āC�Ⴂ��������茩�čs���܂��傤�D

�܂��C�o�^�̃C���^�[�t�F�[�X�ɒ��ڂ��Ă݂܂��D

  • set_trace_func() �͊֐��I���\�b�h�ł����CTracePoint.trace �� TracePoint �N���X�̃N���X���\�b�h�ɂȂ��Ă��܂��D
  • set_trace_func �ł� Proc �I�u�W�F�N�g��z�ɓn���Ă��܂����CTracePoint.trace �ł̓u���b�N��n���Ă��܂��D�������̂ق����^�C�s���O�ʂ����Ȃ���������܂���ˁD
  • TracePoint.trace �ł́C�����ɃV���{���� :line �Ɠn���Ă��܂��D����́C:line �C�x���g�����g���[�X����C�Ƃ����w��ɂȂ�܂��D
  • set_trace_func �͕Ԓl�����܂��񂪁i�g���[�X�Ƃ��ēo�^���� Proc �I�u�W�F�N�g���Ԃ�܂��j�CTracePoint.trace �̕Ԓl�́CTracePoint �I�u�W�F�N�g�ł��āCtrace �Ƃ����ϐ��œo�^���Ă��܂�

����̗�ł͂��̕Ԓl�ł��� TracePoint �I�u�W�F�N�g�͎g���Ă��܂��񂪁Ctrace.disable �Ƃ��邱�ƂŁC���̃g���[�X���������ɂ��邱�Ƃ��ł��܂��D���Ȃ݂ɁC����Ȋ����ł��D

trace = TracePoint.trace{...}
...
trace.disable # �ȍ~�̓g���[�X�������ɂȂ�
...

���ɁC�g���[�X�Ƃ��ēn���u���b�N�����Ă݂܂��D

  • �ς��ƌ��Ă킩��̂��C�u���b�N�p�����[�^�̈Ⴂ�ł��Dset_trace_func �ł� event, file, line, id, binding, klass �ƁC�K�v�����ȃI�u�W�F�N�g���S���n���Ă��܂����CTracePoint.trace �ł� tp �����ł��D
  • ���̍s�ł� set_trace_func �ł͂��� line �Ȃǂ𒼐ڎg���ďo�͂��쐬���Ă��܂����CTracePoint.trace �ł� tp.lineno �ƁCtp �ւ̃��\�b�h�Ăяo�����s�����Ƃōs�ԍ��𓾂ďo�͂��쐬���Ă��܂��D

�Ƃ����킯�ŁC�傫�ȈႢ�Ƃ����������́C���� 4 �‚ɂȂ�܂��D

  • TracePoint.trace �͕Ԓl���d�v�ł���i�������ł���j
  • TracePoint.trace �ɂ̓u���b�N��n��
  • TracePoint.trace �ɂ̓g���[�X�������C�x���g���w�肷��
  • TracePoint.trace �ł́C�~�������̓u���b�N�p�����[�^�itp�j�ւ̃��\�b�h�Ăяo���Ŏ擾����

���āC��������Ă��� set_trace_func �̖��_�͉��������ł��傤���D�`�F�b�N���Ă݂܂��傤�D

  • (1) �Ăяo���C�x���g�̎�ނ𐧌��ł��Ȃ�

TracePoint.trace �ł́C������ :line �̂悤�ɁC�g���[�X�������C�x���g�̎�ނ��w��ł���̂ʼn������Ă��܂��D

  • (2) �����̃g���[�X���C���ꂼ��L���ɂ����薳���ɂ�����ł��Ȃ�

TracePoint.trace �ɂ���ē����� TracePoint �I�u�W�F�N�g�� TracePoint#disable ���\�b�h�ɂ���āC���̃g���[�X�݂̂𖳌��ɏo���܂��D

  • (3) �x��

�x�����R�͂����‚�����܂����DProc �I�u�W�F�N�g���Ăяo���R�X�g��������C�Ƃ������̂ł����C(1) �ŋ����̂Ȃ��C�x���g�ł� Proc �I�u�W�F�N�g�Ă΂�Ȃ��̂ŁCProc �̋N���R�X�g�̖��͎኱�������Ă��܂��D�܂��CBinding �I�u�W�F�N�g��K���쐬���Ă��܂��C�Ƃ������́Ctp.binding �Ƃ������\�b�h�ɂ���� Binding �I�u�W�F�N�g�̍쐬���w������܂ō쐬����Ȃ��̂ŁC�������肠��܂���D

���ۂɂ��߂��Ă݂܂��傤�D10����̃g���[�X�t���̃��\�b�h�Ăяo���ł��D

require 'benchmark'

def m
  a = 1
  b = a
  a = b
end

max = 100_000

Benchmark.bm{|x|
  x.report{
    set_trace_func(proc{|event, file, line, id, binding, klass|
      if event == 'line'
        # do something
      end
    })
    max.times{m}
    set_trace_func(nil)
  }
  x.report{
    trace = TracePoint.trace(:line){|tp|
      # do something
    }
    max.times{m}
    trace.disable
  }
}

���s���ʂł��D

ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
       user     system      total        real
   6.755000   0.016000   6.771000 (  7.176412)
   0.733000   0.000000   0.733000 (  0.775598)

10 �{�قǑ����Ȃ��Ă��܂��D�Ƃ������Cset_trace_func ���x�����������C�Ƃ������������o���邩������܂���D

  • (4) �C�x���g������ȏ㑝�₹�Ȃ�

�V�K API �Ȃ̂ŁC�C�x���g�𑝂₵�Ă��{���܂���D�܂��CTracePoint.trace �ł́C�g���[�X�������C�x���g���w�肷��悤�ɂȂ��Ă���̂ŁC�Ӑ}���Ȃ��C�x���g�����č���悤�ȃg���[�X�������Ȃ��悤�ɂȂ��Ă��܂��i���Ȃ݂ɁC�������ł͑S�C�x���g���󂯕t����悤�ɂȂ��Ă��܂����C�����͎��ȐӔC�ŁD����C������”\�������邱�Ƃ��l�����ď����ĉ������j�D����Ȋ����ŁC�݊����̖����������Ă��܂��D

�Ƃ����킯�ŁCTracePoint �ł́Cset_trace_func �Ɋ܂܂�Ă��� 4 �‚̖����������Ă��邱�Ƃ��킩��܂��D

���āC�����������Ȃ��Ă��܂����̂ŁCTracePoint �ׂ̍����Љ�͖����ɉ񂷂��Ƃɂ��܂��D

�ł́C�����͂��̕ӂŁD

_12(Wed)

Ruby VM �A�h�x���g�J�����_�[�� 12 ���ڂł��D

������ Ruby 2.0 ���瓱�����ꂽ TracePoint �ɂ‚��Ă��Љ�܂��D

�]�����Cset_trace_func(proc_object) �Ƃ����C���^�[�t�F�[�X������܂����D���܂�����p���܂��D

Ruby �C���^�v���^�̃C�x���g���g���[�X���� Proc �I�u�W�F�N�g�Ƃ��Ďw�肳�ꂽ proc ��o�^���܂��B proc �� nil ���w�肵���ꍇ�Ńg���[�X���I�t�ɂ��܂��B�u���b�N���w�肳�ꂽ�ꍇ�͂��̃u���b�N���g���[�X���� Proc �I�u�W�F�N�g�Ƃ��ēo�^���܂��B

�o�^�����g���[�X�iProc �I�u�W�F�N�g�j�́C�C�x���g���������邽�тɌĂ΂�܂��D�C�x���g�̎�ނ͎��̂Ƃ���ł��i���܂�����p���܂��j�D

  • "line": ���̕]���B
  • "call": ���\�b�h�̌Ăяo���B
  • "return": ���\�b�h�Ăяo������̃��^�[���B
  • "c-call": C�ŋL�q���ꂽ���\�b�h�̌Ăяo���B
  • "c-return": C�ŋL�q���ꂽ���\�b�h�Ăяo������̃��^�[���B
  • "class": �N���X��`�A���كN���X��`�A���W���[����`�ւ̓˓��B
  • "end": �N���X��`�A���كN���X��`�A���W���[����`�̏I���B
  • "raise": ��O�̔����B

1.9 �ł́C����𗘗p���āCdebug.rb �� profile.rb �Ȃǂ���������Ă��܂����D

�i���Ȃ݂ɁCThread#set_trace_func �Ȃǂ������ł����C����͏ȗ��j


set_trace_func �́i���������Ƃ�����ɂ́j�֗��ȋ@�\�Ȃ̂ł����C�����‚���肪����܂����D

  • (1) �Ăяo���C�x���g�̎�ނ𐧌��ł��Ȃ�
  • (2) �����̃g���[�X���C���ꂼ��L���ɂ����薳���ɂ�����ł��Ȃ�
  • (3) �x��

(1) �́C�Ⴆ�� line �C�x���g���������������ȁC�Ƃ����ꍇ���C���ׂẴC�x���g�Ńg���[�X���Ă΂�Ă��܂����߁Cline �����̏ꍇ�́C�Ⴆ�Ύ��̂悤�ɏ����K�v������܂����D

set_trace_func(proc{|event, file, line, id, binding, klass|
  case line
  when 'line'
    # ...
  else
    # ���͖�������
  end
})

�傫�Ȗ��ł͂Ȃ��ł����C������Ɩʓ|�������ł��ˁD

(2) �́u�����̃g���[�X���C���ꂼ��L���ɂ����薳���ɂ�����ł��Ȃ��v�Ƃ������ł����C�����̃g���[�X��lj����邱�Ƃ͂ł��܂��D�����C�������•ʂɖ����ɂ�����@�͂Ȃ��C�S�Ė����ɂ�����@��������܂���D

set_trace_func(proc{|*args| p [1, args]})
set_trace_func(proc{|*args| p [2, args]})

p :hello

set_trace_func(nil) # �����Ŗ����ɂ���

p :world

#=>
c:/ko1/ruby/clean-trunk/bin/ruby: warning: -K is specified; it is for 1.8 compatibility and may cause odd behavior
ruby 2.0.0dev (2012-12-21 trunk 38515) [i386-mswin32_100]
[1, ["c-return", "t.rb", 1, :set_trace_func, #<Binding:0x6fbf1c>, Kernel]]
[1, ["line", "t.rb", 2, nil, #<Binding:0x6fbb84>, nil]]
[1, ["c-call", "t.rb", 2, :proc, #<Binding:0x6fb9a4>, Kernel]]
[1, ["c-return", "t.rb", 2, :proc, #<Binding:0x6fb580>, Kernel]]
[1, ["c-call", "t.rb", 2, :set_trace_func, #<Binding:0x6faf68>, Kernel]]
[2, ["c-return", "t.rb", 2, :set_trace_func, #<Binding:0x6fa874>, Kernel]]
[2, ["line", "t.rb", 4, nil, #<Binding:0x6fa324>, nil]]
[2, ["c-call", "t.rb", 4, :p, #<Binding:0x6f9d84>, Kernel]]
[2, ["c-call", "t.rb", 4, :hash, #<Binding:0x6f96b8>, Kernel]]
[2, ["c-return", "t.rb", 4, :hash, #<Binding:0x6f8cb8>, Kernel]]
[2, ["c-call", "t.rb", 4, :inspect, #<Binding:0x6f81b4>, Symbol]]
[2, ["c-return", "t.rb", 4, :inspect, #<Binding:0x6f37f4>, Symbol]]
:hello
[2, ["c-return", "t.rb", 4, :p, #<Binding:0x6f331c>, Kernel]]
[2, ["line", "t.rb", 6, nil, #<Binding:0x6f2d18>, nil]]
[2, ["c-call", "t.rb", 6, :set_trace_func, #<Binding:0x6f228c>, Kernel]]
:world

1�Ԗڂ�2�Ԗڂ̃g���[�X�����ꂼ����s����Ă���̂��킩��Ǝv���܂����C1�‚߂��������ɂ���C�Ƃ������@���Ȃ��Ƃ������Ƃ��킩��܂��D

(3) �̒x���Ƃ����̂́C���킸�����ȂȂ̂ł����C�����Ƃ������ꂴ��ׂ���߂ł��D�v���t�@�C����f�o�b�K����肽���C�ȂǂƂ����p�r�ł́C�g���[�X�͏o���邾���Ώۃv���O�����ɉe����^���Ȃ����Ƃ����߂��܂��D

���������C���̋@�\�̓C�x���g���������邽�тɃg���[�X�����s���܂��̂ŁC���̋N���R�X�g��������܂��D�������C(1) �ŏq�ׂ��ʂ�C�����̂Ȃ��C�x���g���������Ă��C����g���[�X�����s�����܂��D�Ⴆ�� line �C�x���g�����g���[�X�������C�Ƃ����ꍇ���C���̃C�x���g�͉��������������܂���ŁC�������邾���ł��R�X�g�������邱�ƂɂȂ�܂��D

�N���R�X�g�ɂ‚��āC���������ׂ����݂Ă݂܂��ƁC�������� Proc �I�u�W�F�N�g�� call ����R�X�g��������܂��D�������C�������Ԃ�������̂ł�����܂��񂪁C�`�����ς���ΎR�ƂȂ�܂��D���́C���\�b�h�Ăяo�������x���ł��i����́C����̉ۑ�ł��j�D�܂��C�u���b�N�̈����ɓn�����I�u�W�F�N�g�̏�������ςł��D�Ƃ��ɁC�C�x���g�����������ӏ��� Binding �I�u�W�F�N�g�𐶐����܂����C���ꂪ�d���ł��D�f�o�b�K�p�r�ŗ��p����Ƃ��́CBinding �I�u�W�F�N�g���K�v�ɂȂ�܂����C�v���t�@�C���p�r�ł͕s�v�ȏꍇ�������ł��D�Ƃ����킯�ŁC�K�v��������K�v����Ȃ������肷������̏������C���񒚔J�ɂ��Ă���̂Œx���ł��D

���́C�d�l���肨��ю����҂Ƃ��Ă�����–�肪�����āC���ꂪ (4) �C�x���g������ȏ㑝�₹�Ȃ��C�Ƃ����݊����̖��Ȃ̂ł����D�V�����C�x���g��lj����悤�ƍl�����Ƃ��C��قǂ̂悤�ȁC�����̂Ȃ��C�x���g�𖳎�����悤�ȃv���O�����΂���Ȃ�悢�̂ł����C���݂� 8 �‚̃C�x���g�Ńg���[�X�����s����邱�Ƃ����l�����Ă��Ȃ��v���O�������z�肳��C�݊����ɖ�肪�����܂��D�Ƃ������C�C�x���g��lj��������ȁ[�Ǝv���Ă��̂ł���ˁC�Ԃ����Ⴏ�D


���āCset_trace_func �̖����������邽�߂̐V���ȋ@�\�� TracePoint �ɂȂ�܂��D

�Ⴆ�΁C�s�����s���ꂽ�Ƃ��Ƀt�@�C�����ƍs�ԍ��C�����ă��\�b�h����\������v���O�����́Cset_trace_func �ŏ����Ɖ��L�̂悤�ɂȂ�܂��D

def m
  p :hello
  p :world
end

set_trace_func(proc{|event, file, line, id, binding, klass|
  puts "#{file}:#{line} #{id}" if event == 'line'
})

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

����� TracePoint �ŏ���������Ǝ��̂悤�ɂȂ�܂��D

def m
  p :hello
  p :world
end

trace = TracePoint.trace(:line){|tp|
  puts "#{tp.path}:#{tp.lineno} #{tp.method_id}"
}

m

#=>
t.rb:10 
t.rb:2 m
:hello
t.rb:3 m
:world

���܂�C�Ⴂ�͂Ȃ��悤�ȋC�����܂����C�ׂ����Ƃ��낪�ς���Ă��܂��D������ƋL���������Ȃ��Ă��܂����̂ŁC��̓I�� TracePoint �̏Љ�͖����ɍs�����Ƃɂ��܂��D

�ł͍����͂��̕ӂŁD

_11(Tue)

Ruby VM �A�h�x���g�J�����_�[�� 11 ���ڂł��D

����� Flonum �ɂ‚��Ă��Љ�܂����D������ Flonum �̎��������Љ�܂��D

�ڍׂ� 2008 �N�ɘ_�����������̂ł��Q�Ɖ������D���{��ł��D

�X���C�h�̂ق������₷���ł��D�����D���ƁC�����ł� Fixnum �� 2 bit�CFloat �� 1 bit �̃^�O���Ƃ��܂������CRuby 2.0 �Ŏ������ꂽ Flonum �ł́CFloat �� 2 bit�CFixnum �� 1 bit�i����܂łƕς�炸�j�Ƃ����悤�Ɏ����������Ă��܂��D

�ɁC�ŏI�I�ɂǂ��������C�X���C�h�ɂ܂Ƃ߂Ă���܂��D

...�������Ƃ���܂�Ȃ̂ŁC�T�v�ł��D

  • Fixnum �Ɠ����悤�ɊǗ��������̂ŁCVALUE �ɑ��l�𖄂ߍ��ށC�Ƃ������Ƃ��l���܂��D
  • IEEE754 �{���x�\���� 64 bit �Ȃ̂ŁC����� VALUE �ɖ��ߍ��ނ��Ƃɂ��܂��i64bit �‹��̏ꍇ�CVALUE �� 64 bit �Ȃ̂Łj�D
  • �������CVALUE �� Float �ł���C�Ƌ�ʂ���K�v������̂ŁC�Ȃ�Ƃ��������DFixnum �͉��� 1 bit ���g���� Fixnum ������ȊO�𔻕ʂ��Ă���̂ŁC2 bit ���g���� Flonum ������ȊO�𔻒f����悤�ɂ��悤�D
  • �ƂȂ�ƁCIEEE754 �̔{���x�\���� 62 bit �ŕ\�����Ȃ���΂Ȃ�Ȃ����ǁC���𗎂Ƃ������Ȃ��̂łǂ����悤�D

�Ƃ����Ƃ��납��C�n�b�N�������Ă����킯�ł����C���ʓI�ɂ� exponential �̂Ƃ���� 2 bit �ׂ��āC�^�O�𖄂ߍ��ނ悤�ɂ��܂����D�ŁC2 bit �ׂ��Ə�񂪎����Ă��܂����߁C���߂����������͈͈ȊO�i����Љ�� 1.72723e-77 ���傫�� 1.15792e+77 �ȉ��Ƃ����͈́D����C�������������ȁH�@������Ƃ��������j��������CFlonum ����߂�C�Ƃ����悤�ɂȂ��Ă��܂��D�ŁC���͈̔͂Ƃ����̂� exponential �ł����Ɓi�ȉ����j�C�Ƃ������N�������n�b�N�ɂȂ�킯�ł��D���Ƃ͑f���炵���r�b�g���Z�̐��E�ɗ��Ƃ���킯�ł����C���̕ӂ̍œK���� shinh ����ɒ�Ă��Ē����܂����D�S���t�@�[�����D

��̓I�ɂ́Cinclude/ruby/ruby.h �� VALUE rb_float_new(double)�Cdouble rb_float_value(VALUE) ������ł��D���̐����Ƀt���X�g���[�V���������܂������́i�������܂�Ǝv���j�C���ЃR�[�h��ǂ�ł݂ĉ������D�Z������킩��₷���ł���D

�ł͍����͂��̕ӂŁD

_10(Mon)

Ruby VM �A�h�x���g�J�����_�[�� 10 ���ڂł��D

Ruby 2.0 ����C�|�C���^�� 64bit �ł���‹��ł� Flonum �𓱓����� Float�i���������_���j�̌v�Z�̍��������s���Ă��܂��D�����ɂ����ƁC�������Ǘ��̎��Ԃ������Ă��܂��D

Ruby 1.9 �܂ł́CFloat �̌v�Z���ʂ��ƂɁC�ʁX�̃I�u�W�F�N�g��Ԃ��Ă��܂����D

2.times{
  p((1.1 + 1.2).object_id)
}
#=> 5343490
#=> 5343340

�v�Z���ʂł��� 2.3 �Ƃ����I�u�W�F�N�g�ɑ΂��āC���ꂼ��ʁX�� object_id ���^�����Ă��邱�Ƃ��킩�邩�Ǝv���܂��D�‚܂�C�ʁX�̃I�u�W�F�N�g�ɂȂ��Ă��܂��D

����́C�S�Ă� Float �̌v�Z�ɓ��Ă͂܂�܂��āC�Ⴆ�� 1.1 + 1.2 + 1.3 �ł��ƁC�܂��� (1.1+1.2) �̌��ʂł��� 2.3 �����܂��āC����� 1.3 �𑫂��� 3.6 �Ƃ����I�u�W�F�N�g��Ԃ��܂��D�‚܂�C�ŏI�I�ɗ~�����I�u�W�F�N�g�� 3.6 �����Ȃ̂ł����C�����ł� 2.3 �Ƃ����]�v�ȃI�u�W�F�N�g������Ă��邱�ƂɂȂ�܂��D

�m�F���Ă݂܂��傤�i���L�ł́C�I�u�W�F�N�g�X�y�[�X�ɁC���łɕʂ� Float ������̂ŁC1.x �ł͂Ȃ��C100.x �ɕύX���Ă��܂��j�D

x = 100.1 + 100.2 + 100.3
ObjectSpace.each_object(Float){|f|
  p f if f > 100
}
#=>
300.6
200.3
100.3
100.2
100.1
Infinity
1.7976931348623157e+308

�]�v�ȃI�u�W�F�N�g�ł��� 200.3 ����������Ă��邱�Ƃ��킩��܂��D���̗�ł� 1 �‚����̗]�v�ȃI�u�W�F�N�g�ł����Ca0 + a1 + ... + aN �̂悤�� N ��̑����Z������ƁCN-2 �‚̗]�v�ȃI�u�W�F�N�g������Ă��܂����ƂɂȂ�܂��D

���̂悤�ɁCFloat �I�u�W�F�N�g��������������Ă���ƁC(1) Float �I�u�W�F�N�g�����̃I�[�o�w�b�h (2) GC �̃I�[�o�w�b�h�����ɂȂ�܂��D�Ƃ��ɁC���l�v�Z��p�ɂɍs���Ă���A�v���P�[�V�����̏ꍇ�C��{�I�� Float �I�u�W�F�N�g�͒Z���ł��邽�߁C(2) �����ɂȂ邱�Ƃ������ł��D

�ł́C�����͂ǂ����Ƃ����ƁCFixnum �͈̔͂ł͗]�v�ȃI�u�W�F�N�g�͍��܂���D�Ƃ������CFixnum �I�u�W�F�N�g�� GC �Ώۂ̃I�u�W�F�N�g�ł͂���܂���D�m�F���Ă݂܂��傤�D

n = 1 + 2 + 3
ObjectSpace.each_object(Fixnum){|i|
  p i #=> �����o�͂��Ȃ�
}

����́CRuby �����n�iMRI�j���CFixnum ����ʈ������Ă��邽�߂ł��iRHG ��2�� �I�u�W�F�N�g ���Q�Ɓj�D

���ʈ������Ă���̂ŁC�������l�� Fixnum �I�u�W�F�N�g�́C���� object_id �������܂��D��قǂƓ����悤�Ɋm�F���Ă݂܂��傤�D

2.times{
  p((11 + 12).object_id)
}
#=> 47
#=> 47

�ǂ���� 47 �ɂȂ�܂����D�‚܂�C33 �Ƃ��� Fixnum �I�u�W�F�N�g�� object_id �� 33 �Ƃ������Ƃł��i���̐��l���̂́C�����n�ɂ���ĕς�邱�Ƃ�����܂��D�Ⴆ�΁C64bit �Ńr���h���ꂽ Ruby �ł́C67 �ɂȂ�܂��j�D

�܂��CFixnum ����ʈ������Ă���̂ŁCFixnum �I�u�W�F�N�g�� GC �Ώۂ̃I�u�W�F�N�g�Ƃ��Ă͍쐬���ꂸ�C������ Fixnum �I�u�W�F�N�g�𗘗p���Ă��CGC �͋N����܂���D

GC ���N����Ȃ����Ƃ��m�F���Ă݂܂��傤�D

puts "GC count (before): #{GC.count}"
10_000_000.times{|i|
  n = i + i
}
puts "GC count (after): #{GC.count}"
#=>
GC count (before): 4
GC count (after): 4

GC �񐔂� 4 ��̂܂ܕς���Ă��Ȃ��̂ŁC���̌J��Ԃ����s���Ă� GC ���������Ă��Ȃ����Ƃ��킩��܂��D���Ȃ݂ɂ‚��łɁCFloat ���ǂ��Ȃ邩�C�ꉞ�m�F���Ă����܂��傤�D

puts "GC count (before): #{GC.count}"
10_000_000.times{|i|
  n = 1.1 + 1.2
}
puts "GC count (after): #{GC.count}"
#=>
ruby 1.9.3p332 (2012-11-15 revision 37660) [i386-mswin32_100]
GC count (before): 1
GC count (after): 776

775 �� GC ���Ă��邱�Ƃ��킩��܂��D

���̂悤�ɁCFixnum �͓��ʈ�������Ă��邪�CFloat �͓��ʈ�������Ă��Ȃ��C�Ƃ����̂����\��傫�������錴���ł����D

�����ŁCFloat �I�u�W�F�N�g����ʈ������� Float �̌v�Z�𑬂����悤�C�Ƃ����̂� Flonum �ł��DFixnum ���ǂ����ʈ�������āC�ǂ̂悤�Ȑ����������Ă������C�Ƃ����̂��܂Ƃ߂�Ǝ��̂悤�ɂȂ�܂��D

  • �����l�͓��� object_id ������
  • ���������Ă� GC �͑���Ȃ��iGC �Ƃ͓Ɨ��ɊǗ������j
  • �Ȃ̂ŁCObjectSpace �ɂ͏o�����Ȃ�

�ł́CFlonum ���������������n�ŁC����� 64 bit �‹��ł� Float �̓������m�F���Ă݂܂��傤�D

s = Hash.new(0)
puts "GC count (before): #{GC.count}"
10_000_000.times{|i|
  n = 1.1 + 1.2
  s[n.object_id]+=1
}
puts "GC count (after): #{GC.count}"
p s
ObjectSpace.each_object(Float){|f| p f}
#=>
ruby 2.0.0dev (2013-01-24 trunk 38925) [x86_64-linux]
GC count (before): 4
GC count (after): 4
{5404319552844594=>10000000}
NaN
Infinity
1.7976931348623157e+308
2.2250738585072014e-308

���̌��ʂ�����ƁC

  • (1) �����l�͓��� object_id�i5404319552844594�j������
  • (2) ���������Ă� GC �񐔂� 4 �̂܂܂Ȃ̂� GC �͑����Ă��Ȃ�
  • (3) ObjectSpace �ɂ� 2.3 �͏o�����Ȃ�

�Ƃ������Ƃ��킩��C�ق� Fixnum �Ɠ������������‚��Ƃ��킩��܂��D

�����CFixnum �Ƃ�����ƈႤ�̂��CObjectSpace �� Float �̃I�u�W�F�N�g�������Ă��܂��ˁD

NaN
Infinity
1.7976931348623157e+308
2.2250738585072014e-308

�������Ă��܂��D���́CFlonum �ł͑S�Ă� Float �ł͂Ȃ��C����͈͂� Float �I�u�W�F�N�g����ʈ������C���͈̔͊O�� Float �I�u�W�F�N�g�͏]���ǂ���́CFloat �I�u�W�F�N�g�����܂��D���̓��ʈ�������͈͂Ƃ́C+0.0�C����сC1.72723e-77 ���傫�� 1.15792e+77 �ȉ��͈̔͂ł��i�ׂ������l�͈Ⴄ�����j�D�����C���ʂ̐l�͂��͈̔͂𒴂���l�����܂�g��Ȃ��Ǝv���܂��̂ŁC�������� Flonum ���g����񂶂�Ȃ����Ǝv���܂��D

����ɔ����CFloat�CFixnum �Ƃ��� freeze �����悤�ɂȂ�܂����D

p 1.frozen?
p 1.2.frozen?
#=>
true
true

���āC�ł͊̐S�̐��\�����Ă݂܂��傤�D

require 'benchmark'
Benchmark.bm{|x|
  x.report{
    10_000_000.times{|i|
      n = 1.1 + 1.2
    }
  }
}

#=>
ruby 1.9.3p385 (2013-02-06 revision 39113) [x86_64-linux]
       user     system      total        real
   1.760000   0.000000   1.760000 (  1.761259)

ruby 2.0.0dev (2013-01-24 trunk 38925) [x86_64-linux]
       user     system      total        real
   1.210000   0.000000   1.210000 (  1.209062)

2.0 �̂ق��������Ȃ��Ă��邱�Ƃ��킩��Ǝv���܂��D

�ł͍����͂��̕ӂŁD

_9(Sun)

Ruby VM �A�h�x���g�J�����_�[�� 9 ���ڂł��D

����̋L���ł́CObjectSpace::InternalObjectWrapper �Ƃ������̂��o�ꂵ�܂����D���āC����͂��������Ȃ�ł��傤���D

ObjectSpace.reachable_objects_from(obj) �́Cobj �����ڎQ�Ƃ��邷�ׂẴI�u�W�F�N�g��Ԃ��̂ł����C���ɂ� Ruby ����͐G��ׂ��ł͂Ȃ��I�u�W�F�N�g�����݂��܂��D���̂悤�Ȃ��̂̏ꍇ�C��x InternalObjectWrapper �� wrap ���Ă���Ԃ��悤�ɂ��Ă��܂��D

���Ȃ݂ɁC�G��ׂ��łȂ��I�u�W�F�N�g�́C�ʏ�̃��\�b�h�̕Ԓl�ȂǂŎ�邱�Ƃ��o���Ȃ��̂͂������̂��ƁCObjectSpace.each_object �ł���邱�Ƃ͏o���Ȃ��悤�ɂȂ��Ă��܂��D

���ۂɁC�ǂ̂悤�Ȃ��̂����邩�C�����Ă݂܂��傤�D

require 'objspace'
require 'pp'

iseq = RubyVM::InstructionSequence.compile("puts 'hello'")
pp ObjectSpace.reachable_objects_from(iseq)
#=>
[RubyVM::InstructionSequence,
 #<InternalObject:0x1062c54 T_ARRAY>,
 "<compiled>",
 "<compiled>",
 #<InternalObject:0x1062c7c T_NODE>]

�����ł́C4�‚̃I�u�W�F�N�g�����܂����D���̂���2�‚� InternalObject �ɂȂ��Ă��܂��D�c��2�‚� "<compiled>" �Ƃ���������́CISeq#path �Ƃ��Ŏ�邽�߂̕�����ł��ˁD

�ł́C�B���ꂽ Array ������ #<InternalObject:0x1062c54 T_ARRAY> �ɁC���������Ă��邩���Ă݂܂��傤�D

require 'objspace'
require 'pp'

iseq = RubyVM::InstructionSequence.compile("puts 'hello'")
hide_array = ObjectSpace.reachable_objects_from(iseq)[1]
pp ObjectSpace.reachable_objects_from(hide_array)
#=>
["hello"]

�����񃊃e�����Ƃ��ė��p���� "hello" �Ƃ�����������i�[���Ă���Ƃ������Ƃ��킩��܂����D

���������C�Ȃ����̔z����B���I�u�W�F�N�g�ɂ��Ă��邩�Ƃ����ƁC���̔z��� ObjectSpace.each_object �ȂǂŎ��o���āC����ɕύX��������ƁC���̃o�C�g�R�[�h������s����̂ɖ�肪�����邽�߂ł��D�ŁC���̉B���z��I�u�W�F�N�g���Ȃ񂾂������Ƃ����ƁC�o�C�g�R�[�h�����p����I�u�W�F�N�g���C�o�C�g�R�[�h���������Ă��邠������ mark ���邽�߂̔z��ł��D��̓I�ɂ� rb_iseq_t::mark_ary �ł��D

�Ȃ��CInternalObjectWrapper �ɑ΂��� ObjectSpace.reachable_objects_from ���s���ƁC���� wrap �����Ώۂł�������I�u�W�F�N�g���Q�Ƃ��Ă���I�u�W�F�N�g�Q��Ԃ��܂��D���̋@�\�������邱�ƂŁC�u����I�u�W�F�N�g���N�_�Ƃ����C�I�u�W�F�N�g�̊֌W�O���t�v�����p�ł��邱�ƂɂȂ�܂��D

����1�‰����Ă����ƁC����� 1 �Ԗڂɂ��̉B���z��I�u�W�F�N�g������C�Ƃ������Ƃ��킩��܂������C���̏��Ԃ͂Ƃ��ɕۏ؂���Ă��܂���D��̓I�ɂ́Cmark �����̏��ԂŊi�[����Ă������ƂɂȂ�܂��D

���āCInternalObjectWrapper#object_id �́C������񂱂� wrapper �I�u�W�F�N�g�� object_id �����o���܂����Cwrap �����I�u�W�F�N�g�� object_id �����o���������Ƃ�����܂��D������CInternalObjectWrapper#internal_object_id �ɂ���ē��邱�Ƃ��o���܂��D����̋L���ł́C���̋@�\���g���� memsize_of_all_reachable_objects_from(obj) ���������Ă��܂����D

�ł́C�����͂��̕ӂŁD

_8(Sat)

Ruby VM �A�h�x���g�J�����_�[�� 8 ���ڂł��D

���낻�둧�؂ꂵ�Ă��܂����D

�����́C

�ŏЉ��Ă��� ObjectSpace.reachable_objects_from(obj) ���l�^�ɂ��Ă݂܂��D�Ȃ��C���̃��\�b�h�� require 'objspace' �Ƃ��āCobjspace ���C�u������ require ���Ȃ��Ǝg���܂���D

ObjectSpace.reachable_objects_from(obj) �́Cobj ���璼�ڒH�邱�Ƃ��ł���I�u�W�F�N�g�����ׂė񋓂��ĕԂ��܂��D

���ɗ�������܂��D

  • (1) When obj is ["a", "b", "c"], returns [Array, "a", "b", "c"]
  • (2) When obj is ["a", "a"], returns [Array, "a", "a"]
  • (3) When obj is [a = "a", a], returns [Array, "a"]

(1) �́C��薳���Ǝv���܂����C(2)�C(3) �̈Ⴂ�͂킩��ł��傤���D�����I�u�W�F�N�g�𕡐���H�邱�Ƃ��o����Ƃ��C1�‚����Ԃ��Ȃ��悤�ɂȂ��Ă��܂��D

���āC������g���āCobj ����H�邱�Ƃ��ł���C���ׂẴI�u�W�F�N�g���K�v�Ƃ��郁�����T�C�Y���v�Z����R�[�h�������Ă݂܂��D�u���ڂ��ǂ邱�Ƃ��ł���v�ł͂Ȃ��C�u�H�邱�Ƃ��ł���S�ẴI�u�W�F�N�g�v�Ƃ����Ƃ���ɒ��ӂ��ĉ������D�‚܂�C�ċA�I�� ObjectSpace.reachable_objects_from(obj) ��K�p���悤�C�Ƃ����킯�ł��D

�Ⴆ�΁C[['a' * 100, 'b' * 100], 'c' * 100] �Ƃ����z��́C������ 100 �̕�����I�u�W�F�N�g 3 �’H���̂ŁC���v 300 byte �Əo�ė~�����킯�ł��i�����ɂ́CArray �N���X�I�u�W�F�N�g���H���̂ł����C����͌v�Z���ʓ|�Ȃ̂ŏ��O���邱�Ƃɂ��܂��j�D

����I�u�W�F�N�g������郁�����T�C�Y�𓾂�ɂ́CObjectSpace.memsize_of(obj) �Ƃ������\�b�h�𗘗p���܂��D����́C1.9 �̎���������Ă��܂��D

�����ł����C�R�[�h�ł��D

require 'objspace'
require 'pp'

def memsize_of_all_reachable_objects_from(obj, exclude_class = Module)
  objs = {}
  queue = [obj]
  while obj = queue.pop
    next if objs[obj.object_id]
    next unless reachable_objects = ObjectSpace.reachable_objects_from(obj)
    reachable_objects.each{|o|
      case o
      when ObjectSpace::InternalObjectWrapper
        next if objs[o.internal_object_id]
      else
        next if objs[o.object_id]
      end
      queue.push o if !exclude_class || !o.kind_of?(exclude_class)
    }
    objs[obj.respond_to?(:internal_object_id) ? obj.internal_object_id : obj.object_id] = obj
  end
  objs.inject(0){|r, (_, o)| r += ObjectSpace.memsize_of(o)}
end

memsize_of_all_reachable_objects_from(obj, klass=Module) �́Cobj ����H��邷�ׂẴI�u�W�F�N�g�̃T�C�Y��Ԃ��܂��D�������C������ klass �Ŏw�肳�ꂽ�N���X�̃I�u�W�F�N�g�͏��O���܂��D�f�t�H���g�ł� Module �N���X�̃I�u�W�F�N�g�C�‚܂� Array �Ȃǂ͒H��Ȃ��悤�ɂ��Ă݂܂��Dnil �Ƃ��邱�Ƃŏ��O���Ȃ��悤�ɂȂ�܂��D

�ł́C����Ă݂܂��傤�D

p memsize_of_all_reachable_objects_from([['a' * 100, 'b' * 100], 'c' * 100])
#=> 300

������ 300 ���A���Ă��܂����D

���������Ȃ̂ŁCArray ���܂߂ăT�C�Y������Ă݂܂��D

p memsize_of_all_reachable_objects_from([['a' * 100, 'b' * 100], 'c' * 100], nil)
#=> 639428

���炢�����A���Ă��܂����DArray �N���X����H���I�u�W�F�N�g�́C�������ɂ̂ڂ�C���̍��v�T�C�Y���傫���C�Ƃ������ƂɂȂ�܂��i�r���ɂ��� objs �̃G���g���������Ă݂�Ƃ킩��̂ł����C�H�邱�Ƃ��ł��邷�ׂẴI�u�W�F�N�g�� 5604 �‚������ł��D�������C�‹��ɂ��”\��������܂��j�D

memsize_of_all_reachable_objects_from() �́C��r�I�ȒP�ȃ��\�b�h�ł����CObjectSpace::InternalObjectWrapper �Ƃ������̂��g���Ă��邱�Ƃɒ��ӂ��K�v�ł��D����ɂ‚��ẮC�܂����̋@��ɂ��Љ�܂��i�Ƃ��ăl�^���‚Ȃ���j�D������������� ext/objspace/objspace.c ��ǂ�ł݂ĉ������D

�ł́C�����͂��̕ӂŁD


���̘b�� RubyConf Taiwan 2012 �̂��߂ɏ����Ă����R�[�h�ł����D

�����Fhttp://www.atdot.net/~ko1/activities/rubyconf.tw2012_ko1.pdf

�����ɂ́C�}�t���Ő���������܂��D�Q�l�ɂ��ĉ������D

_7(Fri)

Ruby VM �A�h�x���g�J�����_�[�� 7 ���ڂł��D

����̘b�͂��邢����ɏC�������Ă�������̂ŁC������𒍈ӂ��ĉ������D

�Ȃ��C�u���b�N�̒��ŋN�����O�̃N���X�� Timeout::Error �ƈႤ���Ƃ����ƁC������ timeout ���l�X�g�������Ƃ��ɂ����Ƃ킩�邽�߁C�������ł��D

�Ƃ����킯�ŁC�����͂����܂łɂ��Ă����Ă����܂��i�蔲���j�D


���\���K�Ƃ��Ȃ��Ȃ��I���Ȃ��D

_6(Thu)

Ruby VM �A�h�x���g�J�����_�[�� 6 ���ڂł��D

�{���̓��\�b�h�Ăяo���̍������̘b�̑������������Ǝv���Ă����̂ł����C�\���ς��Ĕ񓯊��C�x���g�ɂ‚��Ă̘b���������Ǝv���܂��D

�Ƃ肠���������Ă����ƁCRuby 2.0 ���� timeout(3){loop{}} �̂悤�ȃv���O�������I���Ȃ��Ȃ肻���ł��i�ڍׂ͈ȉ��j�D�������̃v���O�����ŁC���̂悤�ȗႪ�������m�F���Ă݂ĉ������i���ۂɁC�������̃v���O�������ŐV�� trunk �Ńe�X�g���Ē����̂������ł��j�D�����C���̂悤�ȗႪ�݊����ɂ‚��ĂƂĂ����C�Ƃ������ƂɂȂ�悤��������C���̋����͕ύX�����”\��������܂��D


timeout(30) { ... } �Ə����Ă����ƁC30�b�ソ���Ă��u���b�N�����s���̏ꍇ�C�u���b�N�� Timeout::Error ��O�ɂ�蒆�f����܂��D

require 'timeout'
timeout(30){
  sleep 40
}
#=> t.rb:3:in `sleep': execution expired (Timeout::Error)

����͂ǂ�����Ď������Ă��邩�Ƃ����ƁCtimeout �u���b�N�����s���鎞�ɃX���b�h������1�‚��ĂāC���̃X���b�h�� 30 �b��Ƀu���b�N���s���̃X���b�h�� Thread#raise ���g���� Timeout::Error ���\�b�h�������܂��D30 �b�ȓ��Ƀu���b�N���I�������ꍇ�́C���̃^�C���A�E�g�𓊂��Ă���X���b�h���~���邱�Ƃŗ�O�𔭐������Ȃ��悤�ɂ��܂��D

���Č����͊ȒP�Ȃ̂ł����C����ɂ͎��̂悤�Ȗ�肪����܂����D

require 'timeout'
timeout(30){
  begin
    ... # ���� X
  ensure
    ... # ��n������
  end
}

���̂悤�ȃv���O�������N�����Ƃ��C���� X �̌�ŁC�K����n�����������邱�Ƃ����҂���܂��D�Ⴆ�΁C�t�@�C�����������肾�Ƃ��D

�������C���� X ���� Timeout::Error �����������̂Ȃ�ǂ��̂ł����C��n�������̍Œ��� Timeout::Error ����������Ƃ܂������ƂɂȂ�܂��D

���̂悤�Ȗ��ɑΏ����邽�߂ɁCThread.async_interrupt_timing �Ƃ������̂���������܂����i���O�͕ύX�����”\��������܂��D�Ƃ������C�����ύX���܂��j�D

�ʓ|�������b�͒u���Ƃ��āC���̏ꍇ�ǂ�����Ďg�����Ƃ����ƁCThread.async_interrupt_timing(Timeout::Error => :defer) { ... } �Ƃ��Ă����ƁC���̃u���b�N�̕����ł� Timeout::Error ��O�����Ă������i�u���b�N���甲�����Ƃ��͕��ʂɗ�O��������܂��j�ƂȂ�܂��i���Ȃ݂ɁC:defer �Ƃ����V���{�������C�ς��”\��������܂��D�V�����d�l�Ȃ̂ŁC�܂����O�ŔY��ł���̂ł��j�D

�t�ɁCThread.async_interrupt_timing(Timeout::Error => :immediate) �Ǝw�肷��ƁC�����ɗ�O���オ�邱�ƂɂȂ�܂��D

������g���āC��n���̍Œ��ɗ�O�������N���Ȃ��悤�ɂ���ƁC���̂悤�ɏ����܂��D

require 'timeout'
Thread.async_interrupt_timing(Timeout::Error => :defer){
  # �����ł͈�� Timeout::Error �͎󂯎��Ȃ��i���f���Ȃ��j
  timeout(30){
    begin
      Thread.async_interrupt_timing(Timeout::Error => :immediate){ 
        ... # ���� X�D�����ł� Timeout::Error �ɂ���Ē��f�����
      }
    ensure
      ... # ��n�������D�����ł͈�� Timeout::Error �͎󂯎��Ȃ��i���f���Ȃ��j
    end
  }
}

���������΁C��n�������̒��� Timeout::Error �Œ��f����邱�Ƃ��Ȃ����߁C���S�Ɍ�n�����������Ƃ��o���܂��D

���Ȃ݂ɁC

require 'timeout'
timeout(30){
  begin
      ... # ���� X�D�����ł� Timeout::Error �ɂ���Ē��f�����
    }
  ensure
    Thread.async_interrupt_timing(Timeout::Error => :defer){ 
      ... # ��n�������D�����ł͈�� Timeout::Error �͎󂯎��Ȃ��i���f���Ȃ��j
    }
  end
}

�������̂ق����ȒP�ł�������Ȃ����C�ƌ����邩������܂��񂪁C���ꂾ�� ensure ���n�܂����u�Ԃ� Timeout::Error ����M���Č�n�������������Ȃ��Ȃ��Ȃ�C�Ƃ����댯������܂��D���Ȃ݂ɁC���݂� MRI �̎����ł́C���̃^�C�~���O�ł͔񓯊��C�x���g���N���肦�Ȃ��̂ŁC���̐S�z�͂Ȃ��̂ł����C��ʓI�ɂ͋C��t����ׂ��ł��傤�D

���āC���� timeout ���������Ƃɂ��̂悤�ɏ璷�ȋL�q������͖̂ʓ|�Ȃ̂ŁC�݂�ȏ����Ȃ��Ȃ� �� �ςȂƂ���� Timeout::Error ���N����悤�ȃv���O�����ɂȂ��Ă��܂��C�Ƃ������O������܂��D

�����ŁC[Bug #7503] make timeout.rb async-interrupt safe by default �ɂ����āCtimeout �̋�����ς��Ă��܂����Ƃ����ύX�����肳��ɂ���Ă���Ă��܂��i����C�o�O����Ȃ���Ȃ��j�D

��قǁCThread.async_interrupt_timing �ł� :never�i��O�������Ȃ��j �� :immediate�i��O�������ɏグ��j�C�Ƃ����w������܂������C������C:on_blocking �Ƃ����w�肪����܂��i���‚����悤�ł����C:on_blocking �Ƃ������O�͕ύX�����”\��������܂��j�D

���� :on_blocking �Ƃ����w�������ƁC�w�肳�ꂽ��O���C��� I/O �����܂Œx�����邱�Ƃ��o���܂��D�O������̗�O�ɂ���Ē��f�����������p��̑����� I/O �̒��f�Ȃ̂ŁC����Ŏ������C�Ƃ����������o���܂��D

[Bug #7503] �̒�Ăł́C�utimeout �Œ��f�ł���u���b�N���C:on_blocking �ň͂�ł����āC���f�� I/O �����Ȃǂ̃^�C�~���O�ł����o���Ȃ��悤�ɂ��悤�v�Ƃ������̂ɂȂ��Ă��܂��D���̂悤�ɂ��邱�ƂŁCensure �ł̌�n���Ȃǂ̊ԂɊ��荞�܂�邱�Ƃ�h�����Ƃ��o���܂��D

�������C����ɂ͌݊����ɖ�肪����C�Ⴆ�� I/O �����̊܂܂Ȃ��v�Z�� timeout �Ńf�t�H���g�ł͒��f�ł��Ȃ��悤�ɂȂ��Ă��܂��D

require 'timeout'
timeout(30){
  # ���Ԃ̂�����v�Z�iI/O�����j
]

�������́C�������[�v�𒆒f�o���Ȃ��Ȃ�܂��D

require 'timeout'
timeout(30{
  loop{} # �������[�v
}

�܂��C��҂��܂Ƃ��ɏ����l�͋��Ȃ��Ƃ͎v���܂����C�O�҂͂��蓾��񂶂�Ȃ��́C�Ƃ����C�����Ă��܂��i�Ȃ̂ŁC�݊���100%�Ƃ����ڕW���f���Ă��� Ruby 2.0 �ɓ���ėǂ��̂����͂���܂���C����Ȃ��̂ł��j�D

���̂悤�ɁC�]���ʂ葦���ɒ��f���ė~�����Ƃ��́Ctimeout(sec, immediate: true) �̂悤�ɌĂׂΗǂ��C�Ƃ������Ƃł���C���������΂����Ɠ����܂��D�u���̏��������Ăˁv�Ƃ����ċ��e�ł��邩�ǂ����C�����̏C���̌݊����I�ȃL���ɂȂ�܂��D

�Ƃ����킯�ŁC����͎���3�‚̂��Љ�ł����D

  • timeout �ɂ͊댯�������ς�
  • Thread.async_interrupt_timing �ň��S��
  • timeout ��ύX���Ĉ��S��
    • �ύX�͔�݊������ǁC���e�͈͓��H�i�Ƃ���������̎���j

�ł͍����͂��̕ӂŁD


���H�c��`���ې��^�[�~�i���ŏ���p�D���̍΂ł��ǂ�ǂ񏉂߂Ă̂��Ƃ��o������Ă̂͂��肪�������Ƃ��Ȃ��D����C��������Ƃ��Ȃ����Ƃ΂���Ȃ񂾂��ǂ��D

_tarui(Thu Dec 06 10:30:07 +0900 2012)

�R�����g��preview�ɂ��܂��ꂽ�̂ŁA������x���e���Ă݂�B

�����A�ȉ��̂悤�ɂ���K�v���[ ensure�łȂ�Ƃ�����悤�ɂ������ł��ˁB preview2�ł�

# -*- coding: utf-8 -*-
require 'timeout'
e=Class.new(Exception)
Thread.async_interrupt_timing(e => :defer){
  # �����ł͈�� Timeout::Error �͎󂯎��Ȃ��i���f���Ȃ��j
  begin
    timeout(30,e){
      begin
        Thread.async_interrupt_timing(e => :immediate){
          ... # ���� X�D�����ł� timeout �ɂ���Ē��f�����
        }
      ensure
        ... # ��n�������D�����ł͈�� timeout �͎󂯎��Ȃ��i���f���Ȃ��j
      end
    }
    Thread.async_interrupt_timing(e=>:immediate){}
  rescue e
  end
}

trunk(�o�O���Ă邩������Ȃ�)�ł�

# -*- coding: utf-8 -*-
require 'timeout'
e=Class.new(Exception)
timeout(30,e){
  begin
    Thread.async_interrupt_timing(e => :immediate){
      ... # ���� X�D�����ł� timeout �ɂ���Ē��f�����
    }
  ensure
    Thread.async_interrupt_timing(e => :defer){     #blocking�ȏ��������ꍇ�ɕK�v
      ... # ��n�������D�����ł͈�� timeout �͎󂯎��Ȃ��i���f���Ȃ��j
    }
  end
}

�܂���

# -*- coding: utf-8 -*-
require 'timeout'
e=Class.new(Exception)
timeout(30,e){
  # preview2�ł͂�����timeout�ɂ���Ē��f�����”\��������
  Thread.async_interrupt_timing(e => :defer){     #previe2 or ensure��blocking�ȏ��������ꍇ�ɕK�v
    begin
      Thread.async_interrupt_timing(e => :immediate){
        ... # ���� X�D�����ł� timeout �ɂ���Ē��f�����
      }
    ensure
      ... # ��n�������D�����ł͈�� timeout �͎󂯎��Ȃ��i���f���Ȃ��j
    end
    }
  }
}

��ԍŌ�̃R�[�h��preview2�ł�����������肭�������܂��B(�‚܂�R�����g�ŏ������ꏊ��������)

_tarui(Thu Dec 06 11:49:28 +0900 2012)

�@���R�������̂�Y��Ă܂����B�‚܂�Atimeout�̃u���b�N���Ŕ��������O��Timeout::Error�ł͂Ȃ�����ł��B

_5(Wed)

Ruby VM �A�h�x���g�J�����_�[�� 5 ���ڂł��D

�o�b�N�g���[�X�̘b���������̂ŁC������ƕʂ̘b�����܂��D

���N�� RubyConf 2012 �ŁC���\�b�h�̍������̘b�����܂����D Ruby �̓��\�b�h�Ăяo�����R�s���̂ŁC���\�b�h�̍������͑厖�ł��D

Ruby 2.0 �ł́Csend ���\�b�h�̍œK����F�X�ƍs���Ă��܂��D���\�ł́C�����̒��̃G�b�Z���X���Љ�܂����D���\������ http://www.atdot.net/~ko1/activities/rubyconf2012_ko1_pub.pdf �ɂ���̂ŁC�Q�l�ɂ��Ă݂ĉ������D

�����͂��̕ӂŁi�蔲���j�D


RSS �̐����^�C�~���O���[�� 0 ���iJST�j�Ȃ̂ŁC�Ȃ񂩂��ڂ��Ă�悤�Ɍ����Ă������ȁD

_4(Tue)

Ruby VM �A�h�x���g�J�����_�[�� 4 ���ڂł��D

����܂ŁCRuby 2.0 ���瓱������� caller �܂��̘b�����Љ�Ă��܂����D�����̓o�b�N�g���[�X�܂��̍Ō�̘b�ł��D�����D

Ruby �ł́C��O�������Ƀo�b�N�g���[�X��񂪕ۑ�����܂��D�ۑ����Ă����Ȃ��ƁC���ƂŁi�Ⴆ�΃X�^�b�N�������߂�����Łj���̏����Q�Ƃł��Ȃ����߂ł��D

Ruby 1.9 �ȑO�ł́C��O�������� caller ���Ԃ��悤�ȃo�b�N�g���[�X���i������̔z��j�𐶐����C��O�I�u�W�F�N�g���ێ����Ă���悤�ɂȂ��Ă��܂����D�������C����͂�����ƒx���ł��D�t���[���T�C�Y���C������I�u�W�F�N�g�𐶐����āC�z��Ɋi�[���Ȃ���΂Ȃ�܂��񂩂�D

�����ŁCRuby 2.0 �ł́C��O�������ɂ� Thread::Backtrace �Ƃ����I�u�W�F�N�g�𐶐����邱�Ƃɂ��܂����D����́CException �I�u�W�F�N�g����͒��ڂ͎Q�Ƃł��Ȃ�����ȃI�u�W�F�N�g�ɂȂ��Ă��܂��iObjectSpace.each_objects �Ŋ撣��ΎQ�Ƃł��܂��j�D

Exception#backtrace ���Ă΂ꂽ�Ƃ��CThread::Backtrace �I�u�W�F�N�g�𕶎���z��ɂ��鏈��������C�]���́icaller ���Ԃ��悤�ȁj������z������߂č쐬���܂��D���̂悤�ɂ��邱�ƂŁCException#backtrace ���Q�Ƃ��Ȃ��ꍇ�i����t���[�Ƃ��ė�O�𗘗p���Ă���悤�ȏꍇ�j�̃I�[�o�w�b�h���팸���Ă��܂��D

�ł́C���ۂɑ����Ă݂܂��傤�D

require 'benchmark'

def rec n=100, &b
  n == 0 ? yield : rec(n-1, &b)
end

max = 100_000

Benchmark.bm{|x|
  x.report(" 10"){
    max.times{
      begin
        rec(10){raise}
      rescue # ignore raise
      end
    }
  }
  x.report("100"){
    max.times{
      begin
        rec(100){raise}
      rescue # ignore raise
      end
    }
  }
}
__END__
ruby 1.9.3p332 (2012-11-15 revision 37660) [i386-mswin32_100]
             user     system      total        real
 10 rec  2.262000   0.031000   2.293000 (  2.352799)
100 rec 10.437000   0.141000  10.578000 ( 10.638851)

ruby 2.0.0dev (2012-12-01 trunk 38127) [i386-mswin32_100]
            user     system      total        real
 10 rec 0.640000   0.015000   0.655000 (  0.652583)
100 rec 2.199000   0.031000   2.230000 (  2.280790)

�S�X�^�b�N�t���[���́C�o�b�N�g�[���X���𐶐����邽�߂ɕK�v�ɂȂ��� (*1) ��ۑ�������̂ŁC�ǂ����Ă��X�^�b�N�g���[�X�̃T�C�Y�ɔ�Ⴕ�����Ԃ������邱�ƂɂȂ��Ă��܂��܂����C������ 1.9 �ɔ�ׂĐ����Ƒ����Ȃ��Ă��邱�Ƃ��킩��̂ł͂Ȃ��ł��傤���D

(*1) ��̓I�ɂ� iseq + pc �ɂȂ�܂��D�{���͂���������ƕ��G�ł����D

�i��O�I�ɂ�����������Ȃ���O�̐����������Ȃ��āC�������l�͌���I���Ƃ͎v���܂���...�j

�Ȃ��Ccaller ����� caller_locations �́C���� Thread::Backtrace �I�u�W�F�N�g��1�x�������Ă���C������x�[�X�ɕ�����̔z��C�������� Thread::Backtrace::Location �̔z��𐶐����܂��D

�Ƃ����悤�ɁCRuby 2.0 ����o�b�N�g���[�X�܂��̍\����������ƕς��܂����D�ڂ����m�肽���l�� vm_backtrace.c ��ǂ�ł݂ĉ������D

�ł́C���̕ӂŁD


�O���V�傪������ꂽ�̂ŁC���낻��͐s���邩������Ȃ��D

_3(Mon)

Ruby VM �A�h�x���g�J�����_�[�� 3 ���ڂł��D

�������CRuby 2.0 �̐V�@�\�̂��Љ�ł��D

��� ���Љ�� caller_locations �ł����C������g�����ƂŊȒP�Ƀp�X���Ȃǂ��������o�����Ƃ��ł��܂��D�‚܂�Ccaller �ŕK�v�ł������p�X���̐؂�o���̂悤�Ȑ��K�\���̌Ăяo���Ȃǂ��s�v�ɂȂ�܂��D��������ƁC�‚܂�C���\���ǂ��Ȃ�̂ł��D

caller ���v���t�@�C���Ȃǂɗ��p���悤�Ƃ���Ƃ��C���\�͂ƂĂ��厖�ɂȂ�܂��i���\�͑厖�D�����C�e�X�g�ɏo�܂��j�D

�ł́C�������Ă݂܂��傤�D���K�\���Ő؂�o���łƁCpath ���\�b�h�����Ŏ��o���ł����C���Ԃ��v���Ă݂܂����D

require 'benchmark'

max = 100_000

Benchmark.bm{|x|
  x.report{
    max.times{
      /(.+):\d/ =~ caller(0)[0]
    }
  }
  x.report{
    max.times{
      caller_locations(0)[0].path
    }
  }
}
#=>
ruby 2.0.0dev (2012-12-01 trunk 38127) [i386-mswin32_100]
       user     system      total        real
   1.872000   0.000000   1.872000 (  1.882239)
   0.312000   0.000000   0.312000 (  0.315540)

path ���\�b�h�Ŏ��o���ł́C6 �{���x�������Ƃ��킩��܂��D�܂��C����Ⴛ���ł���ˁD

�i�Ȃ��C�����ł͂��傤�e�L�g�[�Ȑ��K�\�����g���Ă��邽�߁C":" ���܂ނ悤�ȃp�X���͐������p�[�X�ł��܂���D���̕ӂ��Cpath ���\�b�h���g�������b�g�ł��ˁj

���āC���\���l����ƁC���������u1��̃t���[�������v���̂Ȃ�C1�ゾ���Ԃ��Ă����΂����̂Ɂv�Ƃ������ƂɂȂ�܂��D

Ruby 2.0 ����CKernel#caller ����� Kernel#caller_locations �͑�2���� n ����邱�Ƃ��ł��C����̓X�^�b�N�̐[���ꏊ���� n �Ž��o���C�Ƃ����Ӗ��ɂȂ�܂��D����Ă݂܂��傤�D

def m
  p caller(0)    #=> ["t.rb:2:in `m'", "t.rb:7:in `<main>'"]
  p caller(0, 1) #=> ["t.rb:3:in `m'"]
  p caller(0, 2) #=> ["t.rb:4:in `m'", "t.rb:7:in `<main>'"]
end

m

���������ƁC�S�����o���C1 �Ǝw�肷��� 1 �‚������o���C�Ƃ������Ƃ��킩�����Ǝv���܂��D

�ł́C���ꂪ���\�ɂǂꂭ�炢�e�����邩���Ă݂܂��傤�D

require 'benchmark'

max = 100_000
Benchmark.bm{|x|
  x.report("caller w/o 2nd arg"){
    max.times{
      caller(0)[0]
    }
  }
  x.report("caller w/ 2nd arg"){
    max.times{
      caller(0, 1)[0]
    }
  }
  x.report("caller_loc w/o 2nd arg"){
    max.times{
      caller_locations(0)[0]
    }
  }
  x.report("caller_loc w/ 2nd arg"){
    max.times{
      caller_locations(0, 1)[0]
    }
  }
}

#=>
ruby 2.0.0dev (2012-12-01 trunk 38127) [i386-mswin32_100]
                            user     system      total        real
caller w/o 2nd arg      1.513000   0.000000   1.513000 (  1.555697)
caller w/ 2nd arg       0.265000   0.000000   0.265000 (  0.259033)
caller_loc w/o 2nd arg  0.297000   0.000000   0.297000 (  0.298538)
caller_loc w/ 2nd arg   0.093000   0.000000   0.093000 (  0.090512)

��2�����Ŏw�肵�����̂������Ƒ������Ƃ��킩��܂��D

�Ȃ��C����̓X�^�b�N�t���[���̃T�C�Y���傫���Ƃ�茰���ɂȂ�܂��i���Ȃ݂ɁC���̂Ƃ��̃X�^�b�N�t���[���̃T�C�Y�� 9 �ł����j�D

���߂��ɁC100�‚قǑ����āi�‚܂�C109�t���[���j�ő����Ă݂܂��傤�D

require 'benchmark'

def rec n=100, &b
  n == 0 ? yield : rec(n-1, &b)
end

max = 100_000
Benchmark.bm{|x|
  x.report("caller w/o 2nd arg"){
    rec{
      max.times{
        caller(0)[0]
      }
    }
  }
  x.report("caller w/ 2nd arg"){
    rec{
      max.times{
        caller(0, 1)[0]
      }
    }
  }
  x.report("caller_loc w/o 2nd arg"){
    rec{
      max.times{
        caller_locations(0)[0]
      }
    }
  }
  x.report("caller_loc w/ 2nd arg"){
    rec{
      max.times{
        caller_locations(0, 1)[0]
      }
    }
  }
}

#=>
ruby 2.0.0dev (2012-12-01 trunk 38127) [i386-mswin32_100]
                            user     system      total        real
caller w/o 2nd arg     19.172000   0.188000  19.360000 ( 19.644995)
caller w/ 2nd arg       0.500000   0.015000   0.515000 (  0.530067)
caller_loc w/o 2nd arg  3.478000   0.000000   3.478000 (  3.494444)
caller_loc w/ 2nd arg   0.297000   0.031000   0.328000 (  0.335042)

�Ȃ�ƁC��40�{���Ⴂ�܂��DRaila �Ȃǂ̃t���[�����[�N�𗘗p����ƁC�X�^�b�N�t���[�����傫���Ȃ邱�Ƃ������̂ŁC���� caller ��1�t���[�����������~�����C�Ƃ������͊��p���Ă��������D

���āCRails �Ƃ����Ⴊ�o�Ă����̂ŁC�����̍Ō�̘b����Љ�܂��D

Rails �Ȃǂ̃t���[�����[�N�̏ꍇ�C�X�^�b�N�̐[���Ƃ���̃t���[���̓t���[�����[�N�̕��ł���C�����̂���A�v���P�[�V�����̃X�^�b�N�t���[���͐󂢂Ƃ���̈ꕔ�����C�Ƃ������Ƃ�����܂��D�‚܂�Ccaller �̕����z������o�������C�Ƃ����p�r�ł��D

�����ŁCcaller ����� caller_locations �͑������� Range ���󂯂�悤�ɂȂ�܂����D

caller(2..8) �Ƃ���ƁC2�ォ��8��܂ł�6�t���[�����̏������o���܂��D�܂��C�t���[�����[�N�̃X�^�b�N�t���[����n����Ă��邱�Ƃ��킩���Ă���΁Ccaller(1..-n) �Ƃ��邱�ƂŁC1��̃t���[������C�S�X�^�b�N�t���[���̃T�C�Y - n �̕����X�^�b�N�t���[�������o�����Ƃ��ł��܂��D

������Ƃ킩��Â炢�ł����CArray#[range] �ƑS�������悤�ɍ���Ă���܂��̂ŁC�������� Array#[range] �̎g���������ĉ������D

���Ȃ݂ɁC�����Љ����2�����̒lj��C����ё�1������ Range ���󂯎���悤�ɂ���g���́CThread#backtrace ����� Thread#backtrace_locations �ɂ��s���Ă��܂��D

�ł́C�����͂��̕ӂŁD


caller �֌W�����łĂ��ˁ[����ˁ[���I

�ł��C����������Ƃ��������̂���D


http://gihyo.jp/news/info/2012/12/0101 �ɕ⑫����Ȃ��āC��͂芨�Ⴂ���Ă���悤�ŁC�����ł��D���ꂩ������Ⴂ���Ă��������D

_2(Sun)

Ruby VM �A�h�x���g�J�����_�[�� 2 ���ڂł��D

�������CRuby 2.0 �̐V�@�\�̂��Љ�ł��D

����܂ŁC���݂̎��s�ӏ��̃o�b�N�g���[�X�����擾���邽�߂� Kernel#caller �Ƃ������\�b�h������܂������C������኱�g���₷������ Kernel#caller_locations �Ƃ������\�b�h����������܂����D

�o�b�N�g���[�X���Ƃ́C���s���̃X���b�h���C�ǂ�ȃ��\�b�h�Ăяo���i����уu���b�N�Ăяo���j���s���Ă��邩�C�Ƃ������̂��������ŁC��O�������ɏo�͂����悤�Ȃ��̂ł��D

require 'pp'

def m1
  raise
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

pp m5
#=>
t.rb:4:in `m1': unhandled exception
	from t.rb:7:in `m2'
	from t.rb:8:in `m3'
	from t.rb:9:in `m4'
	from t.rb:10:in `m5'
	from t.rb:12:in `<main>'

���Ȃ݂ɁC��O�������̃o�b�N�g���[�X���́CException#backtrace �ɂ���Ď擾���邱�Ƃ��ł��܂��D

require 'pp'

def m1
  raise
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

begin
  pp m5
rescue => e
  pp e.backtrace
end

["t.rb:4:in `m1'",
 "t.rb:7:in `m2'",
 "t.rb:8:in `m3'",
 "t.rb:9:in `m4'",
 "t.rb:10:in `m5'",
 "t.rb:13:in `<main>'"]

���āC���݂̃o�b�N�g���[�X���擾���邽�тɖ����O���o���Ă��Ă͑�ςȂ̂ŁCKernel#caller ���\�b�h�����݂��܂��D

require 'pp'

def m1
  caller
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

pp m5
#=>
["t.rb:7:in `m2'",
 "t.rb:8:in `m3'",
 "t.rb:9:in `m4'",
 "t.rb:10:in `m5'",
 "t.rb:12:in `<main>'"]

Exception#backtrace �Ŏ��o�����o�b�N�g���[�X���ɂ���ׂāC`m1' ���\�b�h���s���ł���C�Ƃ�����񂪗����Ă��܂��ˁDcaller ���\�b�h�͑������ɐ����l�����C���–ڂ̃o�b�N�g���[�X���擾����̂��C�Ƃ����w�肪�s���C�f�t�H���g�l�� 1 �ɂȂ��Ă��܂��D�‚܂�C1 ��̃g���[�X���擾����C�Ƃ������ƂɂȂ�܂��D����� 0 �ɂ���ƁC���݂̃t���[���ʒu�̃g���[�X���擾���邱�Ƃ��ł��܂��D

require 'pp'

def m1
  caller(0)
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

pp m5
#=>
["t.rb:4:in `m1'",
 "t.rb:7:in `m2'",
 "t.rb:8:in `m3'",
 "t.rb:9:in `m4'",
 "t.rb:10:in `m5'",
 "t.rb:12:in `<main>'"]

����ŁCException#backtrace �Ɠ����\���ɂȂ�܂����D�Ȃ��C�Ȃ��f�t�H���g�l�� 1 �ł��邩�C�ł����C�����������[�X�P�[�X��������������C�ł����˂��D

���Ȃ݂ɁC���̃X���b�h�̌��݂̃o�b�N�g���[�X���͉����C�Ƃ������Ƃ𒲂ׂ� Thread#backtrace �Ƃ������\�b�h�����݂��܂��D

require 'pp'

def m1
  sleep
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

th = Thread.new{
  m5
}
sleep 0.1
pp th.backtrace
#=>
["t.rb:4:in `sleep'",
 "t.rb:4:in `m1'",
 "t.rb:7:in `m2'",
 "t.rb:8:in `m3'",
 "t.rb:9:in `m4'",
 "t.rb:10:in `m5'",
 "t.rb:13:in `block in <main>'"]

Thraed#backtrace ���\�b�h�𗘗p���邱�ƂŁC�X���b�h th �́C�� sleep �ŐQ�Ă���C�Ƃ������Ƃ��킩��܂��ˁD


���āC1.9 �܂ł� caller �ł́C��L�̂悤�� "#{path}:#{lineno} #{method_name}" �̂悤�Ȍ`�̕�����̔z�񂪕Ԃ��Ă��܂��D�����C���X path �����Clineno �����Cmethod_name �������~�����C�Ƃ����ꍇ������܂��D���̏ꍇ�C���K�\���Ȃ񂩂ŕ������؂�o���Ȃ���΂Ȃ�܂���D

�����ŁCRuby 2.0 ���� Kernel#caller_locations �Ƃ������\�b�h�����������\��ł��i�����j�Dcaller �Ɠ����g�����Ŏg����̂ł����C�Ԃ��Ă���l�� Thread::Backtrace::Location �Ƃ����N���X�̃I�u�W�F�N�g�ɂȂ�܂��D������ƒ����ł����C�ӂ[�̐l�́C���̃N���X�����������Ƃ͖����̂ŋ����ĉ������D

�ł́Ccaller �̑���� caller_locations ���g���Ă݂܂��D

require 'pp'

def m1
  caller_locations
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

pp m5
#=>
["t.rb:7:in `m2'",
 "t.rb:8:in `m3'",
 "t.rb:9:in `m4'",
 "t.rb:10:in `m5'",
 "t.rb:12:in `<main>'"]

�͂��C�������Ɠ������ʂ������܂����ˁD�����悤�ȕ\���ɂȂ��Ă��܂��̂ł�����Ƃ킩��Â炢�̂ŁC�e�v�f�̃N���X���m�F���Ă݂܂��傤�D

require 'pp'

def m1
  caller_locations
end

def m2; m1; end
def m3; m2; end
def m4; m3; end
def m5; m4; end

pp m5.map{|e| e.class}
#=>
[Thread::Backtrace::Location,
 Thread::Backtrace::Location,
 Thread::Backtrace::Location,
 Thread::Backtrace::Location,
 Thread::Backtrace::Location]

Thread::Backtrace::Location �Ƃ����N���X�ł��邱�Ƃ��킩��܂��DThread::Backtrace::Location.inspect ���C�Ӑ}�I�� String#inspect �̌��ʂƓ����\���������ɂȂ��Ă��邩��C�����悤�Ɍ������ł��ˁD

�i���C���Ȃ��� Ruby 2.0 �ł�

[#<Thread::Backtrace::Location:0x0000000159e920>,
 #<Thread::Backtrace::Location:0x0000000159e8f8>,
 #<Thread::Backtrace::Location:0x0000000159e8d0>,
 #<Thread::Backtrace::Location:0x0000000159e8a8>,
 #<Thread::Backtrace::Location:0x0000000159e880>]

�ƕ\���������āH�@���������āC�܂� Ruby 2.0.0 preview2 �����g������Ȃ���ł����I�H �i[ANN] ruby 2.0.0-preview2 released�j�j

�iinspect �̕ύX�� preview2 �����[�X���O�ɓ��ꂽ�̂ł����j

���āCThread::Backtrace::Location �͂����‚��֗̕��ȃ��\�b�h�������Ă��܂��D�܂��Cto_s ���s���ƁCcaller �̕Ԃ�������Ɠ����\�L�ɂȂ�܂��D

���ɂ́C���̂悤�ȃ��\�b�h������܂��D

  • path: �p�X����Ԃ��܂��D
  • absolute_path: �t���p�X���i����΁j�Ԃ��܂��D
  • lineno: �s�ԍ���Ԃ��܂��D
  • label: ���\�b�h���Ȃǂ�Ԃ��܂��D
  • base_label: ���\�b�h���Ȃǂ�Ԃ��܂��D�u���b�N�Ȃǂ̏��͓���܂���D

label �� base_label �Ɋւ��Ă͐������K�v�ł��傤�D

�Ⴆ�΁C�u���b�N�̒��� caller ���Ăяo���ƁC���̂悤�ɕ\������܂��D

1.times{
  p caller(0)
}
#=> ["t.rb:3:in `block in <main>'", "t.rb:2:in `times'", "t.rb:2:in `<main>'"]

�g�b�v���x���Ȃ̂ŁC<main> �����\�b�h���ɂ����镔���łł����C�u���b�N�̒��Ŏ��s����Ă���̂ŁC`block in <main>' �Ƃ����\�L�������Ă���܂��D�����C�����ŗ~�����̂� <main> �����������肷��ƁC������킴�킴���K�\���Ő؂�o���̂͂���ǂ��̂ŁCbase_label �Ƃ���� <main> �̕����������o����C�Ƃ����悤�ɂ��Ă��܂��D

�ł́C���ۂɎ����Ă݂܂��傤�D

require 'pp'

def m1
  1.times{
    $locs = caller_locations
  }
end

def m2; m1; end

class C
  tap{
    m2
  }
end

$locs.each{|loc|
  puts "path         : #{loc.path}"
  puts "absolute_path: #{loc.absolute_path}"
  puts "lineno       : #{loc.lineno}"
  puts "label        : #{loc.label}"
  puts "base_label   : #{loc.base_label}"
}

#=>
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 4
label        : times
base_label   : times
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 4
label        : m1
base_label   : m1
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 9
label        : m2
base_label   : m2
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 13
label        : block in <class:C>
base_label   : <class:C>
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 14
label        : tap
base_label   : tap
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 14
label        : <class:C>
base_label   : <class:C>
path         : t.rb
absolute_path: c:/ko1/src/rb/t.rb
lineno       : 11
label        : <main>
base_label   : <main>

��� �Љ�� ISeq#path �Ȃ񂩂Ɠ����悤�ȃC���^�[�t�F�[�X�ɂȂ��Ă���Ƃ����̂��킩��Ǝv���܂��D�Ƃ������C�����悤�ɂȂ�悤�ɍ��܂����D

�Ȃ��CThread#backtrace ���CThread::Backtrace::Location �̔z���Ԃ� Thread#backtrace_locations �Ƃ������\�b�h���lj�����Ă��܂��D

�ł́C�����͂���Ȋ����ŁD


�Ƃ����킯�ŁCRuby 2.0.0 preview2 ���o�܂����I�i[ANN] ruby 2.0.0-preview2 released�j�j

�F���񎎂��ĉ������D���͂��ĉ��������S�Ă̊F�l�Ɋ��Ӓv���܂��D

_kou(Mon Dec 03 10:10:13 +0900 2012)

inspect�̌��ʂ�


[#<Thread::Backtrace::Location "t.rb", 7, "in `m2'">,
 ...]

�Ƃ��A


[#<["t.rb", 7, "in `m2'"]>,
 ...]

�Ƃ����悤�Ƀp�[�X���ꂽ���ʂ�������Ă����ق������ꂵ���Ȃ��Ǝv���܂����Bcaller_locations���g�������Ƃ��̓p�[�X���ꂽ���ʂ��~�����̂ŁA�ǂ��p�[�X���ꂽ�����킩�����ق����������ł��B to_s�̕���caller�Ɠ����ł悢�Ǝv���܂��B

_������(Mon Dec 03 10:49:40 +0900 2012)

�@ML �ł��܂��傤�Dticket ����ĖႦ�܂����H

_1(Sat)

Ruby VM advent calendar #1

���� 12 ���ł��ˁD�������̂ł��D �A�h�x���g�J�����_�[�Ƃ����̂����s���Ă��邻���Ȃ̂ŁC���[�e�N�i�菑���j�łȂ񂩏����Ă݂܂��D�l�^�� Ruby VM �Ɋ֌W���鉽���Ŗ��߂Ă݂܂��D


VM �Ƃ����� bytecode �ł����CRuby �� VM �Ńo�C�g�R�[�h��\������̂� RubyVM::InstructionSequence �N���X�̃I�u�W�F�N�g�ł��D�����̂� ISeq �Ƃ��܂��D

�������Cpreview2 �ɊԂɍ��킹�邽�߂ɋ}���� RubyVM::InstructionSequence.of(obj) �Ƃ������\�b�h�����܂����D�������邩�Ƃ����ƁCProc �� Method ���󂯎���āCISeq ��Ԃ����\�b�h�ł��D

���ꂩ��CISeq#path �Ȃǂ����܂����DISeq ���ǂ̃t�@�C���ɂ��������C�Ƃ����̂�Ԃ��܂��D�ق��ɂ� variant ������܂����C�܂�����΂킩��܂���ˁD

���ꂪ����ƁC����ȃe�X�g�������܂��D

  LINE_OF_HERE = __LINE__
  def test_location
    iseq = ISeq.of(method(:test_location))

    assert_equal(__FILE__, iseq.path)
    assert(/#{__FILE__}/ =~ iseq.absolute_path)
    assert_equal("test_location", iseq.label)
    assert_equal("test_location", iseq.base_label)
    assert_equal(LINE_OF_HERE+1, iseq.first_lineno)

    line = __LINE__
    iseq = ISeq.of(Proc.new{})
    assert_equal(__FILE__, iseq.path)
    assert(/#{__FILE__}/ =~ iseq.absolute_path)
    assert_equal("test_location", iseq.base_label)
    assert_equal("block in test_location", iseq.label)
    assert_equal(line+1, iseq.first_lineno)
  end

���ꂩ��C���̂悤�ȃR�[�h�ŁC���ݑ��݂��� ISeq �����ׂďW�߂邱�Ƃ��ł��܂��D�ŏI�I�ɁC�t�@�C�������ƂɏW�v���C�s���Ń\�[�g�����`�ŏo�͂��Ă��܂��D

require 'pp'

h = Hash.new{|h, k| h[k] = []}
ObjectSpace.each_object(RubyVM::InstructionSequence){|iseq|
  h[iseq.absolute_path || iseq.path] << iseq
}

h.each{|file, iseqs|
  puts file
  pp iseqs.map{|iseq| [iseq.first_lineno, iseq.label]}.sort
}

�����͂��̕ӂŁD


��������ɃA�h�x���g�J�����_�[�����Ⴂ���Ă���񂾂낤�ȁD

Sasada Koichi / ko1 at atdot dot net
$Date: 2003/04/28 10:27:51 $