एक प्रदर्शन समस्या है जिसे मैं एक अधिक जटिल कोड के हिस्से के रूप में डीबग करने का प्रयास कर रहा हूं। ऐसा लगता है कि append
फ़ंक्शन जिसका उपयोग मैं (Int,Int,Int,Int)
के गतिशील, बढ़ने योग्य वेक्टर बनाने के लिए कर रहा हूं, वेक्टर में लिखे जाने से पहले बॉक्सिंग और अनबॉक्स किए जाने वाले टुपल में Int
में से एक का कारण बन रहा है। मैंने एक सरल कोड लिखा जो इस मुद्दे को पुन: उत्पन्न करता है - ऐसा लगता है कि जब मैं append
फ़ंक्शन में वेक्टर विकास कार्यक्षमता जोड़ता हूं - नीचे नमूना कोड (यह समस्या को पुन: उत्पन्न करने के अलावा बहुत उपयोगी काम नहीं करता है), उसके बाद core
के स्निपेट्स दिखाने के मूल्य बॉक्सिंग और अनबॉक्स्ड जा रहा है:चार tuples के वेक्टर में अनबॉक्सिंग बॉक्स किए गए मान
{-# LANGUAGE BangPatterns #-}
module Test
where
import Data.Vector.Unboxed.Mutable as MU
import Data.Vector.Unboxed as U hiding (mapM_)
import Control.Monad.ST as ST
import Control.Monad.Primitive (PrimState)
import Control.Monad (when)
import GHC.Float.RealFracMethods (int2Float)
import Data.STRef (newSTRef, writeSTRef, readSTRef)
import Data.Word
type MVI1 s = MVector (PrimState (ST s)) Int
type MVI4 s = MVector (PrimState (ST s)) (Int,Int,Int,Int)
data Snakev s = S {-# UNPACK #-}!Int
!(MVI4 s)
newVI1 :: Int -> Int -> ST s (MVI1 s)
newVI1 n x = do
a <- new n
mapM_ (\i -> MU.unsafeWrite a i x) [0..n-1]
return a
-- Growable array - we always append an element. It grows by factor of 1.5 if more capacity is needed
append :: Snakev s -> (Int,Int,Int,Int) -> ST s (Snakev s)
append (S i v) x = do
if i < MU.length v then MU.unsafeWrite v i x >> return (S (i+1) v)
else MU.unsafeGrow v (floor $! 1.5 * (int2Float $ MU.length v)) >>= (\y -> MU.unsafeWrite y i x >> return (S (i+1) y))
gridWalk :: Vector Word8 -> Vector Word8 -> MVI1 s -> MVI1 s -> Snakev s -> Int -> (Vector Word8 -> Vector Word8 -> Int -> Int -> Int) -> ST s (Snakev s)
gridWalk a b fp snodes snakesv !k cmp = do
let offset = 1+U.length a
xp = offset-k
snodep <- MU.unsafeRead snodes xp -- get the index of previous snake node in snakev array
append snakesv (snodep,xp,xp,xp)
{-#INLINABLE gridWalk #-}
GHC gridWalk
में उपयोग के लिए append
का एक संस्करण उत्पन्न करता है। यही कारण है कि समारोह कोर में $wa
है - कृपया बॉक्सिंग इंट तर्क पर ध्यान दें:
$wa
:: forall s.
Int#
-> MVI4 s
-> Int#
-> Int#
-> Int#
-> Int ======= Boxed value - one of (Int,Int,Int,Int) is boxed
-> State# s
-> (# State# s, Snakev s #)
$wa =
\ (@ s)
(ww :: Int#)
(ww1 :: MVI4 s)
(ww2 :: Int#)
(ww3 :: Int#)
(ww4 :: Int#)
(ww5 :: Int) === Boxed value
(w :: State# s) ->
....
....
of ipv12 { __DEFAULT ->
case (writeIntArray# ipv7 ww ww4 (ipv12 `cast` ...)) `cast` ...
of ipv13 { __DEFAULT ->
(# case ww5 of _ { I# x# ->
(writeIntArray# ipv10 ww x# (ipv13 `cast` ...)) `cast` ...
},
S (+# ww 1)
((MV_4
(+# y rb)
==== x below unboxed from arg ww5 ======
((MVector 0 x ipv1) `cast` ...)
((MVector 0 x1 ipv4) `cast` ...)
((MVector 0 x2 ipv7) `cast` ...)
((MVector 0 x3 ipv10) `cast` ...))
`cast` ...) #)
gridWalk
बक्से मूल्य जब append
बुला:
=== function called by gridWalk ======
a :: forall s.
Vector Word8
-> Vector Word8
-> MVI1 s
-> MVI1 s
-> Snakev s
-> Int
-> (Vector Word8 -> Vector Word8 -> Int -> Int -> Int)
-> State# s
-> (# State# s, Snakev s #)
a =
\ (@ s)
(a1 :: Vector Word8)
_
_
(snodes :: MVI1 s)
(snakesv :: Snakev s)
(k :: Int)
_
(eta :: State# s) ->
case k of _ { I# ipv ->
case snodes `cast` ... of _ { MVector rb _ rb2 ->
case a1 `cast` ... of _ { Vector _ rb4 _ ->
let {
y :: Int#
y = -# (+# 1 rb4) ipv } in
case readIntArray# rb2 (+# rb y) (eta `cast` ...)
of _ { (# ipv1, ipv2 #) ->
case snakesv of _ { S ww ww1 ->
====== y boxed below before append called ======
$wa ww ww1 ipv2 y y (I# y) (ipv1 `cast` ...)
}
}
}
}
}
तो, प्रभाव gridWalk
में मूल्य के मुक्केबाजी हो रहा है और (Int,Int,Int,Int)
के वेक्टर में सम्मिलन से पहले append
में अनबॉक्सिंग। append
INLINE
चिह्नित करने से व्यवहार में कोई बदलाव नहीं आता है - उन बॉक्स किए गए मान केवल gridWalk
के फ़ंक्शन बॉडी में स्थानांतरित होते हैं।
मैं इस मूल्य को अनबॉक्स किए जाने के तरीके पर पॉइंटर्स की सराहना करता हूं। मैं इसे रीफैक्टर करते समय append
(यानी, क्षमता बढ़ने पर वेक्टर वृद्धि को संभालने) की कार्यक्षमता रखना चाहूंगा।
GHC
संस्करण 7.6.1
है। वेक्टर संस्करण 0.10
है।
मैं क्यों यह बॉक्सिंग है पता नहीं है, और मैं कर रहा हूँ रात और बियर के इस समय पता लगाने की कोशिश नहीं कर रहा है, लेकिन 'संलग्न करें (एस iv)! x @ (_, _, _,! _) = ...' अंतिम अनबॉक्स भी हो जाता है। निश्चित रूप से फिश लग रहा है, हालांकि, टिकट खोलने लायक हो सकता है। –
@ डैनियल फिशर, हाँ, आप सख्त पैटर्न के साथ अनबॉक्सिंग के बारे में सही हैं। मुझे जीएचसी ट्रैक के लिए पुन: उत्पन्न करने के लिए एक आसान मामला मिलेगा। – Sal