uk.co.petertribble.solview.explorer.ArcStatPanel.java Source code

Java tutorial

Introduction

Here is the source code for uk.co.petertribble.solview.explorer.ArcStatPanel.java

Source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

package uk.co.petertribble.solview.explorer;

import javax.swing.*;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
import uk.co.petertribble.jkstat.api.JKstat;
import uk.co.petertribble.jkstat.api.Kstat;
import uk.co.petertribble.jingle.SpringUtilities;

import org.jfree.chart.*;
import org.jfree.data.general.*;

/**
 * Display ZFS ARC statistics in a Panel.
 * @author Peter Tribble
 * @version 1.0
 */
public class ArcStatPanel extends JPanel implements ActionListener {

    private static final long mb = 1024 * 1024;

    private JKstat jkstat;

    // sizes
    private long arc_size;
    private long target_size;
    private long arc_min_size;
    private long arc_max_size;
    private long mru_size;
    private long mfu_size;

    // labels for sizes
    private JLabel arc_size_label;
    private JLabel target_size_label;
    private JLabel arc_min_size_label;
    private JLabel arc_max_size_label;
    private JLabel mru_size_label;
    private JLabel mfu_size_label;

    // bars for current hit rates
    private JProgressBar arc_hit_bar;
    private JProgressBar demand_hit_bar;
    private JProgressBar pf_hit_bar;
    private JProgressBar mdemand_hit_bar;
    private JProgressBar mpf_hit_bar;

    // cache hit/miss data
    private DefaultPieDataset totalCacheHitsDataset;
    private DefaultPieDataset currentCacheHitsDataset;
    private DefaultPieDataset totalCacheHitsByTypeDataset;
    private DefaultPieDataset currentCacheHitsByTypeDataset;
    private DefaultPieDataset totalCacheMissesByTypeDataset;
    private DefaultPieDataset currentCacheMissesByTypeDataset;

    // saved statistics
    // naming: pf = prefetch; md = metadata
    private long arc_hits;
    private long arc_misses;
    private long mfu_hits;
    private long mru_hits;
    private long mfu_ghost_hits;
    private long mru_ghost_hits;
    private long anon_hits;
    private long demand_data_hits;
    private long demand_md_hits;
    private long pf_data_hits;
    private long pf_md_hits;
    private long demand_data_misses;
    private long demand_md_misses;
    private long pf_data_misses;
    private long pf_md_misses;
    // working statistics
    private long n_arc_hits;
    private long n_arc_misses;
    private long n_mfu_hits;
    private long n_mru_hits;
    private long n_mfu_ghost_hits;
    private long n_mru_ghost_hits;
    private long n_anon_hits;
    private long n_demand_data_hits;
    private long n_demand_md_hits;
    private long n_pf_data_hits;
    private long n_pf_md_hits;
    private long n_demand_data_misses;
    private long n_demand_md_misses;
    private long n_pf_data_misses;
    private long n_pf_md_misses;
    // changes
    private long d_arc_hits;
    private long d_arc_misses;
    private long d_mfu_hits;
    private long d_mru_hits;
    private long d_mfu_ghost_hits;
    private long d_mru_ghost_hits;
    private long d_anon_hits;
    private long d_demand_data_hits;
    private long d_demand_md_hits;
    private long d_pf_data_hits;
    private long d_pf_md_hits;
    private long d_demand_data_misses;
    private long d_demand_md_misses;
    private long d_pf_data_misses;
    private long d_pf_md_misses;

    private int p_d_arc_hit;
    private int p_d_demand_hit;
    private int p_d_pf_hit;
    private int p_d_mdemand_hit;
    private int p_d_mpf_hit;

    private Timer timer;
    private int delay = 5000;

    /**
     * Craete a new ArcStatPanel, to display ZFS ARC statistics graphically.
     *
     * @param jkstat a JKstat object
     * @param interval the desired display update interval in seconds
     */
    public ArcStatPanel(JKstat jkstat, int interval) {
        this.jkstat = jkstat;

        setDelay(interval);

        // FIXME all labels need to be localized

        // create a main panel
        setLayout(new SpringLayout());

        // initialise the datasets
        totalCacheHitsDataset = new DefaultPieDataset();
        currentCacheHitsDataset = new DefaultPieDataset();
        totalCacheHitsByTypeDataset = new DefaultPieDataset();
        currentCacheHitsByTypeDataset = new DefaultPieDataset();
        totalCacheMissesByTypeDataset = new DefaultPieDataset();
        currentCacheMissesByTypeDataset = new DefaultPieDataset();

        // initialise the pie charts
        // args: title, dataset, legend?, tooltips?, urls?
        JFreeChart totalCacheChart = ChartFactory.createPieChart("Total Cache Hits By List", totalCacheHitsDataset,
                false, true, false);
        JFreeChart currentCacheChart = ChartFactory.createPieChart("Current Cache Hits By List",
                currentCacheHitsDataset, false, true, false);
        JFreeChart totalCacheHitsByTypeChart = ChartFactory.createPieChart("Total Cache Hits By Type",
                totalCacheHitsByTypeDataset, false, true, false);
        JFreeChart currentCacheHitsByTypeChart = ChartFactory.createPieChart("Current Cache Hits By Type",
                currentCacheHitsByTypeDataset, false, true, false);
        JFreeChart totalCacheMissesByTypeChart = ChartFactory.createPieChart("Total Cache Misses By Type",
                totalCacheMissesByTypeDataset, false, true, false);
        JFreeChart currentCacheMissesByTypeChart = ChartFactory.createPieChart("Current Cache Misses By Type",
                currentCacheMissesByTypeDataset, false, true, false);

        /*
         * The overall layout is simple: at the top are the overall size
         * statistics. Then the percentages for hits/misses/types for the
         * cache are shown below.
         */
        JPanel infoPanel = new JPanel(new GridLayout(0, 2));
        JPanel hitPanel = new JPanel(new GridLayout(0, 2));
        JPanel cacheByListPanel = new JPanel(new GridLayout(1, 2));
        JPanel cacheHitByTypePanel = new JPanel(new GridLayout(1, 2));
        JPanel cacheMissByTypePanel = new JPanel(new GridLayout(1, 2));

        // cache hit rates, in a separate panel with bars.

        arc_hit_bar = new JProgressBar(0, 100);
        arc_hit_bar.setStringPainted(true);
        demand_hit_bar = new JProgressBar(0, 100);
        demand_hit_bar.setStringPainted(true);
        pf_hit_bar = new JProgressBar(0, 100);
        pf_hit_bar.setStringPainted(true);
        mdemand_hit_bar = new JProgressBar(0, 100);
        mdemand_hit_bar.setStringPainted(true);
        mpf_hit_bar = new JProgressBar(0, 100);
        mpf_hit_bar.setStringPainted(true);
        hitPanel.add(new JLabel("ARC hit rate"));
        hitPanel.add(arc_hit_bar);
        hitPanel.add(new JLabel("Demand data hit rate"));
        hitPanel.add(demand_hit_bar);
        hitPanel.add(new JLabel("Prefetch data hit rate"));
        hitPanel.add(pf_hit_bar);
        hitPanel.add(new JLabel("Demand metadata hit rate"));
        hitPanel.add(mdemand_hit_bar);
        hitPanel.add(new JLabel("Prefetch metadata hit rate"));
        hitPanel.add(mpf_hit_bar);
        hitPanel.setBorder(BorderFactory.createTitledBorder("Cache Hit Rates"));

        Dimension dchart = new Dimension(320, 240);
        ChartPanel cp1a = new ChartPanel(totalCacheChart);
        cp1a.setPreferredSize(dchart);
        ChartPanel cp1b = new ChartPanel(currentCacheChart);
        cp1b.setPreferredSize(dchart);
        ChartPanel cp2a = new ChartPanel(totalCacheHitsByTypeChart);
        cp2a.setPreferredSize(dchart);
        ChartPanel cp2b = new ChartPanel(currentCacheHitsByTypeChart);
        cp2b.setPreferredSize(dchart);
        ChartPanel cp3a = new ChartPanel(totalCacheMissesByTypeChart);
        cp3a.setPreferredSize(dchart);
        ChartPanel cp3b = new ChartPanel(currentCacheMissesByTypeChart);
        cp3b.setPreferredSize(dchart);

        infoPanel.add(new JLabel("Current size"));
        arc_size_label = new JLabel();
        infoPanel.add(arc_size_label);
        infoPanel.add(new JLabel("Target size"));
        target_size_label = new JLabel();
        infoPanel.add(target_size_label);
        infoPanel.add(new JLabel("Min size"));
        arc_min_size_label = new JLabel();
        infoPanel.add(arc_min_size_label);
        infoPanel.add(new JLabel("Max size"));
        arc_max_size_label = new JLabel();
        infoPanel.add(arc_max_size_label);
        infoPanel.add(new JLabel("MRU size"));
        mru_size_label = new JLabel();
        infoPanel.add(mru_size_label);
        infoPanel.add(new JLabel("MFU size"));
        mfu_size_label = new JLabel();
        infoPanel.add(mfu_size_label);
        infoPanel.setBorder(BorderFactory.createTitledBorder("Statistics"));

        cacheByListPanel.add(cp1a);
        cacheByListPanel.add(cp1b);
        cacheHitByTypePanel.add(cp2a);
        cacheHitByTypePanel.add(cp2b);
        cacheMissByTypePanel.add(cp3a);
        cacheMissByTypePanel.add(cp3b);

        add(infoPanel);
        add(hitPanel);
        add(cacheByListPanel);
        add(cacheHitByTypePanel);
        add(cacheMissByTypePanel);

        SpringUtilities.makeCompactGrid(this, 5, 1, 3, 3, 3, 3);

        update();
        startLoop();
    }

    /**
     * Update the statistics and the display.
     */
    private void update() {
        Kstat ks = jkstat.getKstat("zfs", 0, "arcstats");
        if (ks == null) {
            // FIXME what is the smartest response?
            // return;
            n_demand_data_hits = 7;
            n_demand_md_hits = 4;
            n_pf_data_hits = 2;
            n_pf_md_hits = 3;
            n_demand_data_misses = 9;
            n_demand_md_misses = 8;
            n_pf_data_misses = 6;
            n_pf_md_misses = 4;
        } else {
            n_arc_hits = ks.longData("hits");
            n_arc_misses = ks.longData("misses");
            n_mfu_hits = ks.longData("mfu_hits");
            n_mru_hits = ks.longData("mru_hits");
            n_mfu_ghost_hits = ks.longData("mfu_ghost_hits");
            n_mru_ghost_hits = ks.longData("mru_ghost_hits");
            n_anon_hits = n_arc_hits - (n_mfu_hits + n_mru_hits + n_mfu_ghost_hits + n_mru_ghost_hits);
            n_demand_data_hits = ks.longData("demand_data_hits");
            n_demand_md_hits = ks.longData("demand_metadata_hits");
            n_pf_data_hits = ks.longData("prefetch_data_hits");
            n_pf_md_hits = ks.longData("prefetch_metadata_hits");
            n_demand_data_misses = ks.longData("demand_data_misses");
            n_demand_md_misses = ks.longData("demand_metadata_misses");
            n_pf_data_misses = ks.longData("prefetch_data_misses");
            n_pf_md_misses = ks.longData("prefetch_metadata_misses");
            // sizes
            arc_size = ks.longData("size");
            target_size = ks.longData("c");
            arc_min_size = ks.longData("c_min");
            arc_max_size = ks.longData("c_max");
            mru_size = ks.longData("p");
            mfu_size = target_size - mru_size;
        }

        // summary labels
        arc_size_label.setText(Long.toString(arc_size / mb) + " MB");
        target_size_label.setText(Long.toString(target_size / mb) + " MB");
        arc_min_size_label.setText(Long.toString(arc_min_size / mb) + " MB");
        arc_max_size_label.setText(Long.toString(arc_max_size / mb) + " MB");
        mru_size_label.setText(Long.toString(mru_size / mb) + " MB");
        mfu_size_label.setText(Long.toString(mfu_size / mb) + " MB");

        // create deltas
        d_arc_hits = n_arc_hits - arc_hits;
        d_arc_misses = n_arc_misses - arc_misses;
        d_mfu_hits = n_mfu_hits - mfu_hits;
        d_mru_hits = n_mru_hits - mru_hits;
        d_mfu_ghost_hits = n_mfu_ghost_hits - mfu_ghost_hits;
        d_mru_ghost_hits = n_mru_ghost_hits - mru_ghost_hits;
        d_anon_hits = n_anon_hits - anon_hits;
        d_demand_data_hits = n_demand_data_hits - demand_data_hits;
        d_demand_md_hits = n_demand_md_hits - demand_md_hits;
        d_pf_data_hits = n_pf_data_hits - pf_data_hits;
        d_pf_md_hits = n_pf_md_hits - pf_md_hits;
        d_demand_data_misses = n_demand_data_misses - demand_data_misses;
        d_demand_md_misses = n_demand_md_misses - demand_md_misses;
        d_pf_data_misses = n_pf_data_misses - pf_data_misses;
        d_pf_md_misses = n_pf_md_misses - pf_md_misses;

        // save values
        arc_hits = n_arc_hits;
        arc_misses = n_arc_misses;
        mfu_hits = n_mfu_hits;
        mru_hits = n_mru_hits;
        mfu_ghost_hits = n_mfu_ghost_hits;
        mru_ghost_hits = n_mru_ghost_hits;
        anon_hits = n_anon_hits;
        demand_data_hits = n_demand_data_hits;
        demand_md_hits = n_demand_md_hits;
        pf_data_hits = n_pf_data_hits;
        pf_md_hits = n_pf_md_hits;
        demand_data_misses = n_demand_data_misses;
        demand_md_misses = n_demand_md_misses;
        pf_data_misses = n_pf_data_misses;
        pf_md_misses = n_pf_md_misses;

        if ((d_arc_hits + d_arc_misses) > 0) {
            p_d_arc_hit = (int) ((100L * d_arc_hits) / (d_arc_hits + d_arc_misses));
        } else {
            p_d_arc_hit = 0;
        }
        if ((d_demand_data_hits + d_demand_data_misses) > 0) {
            p_d_demand_hit = (int) ((100L * d_demand_data_hits) / (d_demand_data_hits + d_demand_data_misses));
        } else {
            p_d_demand_hit = 0;
        }
        if ((d_pf_data_hits + d_pf_data_misses) > 0) {
            p_d_pf_hit = (int) ((100L * d_pf_data_hits) / (d_pf_data_hits + d_pf_data_misses));
        } else {
            p_d_pf_hit = 0;
        }
        if ((d_demand_md_hits + d_demand_md_misses) > 0) {
            p_d_mdemand_hit = (int) ((100L * d_demand_md_hits) / (d_demand_md_hits + d_demand_md_misses));
        } else {
            p_d_mdemand_hit = 0;
        }
        if ((d_pf_md_hits + d_pf_md_misses) > 0) {
            p_d_mpf_hit = (int) ((100L * d_pf_md_hits) / (d_pf_md_hits + d_pf_md_misses));
        } else {
            p_d_mpf_hit = 0;
        }

        arc_hit_bar.setValue(p_d_arc_hit);
        demand_hit_bar.setValue(p_d_demand_hit);
        pf_hit_bar.setValue(p_d_pf_hit);
        mdemand_hit_bar.setValue(p_d_mdemand_hit);
        mpf_hit_bar.setValue(p_d_mpf_hit);

        // hits by list
        totalCacheHitsDataset.setValue("Anon", anon_hits);
        totalCacheHitsDataset.setValue("Recently Used", mru_hits);
        totalCacheHitsDataset.setValue("Frequently Used", mfu_hits);
        totalCacheHitsDataset.setValue("Recently Used Ghost", mru_ghost_hits);
        totalCacheHitsDataset.setValue("Frequently Used Ghost", mfu_ghost_hits);
        currentCacheHitsDataset.setValue("Anon", d_anon_hits);
        currentCacheHitsDataset.setValue("Recently Used", d_mru_hits);
        currentCacheHitsDataset.setValue("Frequently Used", d_mfu_hits);
        currentCacheHitsDataset.setValue("Recently Used Ghost", d_mru_ghost_hits);
        currentCacheHitsDataset.setValue("Frequently Used Ghost", d_mfu_ghost_hits);

        // totals by type
        totalCacheHitsByTypeDataset.setValue("Demand Data Hits", demand_data_hits);
        totalCacheHitsByTypeDataset.setValue("Demand Metadata Hits", demand_md_hits);
        totalCacheHitsByTypeDataset.setValue("Prefetch Data Hits", pf_data_hits);
        totalCacheHitsByTypeDataset.setValue("Prefetch Metadata Hits", pf_md_hits);
        totalCacheMissesByTypeDataset.setValue("Demand Data Misses", demand_data_misses);
        totalCacheMissesByTypeDataset.setValue("Demand Metadata Misses", demand_md_misses);
        totalCacheMissesByTypeDataset.setValue("Prefetch Data Misses", pf_data_misses);
        totalCacheMissesByTypeDataset.setValue("Prefetch Metadata Misses", pf_md_misses);

        // current activity by type
        currentCacheHitsByTypeDataset.setValue("Demand Data Hits", d_demand_data_hits);
        currentCacheHitsByTypeDataset.setValue("Demand Metadata Hits", d_demand_md_hits);
        currentCacheHitsByTypeDataset.setValue("Prefetch Data Hits", d_pf_data_hits);
        currentCacheHitsByTypeDataset.setValue("Prefetch Metadata Hits", d_pf_md_hits);
        currentCacheMissesByTypeDataset.setValue("Demand Data Misses", d_demand_data_misses);
        currentCacheMissesByTypeDataset.setValue("Demand Metadata Misses", d_demand_md_misses);
        currentCacheMissesByTypeDataset.setValue("Prefetch Data Misses", d_pf_data_misses);
        currentCacheMissesByTypeDataset.setValue("Prefetch Metadata Misses", d_pf_md_misses);
    }

    /**
     * Start the timer loop, so that the accessory updates itself.
     */
    public void startLoop() {
        if (timer == null) {
            timer = new Timer(delay, this);
        }
        timer.start();
    }

    /**
     * Stop the timer loop, so that the display no longer updates.
     */
    public void stopLoop() {
        if (timer != null) {
            timer.stop();
        }
    }

    /**
     * Set the update delay.
     *
     * @param interval the desired update interval, in seconds
     */
    public void setDelay(int interval) {
        delay = interval * 1000;
        if (timer != null) {
            timer.setDelay(delay);
        }
    }

    public void actionPerformed(ActionEvent e) {
        update();
    }
}