12c28215423293e443469a07ae7011135d058b671Garrett Cooper/*
22c28215423293e443469a07ae7011135d058b671Garrett Cooper * Copyright (c) 2004, Bull S.A..  All rights reserved.
32c28215423293e443469a07ae7011135d058b671Garrett Cooper * Created by: Sebastien Decugis
42c28215423293e443469a07ae7011135d058b671Garrett Cooper
52c28215423293e443469a07ae7011135d058b671Garrett Cooper * This program is free software; you can redistribute it and/or modify it
62c28215423293e443469a07ae7011135d058b671Garrett Cooper * under the terms of version 2 of the GNU General Public License as
72c28215423293e443469a07ae7011135d058b671Garrett Cooper * published by the Free Software Foundation.
82c28215423293e443469a07ae7011135d058b671Garrett Cooper *
92c28215423293e443469a07ae7011135d058b671Garrett Cooper * This program is distributed in the hope that it would be useful, but
102c28215423293e443469a07ae7011135d058b671Garrett Cooper * WITHOUT ANY WARRANTY; without even the implied warranty of
112c28215423293e443469a07ae7011135d058b671Garrett Cooper * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
122c28215423293e443469a07ae7011135d058b671Garrett Cooper *
132c28215423293e443469a07ae7011135d058b671Garrett Cooper * You should have received a copy of the GNU General Public License along
14fed9641096e27f79a0f2d9adfe9839dd8d11dc0fWanlong Gao * with this program; if not, write the Free Software Foundation, Inc.,
15fed9641096e27f79a0f2d9adfe9839dd8d11dc0fWanlong Gao * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
162c28215423293e443469a07ae7011135d058b671Garrett Cooper *
172c28215423293e443469a07ae7011135d058b671Garrett Cooper
182c28215423293e443469a07ae7011135d058b671Garrett Cooper * This file is a scalability test for the pthread_cond_timedwait function.
192c28215423293e443469a07ae7011135d058b671Garrett Cooper *
202c28215423293e443469a07ae7011135d058b671Garrett Cooper * It aims to measure the time between end of timeout and actual wakeup
212c28215423293e443469a07ae7011135d058b671Garrett Cooper * with different factors.
222c28215423293e443469a07ae7011135d058b671Garrett Cooper
232c28215423293e443469a07ae7011135d058b671Garrett Cooper * The steps are:
242c28215423293e443469a07ae7011135d058b671Garrett Cooper * -*- Number of threads waiting on the conditionnal variable
252c28215423293e443469a07ae7011135d058b671Garrett Cooper *     -> for an increaing number of threads,
262c28215423293e443469a07ae7011135d058b671Garrett Cooper *        -> create the other threads which will do a pthread_cond_wait on the same cond/mutex
272c28215423293e443469a07ae7011135d058b671Garrett Cooper *        -> When the threads are waiting, create one thread which will measure the time
282c28215423293e443469a07ae7011135d058b671Garrett Cooper *        -> once the timeout has expired and the measure is done, broadcast the condition.
292c28215423293e443469a07ae7011135d058b671Garrett Cooper *     -> do each measure 10 times (with different attributes i.e.)
302c28215423293e443469a07ae7011135d058b671Garrett Cooper *
312c28215423293e443469a07ae7011135d058b671Garrett Cooper * -*- other possible influencial parameters
322c28215423293e443469a07ae7011135d058b671Garrett Cooper *     -> To be defined.
332c28215423293e443469a07ae7011135d058b671Garrett Cooper */
342c28215423293e443469a07ae7011135d058b671Garrett Cooper
352c28215423293e443469a07ae7011135d058b671Garrett Cooper /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
36354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#define _POSIX_C_SOURCE 200112L
372c28215423293e443469a07ae7011135d058b671Garrett Cooper
38354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifndef WITHOUT_XOPEN
39354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#define _XOPEN_SOURCE 600
40354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
412c28215423293e443469a07ae7011135d058b671Garrett Cooper
422c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
432c28215423293e443469a07ae7011135d058b671Garrett Cooper/****************************** standard includes *****************************************/
442c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
45354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <pthread.h>
46354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <stdarg.h>
47354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <stdio.h>
48354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <stdlib.h>
49354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <unistd.h>
502c28215423293e443469a07ae7011135d058b671Garrett Cooper
51354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <time.h>
52354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <errno.h>
53354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include <math.h>
542c28215423293e443469a07ae7011135d058b671Garrett Cooper
552c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
562c28215423293e443469a07ae7011135d058b671Garrett Cooper/******************************   Test framework   *****************************************/
572c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
58354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include "testfrmw.h"
59354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#include "testfrmw.c"
602c28215423293e443469a07ae7011135d058b671Garrett Cooper /* This header is responsible for defining the following macros:
612c28215423293e443469a07ae7011135d058b671Garrett Cooper  * UNRESOLVED(ret, descr);
622c28215423293e443469a07ae7011135d058b671Garrett Cooper  *    where descr is a description of the error and ret is an int (error code for example)
632c28215423293e443469a07ae7011135d058b671Garrett Cooper  * FAILED(descr);
642c28215423293e443469a07ae7011135d058b671Garrett Cooper  *    where descr is a short text saying why the test has failed.
652c28215423293e443469a07ae7011135d058b671Garrett Cooper  * PASSED();
662c28215423293e443469a07ae7011135d058b671Garrett Cooper  *    No parameter.
672c28215423293e443469a07ae7011135d058b671Garrett Cooper  *
682c28215423293e443469a07ae7011135d058b671Garrett Cooper  * Both three macros shall terminate the calling process.
692c28215423293e443469a07ae7011135d058b671Garrett Cooper  * The testcase shall not terminate in any other maneer.
702c28215423293e443469a07ae7011135d058b671Garrett Cooper  *
712c28215423293e443469a07ae7011135d058b671Garrett Cooper  * The other file defines the functions
722c28215423293e443469a07ae7011135d058b671Garrett Cooper  * void output_init()
732c28215423293e443469a07ae7011135d058b671Garrett Cooper  * void output(char * string, ...)
742c28215423293e443469a07ae7011135d058b671Garrett Cooper  *
752c28215423293e443469a07ae7011135d058b671Garrett Cooper  * Those may be used to output information.
762c28215423293e443469a07ae7011135d058b671Garrett Cooper  */
772c28215423293e443469a07ae7011135d058b671Garrett Cooper
782c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
792c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************** Configuration ******************************************/
802c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
812c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifndef SCALABILITY_FACTOR
822c28215423293e443469a07ae7011135d058b671Garrett Cooper#define SCALABILITY_FACTOR 1
832c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
842c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifndef VERBOSE
852c28215423293e443469a07ae7011135d058b671Garrett Cooper#define VERBOSE 1
862c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
872c28215423293e443469a07ae7011135d058b671Garrett Cooper
882c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifndef WITHOUT_ALTCLK
89354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#define USE_ALTCLK		/* make tests with MONOTONIC CLOCK if supported */
902c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
912c28215423293e443469a07ae7011135d058b671Garrett Cooper
92354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#define MES_TIMEOUT  (1000000)	/* ns, offset for the pthread_cond_timedwait call */
932c28215423293e443469a07ae7011135d058b671Garrett Cooper
942c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifdef PLOT_OUTPUT
952c28215423293e443469a07ae7011135d058b671Garrett Cooper#undef VERBOSE
962c28215423293e443469a07ae7011135d058b671Garrett Cooper#define VERBOSE 0
972c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
982c28215423293e443469a07ae7011135d058b671Garrett Cooper
992c28215423293e443469a07ae7011135d058b671Garrett Cooper// #define USE_CANCEL  /* Will cancel the threads instead of signaling the cond */#define
1002c28215423293e443469a07ae7011135d058b671Garrett Cooper
1012c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
1022c28215423293e443469a07ae7011135d058b671Garrett Cooper/***********************************    Test case   *****************************************/
1032c28215423293e443469a07ae7011135d058b671Garrett Cooper/********************************************************************************************/
1042c28215423293e443469a07ae7011135d058b671Garrett Cooper
1052c28215423293e443469a07ae7011135d058b671Garrett Cooperlong altclk_ok, pshared_ok;
1062c28215423293e443469a07ae7011135d058b671Garrett Cooper
107354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaotypedef struct {
1082c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_cond_t *cnd;
1092c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_mutex_t *mtx;
110354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int *predicate;
111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int *tnum;
1122c28215423293e443469a07ae7011135d058b671Garrett Cooper} test_t;
1132c28215423293e443469a07ae7011135d058b671Garrett Cooper
1142c28215423293e443469a07ae7011135d058b671Garrett Cooperstruct {
1152c28215423293e443469a07ae7011135d058b671Garrett Cooper	int mutex_type;
1162c28215423293e443469a07ae7011135d058b671Garrett Cooper	int pshared;
1172c28215423293e443469a07ae7011135d058b671Garrett Cooper	clockid_t cid;
118354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *desc;
1192c28215423293e443469a07ae7011135d058b671Garrett Cooper} test_scenar[] = {
120354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	{
121354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_DEFAULT, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME,
122354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Default"}
123354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
124354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_DEFAULT, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME,
125354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "PShared"}
1262c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifndef WITHOUT_XOPEN
127354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_NORMAL, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME,
129354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Normal"}
130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_NORMAL, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME,
132354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Normal+PShared"}
133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
134354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_ERRORCHECK, PTHREAD_PROCESS_PRIVATE,
135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_REALTIME, "Errorcheck"}
136354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_ERRORCHECK, PTHREAD_PROCESS_SHARED,
138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_REALTIME, "Errorcheck+PShared"}
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
140354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_RECURSIVE, PTHREAD_PROCESS_PRIVATE,
141354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_REALTIME, "Recursive"}
142354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
143354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_RECURSIVE, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME,
144354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Recursive+PShared"}
1452c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
1462c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifdef USE_ALTCLK
147354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
148354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_DEFAULT, PTHREAD_PROCESS_PRIVATE, CLOCK_MONOTONIC,
149354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Monotonic"}
150354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
151354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_DEFAULT, PTHREAD_PROCESS_SHARED, CLOCK_MONOTONIC,
152354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "PShared+Monotonic"}
1532c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifndef WITHOUT_XOPEN
154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
155354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_NORMAL, PTHREAD_PROCESS_PRIVATE, CLOCK_MONOTONIC,
156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Normal+Monotonic"}
157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
158354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_NORMAL, PTHREAD_PROCESS_SHARED, CLOCK_MONOTONIC,
159354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    "Normal+PShared+Monotonic"}
160354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
161354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_ERRORCHECK, PTHREAD_PROCESS_PRIVATE,
162354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_MONOTONIC, "Errorcheck+Monotonic"}
163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
164354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_ERRORCHECK, PTHREAD_PROCESS_SHARED,
165354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_MONOTONIC, "Errorcheck+PShared+Monotonic"}
166354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
167354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_RECURSIVE, PTHREAD_PROCESS_PRIVATE,
168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_MONOTONIC, "Recursive+Monotonic"}
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	, {
170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	PTHREAD_MUTEX_RECURSIVE, PTHREAD_PROCESS_SHARED,
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    CLOCK_MONOTONIC, "Recursive+PShared+Monotonic"}
1722c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
1732c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
1742c28215423293e443469a07ae7011135d058b671Garrett Cooper};
1752c28215423293e443469a07ae7011135d058b671Garrett Cooper
1762c28215423293e443469a07ae7011135d058b671Garrett Cooper#define NSCENAR (sizeof(test_scenar) / sizeof(test_scenar[0]))
1772c28215423293e443469a07ae7011135d058b671Garrett Cooper
178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaopthread_attr_t ta;
1792c28215423293e443469a07ae7011135d058b671Garrett Cooper
1802c28215423293e443469a07ae7011135d058b671Garrett Cooper/* The next structure is used to save the tests measures */
181354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaotypedef struct __mes_t {
182354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int nthreads;
183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long _data[NSCENAR];	/* As we store µsec values, a long type should be amply enough. */
1842c28215423293e443469a07ae7011135d058b671Garrett Cooper	struct __mes_t *next;
1852c28215423293e443469a07ae7011135d058b671Garrett Cooper} mes_t;
1862c28215423293e443469a07ae7011135d058b671Garrett Cooper
1872c28215423293e443469a07ae7011135d058b671Garrett Cooper/**** do_measure
1882c28215423293e443469a07ae7011135d058b671Garrett Cooper * This function will do a timedwait on the cond cnd after locking mtx.
1892c28215423293e443469a07ae7011135d058b671Garrett Cooper * Once the timedwait times out, it will read the clock cid then
1902c28215423293e443469a07ae7011135d058b671Garrett Cooper * compute the difference and put it into ts.
1912c28215423293e443469a07ae7011135d058b671Garrett Cooper * This function must be called once test is ready, as the timeout will be very short. */
192354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid do_measure(pthread_mutex_t * mtx, pthread_cond_t * cnd, clockid_t cid,
193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		struct timespec *ts)
1942c28215423293e443469a07ae7011135d058b671Garrett Cooper{
1952c28215423293e443469a07ae7011135d058b671Garrett Cooper	int ret, rc;
1962c28215423293e443469a07ae7011135d058b671Garrett Cooper
1972c28215423293e443469a07ae7011135d058b671Garrett Cooper	struct timespec ts_cnd, ts_clk;
1982c28215423293e443469a07ae7011135d058b671Garrett Cooper
1992c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* lock the mutex */
2002c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_mutex_lock(mtx);
201354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
202354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Unable to lock mutex");
203354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2042c28215423293e443469a07ae7011135d058b671Garrett Cooper
2052c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Prepare the timeout parameter */
2062c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = clock_gettime(cid, &ts_cnd);
207354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
208354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(errno, "Unable to read clock");
209354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2102c28215423293e443469a07ae7011135d058b671Garrett Cooper
2112c28215423293e443469a07ae7011135d058b671Garrett Cooper	ts_cnd.tv_nsec += MES_TIMEOUT;
212354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (ts_cnd.tv_nsec >= 1000000000) {
2132c28215423293e443469a07ae7011135d058b671Garrett Cooper		ts_cnd.tv_nsec -= 1000000000;
2142c28215423293e443469a07ae7011135d058b671Garrett Cooper		ts_cnd.tv_sec++;
2152c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
2162c28215423293e443469a07ae7011135d058b671Garrett Cooper
2172c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Do the timedwait */
2182c28215423293e443469a07ae7011135d058b671Garrett Cooper	do {
2192c28215423293e443469a07ae7011135d058b671Garrett Cooper		rc = pthread_cond_timedwait(cnd, mtx, &ts_cnd);
2202c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Re-read the clock as soon as possible */
2212c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = clock_gettime(cid, &ts_clk);
222354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
223354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(errno, "Unable to read clock");
224354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
2252c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
2262c28215423293e443469a07ae7011135d058b671Garrett Cooper	while (rc == 0);
227354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc != ETIMEDOUT) {
228354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(rc,
229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   "Timedwait returned an unexpected error (expected ETIMEDOUT)");
230354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2312c28215423293e443469a07ae7011135d058b671Garrett Cooper
2322c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Compute the difference time */
2332c28215423293e443469a07ae7011135d058b671Garrett Cooper	ts->tv_sec = ts_clk.tv_sec - ts_cnd.tv_sec;
2342c28215423293e443469a07ae7011135d058b671Garrett Cooper	ts->tv_nsec = ts_clk.tv_nsec - ts_cnd.tv_nsec;
235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ts->tv_nsec < 0) {
2362c28215423293e443469a07ae7011135d058b671Garrett Cooper		ts->tv_nsec += 1000000000;
2372c28215423293e443469a07ae7011135d058b671Garrett Cooper		ts->tv_sec -= 1;
2382c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
2392c28215423293e443469a07ae7011135d058b671Garrett Cooper
240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ts->tv_sec < 0) {
241354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		FAILED
242354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("The function returned from wait with a timeout before the time has passed\n");
2432c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
2442c28215423293e443469a07ae7011135d058b671Garrett Cooper
2452c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* unlock the mutex */
2462c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_mutex_unlock(mtx);
247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Unable to unlock mutex");
249354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2502c28215423293e443469a07ae7011135d058b671Garrett Cooper
2512c28215423293e443469a07ae7011135d058b671Garrett Cooper	return;
2522c28215423293e443469a07ae7011135d058b671Garrett Cooper}
2532c28215423293e443469a07ae7011135d058b671Garrett Cooper
254354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid *waiter(void *arg)
2552c28215423293e443469a07ae7011135d058b671Garrett Cooper{
256354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	test_t *dt = (test_t *) arg;
2572c28215423293e443469a07ae7011135d058b671Garrett Cooper
2582c28215423293e443469a07ae7011135d058b671Garrett Cooper	int ret;
2592c28215423293e443469a07ae7011135d058b671Garrett Cooper
2602c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_mutex_lock(dt->mtx);
261354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
262354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Mutex lock failed in waiter");
263354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2642c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifdef USE_CANCEL
2652c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)(dt->mtx));
2662c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
2672c28215423293e443469a07ae7011135d058b671Garrett Cooper
2682c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* This thread is ready to wait */
2692c28215423293e443469a07ae7011135d058b671Garrett Cooper	*(dt->tnum) += 1;
2702c28215423293e443469a07ae7011135d058b671Garrett Cooper
271354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
272354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		ret = pthread_cond_wait(dt->cnd, dt->mtx);
273354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2742c28215423293e443469a07ae7011135d058b671Garrett Cooper	while ((ret == 0) && (*(dt->predicate) == 0));
275354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
276354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "pthread_cond_wait failed in waiter");
277354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2782c28215423293e443469a07ae7011135d058b671Garrett Cooper#ifdef USE_CANCEL
279354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	pthread_cleanup_pop(0);	/* We could put 1 and avoid the next line, but we would miss the return code */
2802c28215423293e443469a07ae7011135d058b671Garrett Cooper#endif
2812c28215423293e443469a07ae7011135d058b671Garrett Cooper
2822c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_mutex_unlock(dt->mtx);
283354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
284354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Mutex unlock failed in waiter");
285354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
2862c28215423293e443469a07ae7011135d058b671Garrett Cooper
2872c28215423293e443469a07ae7011135d058b671Garrett Cooper	return NULL;
2882c28215423293e443469a07ae7011135d058b671Garrett Cooper}
2892c28215423293e443469a07ae7011135d058b671Garrett Cooper
2902c28215423293e443469a07ae7011135d058b671Garrett Cooper/**** do_threads_test
2912c28215423293e443469a07ae7011135d058b671Garrett Cooper * This function is responsible for all the testing with a given # of threads
2922c28215423293e443469a07ae7011135d058b671Garrett Cooper *  nthreads is the amount of threads to create.
2932c28215423293e443469a07ae7011135d058b671Garrett Cooper * the return value is:
2942c28215423293e443469a07ae7011135d058b671Garrett Cooper *  < 0 if function was not able to create enough threads.
2952c28215423293e443469a07ae7011135d058b671Garrett Cooper *  cumulated # of nanoseconds otherwise.
2962c28215423293e443469a07ae7011135d058b671Garrett Cooper */
2972c28215423293e443469a07ae7011135d058b671Garrett Cooperlong do_threads_test(int nthreads, mes_t * measure)
2982c28215423293e443469a07ae7011135d058b671Garrett Cooper{
2992c28215423293e443469a07ae7011135d058b671Garrett Cooper	int ret;
3002c28215423293e443469a07ae7011135d058b671Garrett Cooper
3012c28215423293e443469a07ae7011135d058b671Garrett Cooper	int scal, i, j;
3022c28215423293e443469a07ae7011135d058b671Garrett Cooper
3032c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_t *th;
3042c28215423293e443469a07ae7011135d058b671Garrett Cooper
3052c28215423293e443469a07ae7011135d058b671Garrett Cooper	int s;
3062c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_mutexattr_t ma;
3072c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_condattr_t ca;
3082c28215423293e443469a07ae7011135d058b671Garrett Cooper
3092c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_cond_t cnd;
3102c28215423293e443469a07ae7011135d058b671Garrett Cooper	pthread_mutex_t mtx;
3112c28215423293e443469a07ae7011135d058b671Garrett Cooper	int predicate;
3122c28215423293e443469a07ae7011135d058b671Garrett Cooper	int tnum;
3132c28215423293e443469a07ae7011135d058b671Garrett Cooper
3142c28215423293e443469a07ae7011135d058b671Garrett Cooper	test_t td;
3152c28215423293e443469a07ae7011135d058b671Garrett Cooper
3162c28215423293e443469a07ae7011135d058b671Garrett Cooper	struct timespec ts, ts_cumul;
3172c28215423293e443469a07ae7011135d058b671Garrett Cooper
3182c28215423293e443469a07ae7011135d058b671Garrett Cooper	td.mtx = &mtx;
3192c28215423293e443469a07ae7011135d058b671Garrett Cooper	td.cnd = &cnd;
3202c28215423293e443469a07ae7011135d058b671Garrett Cooper	td.predicate = &predicate;
3212c28215423293e443469a07ae7011135d058b671Garrett Cooper	td.tnum = &tnum;
3222c28215423293e443469a07ae7011135d058b671Garrett Cooper
3232c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Allocate space for the threads structures */
324354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	th = (pthread_t *) calloc(nthreads, sizeof(pthread_t));
325354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (th == NULL) {
326354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(errno, "Not enough memory for thread storage");
327354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
328354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef PLOT_OUTPUT
3292c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("%d", nthreads);
330354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
3312c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* For each test scenario (mutex and cond attributes) */
332354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (s = 0; s < NSCENAR; s++) {
3332c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Initialize the attributes */
3342c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = pthread_mutexattr_init(&ma);
335354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
336354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(ret,
337354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				   "Unable to initialize mutex attribute object");
338354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
3392c28215423293e443469a07ae7011135d058b671Garrett Cooper
3402c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = pthread_condattr_init(&ca);
341354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
342354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(ret,
343354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				   "Unable to initialize cond attribute object");
344354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
3452c28215423293e443469a07ae7011135d058b671Garrett Cooper
3462c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Set the attributes according to the scenar and the impl capabilities */
3472c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = pthread_mutexattr_settype(&ma, test_scenar[s].mutex_type);
348354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
349354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(ret, "Unable to set mutex type");
350354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
3512c28215423293e443469a07ae7011135d058b671Garrett Cooper
352354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (pshared_ok > 0) {
353354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			ret =
354354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    pthread_mutexattr_setpshared(&ma,
355354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							 test_scenar[s].
356354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							 pshared);
357354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
358354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret,
359354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   "Unable to set mutex process-shared");
360354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
3612c28215423293e443469a07ae7011135d058b671Garrett Cooper
362354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			ret =
363354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    pthread_condattr_setpshared(&ca,
364354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							test_scenar[s].pshared);
365354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
366354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret,
367354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   "Unable to set cond process-shared");
368354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
3692c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
370354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef USE_ALTCLK
371354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (altclk_ok > 0) {
372354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			ret =
373354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    pthread_condattr_setclock(&ca, test_scenar[s].cid);
374354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
375354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Unable to set clock for cond");
376354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
3772c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
378354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
3792c28215423293e443469a07ae7011135d058b671Garrett Cooper
380354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		ts_cumul.tv_sec = 0;
381354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		ts_cumul.tv_nsec = 0;
3822c28215423293e443469a07ae7011135d058b671Garrett Cooper
383354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
3842c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("Starting case %s\n", test_scenar[s].desc);
385354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
3862c28215423293e443469a07ae7011135d058b671Garrett Cooper
387354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		for (scal = 0; scal < 5 * SCALABILITY_FACTOR; scal++) {
3882c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* Initialize the mutex, the cond, and other data */
3892c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_mutex_init(&mtx, &ma);
390354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
391354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Mutex init failed");
392354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
3932c28215423293e443469a07ae7011135d058b671Garrett Cooper
3942c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_cond_init(&cnd, &ca);
395354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
396354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Cond init failed");
397354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
3982c28215423293e443469a07ae7011135d058b671Garrett Cooper
3992c28215423293e443469a07ae7011135d058b671Garrett Cooper			predicate = 0;
4002c28215423293e443469a07ae7011135d058b671Garrett Cooper			tnum = 0;
4012c28215423293e443469a07ae7011135d058b671Garrett Cooper
4022c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* Create the waiter threads */
403354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			for (i = 0; i < nthreads; i++) {
404354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				ret =
405354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				    pthread_create(&th[i], &ta, waiter,
406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						   (void *)&td);
407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (ret != 0) {	/* We reached the limits */
408354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
409354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					output
410354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					    ("Limit reached with %i threads\n",
411354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					     i);
412354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
413354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef USE_CANCEL
414354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					for (j = i - 1; j >= 0; j--) {
4152c28215423293e443469a07ae7011135d058b671Garrett Cooper						ret = pthread_cancel(th[j]);
416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (ret != 0) {
417354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							UNRESOLVED(ret,
418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								   "Unable to cancel a thread");
419354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						}
4202c28215423293e443469a07ae7011135d058b671Garrett Cooper					}
421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#else
4222c28215423293e443469a07ae7011135d058b671Garrett Cooper					predicate = 1;
4232c28215423293e443469a07ae7011135d058b671Garrett Cooper					ret = pthread_cond_broadcast(&cnd);
424354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					if (ret != 0) {
425354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						UNRESOLVED(ret,
426354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							   "Unable to broadcast the condition");
427354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					}
428354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
429354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					for (j = i - 1; j >= 0; j--) {
4302c28215423293e443469a07ae7011135d058b671Garrett Cooper						ret = pthread_join(th[j], NULL);
431354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						if (ret != 0) {
432354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao							UNRESOLVED(ret,
433354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao								   "Unable to join a canceled thread");
434354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						}
4352c28215423293e443469a07ae7011135d058b671Garrett Cooper					}
4362c28215423293e443469a07ae7011135d058b671Garrett Cooper					free(th);
4372c28215423293e443469a07ae7011135d058b671Garrett Cooper					return -1;
4382c28215423293e443469a07ae7011135d058b671Garrett Cooper				}
4392c28215423293e443469a07ae7011135d058b671Garrett Cooper			}
4402c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* All waiter threads are created now */
441354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 5
4422c28215423293e443469a07ae7011135d058b671Garrett Cooper			output("%i waiter threads created successfully\n", i);
443354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
4442c28215423293e443469a07ae7011135d058b671Garrett Cooper
4452c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_mutex_lock(&mtx);
446354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
447354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Unable to lock mutex");
448354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
4492c28215423293e443469a07ae7011135d058b671Garrett Cooper
4502c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* Wait for all threads be waiting */
451354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			while (tnum < nthreads) {
4522c28215423293e443469a07ae7011135d058b671Garrett Cooper				ret = pthread_mutex_unlock(&mtx);
453354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (ret != 0) {
454354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					UNRESOLVED(ret, "Mutex unlock failed");
455354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
4562c28215423293e443469a07ae7011135d058b671Garrett Cooper
4572c28215423293e443469a07ae7011135d058b671Garrett Cooper				sched_yield();
4582c28215423293e443469a07ae7011135d058b671Garrett Cooper
4592c28215423293e443469a07ae7011135d058b671Garrett Cooper				ret = pthread_mutex_lock(&mtx);
460354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (ret != 0) {
461354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					UNRESOLVED(ret, "Mutex lock failed");
462354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
4632c28215423293e443469a07ae7011135d058b671Garrett Cooper			}
4642c28215423293e443469a07ae7011135d058b671Garrett Cooper
4652c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* All threads are now waiting - we do the measure */
4662c28215423293e443469a07ae7011135d058b671Garrett Cooper
4672c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_mutex_unlock(&mtx);
468354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
469354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Mutex unlock failed");
470354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
471354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 5
472354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			output("%i waiter threads are waiting; start measure\n",
473354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       tnum);
474354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
4752c28215423293e443469a07ae7011135d058b671Garrett Cooper
4762c28215423293e443469a07ae7011135d058b671Garrett Cooper			do_measure(&mtx, &cnd, test_scenar[s].cid, &ts);
4772c28215423293e443469a07ae7011135d058b671Garrett Cooper
478354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 5
479354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			output("Measure for %s returned %d.%09d\n",
480354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			       test_scenar[s].desc, ts.tv_sec, ts.tv_nsec);
481354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
4822c28215423293e443469a07ae7011135d058b671Garrett Cooper
4832c28215423293e443469a07ae7011135d058b671Garrett Cooper			ts_cumul.tv_sec += ts.tv_sec;
4842c28215423293e443469a07ae7011135d058b671Garrett Cooper			ts_cumul.tv_nsec += ts.tv_nsec;
485354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ts_cumul.tv_nsec >= 1000000000) {
4862c28215423293e443469a07ae7011135d058b671Garrett Cooper				ts_cumul.tv_nsec -= 1000000000;
4872c28215423293e443469a07ae7011135d058b671Garrett Cooper				ts_cumul.tv_sec += 1;
4882c28215423293e443469a07ae7011135d058b671Garrett Cooper			}
4892c28215423293e443469a07ae7011135d058b671Garrett Cooper
4902c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* We can release the threads */
4912c28215423293e443469a07ae7011135d058b671Garrett Cooper			predicate = 1;
4922c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_cond_broadcast(&cnd);
493354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
494354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret,
495354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   "Unable to broadcast the condition");
496354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
497354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 5
4982c28215423293e443469a07ae7011135d058b671Garrett Cooper			output("Joining the waiters...\n");
499354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5002c28215423293e443469a07ae7011135d058b671Garrett Cooper
5012c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* We will join every threads */
502354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			for (i = 0; i < nthreads; i++) {
5032c28215423293e443469a07ae7011135d058b671Garrett Cooper				ret = pthread_join(th[i], NULL);
504354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (ret != 0) {
505354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					UNRESOLVED(ret,
506354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						   "Unable to join a thread");
507354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				}
5082c28215423293e443469a07ae7011135d058b671Garrett Cooper
5092c28215423293e443469a07ae7011135d058b671Garrett Cooper			}
5102c28215423293e443469a07ae7011135d058b671Garrett Cooper
5112c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* Destroy everything */
5122c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_mutex_destroy(&mtx);
513354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
514354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Unable to destroy mutex");
515354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
5162c28215423293e443469a07ae7011135d058b671Garrett Cooper
5172c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret = pthread_cond_destroy(&cnd);
518354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (ret != 0) {
519354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				UNRESOLVED(ret, "Unable to destroy cond");
520354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
5212c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
5222c28215423293e443469a07ae7011135d058b671Garrett Cooper
523354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef PLOT_OUTPUT
5242c28215423293e443469a07ae7011135d058b671Garrett Cooper		output(" %d.%09d", ts_cumul.tv_sec, ts_cumul.tv_nsec);
525354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5262c28215423293e443469a07ae7011135d058b671Garrett Cooper
527354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		measure->_data[s] = ts_cumul.tv_sec * 1000000 + (ts_cumul.tv_nsec / 1000);	/* We reduce precision */
5282c28215423293e443469a07ae7011135d058b671Garrett Cooper
5292c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Destroy the mutex attributes */
5302c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = pthread_mutexattr_destroy(&ma);
531354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
532354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(ret, "Unable to destroy mutex attribute");
533354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
5342c28215423293e443469a07ae7011135d058b671Garrett Cooper
5352c28215423293e443469a07ae7011135d058b671Garrett Cooper		ret = pthread_condattr_destroy(&ca);
536354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (ret != 0) {
537354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(ret, "Unable to destroy cond attribute");
538354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
5392c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
5402c28215423293e443469a07ae7011135d058b671Garrett Cooper
5412c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Free the memory */
5422c28215423293e443469a07ae7011135d058b671Garrett Cooper	free(th);
5432c28215423293e443469a07ae7011135d058b671Garrett Cooper
544354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 2
545354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	output("%5d threads; %d.%09d s (%i loops)\n", nthreads, ts_cumul.tv_sec,
546354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	       ts_cumul.tv_nsec, scal);
547354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5482c28215423293e443469a07ae7011135d058b671Garrett Cooper
549354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef PLOT_OUTPUT
5502c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("\n");
551354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5522c28215423293e443469a07ae7011135d058b671Garrett Cooper
5532c28215423293e443469a07ae7011135d058b671Garrett Cooper	return ts_cumul.tv_sec * 1000000000 + ts_cumul.tv_nsec;
5542c28215423293e443469a07ae7011135d058b671Garrett Cooper}
5552c28215423293e443469a07ae7011135d058b671Garrett Cooper
5562c28215423293e443469a07ae7011135d058b671Garrett Cooper/* Forward declaration */
5572c28215423293e443469a07ae7011135d058b671Garrett Cooperint parse_measure(mes_t * measures);
5582c28215423293e443469a07ae7011135d058b671Garrett Cooper
5592c28215423293e443469a07ae7011135d058b671Garrett Cooper/* Main
5602c28215423293e443469a07ae7011135d058b671Garrett Cooper */
561354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint main(int argc, char *argv[])
5622c28215423293e443469a07ae7011135d058b671Garrett Cooper{
5632c28215423293e443469a07ae7011135d058b671Garrett Cooper	int ret, nth;
5642c28215423293e443469a07ae7011135d058b671Garrett Cooper	long dur;
5652c28215423293e443469a07ae7011135d058b671Garrett Cooper
5662c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Initialize the measure list */
5672c28215423293e443469a07ae7011135d058b671Garrett Cooper	mes_t sentinel;
5682c28215423293e443469a07ae7011135d058b671Garrett Cooper	mes_t *m_cur, *m_tmp;
5692c28215423293e443469a07ae7011135d058b671Garrett Cooper	m_cur = &sentinel;
5702c28215423293e443469a07ae7011135d058b671Garrett Cooper	m_cur->next = NULL;
5712c28215423293e443469a07ae7011135d058b671Garrett Cooper
5722c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Initialize the output */
5732c28215423293e443469a07ae7011135d058b671Garrett Cooper	output_init();
5742c28215423293e443469a07ae7011135d058b671Garrett Cooper
5752c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Test machine capabilities */
5762c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* -> clockid_t; pshared; ... */
5772c28215423293e443469a07ae7011135d058b671Garrett Cooper	altclk_ok = sysconf(_SC_CLOCK_SELECTION);
5782c28215423293e443469a07ae7011135d058b671Garrett Cooper	if (altclk_ok > 0)
5792c28215423293e443469a07ae7011135d058b671Garrett Cooper		altclk_ok = sysconf(_SC_MONOTONIC_CLOCK);
580354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifndef USE_ALTCLK
5812c28215423293e443469a07ae7011135d058b671Garrett Cooper	if (altclk_ok > 0)
582354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		output
583354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n");
584354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5852c28215423293e443469a07ae7011135d058b671Garrett Cooper
5862c28215423293e443469a07ae7011135d058b671Garrett Cooper	pshared_ok = sysconf(_SC_THREAD_PROCESS_SHARED);
5872c28215423293e443469a07ae7011135d058b671Garrett Cooper
588354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 0
5892c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("Test starting\n");
590354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	output(" Process-shared primitive %s be tested\n",
591354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	       (pshared_ok > 0) ? "will" : "won't");
592354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	output(" Alternative clock for cond %s be tested\n",
593354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	       (altclk_ok > 0) ? "will" : "won't");
594354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
5952c28215423293e443469a07ae7011135d058b671Garrett Cooper
5962c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Prepare thread attribute */
5972c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_attr_init(&ta);
598354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
599354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Unable to initialize thread attributes");
600354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
6012c28215423293e443469a07ae7011135d058b671Garrett Cooper
6022c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = pthread_attr_setstacksize(&ta, sysconf(_SC_THREAD_STACK_MIN));
603354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
604354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(ret, "Unable to set stack size to minimum value");
605354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
606354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#ifdef PLOT_OUTPUT
6072c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("# COLUMNS %d #threads", NSCENAR + 1);
608354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (nth = 0; nth < NSCENAR; nth++)
6092c28215423293e443469a07ae7011135d058b671Garrett Cooper		output(" %s", test_scenar[nth].desc);
6102c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("\n");
611354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
6122c28215423293e443469a07ae7011135d058b671Garrett Cooper
6132c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Do the testing */
6142c28215423293e443469a07ae7011135d058b671Garrett Cooper	nth = 0;
615354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
6162c28215423293e443469a07ae7011135d058b671Garrett Cooper		nth += 100 * SCALABILITY_FACTOR;
6172c28215423293e443469a07ae7011135d058b671Garrett Cooper
6182c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Create a new measure item */
619d218f348c12b42a78fa0306d9a033bfa4f67238bCyril Hrubis		m_tmp = malloc(sizeof(mes_t));
620354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (m_tmp == NULL) {
621354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			UNRESOLVED(errno,
622354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				   "Unable to alloc memory for measure saving");
623354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
6242c28215423293e443469a07ae7011135d058b671Garrett Cooper		m_tmp->nthreads = nth;
6252c28215423293e443469a07ae7011135d058b671Garrett Cooper		m_tmp->next = NULL;
6262c28215423293e443469a07ae7011135d058b671Garrett Cooper
6272c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Run the test */
6282c28215423293e443469a07ae7011135d058b671Garrett Cooper		dur = do_threads_test(nth, m_tmp);
6292c28215423293e443469a07ae7011135d058b671Garrett Cooper
6302c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* If test was success, add this measure to the list. Otherwise, free the mem */
631354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (dur >= 0) {
6322c28215423293e443469a07ae7011135d058b671Garrett Cooper			m_cur->next = m_tmp;
6332c28215423293e443469a07ae7011135d058b671Garrett Cooper			m_cur = m_tmp;
634354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
6352c28215423293e443469a07ae7011135d058b671Garrett Cooper			free(m_tmp);
6362c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
6372c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
6382c28215423293e443469a07ae7011135d058b671Garrett Cooper	while (dur >= 0);
6392c28215423293e443469a07ae7011135d058b671Garrett Cooper
6402c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We will now parse the results to determine if the measure is ~ constant or is growing. */
6412c28215423293e443469a07ae7011135d058b671Garrett Cooper
6422c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = parse_measure(&sentinel);
6432c28215423293e443469a07ae7011135d058b671Garrett Cooper
6442c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Free the memory from the list */
6452c28215423293e443469a07ae7011135d058b671Garrett Cooper	m_cur = sentinel.next;
646354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (m_cur != NULL) {
6472c28215423293e443469a07ae7011135d058b671Garrett Cooper		m_tmp = m_cur;
6482c28215423293e443469a07ae7011135d058b671Garrett Cooper		m_cur = m_tmp->next;
6492c28215423293e443469a07ae7011135d058b671Garrett Cooper		free(m_tmp);
6502c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
6512c28215423293e443469a07ae7011135d058b671Garrett Cooper
652354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ret != 0) {
6532c28215423293e443469a07ae7011135d058b671Garrett Cooper		FAILED("This function is not scalable");
6542c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
655354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 0
6562c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("The function is scalable\n");
657354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
6582c28215423293e443469a07ae7011135d058b671Garrett Cooper
6592c28215423293e443469a07ae7011135d058b671Garrett Cooper	PASSED;
6602c28215423293e443469a07ae7011135d058b671Garrett Cooper}
6612c28215423293e443469a07ae7011135d058b671Garrett Cooper
6622c28215423293e443469a07ae7011135d058b671Garrett Cooper/***
6632c28215423293e443469a07ae7011135d058b671Garrett Cooper * The next function will seek for the better model for each series of measurements.
6642c28215423293e443469a07ae7011135d058b671Garrett Cooper *
6652c28215423293e443469a07ae7011135d058b671Garrett Cooper * The tested models are: -- X = # threads; Y = latency
6662c28215423293e443469a07ae7011135d058b671Garrett Cooper * -> Y = a;      -- Error is r1 = avg((Y - Yavg)²);
6672c28215423293e443469a07ae7011135d058b671Garrett Cooper * -> Y = aX + b; -- Error is r2 = avg((Y -aX -b)²);
6682c28215423293e443469a07ae7011135d058b671Garrett Cooper *                -- where a = avg ((X - Xavg)(Y - Yavg)) / avg((X - Xavg)²)
6692c28215423293e443469a07ae7011135d058b671Garrett Cooper *                --         Note: We will call _q = sum((X - Xavg) * (Y - Yavg));
6702c28215423293e443469a07ae7011135d058b671Garrett Cooper *                --                       and  _d = sum((X - Xavg)²);
6712c28215423293e443469a07ae7011135d058b671Garrett Cooper *                -- and   b = Yavg - a * Xavg
6722c28215423293e443469a07ae7011135d058b671Garrett Cooper * -> Y = c * X^a;-- Same as previous, but with log(Y) = a log(X) + b; and b = log(c). Error is r3
6732c28215423293e443469a07ae7011135d058b671Garrett Cooper * -> Y = exp(aX + b); -- log(Y) = aX + b. Error is r4
6742c28215423293e443469a07ae7011135d058b671Garrett Cooper *
6752c28215423293e443469a07ae7011135d058b671Garrett Cooper * We compute each error factor (r1, r2, r3, r4) then search which is the smallest (with ponderation).
6762c28215423293e443469a07ae7011135d058b671Garrett Cooper * The function returns 0 when r1 is the best for all cases (latency is constant) and !0 otherwise.
6772c28215423293e443469a07ae7011135d058b671Garrett Cooper */
6782c28215423293e443469a07ae7011135d058b671Garrett Cooper
679354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostruct row {
680354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long X;			/* the X values -- copied from function argument */
681354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long Y[NSCENAR];	/* the Y values -- copied from function argument */
682354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long _x;		/* Value X - Xavg */
683354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long _y[NSCENAR];	/* Value Y - Yavg */
684354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double LnX;		/* Natural logarithm of X values */
685354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double LnY[NSCENAR];	/* Natural logarithm of Y values */
686354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double _lnx;		/* Value LnX - LnXavg */
687354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double _lny[NSCENAR];	/* Value LnY - LnYavg */
6882c28215423293e443469a07ae7011135d058b671Garrett Cooper};
6892c28215423293e443469a07ae7011135d058b671Garrett Cooper
6902c28215423293e443469a07ae7011135d058b671Garrett Cooperint parse_measure(mes_t * measures)
6912c28215423293e443469a07ae7011135d058b671Garrett Cooper{
6922c28215423293e443469a07ae7011135d058b671Garrett Cooper	int ret, i, r;
6932c28215423293e443469a07ae7011135d058b671Garrett Cooper
6942c28215423293e443469a07ae7011135d058b671Garrett Cooper	mes_t *cur;
6952c28215423293e443469a07ae7011135d058b671Garrett Cooper
6962c28215423293e443469a07ae7011135d058b671Garrett Cooper	double Xavg, Yavg[NSCENAR];
6972c28215423293e443469a07ae7011135d058b671Garrett Cooper	double LnXavg, LnYavg[NSCENAR];
6982c28215423293e443469a07ae7011135d058b671Garrett Cooper
6992c28215423293e443469a07ae7011135d058b671Garrett Cooper	int N;
7002c28215423293e443469a07ae7011135d058b671Garrett Cooper
7012c28215423293e443469a07ae7011135d058b671Garrett Cooper	double r1[NSCENAR], r2[NSCENAR], r3[NSCENAR], r4[NSCENAR];
7022c28215423293e443469a07ae7011135d058b671Garrett Cooper
7032c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Some more intermediate vars */
7042c28215423293e443469a07ae7011135d058b671Garrett Cooper	long double _q[3][NSCENAR];
7052c28215423293e443469a07ae7011135d058b671Garrett Cooper	long double _d[3][NSCENAR];
7062c28215423293e443469a07ae7011135d058b671Garrett Cooper
707354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	long double t;		/* temp value */
7082c28215423293e443469a07ae7011135d058b671Garrett Cooper
7092c28215423293e443469a07ae7011135d058b671Garrett Cooper	struct row *Table = NULL;
7102c28215423293e443469a07ae7011135d058b671Garrett Cooper
7112c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Initialize the datas */
7122c28215423293e443469a07ae7011135d058b671Garrett Cooper	Xavg = 0.0;
7132c28215423293e443469a07ae7011135d058b671Garrett Cooper	LnXavg = 0.0;
714354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (i = 0; i < NSCENAR; i++) {
7152c28215423293e443469a07ae7011135d058b671Garrett Cooper		Yavg[i] = 0.0;
7162c28215423293e443469a07ae7011135d058b671Garrett Cooper		LnYavg[i] = 0.0;
7172c28215423293e443469a07ae7011135d058b671Garrett Cooper		r1[i] = 0.0;
7182c28215423293e443469a07ae7011135d058b671Garrett Cooper		r2[i] = 0.0;
7192c28215423293e443469a07ae7011135d058b671Garrett Cooper		r3[i] = 0.0;
7202c28215423293e443469a07ae7011135d058b671Garrett Cooper		r4[i] = 0.0;
721354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_q[0][i] = 0.0;
722354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_q[1][i] = 0.0;
723354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_q[2][i] = 0.0;
724354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_d[0][i] = 0.0;
725354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_d[1][i] = 0.0;
726354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		_d[2][i] = 0.0;
7272c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
728354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	N = 0;
7292c28215423293e443469a07ae7011135d058b671Garrett Cooper	cur = measures;
7302c28215423293e443469a07ae7011135d058b671Garrett Cooper
731354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
7322c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("Data analysis starting\n");
733354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
7342c28215423293e443469a07ae7011135d058b671Garrett Cooper
7352c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We start with reading the list to find:
7362c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * -> number of elements, to assign an array
7372c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * -> average values
7382c28215423293e443469a07ae7011135d058b671Garrett Cooper	 */
739354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (cur->next != NULL) {
7402c28215423293e443469a07ae7011135d058b671Garrett Cooper		cur = cur->next;
7412c28215423293e443469a07ae7011135d058b671Garrett Cooper
7422c28215423293e443469a07ae7011135d058b671Garrett Cooper		N++;
7432c28215423293e443469a07ae7011135d058b671Garrett Cooper
744354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		Xavg += (double)cur->nthreads;
745354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		LnXavg += log((double)cur->nthreads);
7462c28215423293e443469a07ae7011135d058b671Garrett Cooper
747354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		for (i = 0; i < NSCENAR; i++) {
748354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			Yavg[i] += (double)cur->_data[i];
749354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			LnYavg[i] += log((double)cur->_data[i]);
7502c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
7512c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
7522c28215423293e443469a07ae7011135d058b671Garrett Cooper
7532c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We have the sum; we can divide to obtain the average values */
7542c28215423293e443469a07ae7011135d058b671Garrett Cooper	Xavg /= N;
7552c28215423293e443469a07ae7011135d058b671Garrett Cooper	LnXavg /= N;
7562c28215423293e443469a07ae7011135d058b671Garrett Cooper
757354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (i = 0; i < NSCENAR; i++) {
7582c28215423293e443469a07ae7011135d058b671Garrett Cooper		Yavg[i] /= N;
7592c28215423293e443469a07ae7011135d058b671Garrett Cooper		LnYavg[i] /= N;
7602c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
7612c28215423293e443469a07ae7011135d058b671Garrett Cooper
762354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
7632c28215423293e443469a07ae7011135d058b671Garrett Cooper	output(" Found %d rows and %d columns\n", N, NSCENAR);
764354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
7652c28215423293e443469a07ae7011135d058b671Garrett Cooper
7662c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We will now alloc the array ... */
7672c28215423293e443469a07ae7011135d058b671Garrett Cooper	Table = calloc(N, sizeof(struct row));
768354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (Table == NULL) {
769354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		UNRESOLVED(errno, "Unable to alloc space for results parsing");
770354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
7712c28215423293e443469a07ae7011135d058b671Garrett Cooper
7722c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* ... and fill it */
7732c28215423293e443469a07ae7011135d058b671Garrett Cooper	N = 0;
7742c28215423293e443469a07ae7011135d058b671Garrett Cooper	cur = measures;
7752c28215423293e443469a07ae7011135d058b671Garrett Cooper
776354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while (cur->next != NULL) {
7772c28215423293e443469a07ae7011135d058b671Garrett Cooper		cur = cur->next;
7782c28215423293e443469a07ae7011135d058b671Garrett Cooper
779354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		Table[N].X = (long)cur->nthreads;
780354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		Table[N]._x = Table[N].X - Xavg;
781354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		Table[N].LnX = log((double)cur->nthreads);
7822c28215423293e443469a07ae7011135d058b671Garrett Cooper		Table[N]._lnx = Table[N].LnX - LnXavg;
783354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		for (i = 0; i < NSCENAR; i++) {
7842c28215423293e443469a07ae7011135d058b671Garrett Cooper			Table[N].Y[i] = cur->_data[i];
785354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			Table[N]._y[i] = Table[N].Y[i] - Yavg[i];
786354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			Table[N].LnY[i] = log((double)cur->_data[i]);
7872c28215423293e443469a07ae7011135d058b671Garrett Cooper			Table[N]._lny[i] = Table[N].LnY[i] - LnYavg[i];
7882c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
7892c28215423293e443469a07ae7011135d058b671Garrett Cooper
7902c28215423293e443469a07ae7011135d058b671Garrett Cooper		N++;
7912c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
7922c28215423293e443469a07ae7011135d058b671Garrett Cooper
7932c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We won't need the list anymore -- we'll work with the array which should be faster. */
794354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
7952c28215423293e443469a07ae7011135d058b671Garrett Cooper	output(" Data was stored in an array.\n");
796354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
7972c28215423293e443469a07ae7011135d058b671Garrett Cooper
7982c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We need to read the full array at least twice to compute all the error factors */
7992c28215423293e443469a07ae7011135d058b671Garrett Cooper
8002c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* In the first pass, we'll compute:
8012c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * -> r1 for each scenar.
8022c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * -> "a" factor for linear (0), power (1) and exponential (2) approximations -- with using the _d and _q vars.
8032c28215423293e443469a07ae7011135d058b671Garrett Cooper	 */
804354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
8052c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("Starting first pass...\n");
806354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
807354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (r = 0; r < N; r++) {
808354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		for (i = 0; i < NSCENAR; i++) {
809354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			r1[i] +=
810354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    ((double)Table[r]._y[i] / N) *
811354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    (double)Table[r]._y[i];
8122c28215423293e443469a07ae7011135d058b671Garrett Cooper
8132c28215423293e443469a07ae7011135d058b671Garrett Cooper			_q[0][i] += Table[r]._y[i] * Table[r]._x;
8142c28215423293e443469a07ae7011135d058b671Garrett Cooper			_d[0][i] += Table[r]._x * Table[r]._x;
8152c28215423293e443469a07ae7011135d058b671Garrett Cooper
8162c28215423293e443469a07ae7011135d058b671Garrett Cooper			_q[1][i] += Table[r]._lny[i] * Table[r]._lnx;
8172c28215423293e443469a07ae7011135d058b671Garrett Cooper			_d[1][i] += Table[r]._lnx * Table[r]._lnx;
8182c28215423293e443469a07ae7011135d058b671Garrett Cooper
8192c28215423293e443469a07ae7011135d058b671Garrett Cooper			_q[2][i] += Table[r]._lny[i] * Table[r]._x;
8202c28215423293e443469a07ae7011135d058b671Garrett Cooper			_d[2][i] += Table[r]._x * Table[r]._x;
8212c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
8222c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
8232c28215423293e443469a07ae7011135d058b671Garrett Cooper
8242c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* First pass is terminated; a2 = _q[0]/_d[0]; a3 = _q[1]/_d[1]; a4 = _q[2]/_d[2] */
8252c28215423293e443469a07ae7011135d058b671Garrett Cooper
8262c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* In the first pass, we'll compute:
8272c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * -> r2, r3, r4 for each scenar.
8282c28215423293e443469a07ae7011135d058b671Garrett Cooper	 */
8292c28215423293e443469a07ae7011135d058b671Garrett Cooper
830354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
8312c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("Starting second pass...\n");
832354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
833354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (r = 0; r < N; r++) {
834354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		for (i = 0; i < NSCENAR; i++) {
8352c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* r2 = avg((y - ax -b)²);  t = (y - ax - b) = (y - yavg) - a (x - xavg); */
836354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			t = (Table[r]._y[i] -
837354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			     ((_q[0][i] * Table[r]._x) / _d[0][i]));
838354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			r2[i] += t * t / N;
8392c28215423293e443469a07ae7011135d058b671Garrett Cooper
8402c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* r3 = avg((y - c.x^a) ²);
841354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   t = y - c * x ^ a
842354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   = y - log (LnYavg - (_q[1]/_d[1]) * LnXavg) * x ^ (_q[1]/_d[1])
843354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			 */
844354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			t = (Table[r].Y[i]
845354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			     - (logl(LnYavg[i] - (_q[1][i] / _d[1][i]) * LnXavg)
846354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				* powl(Table[r].X, (_q[1][i] / _d[1][i]))
847354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			     ));
848354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			r3[i] += t * t / N;
8492c28215423293e443469a07ae7011135d058b671Garrett Cooper
8502c28215423293e443469a07ae7011135d058b671Garrett Cooper			/* r4 = avg((y - exp(ax+b))²);
851354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   t = y - exp(ax+b)
852354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   = y - exp(_q[2]/_d[2] * x + (LnYavg - (_q[2]/_d[2] * Xavg)));
853354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			   = y - exp(_q[2]/_d[2] * (x - Xavg) + LnYavg);
854354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			 */
855354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			t = (Table[r].Y[i]
856354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			     - expl((_q[2][i] / _d[2][i]) * Table[r]._x +
857354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				    LnYavg[i]));
858354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			r4[i] += t * t / N;
8592c28215423293e443469a07ae7011135d058b671Garrett Cooper
8602c28215423293e443469a07ae7011135d058b671Garrett Cooper		}
8612c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
8622c28215423293e443469a07ae7011135d058b671Garrett Cooper
863354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
8642c28215423293e443469a07ae7011135d058b671Garrett Cooper	output("All computing terminated.\n");
865354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
8662c28215423293e443469a07ae7011135d058b671Garrett Cooper	ret = 0;
867354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (i = 0; i < NSCENAR; i++) {
868354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
8692c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("\nScenario: %s\n", test_scenar[i].desc);
8702c28215423293e443469a07ae7011135d058b671Garrett Cooper
8712c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("  Model: Y = k\n");
8722c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("       k = %g\n", Yavg[i]);
8732c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("    Divergence %g\n", r1[i]);
8742c28215423293e443469a07ae7011135d058b671Garrett Cooper
8752c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("  Model: Y = a * X + b\n");
8762c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("       a = %Lg\n", _q[0][i] / _d[0][i]);
877354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		output("       b = %Lg\n",
878354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       Yavg[i] - ((_q[0][i] / _d[0][i]) * Xavg));
8792c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("    Divergence %g\n", r2[i]);
8802c28215423293e443469a07ae7011135d058b671Garrett Cooper
8812c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("  Model: Y = c * X ^ a\n");
8822c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("       a = %Lg\n", _q[1][i] / _d[1][i]);
883354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		output("       c = %Lg\n",
884354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       logl(LnYavg[i] - (_q[1][i] / _d[1][i]) * LnXavg));
8852c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("    Divergence %g\n", r2[i]);
8862c28215423293e443469a07ae7011135d058b671Garrett Cooper
8872c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("  Model: Y = exp(a * X + b)\n");
8882c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("       a = %Lg\n", _q[2][i] / _d[2][i]);
889354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		output("       b = %Lg\n",
890354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       LnYavg[i] - ((_q[2][i] / _d[2][i]) * Xavg));
8912c28215423293e443469a07ae7011135d058b671Garrett Cooper		output("    Divergence %g\n", r2[i]);
892354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
8932c28215423293e443469a07ae7011135d058b671Garrett Cooper		/* Compare r1 to other values, with some ponderations */
894354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if ((r1[i] > 1.1 * r2[i]) || (r1[i] > 1.2 * r3[i])
895354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    || (r1[i] > 1.3 * r4[i]))
8962c28215423293e443469a07ae7011135d058b671Garrett Cooper			ret++;
897354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#if VERBOSE > 1
8982c28215423293e443469a07ae7011135d058b671Garrett Cooper		else
8992c28215423293e443469a07ae7011135d058b671Garrett Cooper			output(" Sanction: OK\n");
900354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao#endif
9012c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
9022c28215423293e443469a07ae7011135d058b671Garrett Cooper
9032c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We need to free the array */
9042c28215423293e443469a07ae7011135d058b671Garrett Cooper	free(Table);
9052c28215423293e443469a07ae7011135d058b671Garrett Cooper
9062c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We're done */
9072c28215423293e443469a07ae7011135d058b671Garrett Cooper	return ret;
908ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
909