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