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