我最近在我的代码上执行了一些清理,并且在此过程中更改了这个(不是真正的代码):
read = act readSTRef
test1 term i var = do
t <- fromRTerm term
v <- rep var
ty <- v^!varType.read
ts <- v^!terms.read
let ts' = TL.toVector ts
when (ty /= Void && V.length ts' == 1) . updateChild term t i $ ts' V.! 0
V.mapM_ substitute ts'
到此:
read = act readSTRef
test2 term i var = do
t <- fromRTerm term
v <- rep var
ty <- v^!varType.read
ts <- TL.toVector <$> v^!terms.read
when (ty /= Void && V.length ts == 1) . updateChild term t i $ ts V.! 0
V.mapM_ substitute ts
显然,这些在语义上是相同的。但是,后来的运行速度明显变慢了(我测试的只是改变那些线以确保这是实际原因)。看看倾销的核心,我无法找出任何明显的差异,<$>
似乎在两者中都有内联。为什么GHC不能将后者优化为前者?
我应该注意到我的程序中有多个位置可以用任何一种方式编写,<$>
的性能影响在它们之间是一致的(大约每秒半秒)。
我已经删除了测试的核心,因为很明显它们是相同的。所以,这是实际功能的核心。
第一种方式:
case ipv5_X2Q6 of _ [Occ=Dead] {
__DEFAULT ->
case GHC.Prim.writeMutVar#
@ s_aJBu
@ TypeInferencer.Stage
dt5_dMoe
TypeInferencer.Substituted
ipv4_X2Q4
of s2#_aP5h { __DEFAULT ->
letrec {
a15_sSPP [Occ=LoopBreaker]
:: [GHC.Types.Int]
-> [TypeInferencer.RNode s_aJBu]
-> GHC.Prim.State# s_aJBu
-> (# GHC.Prim.State# s_aJBu, () #)
[LclId, Arity=3, Str=DmdType <S,1*U><L,1*U><L,U>]
a15_sSPP =
\ (ds_aPlu :: [GHC.Types.Int])
(_ys_aPlv :: [TypeInferencer.RNode s_aJBu])
(eta_B1 :: GHC.Prim.State# s_aJBu) ->
case ds_aPlu of _ [Occ=Dead] {
[] -> (# eta_B1, GHC.Tuple.() #);
: ipv6_aPlA ipv7_aPlB ->
case _ys_aPlv of _ [Occ=Dead] {
[] -> (# eta_B1, GHC.Tuple.() #);
: ipv8_aPlH ipv9_aPlI ->
tick<substitute.go>
case scc<substitute.go>
(scctick<fromRNode>
GHC.STRef.readSTRef1
@ s_aJBu
@ (Data.Either.Either
(TypeInferencer.Term s_aJBu) (TypeInferencer.Var s_aJBu))
(ipv8_aPlH
`cast` (TypeInferencer.NTCo:RNode[0] <s_aJBu>_N
:: TypeInferencer.RNode s_aJBu
~#
GHC.STRef.STRef
s_aJBu
(Data.Either.Either
(TypeInferencer.Term s_aJBu)
(TypeInferencer.Var s_aJBu)))))
eta_B1
of _ [Occ=Dead] { (# ipv10_X2DV, ipv11_X2DX #) ->
case ipv11_X2DX of _ [Occ=Dead] {
Data.Either.Left ds5_dLX6 ->
case scc<substitute.go> a11_rYpY @ s_aJBu ipv8_aPlH ipv10_X2DV
of _ [Occ=Dead] { (# ipv12_a2tf, ipv13_a2tg #) ->
a15_sSPP ipv7_aPlB ipv9_aPlI ipv12_a2tf
};
Data.Either.Right var_aJrt ->
case scc<substitute.go> a14_sPTG ipv10_X2DV
of _ [Occ=Dead] { (# ipv12_X2PP, ipv13_X2PR #) ->
tick<rep>
case scc<substitute.go>
scc<rep> a4_rYnT @ s_aJBu var_aJrt ipv12_X2PP
of _ [Occ=Dead] { (# ipv14_X2PW, ipv15_X2PY #) ->
case scc<substitute.go>
scc<rep> a3_rYnR @ s_aJBu ipv15_X2PY var_aJrt ipv14_X2PW
of _ [Occ=Dead] { (# ipv16_X2Q0, ipv17_X2Q2 #) ->
case ipv17_X2Q2
of _ [Occ=Dead]
{ TypeInferencer.Var dt6_dMth x1_XJka dt7_dMti dt8_dMtj dt9_dMtk
dt10_dMtl dt11_dMtm ->
case scc<substitute.go>
GHC.Prim.readMutVar#
@ s_aJBu @ TypeInferencer.VarType dt7_dMti ipv16_X2Q0
of _ [Occ=Dead] { (# ipv18_X2Qt, ipv19_X2Qv #) ->
case scc<substitute.go>
GHC.Prim.readMutVar#
@ s_aJBu
@ (TreeList.TreeList (TypeInferencer.RNode s_aJBu))
dt9_dMtk
ipv18_X2Qt
of _ [Occ=Dead] { (# ipv20_X2QL, ipv21_X2QN #) ->
case scc<substitute.go>
scctick<substitute.go.ts'>
TreeList.toVector @ (TypeInferencer.RNode s_aJBu) ipv21_X2QN
of _ [Occ=Dead] { Data.Vector.Vector ww1_sTzM ww2_sTzN ww3_sTzO ->
tick<==>
tick</=>
case scc<substitute.go>
let {
$w$j_sTA0
:: GHC.Prim.State# s_aJBu -> (# GHC.Prim.State# s_aJBu, () #)
[LclId, Arity=1, Str=DmdType <L,U>]
$w$j_sTA0 =
\ (w_sTzY :: GHC.Prim.State# s_aJBu) ->
letrec {
$s$wa_sWUL [Occ=LoopBreaker]
:: GHC.Prim.Int#
-> GHC.Prim.State# s_aJBu
-> (# GHC.Prim.State# s_aJBu, () #)
[LclId, Arity=2, Str=DmdType <L,U><L,U>]
$s$wa_sWUL =
\ (sc_sWUJ :: GHC.Prim.Int#)
(sc1_sWUK :: GHC.Prim.State# s_aJBu) ->
case GHC.Prim.tagToEnum#
@ GHC.Types.Bool (GHC.Prim.>=# sc_sWUJ ww2_sTzN)
of _ [Occ=Dead] {
GHC.Types.False ->
case GHC.Prim.indexArray#
@ (TypeInferencer.RNode s_aJBu)
ww3_sTzO
(GHC.Prim.+# ww1_sTzM sc_sWUJ)
of _ [Occ=Dead] { (# ipv22_aQSr #) ->
case a11_rYpY @ s_aJBu ipv22_aQSr sc1_sWUK
of _ [Occ=Dead] { (# ipv23_X2EL, ipv24_X2EN #) ->
$s$wa_sWUL (GHC.Prim.+# sc_sWUJ 1) ipv23_X2EL
}
};
GHC.Types.True -> (# sc1_sWUK, GHC.Tuple.() #)
}; } in
$s$wa_sWUL 0 w_sTzY } in
第二种方式:
case ipv5_X2Q6 of _ [Occ=Dead] {
__DEFAULT ->
case GHC.Prim.writeMutVar#
@ s_aJBt
@ TypeInferencer.Stage
dt5_dMog
TypeInferencer.Substituted
ipv4_X2Q4
of s2#_aP5h { __DEFAULT ->
letrec {
a15_sSPP [Occ=LoopBreaker]
:: [GHC.Types.Int]
-> [TypeInferencer.RNode s_aJBt]
-> GHC.Prim.State# s_aJBt
-> (# GHC.Prim.State# s_aJBt, () #)
[LclId, Arity=3, Str=DmdType <S,1*U><L,1*U><L,U>]
a15_sSPP =
\ (ds_aPlu :: [GHC.Types.Int])
(_ys_aPlv :: [TypeInferencer.RNode s_aJBt])
(eta_B1 :: GHC.Prim.State# s_aJBt) ->
case ds_aPlu of _ [Occ=Dead] {
[] -> (# eta_B1, GHC.Tuple.() #);
: ipv6_aPlA ipv7_aPlB ->
case _ys_aPlv of _ [Occ=Dead] {
[] -> (# eta_B1, GHC.Tuple.() #);
: ipv8_aPlH ipv9_aPlI ->
tick<substitute.go>
case scc<substitute.go>
(scctick<fromRNode>
GHC.STRef.readSTRef1
@ s_aJBt
@ (Data.Either.Either
(TypeInferencer.Term s_aJBt) (TypeInferencer.Var s_aJBt))
(ipv8_aPlH
`cast` (TypeInferencer.NTCo:RNode[0] <s_aJBt>_N
:: TypeInferencer.RNode s_aJBt
~#
GHC.STRef.STRef
s_aJBt
(Data.Either.Either
(TypeInferencer.Term s_aJBt)
(TypeInferencer.Var s_aJBt)))))
eta_B1
of _ [Occ=Dead] { (# ipv10_X2DV, ipv11_X2DX #) ->
case ipv11_X2DX of _ [Occ=Dead] {
Data.Either.Left ds5_dLX8 ->
case scc<substitute.go> a11_rYpY @ s_aJBt ipv8_aPlH ipv10_X2DV
of _ [Occ=Dead] { (# ipv12_a2tf, ipv13_a2tg #) ->
a15_sSPP ipv7_aPlB ipv9_aPlI ipv12_a2tf
};
Data.Either.Right var_aJrt ->
case scc<substitute.go> a14_sPTG ipv10_X2DV
of _ [Occ=Dead] { (# ipv12_X2PP, ipv13_X2PR #) ->
tick<rep>
case scc<substitute.go>
scc<rep> a4_rYnT @ s_aJBt var_aJrt ipv12_X2PP
of _ [Occ=Dead] { (# ipv14_X2PW, ipv15_X2PY #) ->
case scc<substitute.go>
scc<rep> a3_rYnR @ s_aJBt ipv15_X2PY var_aJrt ipv14_X2PW
of _ [Occ=Dead] { (# ipv16_X2Q0, ipv17_X2Q2 #) ->
case ipv17_X2Q2
of _ [Occ=Dead]
{ TypeInferencer.Var dt6_dMtj x1_XJka dt7_dMtk dt8_dMtl dt9_dMtm
dt10_dMtn dt11_dMto ->
case scc<substitute.go>
GHC.Prim.readMutVar#
@ s_aJBt @ TypeInferencer.VarType dt7_dMtk ipv16_X2Q0
of _ [Occ=Dead] { (# ipv18_X2Qt, ipv19_X2Qv #) ->
case scc<substitute.go>
GHC.Prim.readMutVar#
@ s_aJBt
@ (TreeList.TreeList (TypeInferencer.RNode s_aJBt))
dt9_dMtm
ipv18_X2Qt
of _ [Occ=Dead] { (# ipv20_a6bS, ipv21_a6bT #) ->
case scc<substitute.go>
TreeList.toVector @ (TypeInferencer.RNode s_aJBt) ipv21_a6bT
of _ [Occ=Dead] { Data.Vector.Vector ww1_sTzM ww2_sTzN ww3_sTzO ->
tick<==>
tick</=>
case scc<substitute.go>
let {
$w$j_sTA0
:: GHC.Prim.State# s_aJBt -> (# GHC.Prim.State# s_aJBt, () #)
[LclId, Arity=1, Str=DmdType <L,U>]
$w$j_sTA0 =
\ (w_sTzY :: GHC.Prim.State# s_aJBt) ->
letrec {
$s$wa_sWUL [Occ=LoopBreaker]
:: GHC.Prim.Int#
-> GHC.Prim.State# s_aJBt
-> (# GHC.Prim.State# s_aJBt, () #)
[LclId, Arity=2, Str=DmdType <L,U><L,U>]
$s$wa_sWUL =
\ (sc_sWUJ :: GHC.Prim.Int#)
(sc1_sWUK :: GHC.Prim.State# s_aJBt) ->
case GHC.Prim.tagToEnum#
@ GHC.Types.Bool (GHC.Prim.>=# sc_sWUJ ww2_sTzN)
of _ [Occ=Dead] {
GHC.Types.False ->
case GHC.Prim.indexArray#
@ (TypeInferencer.RNode s_aJBt)
ww3_sTzO
(GHC.Prim.+# ww1_sTzM sc_sWUJ)
of _ [Occ=Dead] { (# ipv22_aQSr #) ->
case a11_rYpY @ s_aJBt ipv22_aQSr sc1_sWUK
of _ [Occ=Dead] { (# ipv23_X2EL, ipv24_X2EN #) ->
$s$wa_sWUL (GHC.Prim.+# sc_sWUJ 1) ipv23_X2EL
}
};
GHC.Types.True -> (# sc1_sWUK, GHC.Tuple.() #)
}; } in
$s$wa_sWUL 0 w_sTzY } in
答案 0 :(得分:3)
我想为后代回答这个问题 - &#34;当程序在未启用分析的情况下构建时,它们运行完全相同&#34;。这非常有意义,因为在启用分析时,内联的附加函数调用必须为成本中心留下一些痕迹。
海森堡的行动原则 - 如果我们过于密切地观察我们的计划,我们最终会改变它!