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 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 */ 301 int main(int argc, char *argv[]) 302 { 303 output_init(); 304 UNRESOLVED(0, "This test requires XSI features"); 305 } 306 #endif 307