1 /* ==================================================================== 2 * Copyright (c) 1998-1999 The Apache Group. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. All advertising materials mentioning features or use of this 17 * software must display the following acknowledgment: 18 * "This product includes software developed by the Apache Group 19 * for use in the Apache HTTP server project (http://www.apache.org/)." 20 * 21 * 4. The names "Apache Server" and "Apache Group" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For written permission, please contact 24 * apache@apache.org. 25 * 26 * 5. Products derived from this software may not be called "Apache" 27 * nor may "Apache" appear in their names without prior written 28 * permission of the Apache Group. 29 * 30 * 6. Redistributions of any form whatsoever must retain the following 31 * acknowledgment: 32 * "This product includes software developed by the Apache Group 33 * for use in the Apache HTTP server project (http://www.apache.org/)." 34 * 35 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46 * OF THE POSSIBILITY OF SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Group and was originally based 51 * on public domain software written at the National Center for 52 * Supercomputing Applications, University of Illinois, Urbana-Champaign. 53 * For more information on the Apache Group and the Apache HTTP server 54 * project, please see <http://www.apache.org/>. 55 * 56 */ 57 58 /* 59 ** This program is based on ZeusBench V1.0 written by Adam Twiss 60 ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/ 61 ** 62 ** This software is provided "as is" and any express or implied waranties, 63 ** including but not limited to, the implied warranties of merchantability and 64 ** fitness for a particular purpose are disclaimed. In no event shall 65 ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special, 66 ** exemplary, or consequential damaged (including, but not limited to, 67 ** procurement of substitute good or services; loss of use, data, or profits; 68 ** or business interruption) however caused and on theory of liability. Whether 69 ** in contract, strict liability or tort (including negligence or otherwise) 70 ** arising in any way out of the use of this software, even if advised of the 71 ** possibility of such damage. 72 ** 73 */ 74 75 /* 76 ** HISTORY: 77 ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996 78 ** with input from Mike Belshe <mbelshe@netscape.com> and 79 ** Michael Campanella <campanella@stevms.enet.dec.com> 80 ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997 81 ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998 82 ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998 83 ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999 84 ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999 85 ** 86 ** - CODE FORK: added Perl XS interface and is now released on CPAN as 87 ** HTTPD::Bench::ApacheBench, September 2000 88 ** - merged code from Apache 1.3.22 ab, October-November 2001 89 ** - various refactors, rewrites, and improvements; see Changes 90 ** 91 */ 92 93 /* 94 * BUGS: 95 * 96 * - uses strcpy/etc. 97 * - has various other poor buffer attacks related to the lazy parsing of 98 * response headers from the server 99 * - doesn't implement much of HTTP/1.x, only accepts certain forms of 100 * responses 101 * - (performance problem) heavy use of strstr shows up top in profile 102 * only an issue for loopback usage 103 */ 104 105 /* ------------------ DEBUGGING --------------------------------------- */ 106 107 // uncomment to turn on debugging messages 108 //#define AB_DEBUG 1 109 110 /* -------------------------------------------------------------------- */ 111 112 #ifdef AB_DEBUG 113 #define AB_DEBUG_XS 1 114 #else 115 #define AB_DEBUG_XS 0 116 #endif 117 118 /* XS library */ 119 #include "EXTERN.h" 120 #include "perl.h" 121 #include "XSUB.h" 122 123 /* ApacheBench source code */ 124 #include "apachebench/util.c" 125 #include "apachebench/xs_util.c" 126 #include "apachebench/http_util.c" 127 #include "apachebench/socket_io.c" 128 #include "apachebench/execute.c" 129 #include "apachebench/regression_data.c" 130 131 /* ------------------- MACROS -------------------------- */ 132 #define ap_min(a,b) ((a)<(b))?(a):(b) 133 #define ap_max(a,b) ((a)>(b))?(a):(b) 134 135 136 MODULE = HTTPD::Bench::ApacheBench PACKAGE = HTTPD::Bench::ApacheBench 137 PROTOTYPES: ENABLE 138 139 HV * 140 ab(input_hash) 141 SV * input_hash; 142 143 PREINIT: 144 char *pt,**url_keys; 145 int i,j,k,arrlen,arrlen2; 146 int def_buffersize; /* default buffersize for all runs */ 147 int def_repeat; /* default number of repeats if unspecified in runs */ 148 int def_memory; /* default memory setting if unspecified in runs */ 149 bool def_keepalive = 0; /* default keepalive setting */ 150 struct global *registry = calloc(1, sizeof(struct global)); 151 int total_started = 0, total_good = 0, total_failed = 0; 152 153 CODE: 154 SV * runs; 155 SV * urls = 0; 156 SV * post_data = 0; 157 SV * head_requests = 0; 158 SV * cookies = 0; 159 SV * ctypes = 0; 160 SV * req_headers = 0; 161 SV * keepalive = 0; 162 SV * url_tlimits = 0; 163 AV * run_group, *tmpav, *tmpav2; 164 SV * tmpsv, *tmpsv2 = 0, *tmpsv3; 165 HV * tmphv; 166 STRLEN len; 167 168 if (AB_DEBUG_XS) printf("AB_DEBUG: start of ab()\n"); 169 170 registry->concurrency = 1; 171 registry->requests = 0; 172 registry->tlimit = 0; 173 registry->min_tlimit.tv_sec = 30; 174 registry->min_tlimit.tv_usec = 0; 175 registry->tail = 0; 176 registry->done = 0; 177 registry->need_to_be_done = 0; 178 strcpy(registry->version, VERSION); 179 strcpy(registry->warn_and_error, "\nWarning messages from ab():"); 180 registry->total_bytes_received = 0; 181 registry->number_of_urls = 0; 182 183 184 /*Get necessary initial information and initialize*/ 185 tmphv = (HV *)SvRV(input_hash); 186 187 tmpsv = *(hv_fetch(tmphv, "concurrency", 11, 0)); 188 registry->concurrency = SvIV(tmpsv); 189 190 tmpsv = *(hv_fetch(tmphv, "timelimit", 9, 0)); 191 if (SvOK(tmpsv)) { 192 registry->tlimit = SvNV(tmpsv); 193 registry->min_tlimit = 194 double2timeval(ap_min(timeval2double(registry->min_tlimit), 195 registry->tlimit)); 196 } 197 198 tmpsv = *(hv_fetch(tmphv, "buffersize", 10, 0)); 199 def_buffersize = SvIV(tmpsv); 200 201 tmpsv = *(hv_fetch(tmphv, "repeat", 6, 0)); 202 def_repeat = SvIV(tmpsv); 203 204 tmpsv = *(hv_fetch(tmphv, "memory", 6, 0)); 205 def_memory = SvIV(tmpsv); 206 207 if (AB_DEBUG_XS) printf("AB_DEBUG: ab() init - stage 1\n"); 208 209 tmpsv = *(hv_fetch(tmphv, "keepalive", 9, 0)); 210 if (SvTRUE(tmpsv)) 211 def_keepalive = 1; 212 213 if (AB_DEBUG_XS) printf("AB_DEBUG: ab() init - stage 2\n"); 214 215 tmpsv = *(hv_fetch(tmphv, "priority", 8, 0)); 216 pt = SvPV(tmpsv, len); 217 if (strcmp(pt, "run_priority") == 0) 218 registry->priority = RUN_PRIORITY; 219 else { 220 registry->priority = EQUAL_OPPORTUNITY; 221 if (strcmp(pt, "equal_opportunity") != 0) 222 myerr(registry->warn_and_error, "Unknown priority value (the only possible priorities are run_priority and equal_opportunity), using default: equal_opportunity"); 223 } 224 225 if (AB_DEBUG_XS) printf("AB_DEBUG: ab() init - stage 3\n"); 226 227 runs = *(hv_fetch(tmphv, "runs", 4, 0)); 228 run_group = (AV *)SvRV(runs); 229 registry->number_of_runs = av_len(run_group) + 1; 230 231 registry->order = malloc(registry->number_of_runs * sizeof(int)); 232 registry->repeats = malloc(registry->number_of_runs * sizeof(int)); 233 registry->position = malloc((registry->number_of_runs+1) * sizeof(int)); 234 registry->memory = malloc(registry->number_of_runs * sizeof(int)); 235 registry->use_auto_cookies = malloc(registry->number_of_runs * sizeof(bool)); 236 237 if (AB_DEBUG_XS) printf("AB_DEBUG: done with ab() initialization\n"); 238 239 for (i = 0,j = 0; i < registry->number_of_runs; i++) { 240 if (AB_DEBUG_XS) printf("AB_DEBUG: starting run %d setup\n", i); 241 242 tmpsv = *(av_fetch(run_group, i, 0)); 243 244 if (SvROK(tmpsv)) 245 tmphv = (HV *)SvRV(tmpsv); 246 247 registry->memory[i] = def_memory; 248 if (hv_exists(tmphv, "memory", 6)) { 249 tmpsv = *(hv_fetch(tmphv, "memory", 6, 0)); 250 registry->memory[i] = SvIV(tmpsv); 251 } 252 253 registry->repeats[i] = def_repeat; 254 if (hv_exists(tmphv, "repeat", 6)) { 255 /* Number of requests to make */ 256 tmpsv = *(hv_fetch(tmphv, "repeat", 6, 0)); 257 registry->repeats[i] = SvIV(tmpsv); 258 } 259 260 registry->use_auto_cookies[i] = 1; 261 if (hv_exists(tmphv, "use_auto_cookies", 16)) { 262 tmpsv = *(hv_fetch(tmphv, "use_auto_cookies", 16, 0)); 263 registry->use_auto_cookies[i] = SvTRUE(tmpsv) ? 1 : 0; 264 } 265 266 registry->requests = ap_max(registry->requests, registry->repeats[i]); 267 268 urls = *(hv_fetch(tmphv, "urls", 4, 0)); 269 tmpav = (AV *) SvRV(urls); 270 registry->position[i] = registry->number_of_urls; 271 registry->number_of_urls += av_len(tmpav) + 1; 272 273 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d: position[%d] == %d\n", i, i, registry->position[i]); 274 275 if (hv_exists(tmphv, "order", 5)) { 276 tmpsv = *(hv_fetch(tmphv, "order", 5, 0)); 277 pt = SvPV(tmpsv, len); 278 if (strcmp(pt, "depth_first") == 0) { 279 registry->order[i] = DEPTH_FIRST; 280 j += 1; 281 } else if (strcmp(pt, "breadth_first") == 0) { 282 registry->order[i] = BREADTH_FIRST; 283 j += registry->repeats[i]; 284 } else { 285 myerr(registry->warn_and_error, "invalid order: order can only be depth_first or breadth_first"); 286 registry->order[i] = BREADTH_FIRST; 287 j += registry->repeats[i]; 288 } 289 } else { 290 registry->order[i] = BREADTH_FIRST; 291 j += registry->repeats[i]; 292 } 293 } 294 if (registry->number_of_urls <= 0) { 295 myerr(registry->warn_and_error, "No urls."); 296 return; 297 } 298 registry->position[registry->number_of_runs] = registry->number_of_urls; 299 registry->concurrency = ap_min(registry->concurrency, j); 300 301 if (AB_DEBUG_XS) printf("AB_DEBUG: set all run info, ready to call initialize()\n"); 302 303 initialize(registry); 304 305 url_keys = malloc(registry->number_of_urls * sizeof(char *)); 306 307 for (k = 0; k < registry->number_of_runs; k++) { 308 if (AB_DEBUG_XS) printf("AB_DEBUG: starting run %d setup2 - postdata + cookie\n", k); 309 310 registry->buffersize[k] = def_buffersize; 311 tmpsv = *(av_fetch(run_group, k, 0)); 312 if (SvROK(tmpsv)) { 313 tmphv = (HV *)SvRV(tmpsv); 314 if (hv_exists(tmphv, "buffersize", 10)) { 315 tmpsv = *(hv_fetch(tmphv, "buffersize", 10, 0)); 316 registry->buffersize[k] = SvIV(tmpsv); 317 } 318 } 319 320 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 1\n", k); 321 322 /* error checking: make sure all of the run specific hashkeys exist */ 323 if (hv_exists(tmphv, "urls", 4)) 324 urls = *(hv_fetch(tmphv, "urls", 4, 0)); 325 if (hv_exists(tmphv, "postdata", 8)) 326 post_data = *(hv_fetch(tmphv, "postdata", 8, 0)); 327 if (hv_exists(tmphv, "head_requests", 13)) 328 head_requests = *(hv_fetch(tmphv, "head_requests", 13, 0)); 329 if (hv_exists(tmphv, "cookies", 7)) 330 cookies = *(hv_fetch(tmphv, "cookies", 7, 0)); 331 if (hv_exists(tmphv, "content_types", 13)) 332 ctypes = *(hv_fetch(tmphv, "content_types", 13, 0)); 333 if (hv_exists(tmphv, "request_headers", 15)) 334 req_headers = *(hv_fetch(tmphv, "request_headers", 15, 0)); 335 if (hv_exists(tmphv, "keepalive", 9)) 336 keepalive = *(hv_fetch(tmphv, "keepalive", 9, 0)); 337 if (hv_exists(tmphv, "timelimits", 10)) 338 url_tlimits = *(hv_fetch(tmphv, "timelimits", 10, 0)); 339 340 /* configure urls */ 341 for (i = registry->position[k]; i < registry->position[k+1]; i++) { 342 tmpav =(AV *) SvRV(urls); 343 tmpsv = *(av_fetch(tmpav, i - registry->position[k], 0)); 344 if (SvPOK(tmpsv)) { 345 pt = SvPV(tmpsv, len); 346 url_keys[i] = pt; 347 348 if (parse_url(registry, pt, i)) { 349 char *warn = malloc(CBUFFSIZE * sizeof(char)); 350 sprintf(warn, "Invalid url: %s, the information for this url may be wrong", pt); 351 myerr(registry->warn_and_error, warn); 352 free(warn); 353 } 354 } else { 355 myerr(registry->warn_and_error, "Undefined url in urls list"); 356 } 357 } 358 359 360 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2\n", k); 361 362 tmpav = (AV *) SvRV(post_data); 363 tmpav2 = (AV *) SvRV(head_requests); 364 365 /* find smaller of post_data array length and urls array length */ 366 arrlen = av_len(tmpav); 367 i = ap_min(registry->position[k+1], 368 registry->position[k] + arrlen + 1); 369 370 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.1\n", k); 371 372 /* find larger of head_requests and post_data (to get the most data) */ 373 arrlen2 = av_len(tmpav2); 374 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.1.1\n", k); 375 i = ap_max(i, registry->position[k] + arrlen2 + 1); 376 377 /* configure post_data or head_requests */ 378 for (j = registry->position[k]; j < i; j++) { 379 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.2, j=%d\n", k, j); 380 if (j - registry->position[k] <= arrlen) 381 tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0)); 382 if (j - registry->position[k] <= arrlen2) 383 tmpsv2 = *(av_fetch(tmpav2, j - registry->position[k], 0)); 384 if (j - registry->position[k] <= arrlen && (SvROK(tmpsv) || SvPOK(tmpsv))) { 385 /* this url is a POST request */ 386 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.3, j=%d\n", k, j); 387 if (SvROK(tmpsv)) { 388 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.4a, j=%d\n", k, j); 389 tmpsv3 = SvRV(tmpsv); 390 if (SvTYPE(tmpsv3) == SVt_PVCV) { 391 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.4a.i, j=%d\n", k, j); 392 registry->postsubs[j] = tmpsv3; 393 registry->posting[j] = 2; 394 } 395 } else if (SvPOK(tmpsv)) { 396 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.4b, j=%d\n", k, j); 397 pt = SvPV(tmpsv, len); 398 registry->postdata[j] = pt; 399 registry->postlen[j] = len; 400 registry->posting[j] = 1; 401 } 402 } else if (j - registry->position[k] <= arrlen2 && SvTRUE(tmpsv2)) 403 /* this url is a HEAD request */ 404 registry->posting[j] = -1; 405 else 406 registry->posting[j] = 0; 407 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.5, j=%d\n", k, j); 408 } 409 410 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 2.6\n", k); 411 412 /*If the number of postdata strings is less than 413 that of urls, then assign empty strings to force GET requests*/ 414 for (j = i; j < registry->position[k+1]; j++) 415 registry->posting[j] = 0; 416 417 418 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 3\n", k); 419 420 /* configure cookies */ 421 registry->cookie[k] = NULL; 422 tmpav = (AV *) SvRV(cookies); 423 if (av_len(tmpav) >= 0) { 424 tmpsv = *(av_fetch(tmpav, 0, 0)); 425 if (SvPOK(tmpsv)) { 426 pt = SvPV(tmpsv, len); 427 if (len != 0) { 428 registry->cookie[k] = malloc((len+1) * sizeof(char)); 429 strcpy(registry->cookie[k], pt); 430 if (AB_DEBUG_XS) printf("AB_DEBUG: cookie[%d] == '%s'\n", k, registry->cookie[k]); 431 } 432 } 433 } 434 435 436 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4\n", k); 437 438 /* find smaller of req_headers array length and urls array length */ 439 tmpav = (AV *) SvRV(req_headers); 440 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.1\n", k); 441 i = ap_min(registry->position[k+1], 442 registry->position[k] + av_len(tmpav) + 1); 443 444 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.2\n", k); 445 /* configure arbitrary request headers */ 446 for (j = registry->position[k]; j < i; j++) { 447 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.3, j=%d\n", k, j); 448 tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0)); 449 if (SvPOK(tmpsv)) { 450 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.4, j=%d\n", k, j); 451 pt = SvPV(tmpsv, len); 452 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.5, j=%d\n", k, j); 453 registry->req_headers[j] = pt; 454 } else 455 registry->req_headers[j] = 0; 456 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 4.6, j=%d\n", k, j); 457 } 458 459 /*If the number of req_headers strings is less than 460 that of urls, then assign NULL (undef) */ 461 for (j = i; j < registry->position[k+1]; j++) 462 registry->req_headers[j] = 0; 463 464 465 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5\n", k); 466 467 /* find smaller of ctypes array length and urls array length */ 468 tmpav = (AV *) SvRV(ctypes); 469 i = ap_min(registry->position[k+1], 470 registry->position[k] + av_len(tmpav) + 1); 471 472 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5.1\n", k); 473 474 /* configure ctypes */ 475 for (j = registry->position[k]; j < i; j++) { 476 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5.2, j=%d\n", k, j); 477 tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0)); 478 if (SvPOK(tmpsv)) { 479 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5.3, j=%d\n", k, j); 480 pt = SvPV(tmpsv, len); 481 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5.4, j=%d\n", k, j); 482 registry->ctypes[j] = pt; 483 } else 484 registry->ctypes[j] = 0; 485 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 5.5, j=%d\n", k, j); 486 } 487 488 /*If the number of ctypes strings is less than 489 that of urls, then assign NULL (undef) */ 490 for (j = i; j < registry->position[k+1]; j++) 491 registry->ctypes[j] = 0; 492 493 494 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6\n", k); 495 496 /* find smaller of keepalive array length and urls array length */ 497 tmpav = (AV *) SvRV(keepalive); 498 i = ap_min(registry->position[k+1], 499 registry->position[k] + av_len(tmpav) + 1); 500 501 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.1\n", k); 502 503 /* configure keepalive */ 504 for (j = registry->position[k]; j < i; j++) { 505 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.2, j=%d\n", k, j); 506 tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0)); 507 if (SvOK(tmpsv)) 508 if (SvTRUE(tmpsv)) 509 registry->keepalive[j] = 1; 510 else 511 registry->keepalive[j] = 0; 512 else 513 registry->keepalive[j] = def_keepalive; 514 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 6.3, j=%d\n", k, j); 515 } 516 517 /*If the number of keepalive strings is less than 518 that of urls, then assign object's default keepalive value */ 519 for (j = i; j < registry->position[k+1]; j++) 520 registry->keepalive[j] = def_keepalive; 521 522 523 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7\n", k); 524 525 /* find smaller of url_tlimits array length and urls array length */ 526 tmpav = (AV *) SvRV(url_tlimits); 527 i = ap_min(registry->position[k+1], 528 registry->position[k] + av_len(tmpav) + 1); 529 530 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.1\n", k); 531 532 /* configure url_tlimits */ 533 for (j = registry->position[k]; j < i; j++) { 534 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.2, j=%d\n", k, j); 535 tmpsv = *(av_fetch(tmpav, j - registry->position[k], 0)); 536 if (SvOK(tmpsv)) { 537 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.3, j=%d\n", k, j); 538 registry->url_tlimit[j] = SvNV(tmpsv); 539 registry->min_tlimit = 540 double2timeval(ap_min(timeval2double(registry->min_tlimit), 541 registry->url_tlimit[j])); 542 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.3.1, j=%d, url_tlimit=%.3f sec, min tlimit so far = %.3f sec\n", k, j, registry->url_tlimit[j], timeval2double(registry->min_tlimit)); 543 } else 544 registry->url_tlimit[j] = 0; 545 if (AB_DEBUG_XS) printf("AB_DEBUG: run %d setup2 - stage 7.4, j=%d\n", k, j); 546 } 547 548 /*If the number of url_tlimits is less than 549 that of urls, then assign 0 for no time limit */ 550 for (j = i; j < registry->position[k+1]; j++) 551 registry->url_tlimit[j] = 0; 552 553 } 554 555 if (AB_DEBUG_XS) printf("AB_DEBUG: ready to test()\n"); 556 557 test(registry); 558 559 if (AB_DEBUG_XS) printf("AB_DEBUG: done with test()\n"); 560 561 RETVAL = newHV();/* ready to get information stored in global variables */ 562 563 for (k = 0; k < registry->number_of_runs; k++) { 564 if (registry->memory[k] >= 1) { 565 AV *started = newAV();/* number of started requests for each url */ 566 AV *good = newAV(); /* number of good responses for each url */ 567 AV *failed = newAV(); /* number of bad responses for each url */ 568 tmpav = newAV(); /* array to keep the thread information */ 569 570 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression info for run %d\n", k); 571 572 for (i = 0; i < registry->repeats[k]; i++) { 573 AV *th_t = newAV(); /* times for processing and connecting */ 574 AV *th_r = newAV(); /* times for http request */ 575 AV *th_c = newAV(); /* connecting times */ 576 AV *page_contents = newAV(); /* pages read from servers */ 577 AV *request_headers = newAV(); /* HTTP requests sent to servers */ 578 AV *request_body = newAV(); /* HTTP requests sent to servers */ 579 AV *headers = newAV(); 580 AV *bytes_posted = newAV(); 581 AV *doc_length = newAV(); 582 AV *bytes_read = newAV(); 583 584 /* variables for calculating min/max/avg times*/ 585 int totalcon = 0, totalreq = 0, total = 0; 586 int mincon = 999999, minreq = 999999, mintot = 999999; 587 int maxcon = 0, maxreq = 0, maxtot = 0; 588 589 /* byte counters */ 590 int total_bytes_posted = 0, total_bytes_read = 0; 591 592 for (j = registry->position[k]; j < registry->position[k+1]; j++) { 593 struct data s = registry->stats[j][i]; 594 mincon = ap_min(mincon, s.ctime); 595 minreq = ap_min(minreq, s.rtime); 596 mintot = ap_min(mintot, s.time); 597 maxcon = ap_max(maxcon, s.ctime); 598 maxreq = ap_max(maxreq, s.rtime); 599 maxtot = ap_max(maxtot, s.time); 600 totalcon += s.ctime; 601 totalreq += s.rtime; 602 total += s.time; 603 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1 - i,j=%d,%d: mintot=%d maxtot=%d total=%d\n", i, j, mintot, maxtot, total); 604 605 total_bytes_posted += registry->totalposted[j]; 606 total_bytes_read += registry->stats[j][i].read; 607 608 av_push(th_c, newSVnv(registry->stats[j][i].ctime)); 609 av_push(th_r, newSVnv(registry->stats[j][i].rtime)); 610 av_push(th_t, newSVnv(registry->stats[j][i].time)); 611 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.1 - i,j=%d,%d\n", i, j); 612 if (i == 0) { 613 av_push(started, newSViv(registry->started[j])); 614 av_push(good, newSViv(registry->good[j])); 615 av_push(failed, newSViv(registry->failed[j])); 616 total_started += registry->started[j]; 617 total_good += registry->good[j]; 618 total_failed += registry->failed[j]; 619 } 620 621 if (registry->memory[k] >= 2) { 622 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.1.0 - i,j=%d,%d header='%s'\n", i, j, registry->stats[j][i].response_headers); 623 if (registry->stats[j][i].response_headers && 624 strlen(registry->stats[j][i].response_headers) > 0) 625 av_push(headers, newSVpv(registry->stats[j][i].response_headers, 0)); 626 else 627 av_push(headers, &PL_sv_undef); 628 if (registry->stats[j][i].request_headers && 629 strlen(registry->stats[j][i].request_headers) > 0) 630 av_push(request_headers, newSVpv(registry->stats[j][i].request_headers, 0)); 631 else 632 av_push(request_headers, &PL_sv_undef); 633 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.1.1 - i,j=%d,%d\n", i, j); 634 av_push(doc_length, newSVnv(registry->stats[j][i].bread)); 635 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.1.2 - i,j=%d,%d\n", i, j); 636 av_push(bytes_read, newSVnv(registry->stats[j][i].read)); 637 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.1.3 - i,j=%d,%d\n", i, j); 638 /*if (registry->posting[j] > 0)*/ 639 av_push(bytes_posted, newSVnv(registry->totalposted[j])); 640 } 641 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.2 - i,j=%d,%d\n", i, j); 642 if (registry->memory[k] >= 3) { 643 if (registry->stats[j][i].response && 644 strlen(registry->stats[j][i].response) > 0) 645 av_push(page_contents, newSVpv(registry->stats[j][i].response, 0)); 646 else 647 av_push(page_contents, &PL_sv_undef); 648 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.2.5 - i,j=%d,%d\n", i, j); 649 if (registry->stats[j][i].request && 650 strlen(registry->stats[j][i].request) > 0) 651 av_push(request_body, newSVpv(registry->stats[j][i].request, 0)); 652 else 653 av_push(request_body, &PL_sv_undef); 654 } 655 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 1.3 - i,j=%d,%d\n", i, j); 656 } 657 658 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 3 - i=%d\n", i); 659 tmphv = newHV(); 660 hv_store(tmphv, "max_connect_time", 16, newSVnv(maxcon), 0); 661 hv_store(tmphv, "max_request_time", 16, newSVnv(maxreq), 0); 662 hv_store(tmphv, "max_response_time", 17, newSVnv(maxtot), 0); 663 hv_store(tmphv, "min_connect_time", 16, newSVnv(mincon), 0); 664 hv_store(tmphv, "min_request_time", 16, newSVnv(minreq), 0); 665 hv_store(tmphv, "min_response_time", 17, newSVnv(mintot), 0); 666 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 4 - i=%d\n", i); 667 hv_store(tmphv, "total_connect_time", 18, newSVnv(totalcon), 0); 668 hv_store(tmphv, "total_request_time", 18, newSVnv(totalreq), 0); 669 hv_store(tmphv, "total_response_time", 19, newSVnv(total), 0); 670 hv_store(tmphv, "average_connect_time", 20, newSVnv((float)totalcon/(j-registry->position[k])), 0); 671 hv_store(tmphv, "average_request_time", 20, newSVnv((float)totalreq/(j-registry->position[k])), 0); 672 hv_store(tmphv, "average_response_time", 21, newSVnv((double)total/(j-registry->position[k])), 0); 673 hv_store(tmphv, "total_bytes_read", 16, newSVnv(total_bytes_read), 0); 674 hv_store(tmphv, "total_bytes_posted", 18, newSVnv(total_bytes_posted), 0); 675 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 5 - i=%d\n", i); 676 677 /* started/good/failed are url-specific, store only 1st time */ 678 if (i == 0) { 679 hv_store(tmphv, "started", 7, newRV_inc((SV *)started), 0); 680 hv_store(tmphv, "good", 4, newRV_inc((SV *)good), 0); 681 hv_store(tmphv, "failed", 6, newRV_inc((SV *)failed), 0); 682 } 683 hv_store(tmphv, "connect_time", 12, newRV_inc((SV *)th_c), 0); 684 hv_store(tmphv, "request_time", 12, newRV_inc((SV *)th_r), 0); 685 hv_store(tmphv, "response_time", 13, newRV_inc((SV *)th_t), 0); 686 if (registry->memory[k] >= 2) { 687 hv_store(tmphv, "headers", 7, newRV_inc((SV *)headers), 0); 688 hv_store(tmphv, "doc_length", 10, newRV_inc((SV *)doc_length), 0); 689 hv_store(tmphv, "bytes_read", 10, newRV_inc((SV *)bytes_read), 0); 690 hv_store(tmphv, "bytes_posted", 12, newRV_inc((SV *)bytes_posted), 0); 691 hv_store(tmphv, "request_headers", 15, newRV_inc((SV *)request_headers), 0); 692 } 693 if (registry->memory[k] >= 3) { 694 hv_store(tmphv, "page_content", 12, newRV_inc((SV *)page_contents), 0); 695 hv_store(tmphv, "request_body", 12, newRV_inc((SV *)request_body), 0); 696 } 697 if (AB_DEBUG_XS) printf("AB_DEBUG: getting regression - stage 6 - i=%d\n", i); 698 av_push(tmpav, newRV_inc((SV*)tmphv)); 699 } 700 { 701 char key[10]; 702 sprintf(key, "run%d", k); 703 hv_store(RETVAL, key, strlen(key), newRV_inc((SV *)tmpav), 0); 704 } 705 } 706 } 707 708 hv_store(RETVAL, "warnings", 8, newSVpv(registry->warn_and_error, 0), 0); 709 hv_store(RETVAL, "total_time", 10, 710 newSVnv(timedif(registry->endtime, registry->starttime)), 0); 711 hv_store(RETVAL, "bytes_received", 14, 712 newSVnv(registry->total_bytes_received), 0); 713 hv_store(RETVAL, "started", 7, newSViv(total_started), 0); 714 hv_store(RETVAL, "good", 4, newSViv(total_good), 0); 715 hv_store(RETVAL, "failed", 6, newSViv(total_failed), 0); 716 717 OUTPUT: 718 RETVAL 719