GHC Haskell производительность рендеринга адресов IPv4

Недавно я создал библиотеку для обработки адресов IPv4 в haskell. Я написал две функции для рендеринга IPv4 Отправить Text и я удивлен, что наивный подход превосходит подход, о котором я на самом деле думал. Вот соответствующие части. Во-первых, есть определениеIPv4:

newtype IPv4 = IPv4 { getIPv4 :: Word32 }

Затем у нас есть средство визуализации IP-адресов, которое я ожидал, чтобы работать хорошо:

toDotDecimalText :: IPv4 -> Text
toDotDecimalText = LText.toStrict . TBuilder.toLazyText . toDotDecimalBuilder
{-# INLINE toDotDecimalText #-}

toDotDecimalBuilder :: IPv4 -> TBuilder.Builder
toDotDecimalBuilder (IPv4 w) = 
  decimal (255 .&. shiftR w 24 )
  <> dot
  <> decimal (255 .&. shiftR w 16 )
  <> dot
  <> decimal (255 .&. shiftR w 8 )
  <> dot
  <> decimal (255 .&. w)
  where dot = TBuilder.singleton '.'
{-# INLINE toDotDecimalBuilder #-}

Наконец, у нас есть наивная реализация:

ipv4ToTextNaive :: IPv4 -> Text
ipv4ToTextNaive i = Text.pack $ concat
  [ show a
  , "."
  , show b
  , "."
  , show c
  , "."
  , show d
  ]
  where (a,b,c,d) = IPv4.toOctets i

И, наконец, вот набор тестов:

main :: IO ()
main = do
  let ipAddr = IPv4 1000000009
  defaultMain 
    [ bgroup "IPv4 to Text" 
      [ bench "Naive" $ whnf ipv4ToTextNaive ipAddr
      , bench "Current Implementation" $ whnf IPv4_Text.encode ipAddr
      ]
    ]

Вы можете попробовать это, клонировав репозиторий, с которым я связан, и затем запустив stack bench --benchmark-arguments '--output=out.html' в каталоге верхнего уровня проекта. Результаты, которые я получаю:

benchmarking IPv4 to Text/Naive
time                 391.1 ns   (389.9 ns .. 392.7 ns)
                     1.000 R²   (1.000 R² .. 1.000 R²)
mean                 394.2 ns   (393.1 ns .. 396.4 ns)
std dev              4.989 ns   (2.990 ns .. 7.700 ns)
variance introduced by outliers: 12% (moderately inflated)

benchmarking IPv4 to Text/Current Implementation
time                 467.5 ns   (466.0 ns .. 469.8 ns)
                     1.000 R²   (0.999 R² .. 1.000 R²)
mean                 470.9 ns   (467.8 ns .. 478.3 ns)
std dev              14.75 ns   (8.245 ns .. 26.96 ns)
variance introduced by outliers: 45% (moderately inflated)

Наивный (который использует [Char] а затем упаковывает его в Text в конце) побеждает тот, который я думал, будет лучше (который использует текст Builder) каждый раз.

Я рассмотрел несколько возможностей. Во-первых, я злоупотребил criterion или неправильно понял слабую голову нормальной формы Text, Другое в том, что Builder не работает так, как я думал. Я всегда представлял их как список различий, который был более умным в отношении битпэков, но из определения я не совсем уверен, чего ожидать.

0 ответов

Другие вопросы по тегам