• 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_cond_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 cond vars
24  *      -> time = 0
25  *      -> init the 10 cond vars with different attributes
26  *      -> output time
27  * -> When memory is full; undo everything:
28  *      -> time=0
29  *      -> destroy the 10 cond vars
30  *      -> output time
31  *      -> free memory
32  */
33 
34  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
35 #define _POSIX_C_SOURCE 200112L
36 
37  /* We need XSI conformance for memory limitation */
38 #ifndef WITHOUT_XOPEN
39 #define _XOPEN_SOURCE	600
40 
41 /********************************************************************************************/
42 /****************************** standard includes *****************************************/
43 /********************************************************************************************/
44 #include <pthread.h>
45 #include <errno.h>
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdarg.h>
50 #include <sys/resource.h>
51 #include <sys/time.h>
52 
53 /********************************************************************************************/
54 /******************************   Test framework   *****************************************/
55 /********************************************************************************************/
56 #include "testfrmw.h"
57 #include "testfrmw.c"
58  /* This header is responsible for defining the following macros:
59   * UNRESOLVED(ret, descr);
60   *    where descr is a description of the error and ret is an int (error code for example)
61   * FAILED(descr);
62   *    where descr is a short text saying why the test has failed.
63   * PASSED();
64   *    No parameter.
65   *
66   * Both three macros shall terminate the calling process.
67   * The testcase shall not terminate in any other maneer.
68   *
69   * The other file defines the functions
70   * void output_init()
71   * void output(char * string, ...)
72   *
73   * Those may be used to output information.
74   */
75 
76 /********************************************************************************************/
77 /********************************** Configuration ******************************************/
78 /********************************************************************************************/
79 #ifndef SCALABILITY_FACTOR
80 #define SCALABILITY_FACTOR 1
81 #endif
82 #ifndef VERBOSE
83 #define VERBOSE 1
84 #endif
85 
86 /********************************************************************************************/
87 /***********************************    Test case   *****************************************/
88 /********************************************************************************************/
89 
90 typedef struct _teststruct {
91 	pthread_cond_t cnd[10 * SCALABILITY_FACTOR];
92 	pthread_condattr_t ca[4];
93 	pthread_condattr_t *pca[10 * SCALABILITY_FACTOR];
94 	struct _teststruct *prev;
95 } teststruct_t;
96 
main(int argc,char * argv[])97 int main(int argc, char *argv[])
98 {
99 	struct rlimit rl;
100 	int ret;
101 	int i;
102 	teststruct_t *cur, *prev;
103 	struct timeval time_zero, time_cour, time_res, time_sav[8];
104 	long sav = 0;
105 
106 	long monotonic, pshared;
107 
108 	pshared = sysconf(_SC_THREAD_PROCESS_SHARED);
109 	monotonic = sysconf(_SC_MONOTONIC_CLOCK);
110 #if VERBOSE > 1
111 	output("Support for process-shared condvars: %li\n", pshared);
112 	output("Support for monotonic clock        : %li\n", monotonic);
113 #endif
114 
115 	/* Limit the process memory to a small value (32Mb 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 		 * pca[0] = NULL
142 		 * pca[1] = Default cond attribute
143 		 * pca[2] = (if supported) pshared cond attribute
144 		 * pca[3] = (if supported) monotonic clock cond attribute
145 		 * pca[4] = (if supported) pshared + monotonic
146 		 * pca[5] = pca[0]...
147 		 */
148 		for (i = 0; i < 4; i++) {
149 			ret = pthread_condattr_init(&(cur->ca[i]));
150 			if (ret != 0) {
151 				UNRESOLVED(ret, "Cond attribute init failed");
152 			}
153 
154 			if ((monotonic > 0) && ((i == 2) || (i == 3))) {
155 				ret =
156 				    pthread_condattr_setclock(&(cur->ca[i]),
157 							      CLOCK_MONOTONIC);
158 				if (ret != 0) {
159 					UNRESOLVED(ret,
160 						   "Set monotonic clock failed");
161 				}
162 			}
163 			if ((pshared > 0) && ((i == 1) || (i == 3))) {
164 				ret =
165 				    pthread_condattr_setpshared(&(cur->ca[i]),
166 								PTHREAD_PROCESS_SHARED);
167 				if (ret != 0) {
168 					UNRESOLVED(ret,
169 						   "Set process shared attribute failed");
170 				}
171 			}
172 
173 		}
174 
175 		for (i = 0; i < (10 * SCALABILITY_FACTOR); i++) {
176 			cur->pca[i] = (i % 5) ? &(cur->ca[i % 4]) : NULL;
177 		}		/* The mutex attributes are now initialized */
178 
179 		/* Save the time */
180 		gettimeofday(&time_zero, NULL);
181 
182 		/* For each condvar, we will:
183 		 * - init the condvar
184 		 * - destroy the condvar
185 		 * - init the condvar
186 		 * - destroy the condvar
187 		 * - init the condvar
188 		 */
189 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
190 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
191 			if (ret) {
192 				UNRESOLVED(ret, "Cond 1st init failed");
193 			}
194 			ret = pthread_cond_destroy(&(cur->cnd[i]));
195 			if (ret) {
196 				UNRESOLVED(ret, "Cond 1st destroy failed");
197 			}
198 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
199 			if (ret) {
200 				UNRESOLVED(ret, "Cond 2nd init failed");
201 			}
202 			ret = pthread_cond_destroy(&(cur->cnd[i]));
203 			if (ret) {
204 				UNRESOLVED(ret, "Cond 2nd destroy failed");
205 			}
206 			ret = pthread_cond_init(&(cur->cnd[i]), cur->pca[i]);
207 			if (ret) {
208 				UNRESOLVED(ret, "Cond 3rd init failed");
209 			}
210 		}
211 		/* Compute the operation duration */
212 		gettimeofday(&time_cour, NULL);
213 		time_res.tv_usec =
214 		    time_cour.tv_usec + 1000000 - time_zero.tv_usec;
215 		if (time_res.tv_usec < 1000000) {
216 			time_res.tv_sec =
217 			    time_cour.tv_sec - 1 - time_zero.tv_sec;
218 		} else {
219 			time_res.tv_sec = time_cour.tv_sec - time_zero.tv_sec;
220 			time_res.tv_usec -= 1000000;
221 		}
222 
223 		if (sav > 3) {
224 			time_sav[4].tv_sec = time_sav[5].tv_sec;
225 			time_sav[4].tv_usec = time_sav[5].tv_usec;
226 			time_sav[5].tv_sec = time_sav[6].tv_sec;
227 			time_sav[5].tv_usec = time_sav[6].tv_usec;
228 			time_sav[6].tv_sec = time_sav[7].tv_sec;
229 			time_sav[6].tv_usec = time_sav[7].tv_usec;
230 			time_sav[7].tv_sec = time_res.tv_sec;
231 			time_sav[7].tv_usec = time_res.tv_usec;
232 		} else {
233 			time_sav[sav].tv_sec = time_res.tv_sec;
234 			time_sav[sav].tv_usec = time_res.tv_usec;
235 		}
236 		sav++;
237 	}
238 	if (errno != ENOMEM) {
239 		UNRESOLVED(errno, "Memory not full");
240 	}
241 
242 	/* Now we just have to cleanup everything. */
243 	while (prev != NULL) {
244 		cur = prev;
245 		prev = cur->prev;
246 
247 		/* Free the condvar resources in the cur element */
248 		for (i = 0; i < 10 * SCALABILITY_FACTOR; i++) {
249 			ret = pthread_cond_destroy(&(cur->cnd[i]));
250 			if (ret) {
251 				UNRESOLVED(ret, "Cond final destroy failed");
252 			}
253 		}
254 		/* Free the cond attributes resources in the cur element */
255 		for (i = 0; i < 4; i++) {
256 			ret = pthread_condattr_destroy(&(cur->ca[i]));
257 			if (ret != 0) {
258 				UNRESOLVED(ret,
259 					   "Cond attribute destroy failed");
260 			}
261 		}
262 		/* Free the element memory */
263 		free(cur);
264 	}
265 #if VERBOSE > 0
266 	if (sav < 8) {
267 		output("Not enough iterations to build statistics\n");
268 	} else {
269 		output("Duration for the operations:\n");
270 		output(" %8i : %2i.%06i s\n", 0, time_sav[0].tv_sec,
271 		       time_sav[0].tv_usec);
272 		output(" %8i : %2i.%06i s\n", 1, time_sav[1].tv_sec,
273 		       time_sav[1].tv_usec);
274 		output(" %8i : %2i.%06i s\n", 2, time_sav[2].tv_sec,
275 		       time_sav[2].tv_usec);
276 		output(" %8i : %2i.%06i s\n", 3, time_sav[3].tv_sec,
277 		       time_sav[3].tv_usec);
278 		output(" [...]\n");
279 		output(" %8i : %2i.%06i s\n", sav - 3, time_sav[4].tv_sec,
280 		       time_sav[4].tv_usec);
281 		output(" %8i : %2i.%06i s\n", sav - 2, time_sav[5].tv_sec,
282 		       time_sav[5].tv_usec);
283 		output(" %8i : %2i.%06i s\n", sav - 1, time_sav[6].tv_sec,
284 		       time_sav[6].tv_usec);
285 		output(" %8i : %2i.%06i s\n", sav, time_sav[7].tv_sec,
286 		       time_sav[7].tv_usec);
287 	}
288 #endif
289 
290 	PASSED;
291 }
292 
293 #else /* WITHOUT_XOPEN */
main(int argc,char * argv[])294 int main(int argc, char *argv[])
295 {
296 	output_init();
297 	UNRESOLVED(0, "This test requires XSI features");
298 }
299 #endif
300