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 "hammer.h" 38 39 #include <sys/sysctl.h> 40 #include <math.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 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 disk_read; 69 int64_t disk_write; 70 int64_t inode_flushes; 71 int64_t commits; 72 int64_t undo; 73 int64_t redo; 74 }; 75 76 static __inline __always_inline 77 int 78 _sysctl(const char *name, int64_t *p) 79 { 80 size_t len = sizeof(*p); 81 return(sysctlbyname(name, p, &len, NULL, 0)); 82 } 83 84 static __inline __always_inline 85 void 86 collect_bstats(struct btree_stats *p) 87 { 88 /* sysctls must exist, so ignore return values */ 89 _sysctl(_HAMMER"btree_lookups", &p->btree_lookups); 90 _sysctl(_HAMMER"btree_searches", &p->btree_searches); 91 _sysctl(_HAMMER"btree_inserts", &p->btree_inserts); 92 _sysctl(_HAMMER"btree_deletes", &p->btree_deletes); 93 _sysctl(_HAMMER"btree_elements", &p->btree_elements); 94 _sysctl(_HAMMER"btree_splits", &p->btree_splits); 95 _sysctl(_HAMMER"btree_iterations", &p->btree_iterations); 96 _sysctl(_HAMMER"btree_root_iterations", &p->btree_root_iterations); 97 _sysctl(_HAMMER"record_iterations", &p->record_iterations); 98 } 99 100 static __inline __always_inline 101 void 102 collect_iostats(struct io_stats *p) 103 { 104 /* sysctls must exist, so ignore return values */ 105 _sysctl(_HAMMER"file_read", &p->file_read); 106 _sysctl(_HAMMER"file_write", &p->file_write); 107 _sysctl(_HAMMER"disk_read", &p->disk_read); 108 _sysctl(_HAMMER"disk_write", &p->disk_write); 109 _sysctl(_HAMMER"inode_flushes", &p->inode_flushes); 110 _sysctl(_HAMMER"commits", &p->commits); 111 _sysctl(_HAMMER"undo", &p->undo); 112 _sysctl(_HAMMER"redo", &p->redo); 113 } 114 115 static __inline __always_inline 116 void 117 print_bstats(const struct btree_stats *p1, const struct btree_stats *p2) 118 { 119 printf("%10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd %10jd", 120 (intmax_t)(p1->btree_lookups - p2->btree_lookups), 121 (intmax_t)(p1->btree_searches - p2->btree_searches), 122 (intmax_t)(p1->btree_inserts - p2->btree_inserts), 123 (intmax_t)(p1->btree_deletes - p2->btree_deletes), 124 (intmax_t)(p1->btree_elements - p2->btree_elements), 125 (intmax_t)(p1->btree_splits - p2->btree_splits), 126 (intmax_t)(p1->btree_iterations - p2->btree_iterations), 127 (intmax_t)(p1->btree_root_iterations - p2->btree_root_iterations), 128 (intmax_t)(p1->record_iterations - p2->record_iterations)); 129 /* no trailing \n */ 130 } 131 132 static __inline __always_inline 133 void 134 print_iostats(const struct io_stats *p1, const struct io_stats *p2) 135 { 136 printf("%9jd %9jd %9jd %9jd %9jd %9jd %9jd %9jd", 137 (intmax_t)(p1->file_read - p2->file_read), 138 (intmax_t)(p1->file_write - p2->file_write), 139 (intmax_t)(p1->disk_read - p2->disk_read), 140 (intmax_t)(p1->disk_write - p2->disk_write), 141 (intmax_t)(p1->inode_flushes - p2->inode_flushes), 142 (intmax_t)(p1->commits - p2->commits), 143 (intmax_t)(p1->undo - p2->undo), 144 (intmax_t)(p1->redo - p2->redo)); 145 /* no trailing \n */ 146 } 147 148 void 149 hammer_cmd_bstats(char **av, int ac) 150 { 151 struct btree_stats st1, st2; 152 struct timespec delay = {1, 0}; 153 int count; 154 155 bzero(&st1, sizeof(st1)); 156 bzero(&st2, sizeof(st2)); 157 158 if (ac > 0) 159 loaddelay(&delay, av[0]); 160 161 for (count = 0; ; ++count) { 162 collect_bstats(&st1); 163 if (count) { 164 if ((count & 15) == 1) 165 printf(bstats_title"\n"); 166 print_bstats(&st1, &st2); 167 printf("\n"); 168 } 169 bcopy(&st1, &st2, sizeof(st2)); 170 nanosleep(&delay, NULL); 171 } 172 } 173 174 void 175 hammer_cmd_iostats(char **av, int ac) 176 { 177 struct io_stats st1, st2; 178 struct timespec delay = {1, 0}; 179 int count; 180 181 bzero(&st1, sizeof(st1)); 182 bzero(&st2, sizeof(st2)); 183 184 if (ac > 0) 185 loaddelay(&delay, av[0]); 186 187 for (count = 0; ; ++count) { 188 collect_iostats(&st1); 189 if (count) { 190 if ((count & 15) == 1) 191 printf(iostats_title"\n"); 192 print_iostats(&st1, &st2); 193 printf("\n"); 194 } 195 bcopy(&st1, &st2, sizeof(st2)); 196 nanosleep(&delay, NULL); 197 } 198 } 199 200 void 201 hammer_cmd_stats(char **av, int ac) 202 { 203 struct btree_stats bst1, bst2; 204 struct io_stats ist1, ist2; 205 struct timespec delay = {1, 0}; 206 int count; 207 208 bzero(&bst1, sizeof(bst1)); 209 bzero(&bst2, sizeof(bst2)); 210 bzero(&ist1, sizeof(ist1)); 211 bzero(&ist2, sizeof(ist2)); 212 213 if (ac > 0) 214 loaddelay(&delay, av[0]); 215 216 for (count = 0; ; ++count) { 217 collect_bstats(&bst1); 218 collect_iostats(&ist1); 219 if (count) { 220 if ((count & 15) == 1) 221 printf(bstats_title"\t"iostats_title"\n"); 222 print_bstats(&bst1, &bst2); 223 printf("\t"); 224 print_iostats(&ist1, &ist2); 225 printf("\n"); 226 } 227 bcopy(&bst1, &bst2, sizeof(bst2)); 228 bcopy(&ist1, &ist2, sizeof(ist2)); 229 nanosleep(&delay, NULL); 230 } 231 } 232 233 /* 234 * Convert a delay string (e.g. "0.1") into a timespec. 235 */ 236 static 237 void 238 loaddelay(struct timespec *ts, const char *arg) 239 { 240 double d; 241 242 d = strtod(arg, NULL); 243 if (d < 0.001) 244 d = 0.001; 245 ts->tv_sec = (int)d; 246 ts->tv_nsec = (int)(modf(d, &d) * 1000000000.0); 247 } 248