pads-haskell-0.1.0.0: examples/HPROF.hs
{-# LANGUAGE TypeFamilies, TypeSynonymInstances, TemplateHaskell, QuasiQuotes, MultiParamTypeClasses, FlexibleInstances, DeriveDataTypeable, NamedFieldPuns, ScopedTypeVariables #-}
module HPROF where
import Language.Pads.Padsc
import Language.Pads.Library.LittleEndian as LE
import qualified Language.Pads.Library.BigEndian as BE
import qualified Language.Pads.Library.Native as Native
import Language.Pads.Testing
import System.IO.Unsafe (unsafePerformIO)
-- the format specified in:
-- https://java.net/downloads/heap-snapshot/hprof-binary-format.html
[pads|
type U4 = BE.Word32
type U2 = BE.Word16
-- total header length: 31 = 19 + 4 + 4 + 4
data Header = Header
{ version :: [Char] length <| 19 |>
, idsiz :: U4
, time_hw :: U4
, time_lw :: U4 }
-- TODO: can we convert this to the date and hard code it?
-- 00 00 01 2b 87 5b 95 3e
-- 299 2270926142
-- 1286466147646 = October 7th, 2010
-- http://www.epochconverter.com/
data Hprof = Hprof
{ hdr :: Header
-- , entry :: Entry
, entries :: Entries -- Originally EntriesB
, theRest :: [Word8] }
-- total entry length: 9 + len = 1 + 4 + 4 + len where len is determined by the tag field
data Entry = Entry
{ tag :: Word8
, time :: U4
, len :: U4
-- fromIntegral :: (Integral a, Num b) => a -> b
, body :: Body <| (fromIntegral(tag) :: Int, fromIntegral(len) :: Int) |>
-- , body2 :: Body <| (fromIntegral(tag) :: Int, fromIntegral(len) :: Int) |>
}
-- ???: Why does fromIntegral work here?
-- !!: Want each Entry to take as many bytes as it needs, and the parser starts reading the next byte as a new Entry
type Entries = [Entry] terminator EOF -- ?? [Entry | EOR]
-- type EntriesB = partition Entries using <| bytes 6 |>
-- ?? Does the list type always have to have corresponding terminator and partition declaration?
type ID = U4 -- !! should take idsiz from the Header
data Body (tag :: Int, len :: Int) =
case <| tag |> of
1 -> One -- ?? One and Two never declared...
{ oneid :: ID
, str :: [Char] length <| len - 4 |> } -- !! should be len - idsiz. len - (idsiz hdr)
| 2 -> Two
{ clsserial :: U4
, objid :: ID
, stkserial :: U4
, clsnamestrid :: ID }
| 3 -> Three
{ clsserial :: Word32 }
| 4 -> Four
{ stkframeid :: ID
, method_nameid :: ID
, method_sigid :: ID
, srcfile_nameid :: ID
, clsserial :: Word32
, stkInfo :: [Word8] } -- !! should take an argument
| 14 -> Fourteen
{ bitmask :: U4 -- bizarre case: using 32 bits when you need 1
, stkdepth :: U2
--, next :: Word8
-- , rest :: [Word8]
}
| otherwise -> Other [Word8]
-- Limitations:
-- One cannot access Header->idsiz from inside of an Entry type?
--
|]
hprof_input_file = "Examples/data/specjbb.hprof"
-- hprof_result :: (Header, Header_md) = unsafePerformIO $ parseFileWith header_parseM hprof_input_file
hprof_result :: (Hprof, Hprof_md) = unsafePerformIO $ parseFileWith hprof_parseM hprof_input_file
-- more readable result
result = fst hprof_result
-- returns first n entries
taken n = Prelude.take n $ entries result
-- gets the nth element. index starts at 1.
getnth n = Prelude.head $ Prelude.drop (n-1) $ entries result
hdrlen = 31
-- returns the number of bytes consumed to read n entries
lenupto n = hdrlen + (foldr (+) 0 $ map ((+9) . len) $ Prelude.take n $ entries result)