mutex.c   [plain text]


/*
 * 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 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * mutex
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/mman.h>

#include "libmicro.h"

static int			optt = 0;
static int			optp = 0;
static int			opth = 0;
static int			opto = 0;

pthread_mutex_t			*lock;

typedef struct {
	int			ts_once;
	pthread_mutex_t		*ts_lock;
} tsd_t;

int
benchmark_init()
{
	lm_tsdsize = sizeof (tsd_t);

	(void) sprintf(lm_usage,
	    "       [-t] (create dummy thread so we are multithreaded)\n"
	    "       [-p] (use inter-process mutex (not support everywhere))\n"
	    "       [-h usecs] (specify mutex hold time (default 0)\n"
	    "notes: measures uncontended pthread_mutex_[un,]lock\n");

	(void) sprintf(lm_optstr, "tph:o:");

	(void) sprintf(lm_header, "%8s", "holdtime");

	return (0);
}

/*ARGSUSED*/
int
benchmark_optswitch(int opt, char *optarg)
{
	switch (opt) {
	case 'p':
		optp = 1;
		break;

	case 't':
		optt = 1;
		break;

	case 'h':
		opth = sizetoint(optarg);
		break;

	case 'o':
		opto = sizetoint(optarg);
		break;

	default:
		return (-1);
	}
	return (0);
}

void *
dummy(void *arg)
{
	(void) pause();
	return (arg);
}

int
benchmark_initrun()
{
	pthread_mutexattr_t	attr;
	int errors = 0;

	/*LINTED*/
	lock = (pthread_mutex_t *)mmap(NULL,
	    getpagesize(),
	    PROT_READ | PROT_WRITE,
	    optp?(MAP_ANON | MAP_SHARED):MAP_ANON|MAP_PRIVATE,
	    -1, 0L) + opto;

	if (lock == MAP_FAILED) {
		errors++;
	} else {
		(void) pthread_mutexattr_init(&attr);
		if (optp)
			(void) pthread_mutexattr_setpshared(&attr,
			    PTHREAD_PROCESS_SHARED);

		if (pthread_mutex_init(lock, &attr) != 0)
			errors++;
	}

	return (errors);
}

int
benchmark_initworker(void *tsd)
{
	int errors = 0;
	tsd_t			*ts = (tsd_t *)tsd;


	if (optt) {
		pthread_t		tid;



		if (pthread_create(&tid, NULL, dummy, NULL) != 0) {
			errors++;
		}
	}

	ts->ts_lock = lock;

	return (errors);
}

void
spinme(int usecs)
{
	long long s = getusecs();

	while (getusecs() - s < usecs)
		;
}

int
benchmark(void *tsd, result_t *res)
{
	tsd_t			*ts = (tsd_t *)tsd;
	int			i;

	for (i = 0; i < lm_optB; i ++) {

		(void) pthread_mutex_lock(ts->ts_lock);
		if (opth)
			spinme(opth);
		(void) pthread_mutex_unlock(ts->ts_lock);

	}

	res->re_count = lm_optB;

	return (0);
}

char *
benchmark_result()
{
	static char		result[256];

	(void) sprintf(result, "%8d", opth);

	return (result);
}