1 1.13 manu /* $NetBSD: debug.c,v 1.13 2018/11/16 02:39:02 manu Exp $ */ 2 1.1 manu 3 1.1 manu /*- 4 1.1 manu * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved. 5 1.1 manu * 6 1.1 manu * Redistribution and use in source and binary forms, with or without 7 1.1 manu * modification, are permitted provided that the following conditions 8 1.1 manu * are met: 9 1.1 manu * 1. Redistributions of source code must retain the above copyright 10 1.1 manu * notice, this list of conditions and the following disclaimer. 11 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 manu * notice, this list of conditions and the following disclaimer in the 13 1.1 manu * documentation and/or other materials provided with the distribution. 14 1.1 manu * 15 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 manu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 manu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 manu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 manu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 manu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 manu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 manu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 manu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 manu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 manu * POSSIBILITY OF SUCH DAMAGE. 26 1.1 manu */ 27 1.1 manu 28 1.1 manu #include <puffs.h> 29 1.6 manu #include <stdio.h> 30 1.9 manu #include <stdlib.h> 31 1.9 manu #include <err.h> 32 1.9 manu #include <errno.h> 33 1.1 manu #include <sys/types.h> 34 1.1 manu 35 1.1 manu #include "perfuse_if.h" 36 1.6 manu #include "perfuse_priv.h" 37 1.1 manu #include "fuse.h" 38 1.1 manu 39 1.1 manu struct perfuse_opcode { 40 1.1 manu int opcode; 41 1.1 manu const char *opname; 42 1.1 manu }; 43 1.1 manu 44 1.1 manu const struct perfuse_opcode perfuse_opcode[] = { 45 1.1 manu { FUSE_LOOKUP, "LOOKUP" }, 46 1.1 manu { FUSE_FORGET, "FORGET" }, 47 1.1 manu { FUSE_GETATTR, "GETATTR" }, 48 1.1 manu { FUSE_SETATTR, "SETATTR" }, 49 1.1 manu { FUSE_READLINK, "READLINK" }, 50 1.1 manu { FUSE_SYMLINK, "SYMLINK" }, 51 1.1 manu { FUSE_MKNOD, "MKNOD" }, 52 1.1 manu { FUSE_MKDIR, "MKDIR" }, 53 1.1 manu { FUSE_UNLINK, "UNLINK" }, 54 1.1 manu { FUSE_RMDIR, "RMDIR" }, 55 1.1 manu { FUSE_RENAME, "RENAME" }, 56 1.1 manu { FUSE_LINK, "LINK" }, 57 1.1 manu { FUSE_OPEN, "OPEN" }, 58 1.1 manu { FUSE_READ, "READ" }, 59 1.1 manu { FUSE_WRITE, "WRITE" }, 60 1.1 manu { FUSE_STATFS, "STATFS" }, 61 1.1 manu { FUSE_RELEASE, "RELEASE" }, 62 1.1 manu { FUSE_FSYNC, "FSYNC" }, 63 1.1 manu { FUSE_SETXATTR, "SETXATTR" }, 64 1.1 manu { FUSE_GETXATTR, "GETXATTR" }, 65 1.1 manu { FUSE_LISTXATTR, "LISTXATTR" }, 66 1.1 manu { FUSE_REMOVEXATTR, "REMOVEXATTR" }, 67 1.1 manu { FUSE_FLUSH, "FLUSH" }, 68 1.1 manu { FUSE_INIT, "INIT" }, 69 1.1 manu { FUSE_OPENDIR, "OPENDIR" }, 70 1.1 manu { FUSE_READDIR, "READDIR" }, 71 1.1 manu { FUSE_RELEASEDIR, "RELEASEDIR" }, 72 1.1 manu { FUSE_FSYNCDIR, "FSYNCDIR" }, 73 1.1 manu { FUSE_GETLK, "GETLK" }, 74 1.1 manu { FUSE_SETLK, "SETLK" }, 75 1.1 manu { FUSE_SETLKW, "SETLKW" }, 76 1.1 manu { FUSE_ACCESS, "ACCESS" }, 77 1.1 manu { FUSE_CREATE, "CREATE" }, 78 1.1 manu { FUSE_INTERRUPT, "INTERRUPT" }, 79 1.1 manu { FUSE_BMAP, "BMAP" }, 80 1.1 manu { FUSE_DESTROY, "DESTROY" }, 81 1.1 manu { FUSE_IOCTL, "IOCTL" }, 82 1.1 manu { FUSE_POLL, "POLL" }, 83 1.1 manu { FUSE_CUSE_INIT, "CUSE_INIT" }, 84 1.1 manu { 0, "UNKNOWN" }, 85 1.1 manu }; 86 1.1 manu 87 1.11 matt const char * const perfuse_qtypestr[] = { 88 1.3 manu "READDIR", 89 1.3 manu "READ", 90 1.3 manu "WRITE", 91 1.3 manu "AFTERWRITE", 92 1.5 manu "OPEN", 93 1.12 manu "AFTERXCHG", 94 1.12 manu "REF" 95 1.3 manu }; 96 1.2 manu 97 1.1 manu const char * 98 1.11 matt perfuse_opname(int opcode) 99 1.1 manu { 100 1.1 manu const struct perfuse_opcode *po; 101 1.1 manu 102 1.1 manu for (po = perfuse_opcode; po->opcode; po++) { 103 1.1 manu if (po->opcode == opcode) 104 1.1 manu return po->opname; 105 1.1 manu } 106 1.1 manu 107 1.1 manu return po->opname; /* "UNKNOWN" */ 108 1.1 manu } 109 1.6 manu 110 1.6 manu char * 111 1.11 matt perfuse_opdump_in(struct perfuse_state *ps, perfuse_msg_t *pm) 112 1.6 manu { 113 1.6 manu struct fuse_in_header *fih; 114 1.6 manu static char buf[BUFSIZ] = ""; 115 1.6 manu 116 1.6 manu fih = GET_INHDR(ps, pm); 117 1.6 manu 118 1.6 manu switch(fih->opcode) { 119 1.6 manu case FUSE_LOOKUP: 120 1.6 manu (void)snprintf(buf, sizeof(buf), "path = \"%s\"", 121 1.6 manu _GET_INPAYLOAD(ps, pm, const char *)); 122 1.6 manu break; 123 1.6 manu default: 124 1.6 manu buf[0] = '\0'; 125 1.6 manu break; 126 1.6 manu } 127 1.6 manu 128 1.6 manu return buf; 129 1.6 manu } 130 1.6 manu 131 1.9 manu struct perfuse_trace * 132 1.11 matt perfuse_trace_begin(struct perfuse_state *ps, puffs_cookie_t opc, 133 1.11 matt perfuse_msg_t *pm) 134 1.9 manu { 135 1.9 manu struct perfuse_trace *pt; 136 1.9 manu 137 1.9 manu if ((pt = malloc(sizeof(*pt))) == NULL) 138 1.9 manu DERR(EX_OSERR, "malloc failed"); 139 1.9 manu 140 1.9 manu pt->pt_opcode = ps->ps_get_inhdr(pm)->opcode; 141 1.9 manu pt->pt_status = inxchg; 142 1.9 manu 143 1.9 manu if (clock_gettime(CLOCK_REALTIME, &pt->pt_start) != 0) 144 1.9 manu DERR(EX_OSERR, "clock_gettime failed"); 145 1.9 manu 146 1.9 manu if (opc == 0) 147 1.9 manu (void)strcpy(pt->pt_path, ""); 148 1.9 manu else 149 1.9 manu (void)strlcpy(pt->pt_path, 150 1.12 manu perfuse_node_path(ps, opc), 151 1.9 manu sizeof(pt->pt_path)); 152 1.9 manu 153 1.9 manu (void)strlcpy(pt->pt_extra, 154 1.9 manu perfuse_opdump_in(ps, pm), 155 1.9 manu sizeof(pt->pt_extra)); 156 1.9 manu 157 1.9 manu TAILQ_INSERT_TAIL(&ps->ps_trace, pt, pt_list); 158 1.9 manu ps->ps_tracecount++; 159 1.9 manu 160 1.9 manu return pt; 161 1.9 manu } 162 1.9 manu 163 1.9 manu void 164 1.11 matt perfuse_trace_end(struct perfuse_state *ps, struct perfuse_trace *pt, int error) 165 1.9 manu { 166 1.9 manu if (clock_gettime(CLOCK_REALTIME, &pt->pt_end) != 0) 167 1.9 manu DERR(EX_OSERR, "clock_gettime failed"); 168 1.9 manu 169 1.9 manu pt->pt_status = done; 170 1.9 manu pt->pt_error = error; 171 1.9 manu 172 1.9 manu while (ps->ps_tracecount > PERFUSE_TRACECOUNT_MAX) { 173 1.9 manu struct perfuse_trace *fpt = TAILQ_FIRST(&ps->ps_trace); 174 1.9 manu 175 1.9 manu if (fpt == NULL || fpt->pt_status != done) 176 1.9 manu break; 177 1.9 manu 178 1.9 manu TAILQ_REMOVE(&ps->ps_trace, fpt, pt_list); 179 1.9 manu free(fpt); 180 1.9 manu ps->ps_tracecount--; 181 1.9 manu } 182 1.9 manu } 183 1.9 manu 184 1.6 manu void 185 1.11 matt perfuse_trace_dump(struct puffs_usermount *pu, FILE *fp) 186 1.6 manu { 187 1.6 manu struct perfuse_state *ps; 188 1.6 manu struct perfuse_trace *pt; 189 1.6 manu struct timespec ts_min[FUSE_OPCODE_MAX]; 190 1.6 manu struct timespec ts_max[FUSE_OPCODE_MAX]; 191 1.6 manu struct timespec ts_total[FUSE_OPCODE_MAX]; 192 1.6 manu int count[FUSE_OPCODE_MAX]; 193 1.6 manu uint64_t avg; 194 1.6 manu int i; 195 1.6 manu 196 1.6 manu if (!(perfuse_diagflags & PDF_TRACE)) 197 1.6 manu return; 198 1.6 manu 199 1.6 manu ps = puffs_getspecific(pu); 200 1.6 manu 201 1.6 manu (void)ftruncate(fileno(fp), 0); 202 1.12 manu (void)fseek(fp, 0UL, SEEK_SET); 203 1.6 manu 204 1.6 manu (void)memset(&ts_min, 0, sizeof(ts_min)); 205 1.6 manu (void)memset(&ts_max, 0, sizeof(ts_max)); 206 1.6 manu (void)memset(&ts_total, 0, sizeof(ts_total)); 207 1.6 manu (void)memset(&count, 0, sizeof(count)); 208 1.6 manu 209 1.6 manu fprintf(fp, "Last %"PRId64" operations\n", ps->ps_tracecount); 210 1.6 manu 211 1.6 manu TAILQ_FOREACH(pt, &ps->ps_trace, pt_list) { 212 1.6 manu const char *quote = pt->pt_path[0] != '\0' ? "\"" : ""; 213 1.6 manu 214 1.10 dholland fprintf(fp, "%lld.%09ld %s %s%s%s %s ", 215 1.10 dholland (long long)pt->pt_start.tv_sec, pt->pt_start.tv_nsec, 216 1.6 manu perfuse_opname(pt->pt_opcode), 217 1.6 manu quote, pt->pt_path, quote, 218 1.6 manu pt->pt_extra); 219 1.6 manu 220 1.6 manu if (pt->pt_status == done) { 221 1.6 manu struct timespec ts; 222 1.6 manu 223 1.6 manu ts.tv_sec = 0; /* delint */ 224 1.6 manu ts.tv_nsec = 0; /* delint */ 225 1.6 manu timespecsub(&pt->pt_end, &pt->pt_start, &ts); 226 1.6 manu 227 1.10 dholland fprintf(fp, "error = %d elapsed = %lld.%09lu ", 228 1.10 dholland pt->pt_error, (long long)ts.tv_sec, 229 1.10 dholland ts.tv_nsec); 230 1.6 manu 231 1.6 manu count[pt->pt_opcode]++; 232 1.6 manu timespecadd(&ts_total[pt->pt_opcode], 233 1.6 manu &ts, 234 1.6 manu &ts_total[pt->pt_opcode]); 235 1.6 manu 236 1.6 manu if (timespeccmp(&ts, &ts_min[pt->pt_opcode], <) || 237 1.6 manu (count[pt->pt_opcode] == 1)) 238 1.6 manu ts_min[pt->pt_opcode] = ts; 239 1.6 manu 240 1.6 manu if (timespeccmp(&ts, &ts_max[pt->pt_opcode], >)) 241 1.6 manu ts_max[pt->pt_opcode] = ts; 242 1.6 manu } else { 243 1.6 manu fprintf(fp, "ongoing "); 244 1.6 manu } 245 1.6 manu 246 1.6 manu fprintf(fp, "\n"); 247 1.6 manu } 248 1.6 manu 249 1.6 manu fprintf(fp, "\nStatistics by operation\n"); 250 1.6 manu fprintf(fp, "operation\tcount\tmin\tavg\tmax\n"); 251 1.6 manu for (i = 0; i < FUSE_OPCODE_MAX; i++) { 252 1.6 manu time_t min; 253 1.6 manu 254 1.6 manu if (count[i] != 0) { 255 1.6 manu avg = timespec2ns(&ts_total[i]) / count[i]; 256 1.6 manu min = ts_min[i].tv_sec; 257 1.6 manu } else { 258 1.6 manu avg = 0; 259 1.6 manu min = 0; 260 1.6 manu } 261 1.6 manu 262 1.10 dholland fprintf(fp, "%s\t%d\t%lld.%09ld\t%lld.%09ld\t%lld.%09ld\t\n", 263 1.6 manu perfuse_opname(i), count[i], 264 1.10 dholland (long long)min, ts_min[i].tv_nsec, 265 1.10 dholland (long long)(time_t)(avg / 1000000000L), 266 1.10 dholland (long)(avg % 1000000000L), 267 1.10 dholland (long long)ts_max[i].tv_sec, ts_max[i].tv_nsec); 268 1.6 manu } 269 1.12 manu 270 1.12 manu fprintf(fp, "\n\nGlobal statistics\n"); 271 1.12 manu fprintf(fp, "Nodes: %d\n", ps->ps_nodecount); 272 1.12 manu fprintf(fp, "Exchanges: %d\n", ps->ps_xchgcount); 273 1.6 manu 274 1.6 manu (void)fflush(fp); 275 1.6 manu return; 276 1.6 manu } 277