DF-5531 / tap_cost.c
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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | /* * DF-5531 — measurement rig: usbpf_xfertap() builds and copies the full * USB transfer record even when NO bpf listener exists. * * DragonFly disabled FreeBSD's early-out: * sys/bus/u4b/usb_pf.c:364-367 * #if 0 // XXX this is not needed on dragonfly * if (!bpf_peers_present(bus->ifp->if_bpf)) return; * #endif * * and DragonFly's bpf only sets ifp->if_bpf non-NULL while a /dev/bpfN * listener is actually attached to the interface (net/bpf.c:297 sets * *driverp = bp in bpf_attachd; bpf.c:324 NULLs it again in * bpf_detachd). bpf_tap() itself NULL-checks and returns immediately * (net/bpf.c:1245-1248) — so with a created-but-unwatched usbus clone, * EVERY USB transfer on that bus still pays: * precompute + kmalloc(totlen) + full payload copy + kfree * under the USB BUS lock on the SUBMIT paths (usb_transfer.c:2630/2813). * * This module calls the production usbpf_xfertap() (global symbol, * usb_pf.c:345) with a synthetic 8x512-byte BULK-OUT xfer against the * real usbus0 bus, and times: * (A) bus->ifp set (clone created, NO listener) -> full work, bpf no-op * (B) bus->ifp NULLed (control) -> early return :362 * * A >> B proves the copy machinery runs with no consumer. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/bus.h> #include <sys/malloc.h> #include <sys/proc.h> #include <sys/socket.h> #include <sys/sockio.h> #include <sys/sysctl.h> #include <sys/condvar.h> #include <machine/cpufunc.h> #include <net/if.h> #include <net/if_var.h> #include <net/if_clone.h> #include <net/if_types.h> #include <net/bpf.h> /* mirror usb_pf.c include order (usb_bus.h depends on these) */ #include <bus/u4b/usb.h> #include <bus/u4b/usbdi.h> #include <bus/u4b/usb_busdma.h> #include <bus/u4b/usb_controller.h> #include <bus/u4b/usb_core.h> #include <bus/u4b/usb_process.h> #include <bus/u4b/usb_device.h> #include <bus/u4b/usb_bus.h> #include <bus/u4b/usb_pf.h> #include <bus/u4b/usb_transfer.h> #define NFRAMES 8 #define FRLEN 512 #define ITERS 20000 static int df5531_run(void) { struct usb_bus *ubus; devclass_t dc; device_t dev; struct ifnet *saved_ifp; struct usb_xfer *xfer; struct usb_xfer_root *xroot; struct usb_device *udev; struct usb_endpoint *ep; struct usb_endpoint_descriptor *edesc; struct usb_page_cache *frb; usb_frlength_t *frl; uint8_t *payload; uint64_t t0, t1, tA, tB; int i, error = 0; dc = devclass_find("usbus"); if (dc == NULL || (dev = devclass_get_device(dc, 0)) == NULL || (ubus = device_get_softc(dev)) == NULL) { kprintf("DF5531: no usbus0\n"); return (ENOENT); } if (ubus->ifp == NULL) { kprintf("DF5531: usbus0 clone not created " "(run: ifconfig usbus0 create)\n"); return (ENOENT); } kprintf("DF5531: bus ifp=%p if_bpf=%p (expect NULL: no listener)\n", ubus->ifp, ubus->ifp->if_bpf); /* ---- fabricate a minimal 8x512 BULK-OUT host xfer ---- */ payload = kmalloc(NFRAMES * FRLEN, M_TEMP, M_WAITOK | M_ZERO); memset(payload, 0xA5, NFRAMES * FRLEN); frb = kmalloc(sizeof(*frb) * NFRAMES, M_TEMP, M_WAITOK | M_ZERO); for (i = 0; i < NFRAMES; i++) frb[i].buffer = payload + i * FRLEN; /* PIO, page_start NULL */ frl = kmalloc(sizeof(*frl) * NFRAMES, M_TEMP, M_WAITOK | M_ZERO); for (i = 0; i < NFRAMES; i++) frl[i] = FRLEN; edesc = kmalloc(sizeof(*edesc), M_TEMP, M_WAITOK | M_ZERO); edesc->bmAttributes = UE_BULK; /* xfer type for header */ ep = kmalloc(sizeof(*ep), M_TEMP, M_WAITOK | M_ZERO); ep->edesc = edesc; udev = kmalloc(sizeof(*udev), M_TEMP, M_WAITOK | M_ZERO); udev->device_index = 1; udev->speed = USB_SPEED_FULL; xroot = kmalloc(sizeof(*xroot), M_TEMP, M_WAITOK | M_ZERO); xroot->bus = ubus; /* REAL bus: bdev,parent */ xroot->udev = udev; xfer = kmalloc(sizeof(*xfer), M_TEMP, M_WAITOK | M_ZERO); xfer->xroot = xroot; xfer->endpoint = ep; xfer->frlengths = frl; xfer->frbuffers = frb; xfer->nframes = NFRAMES; xfer->aframes = NFRAMES; xfer->max_frame_count = NFRAMES; xfer->max_data_length = NFRAMES * FRLEN; xfer->endpointno = 0; /* host -> device (OUT) */ /* flags_int zeroed: usb_mode = USB_MODE_HOST, not control/isoc */ /* ---- (A) clone exists, no listener: tap does ALL the work ---- */ tA = 0; for (i = 0; i < ITERS; i++) { t0 = rdtsc(); usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT); t1 = rdtsc(); tA += t1 - t0; } /* ---- (B) control: bus->ifp == NULL -> early return at :362 ---- */ saved_ifp = ubus->ifp; ubus->ifp = NULL; tB = 0; for (i = 0; i < ITERS; i++) { t0 = rdtsc(); usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT); t1 = rdtsc(); tB += t1 - t0; } ubus->ifp = saved_ifp; kprintf("DF5531: payload=%d bytes, %d iters\n", NFRAMES * FRLEN, ITERS); kprintf("DF5531: (A) ifp set, if_bpf==NULL : %ju cycles/call\n", (uintmax_t)(tA / ITERS)); kprintf("DF5531: (B) ifp NULL (early-return) : %ju cycles/call\n", (uintmax_t)(tB / ITERS)); kprintf("DF5531: overhead ratio A/B : %ju.%ju x\n", (uintmax_t)(tB ? tA / tB : 0), (uintmax_t)(tB ? ((uint64_t)((unsigned long long)tA * 10ULL / (unsigned long long)tB)) % 10ULL : 0)); kprintf("TAP_RESULT=done\n"); kfree(xfer, M_TEMP); kfree(xroot, M_TEMP); kfree(udev, M_TEMP); kfree(ep, M_TEMP); kfree(edesc, M_TEMP); kfree(frl, M_TEMP); kfree(frb, M_TEMP); kfree(payload, M_TEMP); return (error); } static int df5531_load(struct module *m, int what, void *arg) { switch (what) { case MOD_LOAD: df5531_run(); break; default: break; } return (0); } static moduledata_t df5531_tapcost_mod = { "df5531_tapcost", df5531_load, NULL }; DECLARE_MODULE(df5531_tapcost, df5531_tapcost_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(df5531_tapcost, 1); |