1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdarg.h> 33 #include <libintl.h> 34 #include <sys/types.h> 35 #include <sys/ioctl.h> 36 #include <sys/stat.h> 37 #include <kstat.h> 38 #include <locale.h> 39 #include <sys/fs/cachefs_log.h> 40 #include "stats.h" 41 42 void usage(char *); 43 void pr_err(char *, ...); 44 45 static int zflag; 46 char *prog; 47 48 static void print_stats(stats_cookie_t *, cachefs_kstat_key_t *, int); 49 50 int 51 main(int argc, char **argv) 52 { 53 int rc = 0; 54 int i, c, errflg = 0; 55 stats_cookie_t *sc = NULL; 56 cachefs_kstat_key_t *key; 57 58 (void) setlocale(LC_ALL, ""); 59 #if !defined(TEXT_DOMAIN) 60 #define TEXT_DOMAIN "SYS_TEST" 61 #endif /* TEXT_DOMAIN */ 62 (void) textdomain(TEXT_DOMAIN); 63 64 if (prog = strrchr(argv[0], '/')) 65 ++prog; 66 else 67 prog = argv[0]; 68 69 while ((c = getopt(argc, argv, "z")) != EOF) 70 switch (c) { 71 case 'z': 72 ++zflag; 73 break; 74 75 case '?': 76 default: 77 ++errflg; 78 break; 79 } 80 81 if (errflg) { 82 usage(NULL); 83 rc = -1; 84 goto out; 85 } 86 87 /* 88 * handle multiple mountpoints specified on command line 89 */ 90 91 for (i = optind; i < argc; i++) { 92 if ((sc = stats_create_mountpath(argv[i], prog)) == NULL) { 93 pr_err(gettext("Cannot use %s"), argv[i]); 94 rc = 1; 95 continue; 96 } 97 98 if (stats_inerror(sc)) { 99 pr_err(stats_errorstr(sc)); 100 rc = stats_errno(sc); 101 continue; 102 } 103 print_stats(sc, key = stats_getkey(sc), zflag); 104 if (stats_inerror(sc)) { 105 pr_err(stats_errorstr(sc)); 106 rc = stats_errno(sc); 107 } 108 109 stats_destroy(sc); 110 free(key); 111 } 112 113 /* 114 * handle the case where no mountpoints were specified, 115 * i.e. show stats for all. 116 */ 117 118 if (optind >= argc) { 119 sc = stats_create_unbound(prog); 120 121 while ((key = stats_next(sc)) != NULL) { 122 if (! key->ks_mounted) { 123 free(key); 124 continue; 125 } 126 127 print_stats(sc, key, zflag); 128 if (stats_inerror(sc)) { 129 pr_err(stats_errorstr(sc)); 130 rc = stats_errno(sc); 131 } 132 free(key); 133 } 134 stats_destroy(sc); 135 } 136 137 out: 138 return (rc); 139 } 140 141 static void 142 print_stats(stats_cookie_t *sc, cachefs_kstat_key_t *key, int zero) 143 { 144 uint_t misses, passes, fails, modifies; 145 uint_t hitp, passtotal; 146 uint_t gccount; 147 u_longlong_t hits; 148 149 hits = (u_longlong_t)stats_hits(sc); 150 misses = stats_misses(sc); 151 if (hits + misses != 0) 152 hitp = (uint_t)((100 * hits) / (hits + misses)); 153 else 154 hitp = 100; 155 156 passes = stats_passes(sc); 157 fails = stats_fails(sc); 158 passtotal = passes + fails; 159 160 modifies = stats_modifies(sc); 161 162 gccount = stats_gc_count(sc); 163 164 printf("\n %s\n", (char *)(uintptr_t)key->ks_mountpoint); 165 printf(gettext( 166 "\t cache hit rate: %5u%% (%llu hits, %u misses)\n"), 167 hitp, hits, misses); 168 printf(gettext("\t consistency checks: %6d (%d pass, %d fail)\n"), 169 passtotal, passes, fails); 170 printf(gettext("\t modifies: %6d\n"), modifies); 171 printf(gettext("\t garbage collection: %6d\n"), gccount); 172 if (gccount != 0) { 173 time_t gctime = stats_gc_time(sc); 174 time_t before = stats_gc_before(sc); 175 time_t after = stats_gc_after(sc); 176 177 if (gctime != (time_t)0) 178 printf(gettext("\tlast garbage collection: %s"), 179 ctime(&gctime)); 180 } 181 182 if (zero) 183 (void) stats_zero_stats(sc); 184 } 185 186 187 /* 188 * 189 * usage 190 * 191 * Description: 192 * Prints a short usage message. 193 * Arguments: 194 * msgp message to include with the usage message 195 * Returns: 196 * Preconditions: 197 */ 198 199 void 200 usage(char *msgp) 201 { 202 if (msgp) { 203 pr_err("%s", msgp); 204 } 205 206 fprintf(stderr, 207 gettext("Usage: cachefsstat [ -z ] [ path ... ]\n")); 208 } 209 210 /* 211 * 212 * pr_err 213 * 214 * Description: 215 * Prints an error message to stderr. 216 * Arguments: 217 * fmt printf style format 218 * ... arguments for fmt 219 * Returns: 220 * Preconditions: 221 * precond(fmt) 222 */ 223 224 void 225 pr_err(char *fmt, ...) 226 { 227 va_list ap; 228 229 va_start(ap, fmt); 230 (void) fprintf(stderr, gettext("cachefsstat: ")); 231 (void) vfprintf(stderr, fmt, ap); 232 (void) fprintf(stderr, "\n"); 233 va_end(ap); 234 } 235