Skip to content

Commit

Permalink
Merge #118
Browse files Browse the repository at this point in the history
118: CAD-802: Charts view for resources. r=denisshevchenko a=denisshevchenko

Now it's possible to see real-time resources not as progress bars only, but as charts as well. JS library `Chart.js` is used.

Co-authored-by: Denis Shevchenko <denis.shevchenko@iohk.io>
  • Loading branch information
iohk-bors[bot] and Denis Shevchenko committed Jul 1, 2020
2 parents 71ab253 + c664adc commit 64b58f7
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 25 deletions.
1 change: 1 addition & 0 deletions cardano-rt-view/cardano-rt-view.cabal
Expand Up @@ -22,6 +22,7 @@ library

Cardano.Benchmarking.RTView.ErrorBuffer

Cardano.Benchmarking.RTView.GUI.Charts
Cardano.Benchmarking.RTView.GUI.Elements
Cardano.Benchmarking.RTView.GUI.Markup
Cardano.Benchmarking.RTView.GUI.NodeWidget
Expand Down
221 changes: 221 additions & 0 deletions cardano-rt-view/src/Cardano/Benchmarking/RTView/GUI/Charts.hs
@@ -0,0 +1,221 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Cardano.Benchmarking.RTView.GUI.Charts
( prepareChartsJS
-- Charts JS snippets.
, memoryUsageChartJS
, cpuUsageChartJS
, diskUsageChartJS
, networkUsageChartJS
-- Charts updaters.
, updateMemoryUsageChartJS
, updateCPUUsageChartJS
, updateDiskUsageChartJS
, updateNetworkUsageChartJS
) where

import Cardano.Prelude
import Prelude
( String )

prepareChartsJS :: String
prepareChartsJS = concat
[ "window.charts = new Map();"
]

memoryUsageChartJS :: String
memoryUsageChartJS = concat
[ "var ctx = document.getElementById(%1).getContext('2d');"
, "var chart = new Chart(ctx, {"
, " type: 'line',"
, " data: {"
, " labels: [],"
, " datasets: [{"
, " label: 'Memory usage',"
, " backgroundColor: '#FF8000',"
, " borderColor: '#FF8000',"
, " data: [],"
, " fill: false"
, " }]"
, " },"
, " options: {"
, " scales: {"
-- , " xAxes: [{"
-- , " type: 'time'"
-- , " time: {"
-- , " parser: timeFormat,"
-- , " tooltipFormat: 'HH:mm:ss'"
-- , " }"
-- , " }],"
, " yAxes: [{"
, " display: true,"
, " scaleLabel: {"
, " display: true,"
, " labelString: 'MB'"
, " },"
, " ticks: {"
, " min: 0,"
, " max: 200,"
, " stepSize: 50"
, " }"
, " }]"
, " }"
, " }"
, "});"
, "window.charts.set(%1, chart);"
]

cpuUsageChartJS :: String
cpuUsageChartJS = concat
[ "var ctx = document.getElementById(%1).getContext('2d');"
, "var chart = new Chart(ctx, {"
, " type: 'line',"
, " data: {"
, " labels: [],"
, " datasets: [{"
, " label: 'CPU usage',"
, " backgroundColor: '#FE2E2E',"
, " borderColor: '#FE2E2E',"
, " data: [],"
, " fill: false"
, " }]"
, " },"
, " options: {"
, " scales: {"
, " yAxes: [{"
, " display: true,"
, " scaleLabel: {"
, " display: true,"
, " labelString: 'Percent'"
, " },"
, " ticks: {"
, " min: 0,"
, " max: 100,"
, " stepSize: 25"
, " }"
, " }]"
, " }"
, " }"
, "});"
, "window.charts.set(%1, chart);"
]

diskUsageChartJS :: String
diskUsageChartJS = concat
[ "var ctx = document.getElementById(%1).getContext('2d');"
, "var chart = new Chart(ctx, {"
, " type: 'line',"
, " data: {"
, " labels: [],"
, " datasets: [{"
, " label: 'Disk | RD',"
, " backgroundColor: '#0080FF',"
, " borderColor: '#0080FF',"
, " data: [],"
, " fill: false"
, " },{"
, " label: 'Disk | WR',"
, " backgroundColor: '#D358F7',"
, " borderColor: '#D358F7',"
, " data: [],"
, " fill: false"
, " }]"
, " },"
, " options: {"
, " scales: {"
, " yAxes: [{"
, " display: true,"
, " scaleLabel: {"
, " display: true,"
, " labelString: 'KB/s'"
, " },"
, " ticks: {"
, " min: 0,"
, " stepSize: 50"
, " }"
, " }]"
, " }"
, " }"
, "});"
, "window.charts.set(%1, chart);"
]

networkUsageChartJS :: String
networkUsageChartJS = concat
[ "var ctx = document.getElementById(%1).getContext('2d');"
, "var chart = new Chart(ctx, {"
, " type: 'line',"
, " data: {"
, " labels: [],"
, " datasets: [{"
, " label: 'Network | IN',"
, " backgroundColor: '#D7DF01',"
, " borderColor: '#D7DF01',"
, " data: [],"
, " fill: false"
, " },{"
, " label: 'Network | OUT',"
, " backgroundColor: '#00FF80',"
, " borderColor: '#00FF80',"
, " data: [],"
, " fill: false"
, " }]"
, " },"
, " options: {"
, " scales: {"
, " yAxes: [{"
, " display: true,"
, " scaleLabel: {"
, " display: true,"
, " labelString: 'KB/s'"
, " },"
, " ticks: {"
, " min: 0,"
, " stepSize: 100"
, " }"
, " }]"
, " }"
, " }"
, "});"
, "window.charts.set(%1, chart);"
]

-- Chart updaters.
-- Please note that after 900 data points (which are collected in every 30 minutes)
-- we remove outdated points. It allows to avoid too compressed, narrow charts.

updateMemoryUsageChartJS
, updateCPUUsageChartJS
, updateDiskUsageChartJS
, updateNetworkUsageChartJS :: String
updateMemoryUsageChartJS = updateSingleDatasetChartJS
updateCPUUsageChartJS = updateSingleDatasetChartJS
updateDiskUsageChartJS = updateDoubleDatasetChartJS
updateNetworkUsageChartJS = updateDoubleDatasetChartJS

updateSingleDatasetChartJS :: String
updateSingleDatasetChartJS = concat
[ "window.charts.get(%1).data.labels.push(%2);"
, "var len = window.charts.get(%1).data.labels.length;"
, "if (len == 900) {"
, " window.charts.get(%1).data.datasets[0].data.splice(0, len);"
, " window.charts.get(%1).data.labels.splice(0, len);"
, "}"
, "window.charts.get(%1).data.datasets[0].data.push(%3);"
, "window.charts.get(%1).update({duration: 0});"
]

updateDoubleDatasetChartJS :: String
updateDoubleDatasetChartJS = concat
[ "window.charts.get(%1).data.labels.push(%2);"
, "var len = window.charts.get(%1).data.labels.length;"
, "if (len == 900) {"
, " window.charts.get(%1).data.datasets[0].data.splice(0, len);"
, " window.charts.get(%1).data.datasets[1].data.splice(0, len);"
, " window.charts.get(%1).data.labels.splice(0, len);"
, "}"
, "window.charts.get(%1).data.datasets[0].data.push(%3);"
, "window.charts.get(%1).data.datasets[1].data.push(%4);"
, "window.charts.get(%1).update({duration: 0});"
]
15 changes: 14 additions & 1 deletion cardano-rt-view/src/Cardano/Benchmarking/RTView/GUI/Markup.hs
Expand Up @@ -18,6 +18,11 @@ import Graphics.UI.Threepenny.Core

import Cardano.BM.Data.Configuration
( RemoteAddrNamed (..) )
import Cardano.Benchmarking.RTView.GUI.Charts
( cpuUsageChartJS, diskUsageChartJS
, memoryUsageChartJS, networkUsageChartJS
, prepareChartsJS
)
import Cardano.Benchmarking.RTView.GUI.Elements
( NodeStateElements, NodesStateElements
, PeerInfoItem
Expand All @@ -33,7 +38,7 @@ mkPageBody window acceptors = do
-- Create widgets for each node (corresponding to acceptors).
nodeWidgetsWithElems
<- forM acceptors $ \(RemoteAddrNamed nameOfNode _) -> do
(widget, nodeStateElems, peerInfoItems) <- mkNodeWidget
(widget, nodeStateElems, peerInfoItems) <- mkNodeWidget nameOfNode
return (nameOfNode, widget, nodeStateElems, peerInfoItems)

-- Create widgets areas on the page.
Expand Down Expand Up @@ -71,6 +76,14 @@ mkPageBody window acceptors = do
, UI.div #. "w3-row" #+ widgetsAreas
]

UI.runFunction $ UI.ffi prepareChartsJS
forM_ acceptors $ \(RemoteAddrNamed nameOfNode _) -> do
-- Charts for different metrics.
UI.runFunction $ UI.ffi memoryUsageChartJS ("memoryUsageChart-" <> nameOfNode)
UI.runFunction $ UI.ffi cpuUsageChartJS ("cpuUsageChart-" <> nameOfNode)
UI.runFunction $ UI.ffi diskUsageChartJS ("diskUsageChart-" <> nameOfNode)
UI.runFunction $ UI.ffi networkUsageChartJS ("networkUsageChart-" <> nameOfNode)

nodesStateElems
<- forM nodeWidgetsWithElems $ \(nameOfNode, _, nodeStateElems, peerInfoItems) ->
return (nameOfNode, nodeStateElems, peerInfoItems)
Expand Down

0 comments on commit 64b58f7

Please sign in to comment.