/* * CDDL HEADER START * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the "License"). You may not use this file except * in compliance with the License. * * You can obtain a copy of the license at * src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing * permissions and limitations under the License. * * When distributing Covered Code, include this CDDL * HEADER in each file and include the License file at * usr/src/OPENSOLARIS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your * own identifying information: Portions Copyright [yyyy] * [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * routine to benchmark cache-to-cache transfer times... uses * solaris features to find and bind to cpus in the current * processor set, so not likely to work elsewhere. */ #include #include #include #include #include #include #include #include #include #include #include "libmicro.h" static long opts = 1024*512; typedef struct { long **ts_data; long ts_result; pthread_mutex_t ts_lock; } tsd_t; static unsigned int ncpu = 1024; static tsd_t *thread_data[1024]; static processorid_t cpus[1024]; int traverse_ptrchain(long **, int, int); int benchmark_init() { lm_tsdsize = sizeof (tsd_t); (void) sprintf(lm_optstr, "s:"); (void) sprintf(lm_usage, " [-s size] size of access area in bytes" " (default %ld)\n" "notes: measures cache to cache transfer times on Solaris\n", opts); (void) sprintf(lm_header, "%8s", "size"); return (0); } int benchmark_optswitch(int opt, char *optarg) { switch (opt) { case 's': opts = sizetoint(optarg); break; default: return (-1); } return (0); } int benchmark_initrun() { if (pset_info(PS_MYID, NULL, &ncpu, cpus) < 0) { perror("pset_info"); return (1); } return (0); } int benchmark_initworker(void *tsd) { tsd_t *ts = (tsd_t *)tsd; int i, j; processorid_t cpu; ts->ts_data = malloc(opts); if (ts->ts_data == NULL) { return (1); } (void) pthread_mutex_init(&ts->ts_lock, NULL); if (processor_bind(P_LWPID, P_MYID, cpu = cpus[(pthread_self() - 1) % ncpu], NULL) < 0) { perror("processor_bind:"); return (1); } (void) printf("# thread %d using processor %d\n", pthread_self(), cpu); /* * use lmbench style backwards stride */ for (i = 0; i < opts / sizeof (long); i++) { j = i - 128; if (j < 0) j = j + opts / sizeof (long); ts->ts_data[i] = (long *)&(ts->ts_data[j]); } thread_data[pthread_self() - 1] = ts; return (0); } /* * here we go in order for each thread, causing inherent serialization * this is normally not a good idea, but in this case we're trying to * measure cache-to-cache transfer times, and if we run threads in * parallel we're likely to see saturation effects rather than cache-to-cache, * esp. on wimpy memory platforms like P4. */ /*ARGSUSED*/ int benchmark(void *tsd, result_t *res) { tsd_t *ts; int i, j; int count = opts / 128 / sizeof (long); for (j = 0; j < lm_optB; j++) for (i = 0; i < lm_optT; i++) { ts = thread_data[i]; (void) pthread_mutex_lock(&ts->ts_lock); ts->ts_result += traverse_ptrchain( (long **)ts->ts_data, count, 0); (void) pthread_mutex_unlock(&ts->ts_lock); } res->re_count = lm_optB * lm_optT * count; return (0); } int traverse_ptrchain(long **ptr, int count, int value) { int i; for (i = 0; i < count; i += 10) { *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; ptr = (long **)*ptr; *ptr = *ptr + value; } return ((int)*ptr); /* bogus return */ } char * benchmark_result() { static char result[256]; (void) sprintf(result, "%8ld ", opts); return (result); }