2012-06-11 11 views
6

क्यों यहाँ else साथ subeinssubzweielsif साथ की तुलना में धीमी है?क्या एल्सिफ़ से धीमा है?

#!/usr/bin/env perl 
use warnings; 
use 5.012; 
use Benchmark qw(:all); 

my $d = 0; 
my $c = 2; 

sub eins { 
    if ($c == 1) { 
     $d = 1; 
    } 
    else { 
     $d = 2; 
    } 
} 

sub zwei { 
    if ($c == 1) { 
     $d = 1; 
    } 
    elsif ($c == 2) { 
     $d = 2; 
    } 
} 

sub drei { 
    $d = 1; 
    $d = 2 if $c == 2; 
} 

cmpthese(-5, { 
    eins => sub{ eins() }, 
    zwei => sub{ zwei() }, 
    drei => sub{ drei() }, 
}); 

 Rate eins drei zwei 
eins 4167007/s -- -1% -16% 
drei 4207631/s 1% -- -15% 
zwei 4972740/s 19% 18% -- 

     Rate eins drei zwei 
eins 4074356/s -- -8% -16% 
drei 4428649/s 9% -- -9% 
zwei 4854964/s 19% 10% -- 

     Rate eins drei zwei 
eins 3455697/s -- -6% -19% 
drei 3672628/s 6% -- -14% 
zwei 4250826/s 23% 16% -- 

     Rate eins drei zwei 
eins 2832634/s -- -8% -19% 
drei 3088931/s 9% -- -12% 
zwei 3503197/s 24% 13% -- 

     Rate eins zwei drei 
eins 3053821/s -- -17% -26% 
zwei 3701601/s 21% -- -10% 
drei 4131128/s 35% 12% -- 

     Rate eins drei zwei 
eins 3033041/s -- -2% -12% 
drei 3092511/s 2% -- -10% 
zwei 3430837/s 13% 11% -- 

Summary of my perl5 (revision 5 version 16 subversion 0) configuration: 

Platform: 
    osname=linux, osvers=3.1.10-1.9-desktop, archname=x86_64-linux 
    uname='linux linux1 3.1.10-1.9-desktop #1 smp preempt thu apr 5 18:48:38 utc 2012 (4a97ec8) x86_64 x86_64 x86_64 gnulinux ' 
    config_args='-de' 
    hint=recommended, useposix=true, d_sigaction=define 
    useithreads=undef, usemultiplicity=undef 
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef 
    use64bitint=define, use64bitall=define, uselongdouble=undef 
    usemymalloc=n, bincompat5005=undef 
Compiler: 
    cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64', 
    optimize='-O2', 
    cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include' 
    ccversion='', gccversion='4.6.2', gccosandvers='' 
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678 
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16 
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 
    alignbytes=8, prototype=define 
Linker and Libraries: 
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib' 
    libpth=/usr/local/lib /lib/../lib64 /usr/lib/../lib64 /lib /usr/lib /lib64 /usr/lib64 /usr/local/lib64 
    libs=-lnsl -lndbm -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat 
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc 
    libc=/lib/libc-2.14.1.so, so=so, useshrplib=false, libperl=libperl.a 
    gnulibc_version='2.14.1'                                         
Dynamic Linking:                                           
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'                               
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'                           


Characteristics of this binary (from libperl): 
Compile-time options: HAS_TIMES PERLIO_LAYERS PERL_DONT_CREATE_GVSV 
         PERL_MALLOC_WRAP PERL_PRESERVE_IVUV USE_64_BIT_ALL 
         USE_64_BIT_INT USE_LARGE_FILES USE_LOCALE 
         USE_LOCALE_COLLATE USE_LOCALE_CTYPE 
         USE_LOCALE_NUMERIC USE_PERLIO USE_PERL_ATOF 
Built under linux 
Compiled at May 24 2012 20:53:15 
%ENV: 
    PERL_HTML_DISPLAY_COMMAND="/usr/bin/firefox -new-window %s" 
@INC: 
    /usr/local/lib/perl5/site_perl/5.16.0/x86_64-linux 
    /usr/local/lib/perl5/site_perl/5.16.0 
    /usr/local/lib/perl5/5.16.0/x86_64-linux 
    /usr/local/lib/perl5/5.16.0 
    . 
+0

मैं इसे एक टिप्पणी के रूप में डाल रहा हूं क्योंकि मुझे यकीन नहीं है कि पेर्ल काम की गड़बड़ी कैसे होती है, लेकिन मुझे लगता है कि 'ज़्वेई' 'elsif' निर्माण अधिक तेज़ी से पाया जा सकता है क्योंकि यह स्पष्ट रूप से बंधे हुए हैं '$ c' '2' होने के लिए, और' $ c' हमेशा '2' है। यदि दुभाषिया यह समझने के लिए पर्याप्त स्मार्ट है कि '$ c' कभी नहीं बदलता है, जो इसे समझा सकता है। इसके बावजूद आप 'ज़्वेई' धीमे होने की उम्मीद करेंगे, क्योंकि निश्चित रूप से इसे दो बार '$ c' का परीक्षण करना होगा। –

+0

दुभाषिया 'zwei' सशर्त को एक स्विच टेबल में भी बदल सकता है जैसे सी स्विच 'स्विच' के साथ करता है। – msw

+0

@ मैथ्यू वाल्टन, '$ सी' इसे आसानी से बदलकर बदल सकता है, इसलिए दुभाषिया ऐसा कोई अनुकूलन नहीं कर सकता है और नहीं कर सकता है। – ikegami

उत्तर

3

आप अपने विशिष्ट पर्ल संस्करण उत्पन्न opcodes जाँच करने के लिए होगा। दिलचस्प बात यह है कि जब एक डीबगर से चलाने के लिए, परिणाम अलग है:

Win64, Activeperl 5.14.2, from debugger environment: 
      Rate zwei eins drei 
zwei 130806/s -- -0% -1% 
eins 130957/s 0% -- -0% 
drei 131612/s 1% 1% -- 
डिबगर के बिना

, eins सबसे तेज है (के रूप में एक कोड से उम्मीद होती है): असल में

Win64, Activeperl 5.14.2 : 
      Rate drei zwei eins 
drei 3402015/s -- -5% -13% 
zwei 3585171/s 5% -- -8% 
eins 3916856/s 15% 9% -- 

, मैंने नहीं किया

Linux x64, Perl 5.12.1: 
      Rate drei zwei eins 
drei 2439279/s -- -13% -15% 
zwei 2797316/s 15% -- -3% 
eins 2875184/s 18% 3% -- 


: एक प्रणाली यहाँ जहां zwei eins की तुलना में तेजी है परिशिष्ट:

Ikegami की पोस्टिंग पढ़ने के बाद, मैं Win64 पर स्ट्राबेरी 5.16 की कोशिश की, और देखा:

Perl v5.16.0, MSWin32-x64-multi-t 
      Rate eins drei zwei 
eins 3954005/s -- -3% -10% 
drei 4084178/s 3% -- -7% 
zwei 4406707/s 11% 8% -- 

ये हम चले, elsif/zweiतेजी है।

तो, यह 5.16.0 से जुड़ा एक मुद्दा प्रतीत होता है?

4

[यह प्रति जवाब एक उत्तर है, लेकिन यह उपयोगी जानकारी है जो किसी टिप्पणी में फिट नहीं होती है। ]

सबसे पहले, चलिए संकलित रूप से तरफ देखो, अगर $c == 2, "ज़्वेई" का निष्पादन पथ "ईन्स" का शुद्ध सुपरसेट है। ("*" के साथ चिह्नित।)

*1 <0> enter       *1 <0> enter 
*2 <;> nextstate(main 4 -e:2) v:{  *2 <;> nextstate(main 4 -e:2) v:{ 
*3 <#> gvsv[*c] s      *3 <#> gvsv[*c] s 
*4 <$> const[IV 1] s     *4 <$> const[IV 1] s 
*5 <2> eq sK/2       *5 <2> eq sK/2 
*6 <|> cond_expr(other->7) vK/1   *6 <|> cond_expr(other->7) vK/1 
7  <0> enter v      7  <0> enter v 
8  <;> nextstate(main 1 -e:3) v:{ 8  <;> nextstate(main 1 -e:3) v:{ 
9  <$> const[IV 1] s     9  <$> const[IV 1] s 
a  <#> gvsv[*d] s     a  <#> gvsv[*d] s 
b  <2> sassign vKS/2     b  <2> sassign vKS/2 
c  <@> leave vKP      c  <@> leave vKP 
      goto d         goto d 
             *e <#> gvsv[*c] s 
             *f <$> const[IV 2] s 
             *g <2> eq sK/2 
             *h <|> and(other->i) vK/1 
*e <0> enter v       *i  <0> enter v 
*f <;> nextstate(main 2 -e:6) v:{  *j  <;> nextstate(main 2 -e:6) v:{ 
*g <$> const[IV 2] s     *k  <$> const[IV 2] s 
*h <#> gvsv[*d] s      *l  <#> gvsv[*d] s 
*i <2> sassign vKS/2     *m  <2> sassign vKS/2 
*j <@> leave vKP      *n  <@> leave vKP 
*d <@> leave[1 ref] vKP/REFC   *d <@> leave[1 ref] vKP/REFC 

बात यह है कि, मैं आपके परिणामों को पुन: उत्पन्न कर सकता हूं! (V5.16.0 के लिए बनाया गया x86_64-linux-धागे की बहु)

  Rate drei eins zwei 
drei 8974033/s -- -3% -19% 
eins 9263260/s 3% -- -16% 
zwei 11034175/s 23% 19% -- 

      Rate drei eins zwei 
drei 8971868/s -- -1% -21% 
eins 9031677/s 1% -- -20% 
zwei 11333871/s 26% 25% -- 

यह नहीं है एक छोटे से अलग (कि सीपीयू कैशिंग का परिणाम हो सकता है), और यह अलग रन के बीच reproduceable है (इसलिए यह नहीं एक और है बेंचमार्क को प्रभावित करने वाला आवेदन)। मैं उलझन में हूं। अधिक कम ऑप्स करने के लिए -

प्रति यात्रा, यह 22 एनएस (1/11333871 रों 1/9031677 रों) ले रहा है। मैं उम्मीद करता हूं कि यह लगभग 100 एनएस कम लेगा।

+0

क्या आप वाकई इसे कैश या कुछ के लिए जिम्मेदार नहीं ठहरा सकते हैं? हो सकता है कि आप यह देखने के लिए 'oprofile' की जांच कर सकें कि क्या कोई अंतर है (हालांकि मैं थोड़ा सा संदेह कर रहा हूं, मैं आमतौर पर oprofile डेटा को समझने में विफल रहता हूं)। – jpalecek

+0

@jpalecek, कैश कैश एक सौ मशीन ऑपकोड के बराबर हानि के लिए खाता याद कर सकता है? – ikegami

+0

हां, यह हो सकता है। हालांकि, मैं वास्तव में उस व्यवहार से परेशान हूं - किसी भी उचित माहौल में, एक छोटे से दिनचर्या को चलाने से कई कैश मिस उत्पन्न नहीं होनी चाहिए, तो शायद शाखा गलतफहमी हो सकती है? मुझे नहीं पता। – jpalecek

0

मुझे लगता है कि सबसे अच्छा जवाब अच्छी तरह से हो सकता है: "कौन परवाह करता है?"

यह सबसे समयपूर्व प्रकार का माइक्रो-बेंचमार्किंग है। अगर प्रोफाइलिंग में पता चलता है कि वास्तविक कोड धीमा होने का सबसे बड़ा कारण का उपयोग elsif के बजाय else का उपयोग कर रहा है तो मेरे पास बहुत अच्छी टोपी है कि मैं हारने के लिए लापरवाही करूँगा, लेकिन जो मैं दिल की धड़कन में खाऊंगा।

व्यक्तिगत रूप से मैं $d = ($c == 1) ? 1 : 2 लिखूंगा और इसके प्रदर्शन के बारे में सावधानी बरतूंगा।

संबंधित मुद्दे