1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sbin/hammer/cmd_stats.c,v 1.3 2008/07/14 20:28:07 dillon Exp $ 35 */ 36 37 #include <sys/sysctl.h> 38 #include <math.h> 39 40 #include "hammer.h" 41 42 static void loaddelay(struct timespec *ts, const char *arg); 43 44 #define _HAMMER "vfs.hammer.stats_" 45 #define bstats_title \ 46 " lookups searches inserts deletes elements splits iterations rootiters reciters" 47 #define iostats_title \ 48 " f_read f_write f_iopsr f_iopsw d_read d_write i_flushes commits undo redo" 49 50 /* 51 * Taken from sys/vfs/hammer/hammer_vfsops.c 52 */ 53 struct btree_stats { 54 int64_t btree_lookups; 55 int64_t btree_searches; 56 int64_t btree_inserts; 57 int64_t btree_deletes; 58 int64_t btree_elements; 59 int64_t btree_splits; 60 int64_t btree_iterations; 61 int64_t btree_root_iterations; 62 int64_t record_iterations; 63 }; 64 65 struct io_stats { 66 int64_t file_read; 67 int64_t file_write; 68 int64_t file_iopsr; 69 int64_t file_iopsw; 70 int64_t disk_read; 71 int64_t disk_write; 72 int64_t inode_flushes; 73 int64_t commits; 74 int64_t undo; 75 int64_t redo; 76 }; 77 78 static __inline 79 int 80 _sysctl(const char *name, int64_t *p) 81 { 82 size_t len = sizeof(*p); 83 return(sysctlbyname(name, p, &len, NULL, 0)); 84 } 85 86 static __inline 87 void 88 collect_bstats(struct btree_stats *p) 89 { 90 /* sysctls must exist, so ignore return values */ 91 _sysctl(_HAMMER"btree_lookups", &p->btree_lookups); 92 _sysctl(_HAMMER"btree_searches", &p->btree_searches); 93 _sysctl(_HAMMER"btree_inserts", &p->btree_inserts); 94 _sysctl(_HAMMER"btree_deletes", &p->btree_deletes); 95 _sysctl(_HAMMER"btree_elements", &p->btree_elements); 96 _sysctl(_HAMMER"btree_splits", &p->btree_splits); 97 _sysctl(_HAMMER"btree_iterations", &p->btree_iterations); 98 _sysctl(_HAMMER"btree_root_iterations", &p->btree_root_iterations); 99 _sysctl(_HAMMER"record_iterations", &p->record_iterations); 100 } 101 102 static __inline 103 void 104 collect_iostats(struct io_stats *p) 105 { 106 /* sysctls must exist, so ignore return values */ 107 _sysctl(_HAMMER"file_read", &p->file_read); 108 _sysctl(_HAMMER"file_write", &p->file_write); 109 _sysctl(_HAMMER"file_iopsr", &p->file_iopsr); 110 _sysctl(_HAMMER"file_iopsw", &p->file_iopsw); 111 _sysctl(_HAMMER"disk_read", &p->disk_read); 112 _sysctl(_HAMMER"disk_write", &p->disk_write); 113 _sysctl(_HAMMER"inode_flushes", &p->inode_flushes); 114 _sysctl(_HAMMER"commits", &p->commits); 115 _sysctl(_HAMMER"undo", &p->undo); 116 _sysctl(_HAMMER"redo", &p->redo); 117 } 118 119 static __inline 120 void 121 print_bstats(const struct btree_stats *p1, const struct btree_stats *p2) 122 { 123 printf("%10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd", 124 (intmax_t)(p1->btree_lookups - p2->btree_lookups), 125 (intmax_t)(p1->btree_searches - p2->btree_searches), 126 (intmax_t)(p1->btree_inserts - p2->btree_inserts), 127 (intmax_t)(p1->btree_deletes - p2->btree_deletes), 128 (intmax_t)(p1->btree_elements - p2->btree_elements), 129 (intmax_t)(p1->btree_splits - p2->btree_splits), 130 (intmax_t)(p1->btree_iterations - p2->btree_iterations), 131 (intmax_t)(p1->btree_root_iterations - p2->btree_root_iterations), 132 (intmax_t)(p1->record_iterations - p2->record_iterations)); 133 /* no trailing \n */ 134 } 135 136 static __inline 137 void 138 print_iostats(const struct io_stats *p1, const struct io_stats *p2) 139 { 140 printf("%9jd %9jd %9jd %9jd %9jd %9jd %9jd %9jd %9jd %9jd", 141 (intmax_t)(p1->file_read - p2->file_read), 142 (intmax_t)(p1->file_write - p2->file_write), 143 (intmax_t)(p1->file_iopsr - p2->file_iopsr), 144 (intmax_t)(p1->file_iopsw - p2->file_iopsw), 145 (intmax_t)(p1->disk_read - p2->disk_read), 146 (intmax_t)(p1->disk_write - p2->disk_write), 147 (intmax_t)(p1->inode_flushes - p2->inode_flushes), 148 (intmax_t)(p1->commits - p2->commits), 149 (intmax_t)(p1->undo - p2->undo), 150 (intmax_t)(p1->redo - p2->redo)); 151 /* no trailing \n */ 152 } 153 154 void 155 hammer_cmd_bstats(char **av, int ac) 156 { 157 struct btree_stats st1, st2; 158 struct timespec delay = {1, 0}; 159 int count; 160 161 bzero(&st1, sizeof(st1)); 162 bzero(&st2, sizeof(st2)); 163 164 if (ac > 0) 165 loaddelay(&delay, av[0]); 166 167 for (count = 0; ; ++count) { 168 collect_bstats(&st1); 169 if (count) { 170 if ((count & 15) == 1) 171 printf(bstats_title"\n"); 172 print_bstats(&st1, &st2); 173 printf("\n"); 174 } 175 bcopy(&st1, &st2, sizeof(st2)); 176 nanosleep(&delay, NULL); 177 } 178 } 179 180 void 181 hammer_cmd_iostats(char **av, int ac) 182 { 183 struct io_stats st1, st2; 184 struct timespec delay = {1, 0}; 185 int count; 186 187 bzero(&st1, sizeof(st1)); 188 bzero(&st2, sizeof(st2)); 189 190 if (ac > 0) 191 loaddelay(&delay, av[0]); 192 193 for (count = 0; ; ++count) { 194 collect_iostats(&st1); 195 if (count) { 196 if ((count & 15) == 1) 197 printf(iostats_title"\n"); 198 print_iostats(&st1, &st2); 199 printf("\n"); 200 } 201 bcopy(&st1, &st2, sizeof(st2)); 202 nanosleep(&delay, NULL); 203 } 204 } 205 206 void 207 hammer_cmd_stats(char **av, int ac) 208 { 209 struct btree_stats bst1, bst2; 210 struct io_stats ist1, ist2; 211 struct timespec delay = {1, 0}; 212 int count; 213 214 bzero(&bst1, sizeof(bst1)); 215 bzero(&bst2, sizeof(bst2)); 216 bzero(&ist1, sizeof(ist1)); 217 bzero(&ist2, sizeof(ist2)); 218 219 if (ac > 0) 220 loaddelay(&delay, av[0]); 221 222 for (count = 0; ; ++count) { 223 collect_bstats(&bst1); 224 collect_iostats(&ist1); 225 if (count) { 226 if ((count & 15) == 1) { 227 printf(bstats_title"\t"iostats_title"\n"); 228 } 229 print_bstats(&bst1, &bst2); 230 printf("\t"); 231 print_iostats(&ist1, &ist2); 232 printf("\n"); 233 } 234 bcopy(&bst1, &bst2, sizeof(bst2)); 235 bcopy(&ist1, &ist2, sizeof(ist2)); 236 nanosleep(&delay, NULL); 237 } 238 } 239 240 /* 241 * Convert a delay string (e.g. "0.1") into a timespec. 242 */ 243 static 244 void 245 loaddelay(struct timespec *ts, const char *arg) 246 { 247 double d; 248 249 d = strtod(arg, NULL); 250 if (d < 0.001) 251 d = 0.001; 252 ts->tv_sec = (int)d; 253 ts->tv_nsec = (int)(modf(d, &d) * 1000000000.0); 254 } 255