Haskell ã§é«˜é€Ÿãªãƒ—ãƒã‚°ãƒ©ãƒ を書ãã«ã¯ ByteString ã®æ·±ã„知è˜ãŒå¿…è¦ã¨ãªã‚‹ã€‚éµã¨ãªã‚‹ã®ã¯ã€Data.ByteString.Internal ã¨ã„ã†ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã‚る。ã“ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯å…¬é–‹ã•ã‚Œã¦ã„ã‚‹ãŒã€ãƒ‰ã‚ュメントã¯éš ã•ã‚Œã¦ã„ã‚‹ã®ã§ã€è©³ã—ã知るãŸã‚ã«ã¯ã‚½ãƒ¼ã‚¹ã‚’èªã¾ãªã„ã¨ã„ã‘ãªã„。
定義
ByteString ã®å®šç¾©ã¯ä»¥ä¸‹ã®é€šã‚Šã€‚
data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload {-# UNPACK #-} !Int -- offset {-# UNPACK #-} !Int -- length
ãªãœæ§‹æˆå㌠BS ã§ã¯ãªãã€PS ãªã®ã ã‚ã†ï¼Ÿ (追記:元々 PackedString ã¨ã„ã†åž‹åã ã£ãŸã‹ã‚‰ã¨ @ma0e ã•ã‚“ã«æ•™ãˆã¦é ‚ãã¾ã—ãŸã€‚)
ForeignPtr Word8 ã¯ã€ã„ã‚ゆるãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’指ã—ã¦ã‚‹ã€‚ã“ã®ãƒãƒƒãƒ•ã‚¡ãƒ¼ã¯è¤‡æ•°ã® ByteString ã‹ã‚‰å…±æœ‰ã•ã‚Œã‚‹ã€‚ãƒãƒƒãƒ•ã‚¡ãƒ¼ä¸ã®ã©ã“を使ã£ã¦ã„ã‚‹ã‹ã‚’示ã™ãŸã‚ã«ã€ãƒ¡ã‚¿æƒ…å ±ã¨ã—㦠offset 㨠length ãŒã‚る。
Haskell ポインタープログラミングã‚’èªã‚“ã 人ãªã‚‰ã€ãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’èªã¿æ›¸ãã™ã‚‹æ–¹æ³•ã¯åˆ†ã‹ã‚‹ã ã‚ã†ã€‚以下ã®ã‚ˆã†ã«ã™ã‚‹ã®ãŒå®šçŸ³ã§ã‚る。
import Data.ByteString.Internal (ByteString(..)) import Foreign.ForeignPtr (withForeignPtr) import Foreign.Ptr (plusPtr) foo :: ByteString -> IO é©å½“ãªåž‹ foo (PS fptr off len) = withForeignPtr fptr $ \ptr -> do let beg = ptr `plusPtr` off end = beg `plusPtr` len -- beg ã‹ã‚‰ end ã®é–“(endã¯å«ã¾ãªã„)ã‚’èªã¿æ›¸ãã™ã‚‹
書ãæ›ãˆã¦ãƒãƒƒãƒ•ã‚¡ãƒ¼æº¢ã‚Œã‚’èµ·ã“ã•ãªã„ã®ã¯è‡ªå·±è²¬ä»»ã ã—ã€æ›¸ãæ›ãˆã‚‹ãƒãƒƒãƒ•ã‚¡ãƒ¼ãŒå…±æœ‰ã•ã‚Œã¦ãªã„ã“ã¨ã‚’ä¿è¨¼ã™ã‚‹ã®ã‚‚自己責任ã§ã‚る。
大ãã•ã®åˆ†ã‹ã£ã¦ã„ã‚‹ ByteString を作る
ãƒãƒƒãƒ•ã‚¡ãƒ¼æ“作ã¨ã¨ã‚‚ã« ByteString を作りãŸã„å ´åˆã€ã‚らã‹ã˜ã‚ã§ãã‚ãŒã‚‹ ByteString ã®å¤§ãã•ãŒåˆ†ã‹ã£ã¦ã„ã‚‹ãªã‚‰ã€create ãŒä½¿ãˆã‚‹ã€‚
create :: Int -> (Ptr Word8 -> IO ()) -> IO ByteString create l f = do fp <- mallocByteString l withForeignPtr fp $ \p -> f p return $! PS fp 0 l
Int ã¯ã€ãƒãƒƒãƒ•ã‚¡ãƒ¼ã®ãƒã‚¤ãƒˆæ•°ã§ã‚る。Ptr Word8 -> IO () ã¨ã„ã†é–¢æ•°ã§ã€ãƒãƒƒãƒ•ã‚¡ãƒ¼å…¨ä½“(オフセット 0 ã‹ã‚‰æŒ‡å®šã—ãŸãƒã‚¤ãƒˆæ•°)ã‚’åˆæœŸåŒ–ã™ã‚Œã°ã‚ˆã„。
副作用ãŒãªã„ã¨ç¢ºä¿¡ã§ãã‚‹ãªã‚‰ã€unsafeCreate を使ãŠã†ã€‚
unsafeCreate :: Int -> (Ptr Word8 -> IO ()) -> ByteString unsafeCreate l f = unsafeDupablePerformIO (create l f)
大ãã•ãŒåˆ†ã‹ã‚‰ãªã„ ByteString を作る
ã§ãã‚ãŒã‚‹ ByteString ã®å¤§ãã•ãŒåˆ†ã‹ã‚‰ãªã„å ´åˆã€ã©ã†ã™ã‚Œã°ã„ã„ã ã‚ã†ã‹ï¼Ÿ 3ã¤ãらã„方法ãŒã‚る。
createAndTrim
一ã¤ç›®ã¯ createAndTrim を使ã†æ–¹æ³•ã 。å分ãªå¤§ãã•ã®ãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’用æ„ã—ã¦ãƒ‡ãƒ¼ã‚¿ã‚’作りã€å¤§ãã•ãŒåˆ†ã‹ã£ãŸæ™‚点ã§ã€æ–°ã—ã„ ByteString を作る。渡ã™é–¢æ•°ã¯ã€ã§ãã‚ãŒã£ãŸãƒ‡ãƒ¼ã‚¿ã®ãƒã‚¤ãƒˆæ•°ã‚’è¿”ã•ãªã„ã¨ã„ã‘ãªã„。
以下ã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ãŒç¤ºã™ã‚ˆã†ã«ã€ã¯ã˜ã‚ã«ç”¨æ„ã—ãŸãƒãƒƒãƒ•ã‚¡ãƒ¼ã´ã£ãŸã‚Šã®ãƒ‡ãƒ¼ã‚¿ãŒã§ããŸã¨ãã«é™ã‚Šã€ã‚³ãƒ”ーãŒç™ºç”Ÿã—ãªã„。
createAndTrim :: Int -> (Ptr Word8 -> IO Int) -> IO ByteString createAndTrim l f = do fp <- mallocByteString l withForeignPtr fp $ \p -> do l' <- f p if assert (l' <= l) $ l' >= l then return $! PS fp 0 l else create l' $ \p' -> memcpy p' p l'
リスト
二ã¤ç›®ã¯ä¸é–“データã¨ã—ã¦ãƒªã‚¹ãƒˆã‚’作る方法。ãŸã¨ãˆã°ã€[Word8]ã¨ã„ã†ãƒªã‚¹ãƒˆã‚’作ã£ã¦ãŠã„ã¦ã€pack ã™ã‚Œã°ã„ã„。
[Word8]を作る際ã¯ã€ãƒªã‚¹ãƒˆãŒå¾Œã‚ã«ä¼¸ã³ã¦è¡Œãã ã‚ã†ã€‚é€†é †ã®ãƒªã‚¹ãƒˆã‚’作ã£ã¦ reverse ã—ã¦ã‚‚よã„ãŒã€å·®åˆ†ãƒªã‚¹ãƒˆã‚’使ã†æ‰‹ã‚‚ã‚る。ã„ãšã‚Œã®å ´åˆã‚‚ã€ä½œæˆä¸ã«å¤§ãã•ã‚’管ç†ã§ãã‚‹ã‹ã‚‚ã—ã‚Œãªã„。
[Word8]ã®å¤§ãã•ãŒã‚らã‹ã˜ã‚分ã‹ã£ã¦ã„ã‚‹ãªã‚‰ã€pack を使ã†ã‚ˆã‚Šã‚‚ã€create ã—ã¦è‡ªå‰ã§ãƒªã‚¹ãƒˆã®å†…容をãƒãƒƒãƒ•ã‚¡ãƒ¼ã¸ã‚³ãƒ”ーã™ã‚‹æ–¹ãŒã„ã„ã ã‚ã†ã€‚
Builder を使ã†
三ã¤ç›®ã¯ã€Builder を使ã†æ–¹æ³•ã§ã‚る。
二ã¤ç›®ã®æ–¹æ³•ã¯ã€å˜ä¸€ã® Word8 ã¨ã„ã†åž‹ã ã‘を使ã†å ´åˆã«æœ‰åŠ¹ã§ã‚ã£ãŸã€‚一方ã€Builder ã¯ã€ã•ã¾ã–ã¾ãªåž‹ã®ãƒ‡ãƒ¼ã‚¿ã‹ã‚‰ä½œã‚Œã‚‹ã€‚
詳ã—ã„ç†ç”±ã¯çœç•¥ã™ã‚‹ãŒã€
- GHC 7.6.x 以下ã§ã¯ blaze-builder ã® Builder
- GHC 7.8.x 以上ã§ã¯ bytestring 自体㮠Builder
を使ã†ã¨ã„ã„ã ã‚ã†ã€‚
Builder ã¯å·®åˆ†ãƒªã‚¹ãƒˆã®ä¸€ç¨®ã¨è¨€ã‚ã‚Œã¦ã„ã‚‹ãŒã€ãã‚Œã¯èª¤è§£ã‚’æ‹›ãã‚„ã™ã„。Builder ã¨ã¯ã€ä¸Žãˆã‚‰ã‚ŒãŸãƒ‡ãƒ¼ã‚¿ã‚’ãƒãƒƒãƒ•ã‚¡ãƒ¼ã¸ã‚³ãƒ”ーã™ã‚‹é–¢æ•°ã§ã‚ã‚Šã€Builder ã‚’ãã£ã¤ã‘ã‚‹ã“ã¨ã¯ã€é–¢æ•°åˆæˆã‚’ã™ã‚‹ã“ã¨ã§ã‚る。ã“ã®é–¢æ•°ã¯ç¶™ç¶šã‚’用ã„ã¦å®Ÿè£…ã•ã‚Œã¦ã„ã‚‹ã®ã§ã€æœ€çµ‚çš„ã«èµ°ã‚‰ã›ãŸå ´åˆã€ã€Œå·¦ã‹ã‚‰å³ã¸ã€ãƒãƒ•ã‚¡ãƒ¼ã®ã‚³ãƒ”ー関数ãŒèµ°ã‚‹ã€‚(差分リストã®ã‚ˆã†ã«ã€å³çµåˆã«ãªã‚‹è¨³ã§ã¯ãªã„。)
Builder ã«ã¯ã€æœ€çµ‚çš„ãªå¤§ãã•ã‚’予測ã§ããªã„ã¨ã„ã†å•é¡ŒãŒã‚る。ã ã‹ã‚‰ã€ä»¥ä¸‹ã®ã‚ˆã†ã«ä½¿ã‚れる。
- ãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’1ã¤ç”¨ã„ã¦ã€å‡ºåŠ›ã‚’ã™ã‚‹ã€‚ã™ãªã‚ã¡ã€ãƒãƒƒãƒ•ã‚¡ãƒ¼ãŒæº¢ã‚Œãã†ã«ãªã‚‹ã¨æ›¸ã出ã—ã€ãã®ãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’å†åˆ©ç”¨ã™ã‚‹ã“ã¨ã‚’ç¹°ã‚Šè¿”ã™ã€‚具体的ã«ã¯ã€blaze-builder ã§ã¯ toByteStringIO を使ãˆã°ã‚ˆã„。
- ãƒãƒƒãƒ•ã‚¡ãƒ¼ãŒæº¢ã‚ŒãŸãã†ã«ãªã£ãŸã‚‰ã€æ–°ãŸãªãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’用æ„ã—ã¦åˆ©ç”¨ã™ã‚‹ã€‚Strict 㪠ByteString ãŒè¤‡æ•°ã§ãã‚‹ã“ã¨ã«ãªã‚Šã€ãã‚Œã¯ã™ãªã‚ã¡ Lazy ByteString ã§ã‚る。具体的ã«ã¯ã€blaze-builder ã§ã¯ toLazyByteString を使ã†ã€‚
mallocByteString
create ãªã©ã§ä½¿ã‚ã‚Œã¦ã„ã‚‹ mallocByteString を調ã¹ã¦ã¿ã‚ˆã†ã€‚
mallocByteString :: Int -> IO (ForeignPtr a) mallocByteString = mallocPlainForeignPtrBytes
mallocPlainForeignPtrBytes ã¯ã€GHC.GHC.ForeignPtr ã«ã‚る。
mallocPlainForeignPtrBytes :: Int -> IO (ForeignPtr a) mallocPlainForeignPtrBytes (I# size) = IO $ \s -> case newPinnedByteArray# size s of { (# s', mbarr# #) -> (# s', ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#)) (PlainPtr mbarr#) #) }
newPinnedByteArray# ã¯ã€ãã®åãŒç¤ºã™ã‚ˆã†ã«ãƒ”ンæ¢ã‚ã•ã‚ŒãŸãƒ‡ãƒ¼ã‚¿ã‚’割り当ã¦ã‚‹ã€‚コピーCGã§å‹•ã‹ã•ã‚Œã‚‹ã“ã¨ã®ãªã„データã§ã‚る。ã¤ã¾ã‚Šã€ByteString ã®ãƒãƒƒãƒ•ã‚¡ãƒ¼ã¯å¸¸ã«å›ºå®šã•ã‚Œã¦ã„ã‚‹ã®ã§ã€GC ã‚’æ°—ã«ã›ãšã«èªã¿æ›¸ãã—ã¦ã‚ˆã„。
newPinnedByteArray# ã¯ã€rts/PrimOps.cmm:stg_newPinnedByteArrayzh ã®ã“ã¨ã§ã‚ã‚Šã€allocatePinned を呼んã§ã„る。
allocatePinned 㯠rts/sm/Storage.c ã«ã‚ã‚Šã€ä»¥ä¸‹ã®ã‚ˆã†ã« C ã§å®Ÿè£…ã•ã‚Œã¦ã„る。
StgPtr allocatePinned (Capability *cap, W_ n) { StgPtr p; bdescr *bd; // If the request is for a large object, then allocate() // will give us a pinned object anyway. if (n >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) { p = allocate(cap, n); Bdescr(p)->flags |= BF_PINNED; return p; } ...
LARGE_OBJECT_THRESHOLD/sizeof(W_) 以上ã®å¤§ãã•ã®å ´åˆã€allocate を呼ã³å‡ºã™ã“ã¨ãŒåˆ†ã‹ã‚‹ã€‚allocate ã¯åŒã˜ãƒ•ã‚¡ã‚¤ãƒ«ã«å˜åœ¨ã—ã€ã‚³ãƒ¼ãƒ‰ã‚’èªã‚€ã¨å¿…ãšãƒãƒƒã‚¯ã™ã‚‹ã®ãŒåˆ†ã‹ã‚‹ã€‚
StgPtr
allocate (Capability *cap, W_ n) {
...
ACQUIRE_SM_LOCK
bd = allocGroup(req_blocks);
dbl_link_onto(bd, &g0->large_objects);
g0->n_large_blocks += bd->blocks; // might be larger than req_blocks
g0->n_new_large_words += n;
RELEASE_SM_LOCK;
...
ã¤ã¾ã‚Šã€ã‚る大ãã•ä»¥ä¸Šã®ãƒãƒƒãƒ•ã‚¡ãƒ¼ã‚’æŒã¤ ByteString を作æˆã™ã‚‹å ´åˆã¯ã€å¿…ãšã‚°ãƒãƒ¼ãƒãƒ«ãªãƒãƒƒã‚¯ãŒåˆ©ç”¨ã•ã‚Œã‚‹ã®ã 。ã“ã®ã“ã¨ã¯ã€ç‰¹ã« +RTS -N
定義をãŸãã•ã‚“調ã¹ã¦ LARGE_OBJECT_THRESHOLD/sizeof(W_) を計算ã—ã¦ã¿ã‚‹ã¨ã€ä»¥ä¸‹ã®ã‚ˆã†ã«ãªã‚‹ã€‚
注:Simon Marlow 先生ã®æŒ‡æ‘˜ã«ã‚ˆã‚Šæ•°å€¤ã‚’ä¿®æ£ã€‚
- 32ビット環境ã§ã¯ 3276 ãƒã‚¤ãƒˆ(819ワード)以上㮠ByteString を作æˆã™ã‚‹å ´åˆã‚°ãƒãƒ¼ãƒãƒ«ãƒãƒƒã‚¯ãŒä½¿ã‚れる
- 64ビット環境ã§ã¯ 3272 ãƒã‚¤ãƒˆ(409ワード)以上㮠ByteString を作æˆã™ã‚‹å ´åˆã‚°ãƒãƒ¼ãƒãƒ«ãƒãƒƒã‚¯ãŒä½¿ã‚れる
大ã㪠ByteString ã®ä½œæˆã«ã¯æ…Žé‡ã«ãªã‚‹ã“ã¨ã€‚createAndTrim ã« 4,096 を渡ã—ãŸã®ã«ã€ã§ãã‚ãŒã£ãŸ ByteString ã®å¤§ãã•ã¯ 3,300 ãªã‚“ã¦ã®ã¯æœ€æ‚ªã 。ãã‚“ãªé–¢æ•°ã®ä¾‹ã¨ã—ã¦ã¯ã€Network.Socket.ByteString.recv ãŒã‚る。