File: lvm-cache-stats.c

package info (click to toggle)
libblockdev 3.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,140 kB
  • sloc: ansic: 25,226; python: 11,877; makefile: 684; sh: 503; xml: 146
file content (156 lines) | stat: -rw-r--r-- 6,012 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#include <blockdev/blockdev.h>
#include <blockdev/lvm.h>
#include <bytesize/bs_size.h>

void print_usage (const char *cmd) {
    fprintf (stderr,
             "Usage: %s CACHED_LV [CACHED_LV2...]\n"
             "-h    --help   Print this usage info\n"
             "-j    --json   Print stats as JSON\n"
             "Options need to be specified before LVs.\n",
             cmd);
}

void print_size (guint64 bytes, gboolean newline) {
    BSSize size = bs_size_new_from_bytes (bytes, 1);
    char *size_str = bs_size_human_readable (size, BS_BUNIT_MiB, 2, true);
    printf ("%10s%s", size_str, newline ? "\n" : "");
    free (size_str);
    bs_size_free (size);
}

void print_ratio (guint64 part, guint64 total, gboolean space, gboolean newline) {
    float percent = ((float) part / total) * 100;
    printf ("%s[%6.2f%%]%s", space ? " " : "", percent, newline ? "\n" : "");
}

gboolean print_lv_stats (const char *vg_name, const char *lv_name, GError **error) {
    BDLVMLVdata *lv_data = bd_lvm_lvinfo (vg_name, lv_name, error);
    if (!lv_data)
        return FALSE;
    BDLVMCacheStats *stats = bd_lvm_cache_stats (vg_name, lv_name, error);
    if (!stats)
        return FALSE;

    printf ("%s/%s:\n", vg_name, lv_name);
    printf ("  mode:      %13s\n", bd_lvm_cache_get_mode_str (stats->mode, error)); /* ignoring 'error', must be a valid mode */
    printf ("  LV size:      "); print_size (lv_data->size, TRUE);
    printf ("  cache size:   "); print_size (stats->cache_size, FALSE); print_ratio (stats->cache_size, lv_data->size, TRUE, TRUE);
    printf ("  cache used:   "); print_size (stats->cache_used, FALSE); print_ratio (stats->cache_used, stats->cache_size, TRUE, TRUE);
    printf ("  read misses:  %10"G_GUINT64_FORMAT"\n", stats->read_misses);
    printf ("  read hits:    %10"G_GUINT64_FORMAT, stats->read_hits); print_ratio (stats->read_hits, stats->read_hits + stats->read_misses, TRUE, TRUE);
    printf ("  write misses: %10"G_GUINT64_FORMAT"\n", stats->write_misses);
    printf ("  write hits:   %10"G_GUINT64_FORMAT, stats->write_hits); print_ratio (stats->write_hits, stats->write_hits + stats->write_misses, TRUE, TRUE);

    bd_lvm_lvdata_free (lv_data);
    bd_lvm_cache_stats_free (stats);

    return TRUE;
}

gboolean print_lv_stats_json(const char *vg_name, const char *lv_name, GError **error) {
    BDLVMLVdata *lv_data = bd_lvm_lvinfo (vg_name, lv_name, error);
    if (!lv_data)
        return FALSE;
    BDLVMCacheStats *stats = bd_lvm_cache_stats (vg_name, lv_name, error);
    if (!stats)
        return FALSE;

    printf ("{\n");
    printf ("  \"lv\": \"%s/%s\",\n", vg_name, lv_name);
    printf ("  \"mode\": \"%s\",\n", bd_lvm_cache_get_mode_str (stats->mode, error)); /* ignoring 'error', must be a valid mode */
    printf ("  \"lv-size\": %"G_GUINT64_FORMAT",\n", lv_data->size);
    printf ("  \"cache-size\": %"G_GUINT64_FORMAT",\n", stats->cache_size);
    printf ("  \"cache-size-pct\": %0.2f,\n", (double) stats->cache_size / lv_data->size);
    printf ("  \"cache-used\": %"G_GUINT64_FORMAT",\n", stats->cache_size);
    printf ("  \"cache-used-pct\": %0.2f,\n", (double) stats->cache_used / stats->cache_size);
    printf ("  \"read-misses\": %"G_GUINT64_FORMAT",\n", stats->read_misses);
    printf ("  \"read-hits\": %"G_GUINT64_FORMAT",\n", stats->read_hits);
    printf ("  \"read-hit-ratio\": %0.2f,\n", (double)stats->read_hits / (stats->read_hits + stats->read_misses));
    printf ("  \"write-misses\": %"G_GUINT64_FORMAT",\n", stats->write_misses);
    printf ("  \"write-hits\": %"G_GUINT64_FORMAT",\n", stats->write_hits);
    printf ("  \"write-hit-ratio\": %0.2f\n", (double)stats->write_hits / (stats->write_hits + stats->write_misses));
    printf ("}\n");

    bd_lvm_lvdata_free (lv_data);
    bd_lvm_cache_stats_free (stats);

    return TRUE;
}

int main (int argc, char *argv[]) {
    gboolean ret = FALSE;
    GError *error = NULL;

    if ((g_strcmp0 (argv[1], "-h") == 0) || g_strcmp0 (argv[1], "--help") == 0) {
        print_usage (argv[0]);
        return 1;
    }

    gboolean json = FALSE;
    int first_lv_arg = 1;
    for (int i=0; i < argc; i++) {
        if ((g_strcmp0 (argv[i], "-j") == 0) || g_strcmp0 (argv[i], "--json") == 0) {
            json = TRUE;
            first_lv_arg++;
        }
    }

    if (first_lv_arg >= argc) {
        fprintf (stderr, "No cached LV to get the stats for specified!\n");
        print_usage (argv[0]);
        return 1;
    }

    /* check that we are running as root */
    if ((getuid() != 0) || (geteuid() != 0)) {
        fprintf (stderr, "This utility must be run as root.\n");
        return 1;
    }

    /* initialize the library -- we only need the LVM plugin */
    BDPluginSpec lvm_plugin = {BD_PLUGIN_LVM, NULL};
    BDPluginSpec *plugins[] = {&lvm_plugin, NULL};
    ret = bd_init (plugins, NULL, &error);

    if (!ret) {
        fprintf (stderr, "Failed to initialize the libblockdev library: %s\n",
                 error->message);
        return 2;
    }

    gboolean ok = TRUE;
    for (int i = first_lv_arg; i < argc; i++) {
        /* Add one blank line between stats for the individual LVs */
        if (i > first_lv_arg)
            printf("\n");

        char *slash = strchr (argv[i], '/');
        if (!slash) {
            fprintf (stderr, "Invalid LV specified: '%s'. Has to be in the VG/LV format.\n", argv[i]);
            ok = FALSE;
            continue;
        }
        *slash = '\0';
        const char *vg_name = argv[i];
        const char *lv_name = slash + 1;

        if (json)
            ret = print_lv_stats_json (vg_name, lv_name, &error);
        else
            ret = print_lv_stats (vg_name, lv_name, &error);

        if (!ret) {
            fprintf (stderr, "Failed to get stats for '%s/%s': %s\n",
                     vg_name, lv_name, error->message);
            ok = FALSE;
        }
    }

    return ok ? 0 : 3;
}