1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Ebizzy - replicate a large ebusiness type of workload.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Written by Valerie Henson <val@nmt.edu>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Copyright 2006 - 2007 Intel Corporation
7f08c3bdfSopenharmony_ci * Copyright 2007 Valerie Henson <val@nmt.edu>
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Rodrigo Rubira Branco <rrbranco@br.ibm.com> - HP/BSD/Solaris port and some
10f08c3bdfSopenharmony_ci *  						 new features
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify
13f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by
14f08c3bdfSopenharmony_ci * the Free Software Foundation; version 2 of the License.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
17f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
18f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19f08c3bdfSopenharmony_ci * GNU General Public License for more details.
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
22f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software
23f08c3bdfSopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
24f08c3bdfSopenharmony_ci * USA
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci */
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_ci/*
29f08c3bdfSopenharmony_ci * This program is designed to replicate a common web search app
30f08c3bdfSopenharmony_ci * workload.  A lot of search applications have the basic pattern: Get
31f08c3bdfSopenharmony_ci * a request to find a certain record, index into the chunk of memory
32f08c3bdfSopenharmony_ci * that contains it, copy it into another chunk, then look it up via
33f08c3bdfSopenharmony_ci * binary search.  The interesting parts of this workload are:
34f08c3bdfSopenharmony_ci *
35f08c3bdfSopenharmony_ci * Large working set
36f08c3bdfSopenharmony_ci * Data alloc/copy/free cycle
37f08c3bdfSopenharmony_ci * Unpredictable data access patterns
38f08c3bdfSopenharmony_ci *
39f08c3bdfSopenharmony_ci * Fiddle with the command line options until you get something
40f08c3bdfSopenharmony_ci * resembling the kind of workload you want to investigate.
41f08c3bdfSopenharmony_ci *
42f08c3bdfSopenharmony_ci */
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci#include <stdio.h>
45f08c3bdfSopenharmony_ci#include <unistd.h>
46f08c3bdfSopenharmony_ci#include <stdlib.h>
47f08c3bdfSopenharmony_ci#include <sys/mman.h>
48f08c3bdfSopenharmony_ci#include <pthread.h>
49f08c3bdfSopenharmony_ci#include <string.h>
50f08c3bdfSopenharmony_ci#include <time.h>
51f08c3bdfSopenharmony_ci#include <sys/time.h>
52f08c3bdfSopenharmony_ci#include <sys/resource.h>
53f08c3bdfSopenharmony_ci#include <stdint.h>
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci#include "ebizzy.h"
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci/*
58f08c3bdfSopenharmony_ci * Command line options
59f08c3bdfSopenharmony_ci */
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_cistatic unsigned int always_mmap;
62f08c3bdfSopenharmony_cistatic unsigned int never_mmap;
63f08c3bdfSopenharmony_cistatic unsigned int chunks;
64f08c3bdfSopenharmony_cistatic unsigned int use_permissions;
65f08c3bdfSopenharmony_cistatic unsigned int use_holes;
66f08c3bdfSopenharmony_cistatic unsigned int random_size;
67f08c3bdfSopenharmony_cistatic unsigned int chunk_size;
68f08c3bdfSopenharmony_cistatic unsigned int seconds;
69f08c3bdfSopenharmony_cistatic unsigned int threads;
70f08c3bdfSopenharmony_cistatic unsigned int verbose;
71f08c3bdfSopenharmony_cistatic unsigned int linear;
72f08c3bdfSopenharmony_cistatic unsigned int touch_pages;
73f08c3bdfSopenharmony_cistatic unsigned int no_lib_memcpy;
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci/*
76f08c3bdfSopenharmony_ci * Other global variables
77f08c3bdfSopenharmony_ci */
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_citypedef size_t record_t;
80f08c3bdfSopenharmony_cistatic unsigned int record_size = sizeof(record_t);
81f08c3bdfSopenharmony_cistatic char *cmd;
82f08c3bdfSopenharmony_cistatic record_t **mem;
83f08c3bdfSopenharmony_cistatic char **hole_mem;
84f08c3bdfSopenharmony_cistatic unsigned int page_size;
85f08c3bdfSopenharmony_cistatic time_t start_time;
86f08c3bdfSopenharmony_cistatic volatile int threads_go;
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_cistatic void usage(void)
89f08c3bdfSopenharmony_ci{
90f08c3bdfSopenharmony_ci	fprintf(stderr, "Usage: %s [options]\n"
91f08c3bdfSopenharmony_ci		"-T\t\t Just 'touch' the allocated pages\n"
92f08c3bdfSopenharmony_ci		"-l\t\t Don't use library memcpy\n"
93f08c3bdfSopenharmony_ci		"-m\t\t Always use mmap instead of malloc\n"
94f08c3bdfSopenharmony_ci		"-M\t\t Never use mmap\n"
95f08c3bdfSopenharmony_ci		"-n <num>\t Number of memory chunks to allocate\n"
96f08c3bdfSopenharmony_ci		"-p \t\t Prevent mmap coalescing using permissions\n"
97f08c3bdfSopenharmony_ci		"-P \t\t Prevent mmap coalescing using holes\n"
98f08c3bdfSopenharmony_ci		"-R\t\t Randomize size of memory to copy and search\n"
99f08c3bdfSopenharmony_ci		"-s <size>\t Size of memory chunks, in bytes\n"
100f08c3bdfSopenharmony_ci		"-S <seconds>\t Number of seconds to run\n"
101f08c3bdfSopenharmony_ci		"-t <num>\t Number of threads (2 * number cpus by default)\n"
102f08c3bdfSopenharmony_ci		"-v[v[v]]\t Be verbose (more v's for more verbose)\n"
103f08c3bdfSopenharmony_ci		"-z\t\t Linear search instead of binary search\n", cmd);
104f08c3bdfSopenharmony_ci	exit(1);
105f08c3bdfSopenharmony_ci}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci/*
108f08c3bdfSopenharmony_ci * Read options, check them, and set some defaults.
109f08c3bdfSopenharmony_ci */
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_cistatic void read_options(int argc, char *argv[])
112f08c3bdfSopenharmony_ci{
113f08c3bdfSopenharmony_ci	int c;
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci	page_size = getpagesize();
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	/*
118f08c3bdfSopenharmony_ci	 * Set some defaults.  These are currently tuned to run in a
119f08c3bdfSopenharmony_ci	 * reasonable amount of time on my laptop.
120f08c3bdfSopenharmony_ci	 *
121f08c3bdfSopenharmony_ci	 * We could set the static defaults in the declarations, but
122f08c3bdfSopenharmony_ci	 * then the defaults would be split between here and the top
123f08c3bdfSopenharmony_ci	 * of the file, which is annoying.
124f08c3bdfSopenharmony_ci	 */
125f08c3bdfSopenharmony_ci	threads = 2 * sysconf(_SC_NPROCESSORS_ONLN);
126f08c3bdfSopenharmony_ci	chunks = 10;
127f08c3bdfSopenharmony_ci	chunk_size = record_size * 64 * 1024;
128f08c3bdfSopenharmony_ci	seconds = 10;
129f08c3bdfSopenharmony_ci
130f08c3bdfSopenharmony_ci	/* On to option processing */
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci	cmd = argv[0];
133f08c3bdfSopenharmony_ci	opterr = 1;
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci	while ((c = getopt(argc, argv, "lmMn:pPRs:S:t:vzT")) != -1) {
136f08c3bdfSopenharmony_ci		switch (c) {
137f08c3bdfSopenharmony_ci		case 'l':
138f08c3bdfSopenharmony_ci			no_lib_memcpy = 1;
139f08c3bdfSopenharmony_ci			break;
140f08c3bdfSopenharmony_ci		case 'm':
141f08c3bdfSopenharmony_ci			always_mmap = 1;
142f08c3bdfSopenharmony_ci			break;
143f08c3bdfSopenharmony_ci		case 'M':
144f08c3bdfSopenharmony_ci			never_mmap = 1;
145f08c3bdfSopenharmony_ci			break;
146f08c3bdfSopenharmony_ci		case 'n':
147f08c3bdfSopenharmony_ci			chunks = atoi(optarg);
148f08c3bdfSopenharmony_ci			if (chunks == 0)
149f08c3bdfSopenharmony_ci				usage();
150f08c3bdfSopenharmony_ci			break;
151f08c3bdfSopenharmony_ci		case 'p':
152f08c3bdfSopenharmony_ci			use_permissions = 1;
153f08c3bdfSopenharmony_ci			break;
154f08c3bdfSopenharmony_ci		case 'P':
155f08c3bdfSopenharmony_ci			use_holes = 1;
156f08c3bdfSopenharmony_ci			break;
157f08c3bdfSopenharmony_ci		case 'R':
158f08c3bdfSopenharmony_ci			random_size = 1;
159f08c3bdfSopenharmony_ci			break;
160f08c3bdfSopenharmony_ci		case 's':
161f08c3bdfSopenharmony_ci			chunk_size = atoi(optarg);
162f08c3bdfSopenharmony_ci			if (chunk_size == 0)
163f08c3bdfSopenharmony_ci				usage();
164f08c3bdfSopenharmony_ci			break;
165f08c3bdfSopenharmony_ci		case 'S':
166f08c3bdfSopenharmony_ci			seconds = atoi(optarg);
167f08c3bdfSopenharmony_ci			if (seconds == 0)
168f08c3bdfSopenharmony_ci				usage();
169f08c3bdfSopenharmony_ci			break;
170f08c3bdfSopenharmony_ci		case 't':
171f08c3bdfSopenharmony_ci			threads = atoi(optarg);
172f08c3bdfSopenharmony_ci			if (threads == 0)
173f08c3bdfSopenharmony_ci				usage();
174f08c3bdfSopenharmony_ci			break;
175f08c3bdfSopenharmony_ci		case 'T':
176f08c3bdfSopenharmony_ci			touch_pages = 1;
177f08c3bdfSopenharmony_ci			break;
178f08c3bdfSopenharmony_ci		case 'v':
179f08c3bdfSopenharmony_ci			verbose++;
180f08c3bdfSopenharmony_ci			break;
181f08c3bdfSopenharmony_ci		case 'z':
182f08c3bdfSopenharmony_ci			linear = 1;
183f08c3bdfSopenharmony_ci			break;
184f08c3bdfSopenharmony_ci		default:
185f08c3bdfSopenharmony_ci			usage();
186f08c3bdfSopenharmony_ci		}
187f08c3bdfSopenharmony_ci	}
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci	if (verbose)
190f08c3bdfSopenharmony_ci		printf("ebizzy 0.2\n"
191f08c3bdfSopenharmony_ci		       "(C) 2006-7 Intel Corporation\n"
192f08c3bdfSopenharmony_ci		       "(C) 2007 Valerie Henson <val@nmt.edu>\n");
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	if (verbose) {
195f08c3bdfSopenharmony_ci		printf("always_mmap %u\n", always_mmap);
196f08c3bdfSopenharmony_ci		printf("never_mmap %u\n", never_mmap);
197f08c3bdfSopenharmony_ci		printf("chunks %u\n", chunks);
198f08c3bdfSopenharmony_ci		printf("prevent coalescing using permissions %u\n",
199f08c3bdfSopenharmony_ci		       use_permissions);
200f08c3bdfSopenharmony_ci		printf("prevent coalescing using holes %u\n", use_holes);
201f08c3bdfSopenharmony_ci		printf("random_size %u\n", random_size);
202f08c3bdfSopenharmony_ci		printf("chunk_size %u\n", chunk_size);
203f08c3bdfSopenharmony_ci		printf("seconds %d\n", seconds);
204f08c3bdfSopenharmony_ci		printf("threads %u\n", threads);
205f08c3bdfSopenharmony_ci		printf("verbose %u\n", verbose);
206f08c3bdfSopenharmony_ci		printf("linear %u\n", linear);
207f08c3bdfSopenharmony_ci		printf("touch_pages %u\n", touch_pages);
208f08c3bdfSopenharmony_ci		printf("page size %d\n", page_size);
209f08c3bdfSopenharmony_ci	}
210f08c3bdfSopenharmony_ci
211f08c3bdfSopenharmony_ci	/* Check for incompatible options */
212f08c3bdfSopenharmony_ci
213f08c3bdfSopenharmony_ci	if (always_mmap && never_mmap) {
214f08c3bdfSopenharmony_ci		fprintf(stderr, "Both -m \"always mmap\" and -M "
215f08c3bdfSopenharmony_ci			"\"never mmap\" option specified\n");
216f08c3bdfSopenharmony_ci		usage();
217f08c3bdfSopenharmony_ci	}
218f08c3bdfSopenharmony_ci#ifdef __GLIBC__
219f08c3bdfSopenharmony_ci	if (never_mmap)
220f08c3bdfSopenharmony_ci		mallopt(M_MMAP_MAX, 0);
221f08c3bdfSopenharmony_ci#endif
222f08c3bdfSopenharmony_ci	if (chunk_size < record_size) {
223f08c3bdfSopenharmony_ci		fprintf(stderr, "Chunk size %u smaller than record size %u\n",
224f08c3bdfSopenharmony_ci			chunk_size, record_size);
225f08c3bdfSopenharmony_ci		usage();
226f08c3bdfSopenharmony_ci	}
227f08c3bdfSopenharmony_ci}
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_cistatic void touch_mem(char *dest, size_t size)
230f08c3bdfSopenharmony_ci{
231f08c3bdfSopenharmony_ci	int i;
232f08c3bdfSopenharmony_ci	if (touch_pages) {
233f08c3bdfSopenharmony_ci		for (i = 0; i < (long)size; i += page_size)
234f08c3bdfSopenharmony_ci			*(dest + i) = 0xff;
235f08c3bdfSopenharmony_ci	}
236f08c3bdfSopenharmony_ci}
237f08c3bdfSopenharmony_ci
238f08c3bdfSopenharmony_cistatic void *alloc_mem(size_t size)
239f08c3bdfSopenharmony_ci{
240f08c3bdfSopenharmony_ci	char *p;
241f08c3bdfSopenharmony_ci	int err = 0;
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci	if (always_mmap) {
244f08c3bdfSopenharmony_ci		p = mmap(NULL, size, (PROT_READ | PROT_WRITE),
245f08c3bdfSopenharmony_ci			 (MAP_PRIVATE | MAP_ANONYMOUS), -1, 0);
246f08c3bdfSopenharmony_ci		if (p == MAP_FAILED)
247f08c3bdfSopenharmony_ci			err = 1;
248f08c3bdfSopenharmony_ci	} else {
249f08c3bdfSopenharmony_ci		p = malloc(size);
250f08c3bdfSopenharmony_ci		if (p == NULL)
251f08c3bdfSopenharmony_ci			err = 1;
252f08c3bdfSopenharmony_ci	}
253f08c3bdfSopenharmony_ci
254f08c3bdfSopenharmony_ci	if (err) {
255f08c3bdfSopenharmony_ci		fprintf(stderr, "Couldn't allocate %zu bytes, try smaller "
256f08c3bdfSopenharmony_ci			"chunks or size options\n"
257f08c3bdfSopenharmony_ci			"Using -n %u chunks and -s %u size\n",
258f08c3bdfSopenharmony_ci			size, chunks, chunk_size);
259f08c3bdfSopenharmony_ci		exit(1);
260f08c3bdfSopenharmony_ci	}
261f08c3bdfSopenharmony_ci
262f08c3bdfSopenharmony_ci	return (p);
263f08c3bdfSopenharmony_ci}
264f08c3bdfSopenharmony_ci
265f08c3bdfSopenharmony_cistatic void free_mem(void *p, size_t size)
266f08c3bdfSopenharmony_ci{
267f08c3bdfSopenharmony_ci	if (always_mmap)
268f08c3bdfSopenharmony_ci		munmap(p, size);
269f08c3bdfSopenharmony_ci	else
270f08c3bdfSopenharmony_ci		free(p);
271f08c3bdfSopenharmony_ci}
272f08c3bdfSopenharmony_ci
273f08c3bdfSopenharmony_ci/*
274f08c3bdfSopenharmony_ci * Factor out differences in memcpy implementation by optionally using
275f08c3bdfSopenharmony_ci * our own simple memcpy implementation.
276f08c3bdfSopenharmony_ci */
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_cistatic void my_memcpy(void *dest, void *src, size_t len)
279f08c3bdfSopenharmony_ci{
280f08c3bdfSopenharmony_ci	char *d = (char *)dest;
281f08c3bdfSopenharmony_ci	char *s = (char *)src;
282f08c3bdfSopenharmony_ci	int i;
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	for (i = 0; i < (long)len; i++)
285f08c3bdfSopenharmony_ci		d[i] = s[i];
286f08c3bdfSopenharmony_ci	return;
287f08c3bdfSopenharmony_ci}
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_cistatic void allocate(void)
290f08c3bdfSopenharmony_ci{
291f08c3bdfSopenharmony_ci	unsigned int i;
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ci	mem = alloc_mem(chunks * sizeof(record_t *));
294f08c3bdfSopenharmony_ci
295f08c3bdfSopenharmony_ci	if (use_holes)
296f08c3bdfSopenharmony_ci		hole_mem = alloc_mem(chunks * sizeof(record_t *));
297f08c3bdfSopenharmony_ci
298f08c3bdfSopenharmony_ci	for (i = 0; i < chunks; i++) {
299f08c3bdfSopenharmony_ci		mem[i] = (record_t *) alloc_mem(chunk_size);
300f08c3bdfSopenharmony_ci		/* Prevent coalescing using holes */
301f08c3bdfSopenharmony_ci		if (use_holes)
302f08c3bdfSopenharmony_ci			hole_mem[i] = alloc_mem(page_size);
303f08c3bdfSopenharmony_ci	}
304f08c3bdfSopenharmony_ci
305f08c3bdfSopenharmony_ci	/* Free hole memory */
306f08c3bdfSopenharmony_ci	if (use_holes)
307f08c3bdfSopenharmony_ci		for (i = 0; i < chunks; i++)
308f08c3bdfSopenharmony_ci			free_mem(hole_mem[i], page_size);
309f08c3bdfSopenharmony_ci
310f08c3bdfSopenharmony_ci	if (verbose)
311f08c3bdfSopenharmony_ci		printf("Allocated memory\n");
312f08c3bdfSopenharmony_ci}
313f08c3bdfSopenharmony_ci
314f08c3bdfSopenharmony_cistatic void write_pattern(void)
315f08c3bdfSopenharmony_ci{
316f08c3bdfSopenharmony_ci	unsigned int i, j;
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_ci	for (i = 0; i < chunks; i++) {
319f08c3bdfSopenharmony_ci		for (j = 0; j < chunk_size / record_size; j++)
320f08c3bdfSopenharmony_ci			mem[i][j] = (record_t) j;
321f08c3bdfSopenharmony_ci		/* Prevent coalescing by alternating permissions */
322f08c3bdfSopenharmony_ci		if (use_permissions && (i % 2) == 0)
323f08c3bdfSopenharmony_ci			mprotect((void *)mem[i], chunk_size, PROT_READ);
324f08c3bdfSopenharmony_ci	}
325f08c3bdfSopenharmony_ci	if (verbose)
326f08c3bdfSopenharmony_ci		printf("Wrote memory\n");
327f08c3bdfSopenharmony_ci}
328f08c3bdfSopenharmony_ci
329f08c3bdfSopenharmony_cistatic void *linear_search(record_t key, record_t * base, size_t size)
330f08c3bdfSopenharmony_ci{
331f08c3bdfSopenharmony_ci	record_t *p;
332f08c3bdfSopenharmony_ci	record_t *end = base + (size / record_size);
333f08c3bdfSopenharmony_ci
334f08c3bdfSopenharmony_ci	for (p = base; p < end; p++)
335f08c3bdfSopenharmony_ci		if (*p == key)
336f08c3bdfSopenharmony_ci			return p;
337f08c3bdfSopenharmony_ci	return NULL;
338f08c3bdfSopenharmony_ci}
339f08c3bdfSopenharmony_ci
340f08c3bdfSopenharmony_cistatic int compare(const void *p1, const void *p2)
341f08c3bdfSopenharmony_ci{
342f08c3bdfSopenharmony_ci	return (*(record_t *) p1 - *(record_t *) p2);
343f08c3bdfSopenharmony_ci}
344f08c3bdfSopenharmony_ci
345f08c3bdfSopenharmony_ci/*
346f08c3bdfSopenharmony_ci * Stupid ranged random number function.  We don't care about quality.
347f08c3bdfSopenharmony_ci *
348f08c3bdfSopenharmony_ci * Inline because it's starting to be a scaling issue.
349f08c3bdfSopenharmony_ci */
350f08c3bdfSopenharmony_ci
351f08c3bdfSopenharmony_cistatic inline unsigned int rand_num(unsigned int max, unsigned int *state)
352f08c3bdfSopenharmony_ci{
353f08c3bdfSopenharmony_ci	*state *= 1103515245 + 12345;
354f08c3bdfSopenharmony_ci	return ((*state / 65536) % max);
355f08c3bdfSopenharmony_ci}
356f08c3bdfSopenharmony_ci
357f08c3bdfSopenharmony_ci/*
358f08c3bdfSopenharmony_ci * This function is the meat of the program; the rest is just support.
359f08c3bdfSopenharmony_ci *
360f08c3bdfSopenharmony_ci * In this function, we randomly select a memory chunk, copy it into a
361f08c3bdfSopenharmony_ci * newly allocated buffer, randomly select a search key, look it up,
362f08c3bdfSopenharmony_ci * then free the memory.  An option tells us to allocate and copy a
363f08c3bdfSopenharmony_ci * randomly sized chunk of the memory instead of the whole thing.
364f08c3bdfSopenharmony_ci *
365f08c3bdfSopenharmony_ci * Linear search provided for sanity checking.
366f08c3bdfSopenharmony_ci *
367f08c3bdfSopenharmony_ci */
368f08c3bdfSopenharmony_ci
369f08c3bdfSopenharmony_cistatic uintptr_t search_mem(void)
370f08c3bdfSopenharmony_ci{
371f08c3bdfSopenharmony_ci	record_t key, *found;
372f08c3bdfSopenharmony_ci	record_t *src, *copy;
373f08c3bdfSopenharmony_ci	unsigned int chunk;
374f08c3bdfSopenharmony_ci	size_t copy_size = chunk_size;
375f08c3bdfSopenharmony_ci	uintptr_t i;
376f08c3bdfSopenharmony_ci	unsigned int state = 0;
377f08c3bdfSopenharmony_ci
378f08c3bdfSopenharmony_ci	for (i = 0; threads_go == 1; i++) {
379f08c3bdfSopenharmony_ci		chunk = rand_num(chunks, &state);
380f08c3bdfSopenharmony_ci		src = mem[chunk];
381f08c3bdfSopenharmony_ci		/*
382f08c3bdfSopenharmony_ci		 * If we're doing random sizes, we need a non-zero
383f08c3bdfSopenharmony_ci		 * multiple of record size.
384f08c3bdfSopenharmony_ci		 */
385f08c3bdfSopenharmony_ci		if (random_size)
386f08c3bdfSopenharmony_ci			copy_size = (rand_num(chunk_size / record_size, &state)
387f08c3bdfSopenharmony_ci				     + 1) * record_size;
388f08c3bdfSopenharmony_ci		copy = alloc_mem(copy_size);
389f08c3bdfSopenharmony_ci
390f08c3bdfSopenharmony_ci		if (touch_pages) {
391f08c3bdfSopenharmony_ci			touch_mem((char *)copy, copy_size);
392f08c3bdfSopenharmony_ci		} else {
393f08c3bdfSopenharmony_ci
394f08c3bdfSopenharmony_ci			if (no_lib_memcpy)
395f08c3bdfSopenharmony_ci				my_memcpy(copy, src, copy_size);
396f08c3bdfSopenharmony_ci			else
397f08c3bdfSopenharmony_ci				memcpy(copy, src, copy_size);
398f08c3bdfSopenharmony_ci
399f08c3bdfSopenharmony_ci			key = rand_num(copy_size / record_size, &state);
400f08c3bdfSopenharmony_ci
401f08c3bdfSopenharmony_ci			if (verbose > 2)
402f08c3bdfSopenharmony_ci				printf("Search key %zu, copy size %zu\n", key,
403f08c3bdfSopenharmony_ci				       copy_size);
404f08c3bdfSopenharmony_ci			if (linear)
405f08c3bdfSopenharmony_ci				found = linear_search(key, copy, copy_size);
406f08c3bdfSopenharmony_ci			else
407f08c3bdfSopenharmony_ci				found =
408f08c3bdfSopenharmony_ci				    bsearch(&key, copy, copy_size / record_size,
409f08c3bdfSopenharmony_ci					    record_size, compare);
410f08c3bdfSopenharmony_ci
411f08c3bdfSopenharmony_ci			/* Below check is mainly for memory corruption or other bug */
412f08c3bdfSopenharmony_ci			if (found == NULL) {
413f08c3bdfSopenharmony_ci				fprintf(stderr, "Couldn't find key %zd\n", key);
414f08c3bdfSopenharmony_ci				exit(1);
415f08c3bdfSopenharmony_ci			}
416f08c3bdfSopenharmony_ci		}		/* end if ! touch_pages */
417f08c3bdfSopenharmony_ci
418f08c3bdfSopenharmony_ci		free_mem(copy, copy_size);
419f08c3bdfSopenharmony_ci	}
420f08c3bdfSopenharmony_ci
421f08c3bdfSopenharmony_ci	return (i);
422f08c3bdfSopenharmony_ci}
423f08c3bdfSopenharmony_ci
424f08c3bdfSopenharmony_cistatic void *thread_run(void *arg __attribute__((unused)))
425f08c3bdfSopenharmony_ci{
426f08c3bdfSopenharmony_ci	uintptr_t records_thread;
427f08c3bdfSopenharmony_ci
428f08c3bdfSopenharmony_ci	if (verbose > 1)
429f08c3bdfSopenharmony_ci		printf("Thread started\n");
430f08c3bdfSopenharmony_ci
431f08c3bdfSopenharmony_ci	/* Wait for the start signal */
432f08c3bdfSopenharmony_ci
433f08c3bdfSopenharmony_ci	while (threads_go == 0) ;
434f08c3bdfSopenharmony_ci
435f08c3bdfSopenharmony_ci	records_thread = search_mem();
436f08c3bdfSopenharmony_ci
437f08c3bdfSopenharmony_ci	if (verbose > 1)
438f08c3bdfSopenharmony_ci		printf("Thread finished, %f seconds\n",
439f08c3bdfSopenharmony_ci		       difftime(time(NULL), start_time));
440f08c3bdfSopenharmony_ci
441f08c3bdfSopenharmony_ci	return (void *)records_thread;
442f08c3bdfSopenharmony_ci}
443f08c3bdfSopenharmony_ci
444f08c3bdfSopenharmony_cistatic struct timeval difftimeval(struct timeval *end, struct timeval *start)
445f08c3bdfSopenharmony_ci{
446f08c3bdfSopenharmony_ci	struct timeval diff;
447f08c3bdfSopenharmony_ci	diff.tv_sec = end->tv_sec - start->tv_sec;
448f08c3bdfSopenharmony_ci	diff.tv_usec = end->tv_usec - start->tv_usec;
449f08c3bdfSopenharmony_ci	return diff;
450f08c3bdfSopenharmony_ci}
451f08c3bdfSopenharmony_ci
452f08c3bdfSopenharmony_cistatic void start_threads(void)
453f08c3bdfSopenharmony_ci{
454f08c3bdfSopenharmony_ci	pthread_t thread_array[threads];
455f08c3bdfSopenharmony_ci	double elapsed;
456f08c3bdfSopenharmony_ci	unsigned int i;
457f08c3bdfSopenharmony_ci	struct rusage start_ru, end_ru;
458f08c3bdfSopenharmony_ci	struct timeval usr_time, sys_time;
459f08c3bdfSopenharmony_ci	double records_per_sec = 0.0;
460f08c3bdfSopenharmony_ci	int err;
461f08c3bdfSopenharmony_ci
462f08c3bdfSopenharmony_ci	if (verbose)
463f08c3bdfSopenharmony_ci		printf("Threads starting\n");
464f08c3bdfSopenharmony_ci
465f08c3bdfSopenharmony_ci	for (i = 0; i < threads; i++) {
466f08c3bdfSopenharmony_ci		err = pthread_create(&thread_array[i], NULL, thread_run, NULL);
467f08c3bdfSopenharmony_ci		if (err) {
468f08c3bdfSopenharmony_ci			fprintf(stderr, "Error creating thread %d\n", i);
469f08c3bdfSopenharmony_ci			exit(1);
470f08c3bdfSopenharmony_ci		}
471f08c3bdfSopenharmony_ci	}
472f08c3bdfSopenharmony_ci
473f08c3bdfSopenharmony_ci	/*
474f08c3bdfSopenharmony_ci	 * Begin accounting - this is when we actually do the things
475f08c3bdfSopenharmony_ci	 * we want to measure. */
476f08c3bdfSopenharmony_ci
477f08c3bdfSopenharmony_ci	getrusage(RUSAGE_SELF, &start_ru);
478f08c3bdfSopenharmony_ci	start_time = time(NULL);
479f08c3bdfSopenharmony_ci	threads_go = 1;
480f08c3bdfSopenharmony_ci	sleep(seconds);
481f08c3bdfSopenharmony_ci	threads_go = 0;
482f08c3bdfSopenharmony_ci	elapsed = difftime(time(NULL), start_time);
483f08c3bdfSopenharmony_ci	getrusage(RUSAGE_SELF, &end_ru);
484f08c3bdfSopenharmony_ci
485f08c3bdfSopenharmony_ci	/*
486f08c3bdfSopenharmony_ci	 * The rest is just clean up.
487f08c3bdfSopenharmony_ci	 */
488f08c3bdfSopenharmony_ci
489f08c3bdfSopenharmony_ci	for (i = 0; i < threads; i++) {
490f08c3bdfSopenharmony_ci		uintptr_t record_thread;
491f08c3bdfSopenharmony_ci		err = pthread_join(thread_array[i], (void *)&record_thread);
492f08c3bdfSopenharmony_ci		if (err) {
493f08c3bdfSopenharmony_ci			fprintf(stderr, "Error joining thread %d\n", i);
494f08c3bdfSopenharmony_ci			exit(1);
495f08c3bdfSopenharmony_ci		}
496f08c3bdfSopenharmony_ci		records_per_sec += ((double)record_thread / elapsed);
497f08c3bdfSopenharmony_ci	}
498f08c3bdfSopenharmony_ci
499f08c3bdfSopenharmony_ci	if (verbose)
500f08c3bdfSopenharmony_ci		printf("Threads finished\n");
501f08c3bdfSopenharmony_ci
502f08c3bdfSopenharmony_ci	printf("%tu records/s\n", (uintptr_t) records_per_sec);
503f08c3bdfSopenharmony_ci
504f08c3bdfSopenharmony_ci	usr_time = difftimeval(&end_ru.ru_utime, &start_ru.ru_utime);
505f08c3bdfSopenharmony_ci	sys_time = difftimeval(&end_ru.ru_stime, &start_ru.ru_stime);
506f08c3bdfSopenharmony_ci
507f08c3bdfSopenharmony_ci	printf("real %5.2f s\n", elapsed);
508f08c3bdfSopenharmony_ci	printf("user %5.2f s\n", usr_time.tv_sec + usr_time.tv_usec / 1e6);
509f08c3bdfSopenharmony_ci	printf("sys  %5.2f s\n", sys_time.tv_sec + sys_time.tv_usec / 1e6);
510f08c3bdfSopenharmony_ci}
511f08c3bdfSopenharmony_ci
512f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
513f08c3bdfSopenharmony_ci{
514f08c3bdfSopenharmony_ci	read_options(argc, argv);
515f08c3bdfSopenharmony_ci
516f08c3bdfSopenharmony_ci	allocate();
517f08c3bdfSopenharmony_ci
518f08c3bdfSopenharmony_ci	write_pattern();
519f08c3bdfSopenharmony_ci
520f08c3bdfSopenharmony_ci	start_threads();
521f08c3bdfSopenharmony_ci
522f08c3bdfSopenharmony_ci	return 0;
523f08c3bdfSopenharmony_ci}
524