1bbbf1280Sopenharmony_ci/*
2bbbf1280Sopenharmony_ci * Ones' complement checksum test & benchmark
3bbbf1280Sopenharmony_ci *
4bbbf1280Sopenharmony_ci * Copyright (c) 2016-2020, Arm Limited.
5bbbf1280Sopenharmony_ci * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6bbbf1280Sopenharmony_ci */
7bbbf1280Sopenharmony_ci
8bbbf1280Sopenharmony_ci#define _GNU_SOURCE
9bbbf1280Sopenharmony_ci#include <inttypes.h>
10bbbf1280Sopenharmony_ci#include <stdbool.h>
11bbbf1280Sopenharmony_ci#include <stdint.h>
12bbbf1280Sopenharmony_ci#include <stdio.h>
13bbbf1280Sopenharmony_ci#include <stdlib.h>
14bbbf1280Sopenharmony_ci#include <string.h>
15bbbf1280Sopenharmony_ci#include <sys/mman.h>
16bbbf1280Sopenharmony_ci#include <time.h>
17bbbf1280Sopenharmony_ci#include <unistd.h>
18bbbf1280Sopenharmony_ci#include "../include/networking.h"
19bbbf1280Sopenharmony_ci
20bbbf1280Sopenharmony_ci#if WANT_ASSERT
21bbbf1280Sopenharmony_ci#undef NDEBUG
22bbbf1280Sopenharmony_ci#include <assert.h>
23bbbf1280Sopenharmony_ci#define Assert(exp) assert(exp)
24bbbf1280Sopenharmony_ci#else
25bbbf1280Sopenharmony_ci#define Assert(exp) (void) (exp)
26bbbf1280Sopenharmony_ci#endif
27bbbf1280Sopenharmony_ci
28bbbf1280Sopenharmony_ci#ifdef __GNUC__
29bbbf1280Sopenharmony_ci#define may_alias __attribute__((__may_alias__))
30bbbf1280Sopenharmony_ci#else
31bbbf1280Sopenharmony_ci#define may_alias
32bbbf1280Sopenharmony_ci#endif
33bbbf1280Sopenharmony_ci
34bbbf1280Sopenharmony_ci#define CACHE_LINE 64
35bbbf1280Sopenharmony_ci#define ALIGN(x, y) (((x) + (y) - 1) & ~((y) - 1))
36bbbf1280Sopenharmony_ci
37bbbf1280Sopenharmony_ci/* Reference implementation - do not modify! */
38bbbf1280Sopenharmony_cistatic uint16_t
39bbbf1280Sopenharmony_cichecksum_simple(const void *ptr, uint32_t nbytes)
40bbbf1280Sopenharmony_ci{
41bbbf1280Sopenharmony_ci    const uint16_t *may_alias hptr = ptr;
42bbbf1280Sopenharmony_ci    uint64_t sum = 0;/* Need 64-bit accumulator when nbytes > 64K */
43bbbf1280Sopenharmony_ci
44bbbf1280Sopenharmony_ci    /* Sum all halfwords, assume misaligned accesses are handled in HW */
45bbbf1280Sopenharmony_ci    for (uint32_t nhalfs = nbytes >> 1; nhalfs != 0; nhalfs--)
46bbbf1280Sopenharmony_ci    {
47bbbf1280Sopenharmony_ci	sum += *hptr++;
48bbbf1280Sopenharmony_ci    }
49bbbf1280Sopenharmony_ci
50bbbf1280Sopenharmony_ci    /* Add any trailing odd byte */
51bbbf1280Sopenharmony_ci    if ((nbytes & 0x01) != 0)
52bbbf1280Sopenharmony_ci    {
53bbbf1280Sopenharmony_ci	sum += *(uint8_t *) hptr;
54bbbf1280Sopenharmony_ci    }
55bbbf1280Sopenharmony_ci
56bbbf1280Sopenharmony_ci    /* Fold 64-bit sum to 32 bits */
57bbbf1280Sopenharmony_ci    sum = (sum & 0xffffffff) + (sum >> 32);
58bbbf1280Sopenharmony_ci    sum = (sum & 0xffffffff) + (sum >> 32);
59bbbf1280Sopenharmony_ci    Assert(sum == (uint32_t) sum);
60bbbf1280Sopenharmony_ci
61bbbf1280Sopenharmony_ci    /* Fold 32-bit sum to 16 bits */
62bbbf1280Sopenharmony_ci    sum = (sum & 0xffff) + (sum >> 16);
63bbbf1280Sopenharmony_ci    sum = (sum & 0xffff) + (sum >> 16);
64bbbf1280Sopenharmony_ci    Assert(sum == (uint16_t) sum);
65bbbf1280Sopenharmony_ci
66bbbf1280Sopenharmony_ci    return (uint16_t) sum;
67bbbf1280Sopenharmony_ci}
68bbbf1280Sopenharmony_ci
69bbbf1280Sopenharmony_cistatic struct
70bbbf1280Sopenharmony_ci{
71bbbf1280Sopenharmony_ci    uint16_t (*cksum_fp)(const void *, uint32_t);
72bbbf1280Sopenharmony_ci    const char *name;
73bbbf1280Sopenharmony_ci} implementations[] =
74bbbf1280Sopenharmony_ci{
75bbbf1280Sopenharmony_ci    { checksum_simple, "simple"},
76bbbf1280Sopenharmony_ci    { __chksum, "scalar"},
77bbbf1280Sopenharmony_ci#if __arm__
78bbbf1280Sopenharmony_ci    { __chksum_arm_simd, "simd" },
79bbbf1280Sopenharmony_ci#elif __aarch64__
80bbbf1280Sopenharmony_ci    { __chksum_aarch64_simd, "simd" },
81bbbf1280Sopenharmony_ci#endif
82bbbf1280Sopenharmony_ci    { NULL, NULL}
83bbbf1280Sopenharmony_ci};
84bbbf1280Sopenharmony_ci
85bbbf1280Sopenharmony_cistatic int
86bbbf1280Sopenharmony_cifind_impl(const char *name)
87bbbf1280Sopenharmony_ci{
88bbbf1280Sopenharmony_ci    for (int i = 0; implementations[i].name != NULL; i++)
89bbbf1280Sopenharmony_ci    {
90bbbf1280Sopenharmony_ci	if (strcmp(implementations[i].name, name) == 0)
91bbbf1280Sopenharmony_ci	{
92bbbf1280Sopenharmony_ci	    return i;
93bbbf1280Sopenharmony_ci	}
94bbbf1280Sopenharmony_ci    }
95bbbf1280Sopenharmony_ci    return -1;
96bbbf1280Sopenharmony_ci}
97bbbf1280Sopenharmony_ci
98bbbf1280Sopenharmony_cistatic uint16_t (*CKSUM_FP)(const void *, uint32_t);
99bbbf1280Sopenharmony_cistatic volatile uint16_t SINK;
100bbbf1280Sopenharmony_ci
101bbbf1280Sopenharmony_cistatic bool
102bbbf1280Sopenharmony_civerify(const void *data, uint32_t offset, uint32_t size)
103bbbf1280Sopenharmony_ci{
104bbbf1280Sopenharmony_ci
105bbbf1280Sopenharmony_ci    uint16_t csum_expected = checksum_simple(data, size);
106bbbf1280Sopenharmony_ci    uint16_t csum_actual = CKSUM_FP(data, size);
107bbbf1280Sopenharmony_ci    if (csum_actual != csum_expected)
108bbbf1280Sopenharmony_ci    {
109bbbf1280Sopenharmony_ci	fprintf(stderr, "\nInvalid checksum for offset %u size %u: "
110bbbf1280Sopenharmony_ci		"actual %04x expected %04x (valid)",
111bbbf1280Sopenharmony_ci		offset, size, csum_actual, csum_expected);
112bbbf1280Sopenharmony_ci	if (size < 65536)
113bbbf1280Sopenharmony_ci	{
114bbbf1280Sopenharmony_ci	    /* Fatal error */
115bbbf1280Sopenharmony_ci	    exit(EXIT_FAILURE);
116bbbf1280Sopenharmony_ci	}
117bbbf1280Sopenharmony_ci	/* Else some implementations only support sizes up to 2^16 */
118bbbf1280Sopenharmony_ci	return false;
119bbbf1280Sopenharmony_ci    }
120bbbf1280Sopenharmony_ci    return true;
121bbbf1280Sopenharmony_ci}
122bbbf1280Sopenharmony_ci
123bbbf1280Sopenharmony_cistatic uint64_t
124bbbf1280Sopenharmony_ciclock_get_ns(void)
125bbbf1280Sopenharmony_ci{
126bbbf1280Sopenharmony_ci    struct timespec ts;
127bbbf1280Sopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &ts);
128bbbf1280Sopenharmony_ci    return ts.tv_sec * (uint64_t) 1000000000 + ts.tv_nsec;
129bbbf1280Sopenharmony_ci}
130bbbf1280Sopenharmony_ci
131bbbf1280Sopenharmony_cistatic void
132bbbf1280Sopenharmony_cibenchmark(const uint8_t *base,
133bbbf1280Sopenharmony_ci	  size_t poolsize,
134bbbf1280Sopenharmony_ci	  uint32_t blksize,
135bbbf1280Sopenharmony_ci	  uint32_t numops,
136bbbf1280Sopenharmony_ci	  uint64_t cpufreq)
137bbbf1280Sopenharmony_ci{
138bbbf1280Sopenharmony_ci    printf("%11u ", (unsigned int) blksize); fflush(stdout);
139bbbf1280Sopenharmony_ci
140bbbf1280Sopenharmony_ci    uint64_t start = clock_get_ns();
141bbbf1280Sopenharmony_ci    for (uint32_t i = 0; i < numops; i ++)
142bbbf1280Sopenharmony_ci    {
143bbbf1280Sopenharmony_ci	/* Read a random value from the pool */
144bbbf1280Sopenharmony_ci	uint32_t random = ((uint32_t *) base)[i % (poolsize / 4)];
145bbbf1280Sopenharmony_ci	/* Generate a random starting address */
146bbbf1280Sopenharmony_ci	const void *data = &base[random % (poolsize - blksize)];
147bbbf1280Sopenharmony_ci	SINK = CKSUM_FP(data, blksize);
148bbbf1280Sopenharmony_ci    }
149bbbf1280Sopenharmony_ci    uint64_t end = clock_get_ns();
150bbbf1280Sopenharmony_ci
151bbbf1280Sopenharmony_ci#define MEGABYTE 1000000 /* Decimal megabyte (MB) */
152bbbf1280Sopenharmony_ci    uint64_t elapsed_ns = end - start;
153bbbf1280Sopenharmony_ci    uint64_t elapsed_ms = elapsed_ns / 1000000;
154bbbf1280Sopenharmony_ci    uint32_t blks_per_s = (uint32_t) ((numops / elapsed_ms) * 1000);
155bbbf1280Sopenharmony_ci    uint64_t accbytes = (uint64_t) numops * blksize;
156bbbf1280Sopenharmony_ci    printf("%11ju ", (uintmax_t) ((accbytes / elapsed_ms) * 1000) / MEGABYTE);
157bbbf1280Sopenharmony_ci    unsigned int cyc_per_blk = cpufreq / blks_per_s;
158bbbf1280Sopenharmony_ci    printf("%11u ", cyc_per_blk);
159bbbf1280Sopenharmony_ci    if (blksize != 0)
160bbbf1280Sopenharmony_ci    {
161bbbf1280Sopenharmony_ci	unsigned int cyc_per_byte = 1000 * cyc_per_blk / blksize;
162bbbf1280Sopenharmony_ci	printf("%7u.%03u ",
163bbbf1280Sopenharmony_ci		cyc_per_byte / 1000, cyc_per_byte % 1000);
164bbbf1280Sopenharmony_ci    }
165bbbf1280Sopenharmony_ci    printf("\n");
166bbbf1280Sopenharmony_ci}
167bbbf1280Sopenharmony_ci
168bbbf1280Sopenharmony_ciint main(int argc, char *argv[])
169bbbf1280Sopenharmony_ci{
170bbbf1280Sopenharmony_ci    int c;
171bbbf1280Sopenharmony_ci    bool DUMP = false;
172bbbf1280Sopenharmony_ci    uint32_t IMPL = 0;/* Simple implementation */
173bbbf1280Sopenharmony_ci    uint64_t CPUFREQ = 0;
174bbbf1280Sopenharmony_ci    uint32_t BLKSIZE = 0;
175bbbf1280Sopenharmony_ci    uint32_t NUMOPS = 1000000;
176bbbf1280Sopenharmony_ci    uint32_t POOLSIZE = 512 * 1024;/* Typical ARM L2 cache size */
177bbbf1280Sopenharmony_ci
178bbbf1280Sopenharmony_ci    setvbuf(stdout, NULL, _IOLBF, 160);
179bbbf1280Sopenharmony_ci    while ((c = getopt(argc, argv, "b:df:i:n:p:")) != -1)
180bbbf1280Sopenharmony_ci    {
181bbbf1280Sopenharmony_ci	switch (c)
182bbbf1280Sopenharmony_ci	{
183bbbf1280Sopenharmony_ci	    case 'b' :
184bbbf1280Sopenharmony_ci		{
185bbbf1280Sopenharmony_ci		    int blksize = atoi(optarg);
186bbbf1280Sopenharmony_ci		    if (blksize < 1 || blksize > POOLSIZE / 2)
187bbbf1280Sopenharmony_ci		    {
188bbbf1280Sopenharmony_ci			fprintf(stderr, "Invalid block size %d\n", blksize);
189bbbf1280Sopenharmony_ci			exit(EXIT_FAILURE);
190bbbf1280Sopenharmony_ci		    }
191bbbf1280Sopenharmony_ci		    BLKSIZE = (unsigned) blksize;
192bbbf1280Sopenharmony_ci		    break;
193bbbf1280Sopenharmony_ci		}
194bbbf1280Sopenharmony_ci	    case 'd' :
195bbbf1280Sopenharmony_ci		DUMP = true;
196bbbf1280Sopenharmony_ci		break;
197bbbf1280Sopenharmony_ci	    case 'f' :
198bbbf1280Sopenharmony_ci		{
199bbbf1280Sopenharmony_ci		    int64_t cpufreq = atoll(optarg);
200bbbf1280Sopenharmony_ci		    if (cpufreq < 1)
201bbbf1280Sopenharmony_ci		    {
202bbbf1280Sopenharmony_ci			fprintf(stderr, "Invalid CPU frequency %"PRId64"\n",
203bbbf1280Sopenharmony_ci				cpufreq);
204bbbf1280Sopenharmony_ci			exit(EXIT_FAILURE);
205bbbf1280Sopenharmony_ci		    }
206bbbf1280Sopenharmony_ci		    CPUFREQ = cpufreq;
207bbbf1280Sopenharmony_ci		    break;
208bbbf1280Sopenharmony_ci		}
209bbbf1280Sopenharmony_ci	    case 'i' :
210bbbf1280Sopenharmony_ci		{
211bbbf1280Sopenharmony_ci		    int impl = find_impl(optarg);
212bbbf1280Sopenharmony_ci		    if (impl < 0)
213bbbf1280Sopenharmony_ci		    {
214bbbf1280Sopenharmony_ci			fprintf(stderr, "Invalid implementation %s\n", optarg);
215bbbf1280Sopenharmony_ci			goto usage;
216bbbf1280Sopenharmony_ci		    }
217bbbf1280Sopenharmony_ci		    IMPL = (unsigned) impl;
218bbbf1280Sopenharmony_ci		    break;
219bbbf1280Sopenharmony_ci		}
220bbbf1280Sopenharmony_ci	    case 'n' :
221bbbf1280Sopenharmony_ci		{
222bbbf1280Sopenharmony_ci		    int numops = atoi(optarg);
223bbbf1280Sopenharmony_ci		    if (numops < 1)
224bbbf1280Sopenharmony_ci		    {
225bbbf1280Sopenharmony_ci			fprintf(stderr, "Invalid number of operations %d\n", numops);
226bbbf1280Sopenharmony_ci			exit(EXIT_FAILURE);
227bbbf1280Sopenharmony_ci		    }
228bbbf1280Sopenharmony_ci		    NUMOPS = (unsigned) numops;
229bbbf1280Sopenharmony_ci		    break;
230bbbf1280Sopenharmony_ci		}
231bbbf1280Sopenharmony_ci	    case 'p' :
232bbbf1280Sopenharmony_ci		{
233bbbf1280Sopenharmony_ci		    int poolsize = atoi(optarg);
234bbbf1280Sopenharmony_ci		    if (poolsize < 4096)
235bbbf1280Sopenharmony_ci		    {
236bbbf1280Sopenharmony_ci			fprintf(stderr, "Invalid pool size %d\n", poolsize);
237bbbf1280Sopenharmony_ci			exit(EXIT_FAILURE);
238bbbf1280Sopenharmony_ci		    }
239bbbf1280Sopenharmony_ci		    char c = optarg[strlen(optarg) - 1];
240bbbf1280Sopenharmony_ci		    if (c == 'M')
241bbbf1280Sopenharmony_ci		    {
242bbbf1280Sopenharmony_ci			POOLSIZE = (unsigned) poolsize * 1024 * 1024;
243bbbf1280Sopenharmony_ci		    }
244bbbf1280Sopenharmony_ci		    else if (c == 'K')
245bbbf1280Sopenharmony_ci		    {
246bbbf1280Sopenharmony_ci			POOLSIZE = (unsigned) poolsize * 1024;
247bbbf1280Sopenharmony_ci		    }
248bbbf1280Sopenharmony_ci		    else
249bbbf1280Sopenharmony_ci		    {
250bbbf1280Sopenharmony_ci			POOLSIZE = (unsigned) poolsize;
251bbbf1280Sopenharmony_ci		    }
252bbbf1280Sopenharmony_ci		    break;
253bbbf1280Sopenharmony_ci		}
254bbbf1280Sopenharmony_ci	    default :
255bbbf1280Sopenharmony_ciusage :
256bbbf1280Sopenharmony_ci		fprintf(stderr, "Usage: checksum <options>\n"
257bbbf1280Sopenharmony_ci			"-b <blksize>    Block size\n"
258bbbf1280Sopenharmony_ci			"-d              Dump first 96 bytes of data\n"
259bbbf1280Sopenharmony_ci			"-f <cpufreq>    CPU frequency (Hz)\n"
260bbbf1280Sopenharmony_ci			"-i <impl>       Implementation\n"
261bbbf1280Sopenharmony_ci			"-n <numops>     Number of operations\n"
262bbbf1280Sopenharmony_ci			"-p <poolsize>   Pool size (K or M suffix)\n"
263bbbf1280Sopenharmony_ci		       );
264bbbf1280Sopenharmony_ci		printf("Implementations:");
265bbbf1280Sopenharmony_ci		for (int i = 0; implementations[i].name != NULL; i++)
266bbbf1280Sopenharmony_ci		{
267bbbf1280Sopenharmony_ci		    printf(" %s", implementations[i].name);
268bbbf1280Sopenharmony_ci		}
269bbbf1280Sopenharmony_ci		printf("\n");
270bbbf1280Sopenharmony_ci		exit(EXIT_FAILURE);
271bbbf1280Sopenharmony_ci	}
272bbbf1280Sopenharmony_ci    }
273bbbf1280Sopenharmony_ci    if (optind > argc)
274bbbf1280Sopenharmony_ci    {
275bbbf1280Sopenharmony_ci	goto usage;
276bbbf1280Sopenharmony_ci    }
277bbbf1280Sopenharmony_ci
278bbbf1280Sopenharmony_ci    CKSUM_FP = implementations[IMPL].cksum_fp;
279bbbf1280Sopenharmony_ci    POOLSIZE = ALIGN(POOLSIZE, CACHE_LINE);
280bbbf1280Sopenharmony_ci    uint8_t *base = mmap(0, POOLSIZE, PROT_READ|PROT_WRITE,
281bbbf1280Sopenharmony_ci			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
282bbbf1280Sopenharmony_ci    if (base == MAP_FAILED)
283bbbf1280Sopenharmony_ci    {
284bbbf1280Sopenharmony_ci	perror("aligned_alloc"), exit(EXIT_FAILURE);
285bbbf1280Sopenharmony_ci    }
286bbbf1280Sopenharmony_ci    for (size_t i = 0; i < POOLSIZE / 4; i++)
287bbbf1280Sopenharmony_ci    {
288bbbf1280Sopenharmony_ci	((uint32_t *) base)[i] = rand();
289bbbf1280Sopenharmony_ci    }
290bbbf1280Sopenharmony_ci
291bbbf1280Sopenharmony_ci    printf("Implementation: %s\n", implementations[IMPL].name);
292bbbf1280Sopenharmony_ci    printf("numops %u, poolsize ", NUMOPS);
293bbbf1280Sopenharmony_ci    if (POOLSIZE % (1024 * 1024) == 0)
294bbbf1280Sopenharmony_ci    {
295bbbf1280Sopenharmony_ci	printf("%uMiB", POOLSIZE / (1024 * 1024));
296bbbf1280Sopenharmony_ci    }
297bbbf1280Sopenharmony_ci    else if (POOLSIZE % 1024 == 0)
298bbbf1280Sopenharmony_ci    {
299bbbf1280Sopenharmony_ci	printf("%uKiB", POOLSIZE / 1024);
300bbbf1280Sopenharmony_ci    }
301bbbf1280Sopenharmony_ci    else
302bbbf1280Sopenharmony_ci    {
303bbbf1280Sopenharmony_ci	printf("%uB", POOLSIZE);
304bbbf1280Sopenharmony_ci    }
305bbbf1280Sopenharmony_ci    printf(", blocksize %u, CPU frequency %juMHz\n",
306bbbf1280Sopenharmony_ci	   BLKSIZE, (uintmax_t) (CPUFREQ / 1000000));
307bbbf1280Sopenharmony_ci#if WANT_ASSERT
308bbbf1280Sopenharmony_ci    printf("Warning: assertions are enabled\n");
309bbbf1280Sopenharmony_ci#endif
310bbbf1280Sopenharmony_ci
311bbbf1280Sopenharmony_ci    if (DUMP)
312bbbf1280Sopenharmony_ci    {
313bbbf1280Sopenharmony_ci	/* Print out first 96 bytes of data for human debugging */
314bbbf1280Sopenharmony_ci	for (int i = 0; i < 96; i++)
315bbbf1280Sopenharmony_ci	{
316bbbf1280Sopenharmony_ci	    if (i % 8 == 0)
317bbbf1280Sopenharmony_ci		printf("%2u:", i);
318bbbf1280Sopenharmony_ci	    printf(" %02x", base[i]);
319bbbf1280Sopenharmony_ci	    if (i % 8 == 7)
320bbbf1280Sopenharmony_ci		printf("\n");
321bbbf1280Sopenharmony_ci	}
322bbbf1280Sopenharmony_ci    }
323bbbf1280Sopenharmony_ci
324bbbf1280Sopenharmony_ci    /* Verify that chosen algorithm handles all combinations of offsets and sizes */
325bbbf1280Sopenharmony_ci    printf("Verifying..."); fflush(stdout);
326bbbf1280Sopenharmony_ci    bool success = true;
327bbbf1280Sopenharmony_ci    /* Check all (relevant) combinations of size and offset */
328bbbf1280Sopenharmony_ci    for (int size = 0; size <= 256; size++)
329bbbf1280Sopenharmony_ci    {
330bbbf1280Sopenharmony_ci	for (int offset = 0; offset < 255; offset++)
331bbbf1280Sopenharmony_ci	{
332bbbf1280Sopenharmony_ci	    /* Check at start of mapped memory */
333bbbf1280Sopenharmony_ci	    success &= verify(&base[offset], offset, size);
334bbbf1280Sopenharmony_ci	    /* Check at end of mapped memory */
335bbbf1280Sopenharmony_ci	    uint8_t *p = base + POOLSIZE - (size + offset);
336bbbf1280Sopenharmony_ci	    success &= verify(p, (uintptr_t) p % 64, size);
337bbbf1280Sopenharmony_ci	}
338bbbf1280Sopenharmony_ci    }
339bbbf1280Sopenharmony_ci    /* Check increasingly larger sizes */
340bbbf1280Sopenharmony_ci    for (size_t size = 1; size < POOLSIZE; size *= 2)
341bbbf1280Sopenharmony_ci    {
342bbbf1280Sopenharmony_ci	success &= verify(base, 0, size);
343bbbf1280Sopenharmony_ci    }
344bbbf1280Sopenharmony_ci    /* Check the full size, this can detect accumulator overflows */
345bbbf1280Sopenharmony_ci    success &= verify(base, 0, POOLSIZE);
346bbbf1280Sopenharmony_ci    printf("%s\n", success ? "OK" : "failure");
347bbbf1280Sopenharmony_ci
348bbbf1280Sopenharmony_ci    /* Print throughput in decimal megabyte (1000000B) per second */
349bbbf1280Sopenharmony_ci    if (CPUFREQ != 0)
350bbbf1280Sopenharmony_ci    {
351bbbf1280Sopenharmony_ci	printf("%11s %11s %11s %11s\n",
352bbbf1280Sopenharmony_ci	       "block size", "MB/s", "cycles/blk", "cycles/byte");
353bbbf1280Sopenharmony_ci    }
354bbbf1280Sopenharmony_ci    else
355bbbf1280Sopenharmony_ci    {
356bbbf1280Sopenharmony_ci	printf("%11s %11s %11s %11s\n",
357bbbf1280Sopenharmony_ci	       "block size", "MB/s", "ns/blk", "ns/byte");
358bbbf1280Sopenharmony_ci	CPUFREQ = 1000000000;
359bbbf1280Sopenharmony_ci    }
360bbbf1280Sopenharmony_ci    if (BLKSIZE != 0)
361bbbf1280Sopenharmony_ci    {
362bbbf1280Sopenharmony_ci	benchmark(base, POOLSIZE, BLKSIZE, NUMOPS, CPUFREQ);
363bbbf1280Sopenharmony_ci    }
364bbbf1280Sopenharmony_ci    else
365bbbf1280Sopenharmony_ci    {
366bbbf1280Sopenharmony_ci	static const uint16_t sizes[] =
367bbbf1280Sopenharmony_ci	    { 20, 42, 102, 250, 612, 1500, 3674, 9000, 0 };
368bbbf1280Sopenharmony_ci	for (int i = 0; sizes[i] != 0; i++)
369bbbf1280Sopenharmony_ci	{
370bbbf1280Sopenharmony_ci	    uint32_t numops = NUMOPS * 10000 / (40 + sizes[i]);
371bbbf1280Sopenharmony_ci	    benchmark(base, POOLSIZE, sizes[i], numops, CPUFREQ);
372bbbf1280Sopenharmony_ci	}
373bbbf1280Sopenharmony_ci    }
374bbbf1280Sopenharmony_ci
375bbbf1280Sopenharmony_ci    if (munmap(base, POOLSIZE) != 0)
376bbbf1280Sopenharmony_ci    {
377bbbf1280Sopenharmony_ci	perror("munmap"), exit(EXIT_FAILURE);
378bbbf1280Sopenharmony_ci    }
379bbbf1280Sopenharmony_ci
380bbbf1280Sopenharmony_ci    return success ? EXIT_SUCCESS : EXIT_FAILURE;
381bbbf1280Sopenharmony_ci}
382