Performance: Faster to define a function writing out all arguments?

Alexander Fuchs alexander.fuchs at uni-koblenz.de
Wed May 7 10:25:04 EDT 2008


Hi there,

I am trying to write my first serious Haskell program, but have problems 
understanding 'strange' performance results. It seems to be a ghc 
specific question, so I am asking here.

In a happy parser I have this code 1):

%monad { Parsed } { thenP } { returnP }

type Parsed = State Env.Env

returnP :: a -> Parsed a
returnP a = return a

thenP :: Parsed a -> (a -> Parsed b) -> Parsed b
thenP x k = x >>= k


An alternative was this 2) (yes, redundant in happy):

returnP :: a -> Parsed a
returnP = return

thenP :: Parsed a -> (a -> Parsed b) -> Parsed b
thenP = (>>=)



And strangely enough on my machine 1) is faster by a few percent than 2) 
using ghc 6.8.2 with -O2. A few percent might seem unimportant, but I am 
currently developing my Haskell style. And I want to write efficient 
code by default, if that doesn't lead to obfuscation.


Now, first I dislike using option 1) because it seems pointlessly 
verbose. Second, I have no clue why option 2) should be faster.


Using ghc -O2 -C I get two code blocks with 1) (appended at the end of 
this mail), whereas I get nothing with 2.
Unfortunately, that doesn't help me as I have no clue what it means.

There are also various strictness annotations throughout the code to 
make parsing less memory hungry (and getting an intuition about what is 
appropriate here drives me crazy). Random guess: perhaps somehow 
strictness analysis of ghc benefits from the code in 1)?

Or does ghc create specialized versions of return and >>= for State 
instantiated to Parsed, i.e. State Env.Env?


Anyhow, I am puzzled and grateful for any explanations and 
recommendations about what is going on and when to avoid style 2).


Thanks,
	Alexander


C-- code blocks:

-------------------------------------------------------
EI_(DarwinziTptpziParser_a106_info);
StgWord DarwinziTptpziParser_a106_closure[] = {
(W_)&DarwinziTptpziParser_a106_info
};

static StgWord s8Ey_info[] = {
0x42U, 0x22U
};

IF_(s8Ey_ret) {
W_ _c8EL;
FB_
Sp[2] = *((P_)(R1.w+7));
_c8EL = *((P_)(R1.w+3));
R1.w = Sp[1];
Sp[1] = _c8EL;
Sp=Sp+1;
JMP_((W_)&stg_ap_pp_fast);
FE_
}

StgWord DarwinziTptpziParser_a106_info[] = {
0x30014U, 0x0, 0xfU
};

EI_(DarwinziTptpziParser_a106_closure);
II_(s8Ey_info);
FN_(DarwinziTptpziParser_a106_entry) {
FB_
if ((W_)(((W_)Sp - 0x4U) < (W_)SpLim)) goto _c8EO;
R1.w = *Sp;
Sp[-1] = Sp[2];
*Sp = (W_)&s8Ey_info;
Sp=Sp-1;
JMP_((W_)&stg_ap_p_fast);
_c8EO:
R1.w = (W_)&DarwinziTptpziParser_a106_closure;
JMP_(stg_gc_fun);
FE_
}
-------------------------------------------------------



-------------------------------------------------------
II_(r6AT_info);
static StgWord r6AT_closure[] = {
(W_)&r6AT_info, 0x0, 0x0, 0x0
};

static char c97W_str[] = "Internal Happy error\012";

static StgWord r6AT_info[] = {
0x0, 0x16U
};

EI_(base_GHCziBase_unpackCStringzh_info);
IF_(r6AT_entry) {
FB_
if ((W_)(((W_)Sp - 0xcU) < (W_)SpLim)) goto _c97Z;
Hp=Hp+2;
if ((W_)((W_)Hp > (W_)HpLim)) goto _c97Z;
Hp[-1] = (W_)&stg_CAF_BLACKHOLE_info;
newCAF((void *)R1.w);
R1.p[1] = (W_)Hp-4;
*R1.p = (W_)&stg_IND_STATIC_info;
Sp[-2] = (W_)&stg_upd_frame_info;
Sp[-1] = (W_)Hp-4;
Sp[-3] = (W_)&c97W_str;
Sp=Sp-3;
JMP_((W_)&base_GHCziBase_unpackCStringzh_info);
_c97Z:
HpAlloc = 0x8U;
JMP_(stg_gc_enter_1);
FE_
}
EI_(base_GHCziErr_error_closure);
II_(r6AT_closure);
StgWord DarwinziTptpziParser_notHappyAtAll_srt[] = {
(W_)&base_GHCziErr_error_closure, (W_)&r6AT_closure
};

EI_(DarwinziTptpziParser_notHappyAtAll_info);
StgWord DarwinziTptpziParser_notHappyAtAll_closure[] = {
(W_)&DarwinziTptpziParser_notHappyAtAll_info, 0x0, 0x0, 0x0
};

StgWord DarwinziTptpziParser_notHappyAtAll_info[] = {
((W_)&DarwinziTptpziParser_notHappyAtAll_srt+0), 0x0, 0x30016U
};

EI_(base_GHCziErr_error_closure);
II_(r6AT_closure);
FN_(DarwinziTptpziParser_notHappyAtAll_entry) {
FB_
if ((W_)(((W_)Sp - 0xcU) < (W_)SpLim)) goto _c989;
Hp=Hp+2;
if ((W_)((W_)Hp > (W_)HpLim)) goto _c989;
Hp[-1] = (W_)&stg_CAF_BLACKHOLE_info;
newCAF((void *)R1.w);
R1.p[1] = (W_)Hp-4;
*R1.p = (W_)&stg_IND_STATIC_info;
Sp[-2] = (W_)&stg_upd_frame_info;
Sp[-1] = (W_)Hp-4;
R1.w = (W_)&base_GHCziErr_error_closure;
Sp[-3] = (W_)&r6AT_closure;
Sp=Sp-3;
JMP_((W_)&stg_ap_p_fast);
_c989:
HpAlloc = 0x8U;
JMP_(stg_gc_enter_1);
FE_
}
-------------------------------------------------------







More information about the Glasgow-haskell-users mailing list