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 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 */ 294 int main(int argc, char *argv[]) 295 { 296 output_init(); 297 UNRESOLVED(0, "This test requires XSI features"); 298 } 299 #endif 300