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