PerlでのMRO::Compatの__get_linear_isa_dfsが遅い件について

# Perl MRO::Compat

経緯:
なんかやたらクローンでまわしている処理が重いためNYTProfで計測しました。
分かったことがMRO::Compatの__get_linear_isa_dfsを何十万回と呼び出していました。
何回もMRO::Compatを呼んでいたのは、DBIx::Class::Rowのinflate_resultを利用して動的にRoleを追加していた点でした。

対象環境
perl: 5.8.9
Moose: 2.0202
MRO::Compat: 0.11
DBIx::Class: 0.08119

分かったこと
1、MRO::Compatの__get_linear_isa_dfsはPerlのバージョンが5.009_005以下で呼ばれる。
2、最終的にどうすれば分からないことが判明した。

1、MRO::Compatの__get_linear_isa_dfsはPerlのバージョンが5.009_005以下で呼ばれる。

メソッド解決順序について


前回のブログとなんか繋がる内容ですね。

MRO-Compat-0.11/lib/MRO/Compat.pm
our $VERSION = '0.11';
 
BEGIN {
    # Alias our private functions over to
    # the mro:: namespace and load
    # Class::C3 if Perl < 5.9.5
    if($] < 5.009_005) {
        $mro::VERSION # to fool Module::Install when generating META.yml
            = $VERSION;
        $INC{'mro.pm'} = __FILE__;
        *mro::import            = \&__import;
        *mro::get_linear_isa    = \&__get_linear_isa;
        *mro::set_mro           = \&__set_mro;
        *mro::get_mro           = \&__get_mro;
        *mro::get_isarev        = \&__get_isarev;
        *mro::is_universal      = \&__is_universal;
        *mro::method_changed_in = \&__method_changed_in;
        *mro::invalidate_all_method_caches
                                = \&__invalidate_all_method_caches;
        require Class::C3;
        if($Class::C3::XS::VERSION && $Class::C3::XS::VERSION > 0.03) {
            *mro::get_pkg_gen   = \&__get_pkg_gen_c3xs;
        }
        else {
            *mro::get_pkg_gen   = \&__get_pkg_gen_pp;
        }
    }
 
    # Load mro.pm and provide no-op Class::C3::.*initialize() funcs for 5.9.5+
    else {
        require mro;
        no warnings 'redefine';
        *Class::C3::initialize = sub { 1 };
        *Class::C3::reinitialize = sub { 1 };
        *Class::C3::uninitialize = sub { 1 };
    }
} 



sub __get_linear_isa_dfs {
    no strict 'refs';
 
    my $classname = shift;
 
    my @lin = ($classname);
    my %stored;
    foreach my $parent (@{"$classname\::ISA"}) {
    	print "$parent\n"; ##ここを追加
        my $plin = __get_linear_isa_dfs($parent);
        foreach (@$plin) {
            next if exists $stored{$_};
            push(@lin, $_);
            $stored{$_} = 1;
        }
    }
    return \@lin;
}

以下結果です。  

```
DBIx::Class::InflateColumn::DateTime
DBIx::Class::InflateColumn
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::UUIDColumns
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Relationship
DBIx::Class::Relationship::Helpers
DBIx::Class::Relationship::HasMany
DBIx::Class::Relationship::HasOne
DBIx::Class::Relationship::BelongsTo
DBIx::Class::Relationship::ManyToMany
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Relationship::Accessor
DBIx::Class::Relationship::CascadeActions
DBIx::Class::Relationship::ProxyMethods
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Relationship::Base
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::InflateColumn
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::PK::Auto
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::ResultSourceProxy::Table
DBIx::Class::ResultSourceProxy
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
DBIx::Class::Componentised
Class::C3::Componentised
Class::Accessor::Grouped
Moose::Object

```

めっちゃDBIx::Class::ComponentisedとClass::C3::ComponentisedとClass::Accessor::Groupedを呼んでいる

次はさらに2回目のforeachも見てみました。

sub __get_linear_isa_dfs {
    no strict 'refs';
 
    my $classname = shift;
 
    my @lin = ($classname);
    my %stored;
    foreach my $parent (@{"$classname\::ISA"}) {
    	print "$parent\n"; ##ここを追加
        my $plin = __get_linear_isa_dfs($parent);
        foreach (@$plin) {
        	print "OYA:::$_\n"; ##ここを追加
            next if exists $stored{$_};
            push(@lin, $_);
            $stored{$_} = 1;
        }
    }
    return \@lin;
}


```
Tachyon::Schema::Result
DBIx::Class::InflateColumn::DateTime
DBIx::Class::InflateColumn
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped

OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::InflateColumn
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::InflateColumn::DateTime
OYA:::DBIx::Class::InflateColumn
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::UUIDColumns
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::UUIDColumns
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Relationship
DBIx::Class::Relationship::Helpers

DBIx::Class::Relationship::HasMany
OYA:::DBIx::Class::Relationship::HasMany

DBIx::Class::Relationship::HasOne
OYA:::DBIx::Class::Relationship::HasOne

DBIx::Class::Relationship::BelongsTo
OYA:::DBIx::Class::Relationship::BelongsTo

DBIx::Class::Relationship::ManyToMany
OYA:::DBIx::Class::Relationship::ManyToMany

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship::Helpers
OYA:::DBIx::Class::Relationship::HasMany
OYA:::DBIx::Class::Relationship::HasOne
OYA:::DBIx::Class::Relationship::BelongsTo
OYA:::DBIx::Class::Relationship::ManyToMany
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Relationship::Accessor
OYA:::DBIx::Class::Relationship::Accessor

DBIx::Class::Relationship::CascadeActions
OYA:::DBIx::Class::Relationship::CascadeActions

DBIx::Class::Relationship::ProxyMethods
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship::ProxyMethods
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Relationship::Base
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship::Base
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship
OYA:::DBIx::Class::Relationship::Helpers
OYA:::DBIx::Class::Relationship::HasMany
OYA:::DBIx::Class::Relationship::HasOne
OYA:::DBIx::Class::Relationship::BelongsTo
OYA:::DBIx::Class::Relationship::ManyToMany
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship::Accessor
OYA:::DBIx::Class::Relationship::CascadeActions
OYA:::DBIx::Class::Relationship::ProxyMethods
OYA:::DBIx::Class::Relationship::Base

DBIx::Class::InflateColumn
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::InflateColumn
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::PK::Auto
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::PK::Auto
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::PK
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::ResultSourceProxy::Table
DBIx::Class::ResultSourceProxy
DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::ResultSourceProxy
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::ResultSourceProxy::Table
OYA:::DBIx::Class::ResultSourceProxy
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped

DBIx::Class::Componentised

Class::C3::Componentised
OYA:::Class::C3::Componentised
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised

Class::Accessor::Grouped
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Core
OYA:::DBIx::Class::Relationship
OYA:::DBIx::Class::Relationship::Helpers
OYA:::DBIx::Class::Relationship::HasMany
OYA:::DBIx::Class::Relationship::HasOne
OYA:::DBIx::Class::Relationship::BelongsTo
OYA:::DBIx::Class::Relationship::ManyToMany
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::Relationship::Accessor
OYA:::DBIx::Class::Relationship::CascadeActions
OYA:::DBIx::Class::Relationship::ProxyMethods
OYA:::DBIx::Class::Relationship::Base
OYA:::DBIx::Class::InflateColumn
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::PK::Auto
OYA:::DBIx::Class::PK
OYA:::DBIx::Class::ResultSourceProxy::Table
OYA:::DBIx::Class::ResultSourceProxy
OYA:::Tachyon::Schema::Result
OYA:::DBIx::Class::InflateColumn::DateTime
OYA:::DBIx::Class::InflateColumn
OYA:::DBIx::Class::Row
OYA:::DBIx::Class::Componentised
OYA:::Class::C3::Componentised
OYA:::Class::Accessor::Grouped
OYA:::DBIx::Class::UUIDColumns
OYA:::DBIx::Class::Core
OYA:::DBIx::Class::Relationship
OYA:::DBIx::Class::Relationship::Helpers
OYA:::DBIx::Class::Relationship::HasMany
OYA:::DBIx::Class::Relationship::HasOne
OYA:::DBIx::Class::Relationship::BelongsTo
OYA:::DBIx::Class::Relationship::ManyToMany
OYA:::DBIx::Class::Relationship::Accessor
OYA:::DBIx::Class::Relationship::CascadeActions
OYA:::DBIx::Class::Relationship::ProxyMethods
OYA:::DBIx::Class::Relationship::Base
OYA:::DBIx::Class::PK::Auto
OYA:::DBIx::Class::PK
OYA:::DBIx::Class::ResultSourceProxy::Table
OYA:::DBIx::Class::ResultSourceProxy
Moose::Object
OYA:::Moose::Object
$VAR1 = [
          'Tachyon::Schema::Result::Campaign',
          'Tachyon::Schema::Result',
          'DBIx::Class::InflateColumn::DateTime',
          'DBIx::Class::InflateColumn',
          'DBIx::Class::Row',
          'DBIx::Class',
          'DBIx::Class::Componentised',
          'Class::C3::Componentised',
          'Class::Accessor::Grouped',
          'DBIx::Class::UUIDColumns',
          'DBIx::Class::Core',
          'DBIx::Class::Relationship',
          'DBIx::Class::Relationship::Helpers',
          'DBIx::Class::Relationship::HasMany',
          'DBIx::Class::Relationship::HasOne',
          'DBIx::Class::Relationship::BelongsTo',
          'DBIx::Class::Relationship::ManyToMany',
          'DBIx::Class::Relationship::Accessor',
          'DBIx::Class::Relationship::CascadeActions',
          'DBIx::Class::Relationship::ProxyMethods',
          'DBIx::Class::Relationship::Base',
          'DBIx::Class::PK::Auto',
          'DBIx::Class::PK',
          'DBIx::Class::ResultSourceProxy::Table',
          'DBIx::Class::ResultSourceProxy',
          'Moose::Object'
        ];
```