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