{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} module Eventlog.Detailed where import qualified Data.Map as Map import Eventlog.Types import qualified Data.Text as T import Text.Blaze.Html import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A import Data.Array.Unboxed (UArray, bounds) import qualified Data.Array.Unboxed as A import Data.Fixed import Control.Monad import Data.Maybe data InfoTableLocStatus = None -- None of the entries have InfoTableLoc | Missing -- This one is just missing | Here InfoTableLoc -- Here is is mkMissing :: Maybe InfoTableLoc -> InfoTableLocStatus mkMissing = maybe Missing Here mkClosureInfo :: Map.Map Bucket a -> Map.Map InfoTablePtr InfoTableLoc -> Map.Map Bucket (InfoTableLocStatus, a) mkClosureInfo b ipes = Map.mapWithKey (\k v -> (mkMissing $ Map.lookup (toItblPointer k) ipes, v)) b renderClosureInfo :: (UArray Int Double, UArray (Int, Int) Double) -- Raw Data -> Maybe (Map.Map InfoTablePtr InfoTableLoc) -- Do we have IPE information? -> Map.Map Bucket (Int, BucketInfo) -- Buckets -> Html renderClosureInfo (ts, bs) mipes raw_bs = do let cs = case mipes of Just ipes -> mkClosureInfo raw_bs ipes Nothing -> Map.map (\v -> (None, v)) raw_bs H.table ! A.id "closure_table" ! A.class_ "table table-striped closureTable" $ do H.thead $ H.tr $ do H.th "Profile" numTh "n" H.th "Label" when (isJust mipes) $ do H.th "Description" H.th "CTy" H.th "Type" H.th "Module" H.th "Loc" numTh ("Integrated Size" <> H.br <> "(MiB s)") numTh "Stddev (MiB) " numTh "Intercept" numTh "Slope" numTh "Fit (R²)" Map.foldrWithKey (\k a res -> renderEntry k a >> res) (mempty :: Html) cs H.script $ preEscapedToHtml initTable where numTh lbl = H.th ! H.dataAttribute "sortas" "numeric" $ lbl trunc :: Double -> Fixed E2 trunc = realToFrac render = showFixed True renderInfoTableLoc :: InfoTableLoc -> Html renderInfoTableLoc (InfoTableLoc table_name cd tydesc _lbl m sloc) = do H.td (toHtml table_name) H.td (toHtml (show @ClosureType cd)) H.td (toHtml tydesc) H.td (toHtml m) H.td (toHtml sloc) renderInfoTableLocStatus :: InfoTableLocStatus -> Html renderInfoTableLocStatus itls = case itls of Here itl -> renderInfoTableLoc itl Missing -> emptyItlColumns None -> mempty emptyItlColumns = do H.td "" H.td "" H.td "" H.td "" H.td "" renderEntry (Bucket k) (mitl, (n, BucketInfo _ _ tot std mg)) = do let (a, b, r2) = case mg of Nothing -> ("", "", "") Just (ad, bd, r2d) -> (render $ trunc ad , render $ trunc bd , render $ trunc r2d) H.tr $ do H.td (renderSpark (getBandValues n (ts, bs))) H.td (toHtml n) H.td (toHtml k) renderInfoTableLocStatus mitl H.td (toHtml (render $ trunc (tot / 1e6))) H.td (toHtml (render $ trunc (std / 1e6))) H.td (toHtml a) H.td (toHtml b) H.td (toHtml r2) renderSpark :: [(Double, Double)] -> Html renderSpark vs = H.span ! A.class_ "linechart" $ toHtml (T.intercalate "," (map renderLine vs)) where rdouble = T.pack . showFixed True . realToFrac @Double @(Fixed E2) renderLine (x,y) = rdouble x <> ":" <> rdouble y initTable :: T.Text initTable = "$(document).ready(function() {\ \$(\".closureTable\").fancyTable({\ \ sortColumn: 1,\ \ pagination: true,\ \ perPage:10,\ \ globalSearch:false,\ \ globalSearchExcludes: [7,8,9,10,11,12],\ \ sortOrder: 'descending',\ \ onUpdate: function(){$.sparkline_display_visible()}\ \});\ \$.fn.sparkline.defaults.common.chartRangeMin = 0;\ \$.fn.sparkline.defaults.common.width = 200;\ \$('.linechart').sparkline()\ \});" getBandValues :: Int -> (UArray Int Double, UArray (Int, Int) Double) -> [(Double, Double)] getBandValues k (ts, vs) = let (t1, tn) = bounds ts go i = flip map [t1 .. tn] $ \t -> ((ts A.! t), (vs A.! (i, t))) in go k