1 /* $NetBSD: in_cksum.c,v 1.3 2015/01/06 21:36:38 joerg 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.3 2015/01/06 21:36:38 joerg 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 static void 103 randomise_mbuf_chain(struct mbuf *m) 104 { 105 int i, data, len; 106 107 for (i = 0; i < m->m_len; i += sizeof(int)) { 108 data = rand(); 109 if (i + sizeof(int) < (size_t)m->m_len) 110 len = sizeof(int); 111 else 112 len = m->m_len - i; 113 memcpy(m->m_data + i, &data, len); 114 } 115 if (m->m_next) 116 randomise_mbuf_chain(m->m_next); 117 } 118 119 static int 120 mbuf_len(struct mbuf *m) 121 { 122 return m == NULL ? 0 : m->m_len + mbuf_len(m->m_next); 123 } 124 125 int in_cksum_portable(struct mbuf *, int); 126 int in_cksum(struct mbuf *, int); 127 128 int 129 main(int argc, char **argv) 130 { 131 struct rusage res; 132 struct timeval tv, old_tv; 133 int loops, old_sum, off, len; 134 #ifdef HAVE_CPU_IN_CKSUM 135 int new_sum; 136 #endif 137 long i, iterations; 138 uint32_t init_sum; 139 struct mbuf *m; 140 bool verbose; 141 int c; 142 143 loops = 16; 144 verbose = false; 145 random_aligned = 0; 146 iterations = 100000; 147 148 while ((c = getopt(argc, argv, "i:l:u:v")) != -1) { 149 switch (c) { 150 case 'i': 151 iterations = atoi(optarg); 152 break; 153 case 'l': 154 loops = atoi(optarg); 155 break; 156 case 'u': 157 random_aligned = atoi(optarg); 158 break; 159 case 'v': 160 verbose = true; 161 break; 162 default: 163 errx(1, "%s [-l <loops>] [-u <unalign> [-i <iterations> " 164 "[<mbuf-size> ...]", getprogname()); 165 } 166 } 167 168 for (; loops; --loops) { 169 if ((m = allocate_mbuf_chain(argv + 4)) == NULL) 170 continue; 171 randomise_mbuf_chain(m); 172 init_sum = rand(); 173 len = mbuf_len(m); 174 175 /* force one loop over all data */ 176 if (loops == 1) 177 off = 0; 178 else 179 off = len ? rand() % len : 0; 180 181 len -= off; 182 old_sum = portable_cpu_in_cksum(m, len, off, init_sum); 183 #ifdef HAVE_CPU_IN_CKSUM 184 new_sum = cpu_in_cksum(m, len, off, init_sum); 185 if (old_sum != new_sum) 186 errx(1, "comparison failed: %x %x", old_sum, new_sum); 187 #else 188 __USE(old_sum); 189 #endif 190 191 if (iterations == 0) 192 continue; 193 194 getrusage(RUSAGE_SELF, &res); 195 tv = res.ru_utime; 196 for (i = iterations; i; --i) 197 (void)portable_cpu_in_cksum(m, len, off, init_sum); 198 getrusage(RUSAGE_SELF, &res); 199 timersub(&res.ru_utime, &tv, &old_tv); 200 if (verbose) 201 printf("portable version: %jd.%06jd\n", 202 (intmax_t)old_tv.tv_sec, (intmax_t)old_tv.tv_usec); 203 204 #ifdef HAVE_CPU_IN_CKSUM 205 getrusage(RUSAGE_SELF, &res); 206 tv = res.ru_utime; 207 for (i = iterations; i; --i) 208 (void)cpu_in_cksum(m, len, off, init_sum); 209 getrusage(RUSAGE_SELF, &res); 210 timersub(&res.ru_utime, &tv, &tv); 211 if (verbose) { 212 printf("test version: %jd.%06jd\n", 213 (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec); 214 printf("relative time: %3.g%%\n", 215 100 * ((double)tv.tv_sec * 1e6 + tv.tv_usec) / 216 ((double)old_tv.tv_sec * 1e6 + old_tv.tv_usec + 1)); 217 } 218 #endif 219 free_mbuf_chain(m); 220 } 221 222 return 0; 223 } 224