tetcore-analytics 0.1.4

Tetcore Telemetry Analytics for Rust
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Tetcore Analytics - Benchmarks</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css">
    <link rel=stylesheet href=https://cdn.jsdelivr.net/npm/pretty-print-json@0.2/dist/pretty-print-json.css>
    <script src=https://cdn.jsdelivr.net/npm/pretty-print-json@0.2/dist/pretty-print-json.min.js></script>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>


<nav class="navbar" role="navigation" aria-label="main navigation">
    <div class="navbar-menu is-active">
        <div class="navbar-start">
            <div class=" navbar-item">
                <h1 class="title">
                    Tetcore Analytics | Benchmarks
                </h1>
            </div>

            <div class="navbar-item">
                <div class="field">
                    <div class="control">
                        <div class="select">
                            <select id="benchmark-select">
                            </select>
                        </div>
                    </div>
                </div>
            </div>

            <div class="navbar-item">
                <div class="field has-addons">
                    <div class="control">
                        <div class="select">
                            <select id="event-select">
                            </select>
                        </div>
                    </div>
                </div>
            </div>

            <div class="navbar-item">
                <div class="field">
                    <div class="control">
                        <div class="select">
                            <select id="target-select">
                            </select>
                        </div>
                    </div>
                </div>
            </div>

            <div class="navbar-item">
                <div class="field">

                    <div class="control">
                        <button class="button is-primary" onclick="viewGraphs()">View</button>
                    </div>
                </div>
            </div>

        </div>
    </div>
</nav>

<template id="graph-template">
    <div class="container"></div>
</template>

<section class="section">
    <div class="container">

        <div id="benchmark-info" class="notification"></div>
    </div>
</section>

<section class="section" id="graphs">
</section>

<script>
    let benchmarks = new Map();
    let benchmarkEvents = new Map();
    let timings = new Map();
    const benchmarkSelect = document.querySelector('#benchmark-select');
    const targetSelect = document.querySelector('#target-select');
    const eventSelect = document.querySelector('#event-select');
    const benchmarkInfo = document.querySelector('#benchmark-info');

    benchmarkSelect.addEventListener('change', (event) => {
        // Update info panel
        const id = parseInt(event.target.value);
        updateBenchmarkInfo(benchmarks.get(id));
        // Fetch and populate targets
        let request = new Request(`/benchmarks/${id}/targets`);

        fetch(request)
            .then(response => response.json())
            .then(json => {
                targetSelect.options.length = 0;
                const opt = new Option('ALL', 'ALL');
                targetSelect.options.add(opt);
                for (const target of json) {
                    const opt = new Option(target.target, target.target);
                    targetSelect.options.add(opt);
                }
            });

        // Fetch and populate events
        let eventsRequest = new Request(`/benchmarks/${id}/events`);

        fetch(eventsRequest)
            .then(response => response.json())
            .then(json => {
                eventSelect.options.length = 0;
                benchmarkEvents.clear();
                for (const event of json) {
                    benchmarkEvents.set(event.id, event);
                    if (event.phase !== 'end') {
                        const opt = new Option(event.name, event.id);
                        eventSelect.options.add(opt);
                    }
                }
            });

    });

    function updateBenchmarkInfo(benchmark) {
        benchmarkInfo.innerHTML = prettyPrintJson.toHtml(benchmark);
    }

    function viewGraphs() {
        let e = document.getElementById('graphs');
        let child = e.lastElementChild;
        while (child) {
            e.removeChild(child);
            child = e.lastElementChild;
        }
        timings.clear();
        // Fetch data and draw benchmarks
        const startEvent = benchmarkEvents.get(parseInt(eventSelect.value));
        const endEvent = Array.from(benchmarkEvents.values()).find((item) =>
            item.name === startEvent.name && item.phase === 'end'
        );
        const peer_id = benchmarks.get(parseInt(benchmarkSelect.value)).setup.tetcore.peerId;
        let logsRequest = `/nodes/logs?peer_id=${peer_id}&msg=tracing.profiling&start_time=${startEvent.created_at}&end_time=${endEvent.created_at}&limit=100000`;

        let currentTarget = targetSelect.value;
        if (currentTarget !== 'ALL') {
            logsRequest += `&target=${currentTarget}`;
        }
        fetch(new Request(logsRequest))
            .then(response => response.json())
            .then(json => {
                for (log of json) {
                    let key = `${log.logs.target}::${log.logs.name}`;
                    if (!timings.has(key)) {
                        console.log(key);
                        timings.set(key, [])
                    }
                    timings.get(key).push(log)
                }
                const keys = Array.from(timings.keys()).sort(); // sort keys for map to draw benchmarks alphabetically ordered
                let latest_time = 0;
                for (const key of keys) {
                    let lt = Date.parse(timings.get("pallet_balances::transfer")[0].created_at);
                    if (lt >  latest_time) {
                        latest_time = lt;
                    }
                }
                for (const key of keys) {
                    drawGraph(timings.get(key).reverse(), startEvent.created_at, endEvent.latest_time); // Reverse to show benchmarks in chronologically ascending order
                }
            });
    }


    function drawGraph(graph_data, start_x, end_x) {
        let graphName = `${graph_data[0].logs.target}::${graph_data[0].logs.name}`;
        let yData = graph_data.map(function (obj) {
            return obj.logs.time / 1000000;
        });
        let trace = {
            type: "scatter",
            mode: "lines+markers",
            name: graphName,
            y: yData,
            x: graph_data.map(function (obj) {
                return new Date(obj.created_at);
            }),
            text: graph_data.map(function (obj) {
                return prettyPrintJson.toHtml(obj.logs);
            }),
            marker: { size: 8 },

        }
        let data = [trace];
        let layout = {
            title: graphName,
            xaxis: {range: [new Date(start_x), new Date(end_x)]},
            yaxis: { title: "Execution time (ms)"}
        };
        let template = document.querySelector('#graph-template');
        var node = template.content.cloneNode(true);
        var divItem = node.querySelector('div');
        divItem.id = graphName;
        document.getElementById('graphs').appendChild(node);
        Plotly.newPlot(graphName, data, layout);
    }

    function loadBenchmarks() {
        benchmarkSelect.options.length = 0;
        benchmarks.set(0, "Please select a benchmark");
        const opt = new Option("Please select a benchmark", 0);
        benchmarkSelect.options.add(opt);
        let request = new Request('/benchmarks');
        fetch(request)
            .then(response => response.json())
            .then(json => {
                for (const benchmark of json) {
                    benchmarks.set(benchmark.id, benchmark);
                    const opt = new Option(benchmark.created_at, benchmark.id);
                    benchmarkSelect.options.add(opt);
                }
            });
    }

    loadBenchmarks();

</script>
</body>
</html>