• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2004, Bull S.A..  All rights reserved.
3  * Created by: Sebastien Decugis
4 
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17 
18  * This file is a scalability test for the pthread_mutex_init function.
19 
20  * The steps are:
21  * -> Restrict the memory to 32Mb * SCALABILITY_FACTOR
22  * -> While there is free memory
23  *      -> allocate memory for 10 mutex
24  *      -> time = 0
25  *      -> init the 10 mutex with different attributes
26  *      -> output time
27  * -> When memory is full; undo everything:
28  *      -> time=0
29  *      -> destroy the 10 mutexes
30  *      -> output time
31  *      -> free memory
32  * -> We could additionally lock each mutex after init, and unlock before destroy.
33  */
34 
35  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
36 #define _POSIX_C_SOURCE 200112L
37 
38  /* We enable the following line to have mutex attributes defined */
39 #ifndef WITHOUT_XOPEN
40 #define _XOPEN_SOURCE	600
41 
42 /********************************************************************************************/
43 /****************************** standard includes *****************************************/
44 /********************************************************************************************/
45 #include <pthread.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51 #include <sys/resource.h>
52 #include <sys/time.h>
53 
54 /********************************************************************************************/
55 /******************************   Test framework   *****************************************/
56 /********************************************************************************************/
57 #include "testfrmw.h"
58 #include "testfrmw.c"
59  /* This header is responsible for defining the following macros:
60   * UNRESOLVED(ret, descr);
61   *    where descr is a description of the error and ret is an int (error code for example)
62   * FAILED(descr);
63   *    where descr is a short text saying why the test has failed.
64   * PASSED();
65   *    No parameter.
66   *
67   * Both three macros shall terminate the calling process.
68   * The testcase shall not terminate in any other maneer.
69   *
70   * The other file defines the functions
71   * void output_init()
72   * void output(char * string, ...)
73   *
74   * Those may be used to output information.
75   */
76 
77 /********************************************************************************************/
78 /********************************** Configuration ******************************************/
79 /********************************************************************************************/
80 #ifndef SCALABILITY_FACTOR
81 #define SCALABILITY_FACTOR 1
82 #endif
83 #ifndef VERBOSE
84 #define VERBOSE 1
85 #endif
86 
87 #define WITH_LOCKS
88 
89 /********************************************************************************************/
90 /***********************************    Test case   *****************************************/
91 /********************************************************************************************/
92 
93 typedef struct _teststruct {
94 	pthread_mutex_t mtx[10 * SCALABILITY_FACTOR];
95 	pthread_mutexattr_t ma[5];
96 	pthread_mutexattr_t *pma[10 * SCALABILITY_FACTOR];
97 	struct _teststruct *prev;
98 } teststruct_t;
99 
100 int types[] = { PTHREAD_MUTEX_NORMAL,
101 	PTHREAD_MUTEX_ERRORCHECK,
102 	PTHREAD_MUTEX_RECURSIVE,
103 	PTHREAD_MUTEX_DEFAULT
104 };
105 
main(int argc,char * argv[])106 int main(int argc, char *argv[])
107 {
108 	struct rlimit rl;
109 	int ret;
110 	int i;
111 	teststruct_t *cur, *prev;
112 	struct timeval time_zero, time_cour, time_res, time_sav[8];
113 	long sav = 0;
114 
115 	/* Limit the process memory to a small value (64Mb for example). */
116 	rl.rlim_max = 1024 * 1024 * 32 * SCALABILITY_FACTOR;
117 	rl.rlim_cur = rl.rlim_max;
118 	if ((ret = setrlimit(RLIMIT_AS, &rl))) {
119 		UNRESOLVED(ret, "Memory limitation failed");
120 	}
121 #if VERBOSE > 1
122 	output(";Memory is now limited to %dMb\n", rl.rlim_max >> 20);
123 #endif
124 
125 	prev = NULL;
126 	cur = NULL;
127 
128 	/* Loop while we have memory left */
129 	while (1) {
130 		/* Allocate memory for 10 mutex and related stuff */
131 		cur = malloc(sizeof(teststruct_t));
132 		if (cur == NULL)	/* No memory left */
133 			break;
134 
135 		/* Link to the previous so we are able to free memory */
136 		cur->prev = prev;
137 		prev = cur;
138 
139 		/* Initialize the mutex attributes */
140 		/* We will have:
141 		 * pma[0] = NULL
142 		 * pma[1] = NORMAL type mutex attribute
143 		 * pma[2] = RECURSIVE type mutex attribute
144 		 * pma[3] = ERRORCHECK type mutex attribute
145 		 * pma[4] = DEFAULT type mutex attribute
146 		 * pma[5] = default mutex attribute
147 		 * pma[6] = NORMAL type mutex attribute
148 		 * pma[7] = RECURSIVE type mutex attribute
149 		 * pma[8] = ERRORCHECK type mutex attribute
150 		 * pma[9] = DEFAULT type mutex attribute
151 		 * pma[10] = pma[5] ...
152 		 */
153 		for (i = 0; i < 5; i++) {
154 			if ((ret = pthread_mutexattr_init(&(cur->ma[i])))) {
155 				UNRESOLVED(ret, "Mutex attribute init failed");
156 			}
157 			if (i) {
158 				if ((ret =
159 				     pthread_mutexattr_settype(&(cur->ma[i]),
160 							       types[i - 1]))) {
161 					UNRESOLVED(ret, "Mutex settype failed");
162 				}
163 			}
164 		}
165 		cur->pma[0] = NULL;
166 		for (i = 1; i < (10 * SCALABILITY_FACTOR); i++) {
167 			cur->pma[i] = &(cur->ma[i % 5]);
168 		}		/* The mutex attributes are now initialized */
169 
170 		/* Save the time */
171 		gettimeofday(&time_zero, NULL);
172 
173 		/* For each mutex, we will:
174 		 * - init the mutex
175 		 * - destroy the mutex
176 		 * - init the mutex
177 		 * - lock the mutex
178 		 * - unlock the mutex
179 		 * if WITH_LOCKS,
180 		 * - lock the mutex
181 		 */
182 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
183 			ret = pthread_mutex_init(&(cur->mtx[i]), cur->pma[i]);
184 			if (ret) {
185 				UNRESOLVED(ret, "Mutex 1st init failed");
186 			}
187 			ret = pthread_mutex_destroy(&(cur->mtx[i]));
188 			if (ret) {
189 				UNRESOLVED(ret, "Mutex 1st destroy failed");
190 			}
191 			ret = pthread_mutex_init(&(cur->mtx[i]), cur->pma[i]);
192 			if (ret) {
193 				UNRESOLVED(ret, "Mutex 2nd init failed");
194 			}
195 			ret = pthread_mutex_lock(&(cur->mtx[i]));
196 			if (ret) {
197 				UNRESOLVED(ret, "Mutex 1st lock failed");
198 			}
199 			ret = pthread_mutex_unlock(&(cur->mtx[i]));
200 			if (ret) {
201 				UNRESOLVED(ret, "Mutex 1st unlock failed");
202 			}
203 #ifdef WITH_LOCKS
204 			ret = pthread_mutex_lock(&(cur->mtx[i]));
205 			if (ret) {
206 				UNRESOLVED(ret, "Mutex 2st lock failed");
207 			}
208 #endif
209 		}
210 		/* Compute the operation duration */
211 		gettimeofday(&time_cour, NULL);
212 		time_res.tv_usec =
213 		    time_cour.tv_usec + 1000000 - time_zero.tv_usec;
214 		if (time_res.tv_usec < 1000000) {
215 			time_res.tv_sec =
216 			    time_cour.tv_sec - 1 - time_zero.tv_sec;
217 		} else {
218 			time_res.tv_sec = time_cour.tv_sec - time_zero.tv_sec;
219 			time_res.tv_usec -= 1000000;
220 		}
221 
222 		if (sav > 3) {
223 			time_sav[4].tv_sec = time_sav[5].tv_sec;
224 			time_sav[4].tv_usec = time_sav[5].tv_usec;
225 			time_sav[5].tv_sec = time_sav[6].tv_sec;
226 			time_sav[5].tv_usec = time_sav[6].tv_usec;
227 			time_sav[6].tv_sec = time_sav[7].tv_sec;
228 			time_sav[6].tv_usec = time_sav[7].tv_usec;
229 			time_sav[7].tv_sec = time_res.tv_sec;
230 			time_sav[7].tv_usec = time_res.tv_usec;
231 		} else {
232 			time_sav[sav].tv_sec = time_res.tv_sec;
233 			time_sav[sav].tv_usec = time_res.tv_usec;
234 		}
235 		sav++;
236 #if VERBOSE > 2
237 		output("%4i.%06i;\n", time_res.tv_sec, time_res.tv_usec);
238 #endif
239 	}
240 	if (errno != ENOMEM) {
241 		UNRESOLVED(errno, "Memory not full");
242 	}
243 
244 	/* Now we just have to cleanup everything. */
245 	while (prev != NULL) {
246 		cur = prev;
247 		prev = cur->prev;
248 
249 		/* Free the mutex resources in the cur element */
250 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
251 #ifdef WITH_LOCKS
252 			ret = pthread_mutex_unlock(&(cur->mtx[i]));
253 			if (ret) {
254 				UNRESOLVED(ret, "Mutex 2nd unlock failed");
255 			}
256 #endif
257 			ret = pthread_mutex_destroy(&(cur->mtx[i]));
258 			if (ret) {
259 				UNRESOLVED(ret, "Mutex 2nd destroy failed");
260 			}
261 		}
262 		/* Free the mutex attributes resources in the cur element */
263 		for (i = 0; i < 5; i++) {
264 			if ((ret = pthread_mutexattr_destroy(&(cur->ma[i])))) {
265 				UNRESOLVED(ret,
266 					   "Mutex attribute destroy failed");
267 			}
268 		}
269 		/* Free the element memory */
270 		free(cur);
271 	}
272 #if VERBOSE > 0
273 	if (sav < 8) {
274 		output("Not enough iterations to build statistics\n");
275 	} else {
276 		output("Duration for the operations:\n");
277 		output(" %8i : %2i.%06i s\n", 0, time_sav[0].tv_sec,
278 		       time_sav[0].tv_usec);
279 		output(" %8i : %2i.%06i s\n", 1, time_sav[1].tv_sec,
280 		       time_sav[1].tv_usec);
281 		output(" %8i : %2i.%06i s\n", 2, time_sav[2].tv_sec,
282 		       time_sav[2].tv_usec);
283 		output(" %8i : %2i.%06i s\n", 3, time_sav[3].tv_sec,
284 		       time_sav[3].tv_usec);
285 		output(" [...]\n");
286 		output(" %8i : %2i.%06i s\n", sav - 3, time_sav[4].tv_sec,
287 		       time_sav[4].tv_usec);
288 		output(" %8i : %2i.%06i s\n", sav - 2, time_sav[5].tv_sec,
289 		       time_sav[5].tv_usec);
290 		output(" %8i : %2i.%06i s\n", sav - 1, time_sav[6].tv_sec,
291 		       time_sav[6].tv_usec);
292 		output(" %8i : %2i.%06i s\n", sav, time_sav[7].tv_sec,
293 		       time_sav[7].tv_usec);
294 	}
295 #endif
296 
297 	PASSED;
298 }
299 
300 #else /* WITHOUT_XOPEN */
main(int argc,char * argv[])301 int main(int argc, char *argv[])
302 {
303 	output_init();
304 	UNRESOLVED(0, "This test requires XSI features");
305 }
306 #endif
307