1 1.5 christos /* $NetBSD: in_cksum.c,v 1.5 2015/10/18 18:27:25 christos Exp $ */ 2 1.1 christos /*- 3 1.1 christos * Copyright (c) 2008 Joerg Sonnenberger <joerg (at) NetBSD.org>. 4 1.1 christos * All rights reserved. 5 1.1 christos * 6 1.1 christos * Redistribution and use in source and binary forms, with or without 7 1.1 christos * modification, are permitted provided that the following conditions 8 1.1 christos * are met: 9 1.1 christos * 10 1.1 christos * 1. Redistributions of source code must retain the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer. 12 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 christos * notice, this list of conditions and the following disclaimer in 14 1.1 christos * the documentation and/or other materials provided with the 15 1.1 christos * distribution. 16 1.1 christos * 17 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 christos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 1.1 christos * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 1.1 christos * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 1.1 christos * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 1.1 christos * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 1.1 christos * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 1.1 christos * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 1.1 christos * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 1.1 christos * SUCH DAMAGE. 29 1.1 christos */ 30 1.1 christos 31 1.1 christos #include <sys/cdefs.h> 32 1.5 christos __KERNEL_RCSID(0, "$NetBSD: in_cksum.c,v 1.5 2015/10/18 18:27:25 christos Exp $"); 33 1.1 christos 34 1.1 christos #include <sys/param.h> 35 1.1 christos #include <sys/mbuf.h> 36 1.1 christos #include <sys/resource.h> 37 1.1 christos #include <err.h> 38 1.1 christos #include <stdbool.h> 39 1.1 christos #include <stdio.h> 40 1.2 christos #include <stdarg.h> 41 1.1 christos #include <unistd.h> 42 1.1 christos #include <stdlib.h> 43 1.1 christos #include <string.h> 44 1.1 christos 45 1.1 christos #define cpu_in_cksum portable_cpu_in_cksum 46 1.1 christos #include "cpu_in_cksum.c" 47 1.1 christos 48 1.1 christos #ifdef HAVE_CPU_IN_CKSUM 49 1.2 christos #undef cpu_in_cksum 50 1.1 christos int cpu_in_cksum(struct mbuf*, int, int, uint32_t); 51 1.1 christos #endif 52 1.1 christos 53 1.1 christos static bool random_aligned; 54 1.1 christos 55 1.3 joerg void panic(const char *, ...) __printflike(1, 2); 56 1.2 christos void 57 1.2 christos panic(const char *fmt, ...) 58 1.2 christos { 59 1.2 christos va_list ap; 60 1.2 christos va_start(ap, fmt); 61 1.2 christos verrx(1, fmt, ap); 62 1.2 christos va_end(ap); 63 1.2 christos } 64 1.2 christos 65 1.1 christos static void 66 1.1 christos free_mbuf_chain(struct mbuf *m) 67 1.1 christos { 68 1.1 christos struct mbuf *next; 69 1.1 christos 70 1.1 christos if (m == NULL) 71 1.1 christos return; 72 1.1 christos 73 1.1 christos next = m->m_next; 74 1.1 christos free(m); 75 1.1 christos free_mbuf_chain(next); 76 1.1 christos } 77 1.1 christos 78 1.1 christos static struct mbuf * 79 1.1 christos allocate_mbuf_chain(char **lens) 80 1.1 christos { 81 1.1 christos int len, off; 82 1.1 christos struct mbuf *m; 83 1.1 christos 84 1.1 christos if (*lens == NULL) 85 1.1 christos return NULL; 86 1.1 christos 87 1.1 christos len = atoi(*lens); 88 1.1 christos off = random_aligned ? rand() % 64 : 0; 89 1.1 christos 90 1.1 christos m = malloc(sizeof(struct m_hdr) + len + off); 91 1.1 christos if (m == NULL) 92 1.1 christos err(EXIT_FAILURE, "malloc failed"); 93 1.1 christos 94 1.1 christos m->m_data = (char *)m + sizeof(struct m_hdr) + off; 95 1.1 christos m->m_len = len; 96 1.1 christos 97 1.1 christos m->m_next = allocate_mbuf_chain(lens + 1); 98 1.1 christos 99 1.1 christos return m; 100 1.1 christos } 101 1.1 christos 102 1.4 christos #ifdef MBUFDUMP 103 1.4 christos static void 104 1.4 christos dump_mbuf(const struct mbuf *m, int len, int off) 105 1.4 christos { 106 1.4 christos int x = 0; 107 1.4 christos if (len <= 0) 108 1.4 christos return; 109 1.4 christos 110 1.4 christos printf("Starting len=%d off=%d:\n", len, off); 111 1.4 christos if (off > 0) { 112 1.4 christos for (; m; m = m->m_next) 113 1.4 christos if (off > m->m_len) 114 1.4 christos off -= m->m_len; 115 1.4 christos else 116 1.4 christos break; 117 1.4 christos if (m == NULL || off > m->m_len) 118 1.4 christos errx(1, "out of data"); 119 1.4 christos } 120 1.4 christos 121 1.4 christos unsigned char *ptr = mtod(m, unsigned char *) + off; 122 1.4 christos unsigned char *eptr = ptr + m->m_len; 123 1.4 christos printf("["); 124 1.4 christos for (;;) { 125 1.4 christos if (ptr == eptr) { 126 1.4 christos m = m->m_next; 127 1.4 christos if (m == NULL) 128 1.4 christos errx(1, "out of data"); 129 1.4 christos ptr = mtod(m, unsigned char *); 130 1.4 christos eptr = ptr + m->m_len; 131 1.4 christos printf("]\n["); 132 1.4 christos x = 0; 133 1.4 christos } 134 1.4 christos printf("%.2x ", *ptr++); 135 1.4 christos if (++x % 16 == 0) 136 1.4 christos printf("\n"); 137 1.4 christos if (--len == 0) 138 1.4 christos break; 139 1.4 christos } 140 1.4 christos printf("]\n"); 141 1.4 christos fflush(stdout); 142 1.4 christos } 143 1.4 christos #endif 144 1.4 christos 145 1.1 christos static void 146 1.1 christos randomise_mbuf_chain(struct mbuf *m) 147 1.1 christos { 148 1.1 christos int i, data, len; 149 1.1 christos 150 1.1 christos for (i = 0; i < m->m_len; i += sizeof(int)) { 151 1.1 christos data = rand(); 152 1.1 christos if (i + sizeof(int) < (size_t)m->m_len) 153 1.1 christos len = sizeof(int); 154 1.1 christos else 155 1.1 christos len = m->m_len - i; 156 1.1 christos memcpy(m->m_data + i, &data, len); 157 1.1 christos } 158 1.1 christos if (m->m_next) 159 1.1 christos randomise_mbuf_chain(m->m_next); 160 1.1 christos } 161 1.1 christos 162 1.1 christos static int 163 1.1 christos mbuf_len(struct mbuf *m) 164 1.1 christos { 165 1.1 christos return m == NULL ? 0 : m->m_len + mbuf_len(m->m_next); 166 1.1 christos } 167 1.1 christos 168 1.1 christos int in_cksum_portable(struct mbuf *, int); 169 1.1 christos int in_cksum(struct mbuf *, int); 170 1.1 christos 171 1.1 christos int 172 1.1 christos main(int argc, char **argv) 173 1.1 christos { 174 1.1 christos struct rusage res; 175 1.1 christos struct timeval tv, old_tv; 176 1.1 christos int loops, old_sum, off, len; 177 1.1 christos #ifdef HAVE_CPU_IN_CKSUM 178 1.1 christos int new_sum; 179 1.1 christos #endif 180 1.1 christos long i, iterations; 181 1.1 christos uint32_t init_sum; 182 1.1 christos struct mbuf *m; 183 1.1 christos bool verbose; 184 1.1 christos int c; 185 1.1 christos 186 1.1 christos loops = 16; 187 1.1 christos verbose = false; 188 1.1 christos random_aligned = 0; 189 1.1 christos iterations = 100000; 190 1.1 christos 191 1.1 christos while ((c = getopt(argc, argv, "i:l:u:v")) != -1) { 192 1.1 christos switch (c) { 193 1.1 christos case 'i': 194 1.1 christos iterations = atoi(optarg); 195 1.1 christos break; 196 1.1 christos case 'l': 197 1.1 christos loops = atoi(optarg); 198 1.1 christos break; 199 1.1 christos case 'u': 200 1.1 christos random_aligned = atoi(optarg); 201 1.1 christos break; 202 1.1 christos case 'v': 203 1.1 christos verbose = true; 204 1.1 christos break; 205 1.1 christos default: 206 1.1 christos errx(1, "%s [-l <loops>] [-u <unalign> [-i <iterations> " 207 1.1 christos "[<mbuf-size> ...]", getprogname()); 208 1.1 christos } 209 1.1 christos } 210 1.1 christos 211 1.1 christos for (; loops; --loops) { 212 1.1 christos if ((m = allocate_mbuf_chain(argv + 4)) == NULL) 213 1.1 christos continue; 214 1.1 christos randomise_mbuf_chain(m); 215 1.1 christos init_sum = rand(); 216 1.1 christos len = mbuf_len(m); 217 1.1 christos 218 1.1 christos /* force one loop over all data */ 219 1.1 christos if (loops == 1) 220 1.1 christos off = 0; 221 1.1 christos else 222 1.1 christos off = len ? rand() % len : 0; 223 1.1 christos 224 1.1 christos len -= off; 225 1.1 christos old_sum = portable_cpu_in_cksum(m, len, off, init_sum); 226 1.1 christos #ifdef HAVE_CPU_IN_CKSUM 227 1.4 christos #ifdef MBUFDUMP 228 1.4 christos printf("m->m_len=%d len=%d off=%d\n", m->m_len, len, off); 229 1.4 christos dump_mbuf(m, len, off); 230 1.4 christos #endif 231 1.1 christos new_sum = cpu_in_cksum(m, len, off, init_sum); 232 1.1 christos if (old_sum != new_sum) 233 1.1 christos errx(1, "comparison failed: %x %x", old_sum, new_sum); 234 1.1 christos #else 235 1.1 christos __USE(old_sum); 236 1.1 christos #endif 237 1.1 christos 238 1.1 christos if (iterations == 0) 239 1.1 christos continue; 240 1.1 christos 241 1.1 christos getrusage(RUSAGE_SELF, &res); 242 1.1 christos tv = res.ru_utime; 243 1.1 christos for (i = iterations; i; --i) 244 1.1 christos (void)portable_cpu_in_cksum(m, len, off, init_sum); 245 1.1 christos getrusage(RUSAGE_SELF, &res); 246 1.1 christos timersub(&res.ru_utime, &tv, &old_tv); 247 1.1 christos if (verbose) 248 1.1 christos printf("portable version: %jd.%06jd\n", 249 1.1 christos (intmax_t)old_tv.tv_sec, (intmax_t)old_tv.tv_usec); 250 1.1 christos 251 1.1 christos #ifdef HAVE_CPU_IN_CKSUM 252 1.1 christos getrusage(RUSAGE_SELF, &res); 253 1.1 christos tv = res.ru_utime; 254 1.1 christos for (i = iterations; i; --i) 255 1.1 christos (void)cpu_in_cksum(m, len, off, init_sum); 256 1.1 christos getrusage(RUSAGE_SELF, &res); 257 1.1 christos timersub(&res.ru_utime, &tv, &tv); 258 1.1 christos if (verbose) { 259 1.1 christos printf("test version: %jd.%06jd\n", 260 1.1 christos (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec); 261 1.1 christos printf("relative time: %3.g%%\n", 262 1.1 christos 100 * ((double)tv.tv_sec * 1e6 + tv.tv_usec) / 263 1.1 christos ((double)old_tv.tv_sec * 1e6 + old_tv.tv_usec + 1)); 264 1.1 christos } 265 1.1 christos #endif 266 1.1 christos free_mbuf_chain(m); 267 1.1 christos } 268 1.1 christos 269 1.1 christos return 0; 270 1.1 christos } 271