00001 /* Copyright (C) 2005 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00016 00017 original idea: Brian Aker via playing with ab for too many years 00018 coded by: Patrick Galbraith 00019 */ 00020 00021 00022 /* 00023 MySQL Slap 00024 00025 A simple program designed to work as if multiple clients querying the database, 00026 then reporting the timing of each stage. 00027 00028 MySQL slap runs three stages: 00029 1) Create schema,table, and optionally any SP or data you want to beign 00030 the test with. (single client) 00031 2) Load test (many clients) 00032 3) Cleanup (disconnection, drop table if specified, single client) 00033 00034 Examples: 00035 00036 Supply your own create and query SQL statements, with 50 clients 00037 querying (200 selects for each): 00038 00039 mysqlslap --create="CREATE TABLE A (a int);INSERT INTO A (23)" \ 00040 --query="SELECT * FROM A" --concurrency=50 --iterations=200 00041 00042 Let the program build the query SQL statement with a table of two int 00043 columns, three varchar columns, five clients querying (20 times each), 00044 don't create the table or insert the data (using the previous test's 00045 schema and data): 00046 00047 mysqlslap --concurrency=5 --iterations=20 \ 00048 --number-int-cols=2 --number-char-cols=3 \ 00049 --auto-generate-sql 00050 00051 Tell the program to load the create, insert and query SQL statements from 00052 the specified files, where the create.sql file has multiple table creation 00053 statements delimited by ';' and multiple insert statements delimited by ';'. 00054 The --query file will have multiple queries delimited by ';', run all the 00055 load statements, and then run all the queries in the query file 00056 with five clients (five times each): 00057 00058 mysqlslap --concurrency=5 \ 00059 --iterations=5 --query=query.sql --create=create.sql \ 00060 --delimiter=";" 00061 00062 TODO: 00063 Add language for better tests 00064 String length for files and those put on the command line are not 00065 setup to handle binary data. 00066 Report results of each thread into the lock file we use. 00067 More stats 00068 Break up tests and run them on multiple hosts at once. 00069 Allow output to be fed into a database directly. 00070 00071 */ 00072 00073 #define SHOW_VERSION "0.9" 00074 00075 #define HUGE_STRING_LENGTH 8096 00076 #define RAND_STRING_SIZE 126 00077 00078 #include "client_priv.h" 00079 #ifdef HAVE_LIBPTHREAD 00080 #include <my_pthread.h> 00081 #endif 00082 #include <my_sys.h> 00083 #include <m_string.h> 00084 #include <mysql.h> 00085 #include <mysqld_error.h> 00086 #include <my_dir.h> 00087 #include <signal.h> 00088 #include <stdarg.h> 00089 #include <sslopt-vars.h> 00090 #include <sys/types.h> 00091 #ifndef __WIN__ 00092 #include <sys/wait.h> 00093 #endif 00094 #include <ctype.h> 00095 00096 #define MYSLAPLOCK "/myslaplock.lck" 00097 #define MYSLAPLOCK_DIR "/tmp" 00098 00099 #ifdef __WIN__ 00100 #define srandom srand 00101 #define random rand 00102 #define snprintf _snprintf 00103 #endif 00104 00105 #ifdef HAVE_SMEM 00106 static char *shared_memory_base_name=0; 00107 #endif 00108 00109 static char **defaults_argv; 00110 00111 static char *host= NULL, *opt_password= NULL, *user= NULL, 00112 *user_supplied_query= NULL, 00113 *default_engine= NULL, 00114 *opt_mysql_unix_port= NULL; 00115 00116 const char *delimiter= "\n"; 00117 00118 const char *create_schema_string= "mysqlslap"; 00119 00120 const char *lock_directory; 00121 char lock_file_str[FN_REFLEN]; 00122 00123 static my_bool opt_preserve; 00124 00125 static my_bool opt_only_print= FALSE; 00126 00127 static my_bool opt_slave; 00128 00129 static my_bool opt_compress= FALSE, tty_password= FALSE, 00130 opt_silent= FALSE, 00131 auto_generate_sql= FALSE; 00132 00133 static unsigned long connect_flags= CLIENT_MULTI_RESULTS; 00134 00135 static int verbose, num_int_cols, num_char_cols, delimiter_length; 00136 static int iterations; 00137 static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; 00138 static ulonglong actual_queries= 0; 00139 static ulonglong num_of_query; 00140 const char *concurrency_str= NULL; 00141 static char *create_string; 00142 uint *concurrency; 00143 00144 const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace"; 00145 const char *opt_csv_str; 00146 File csv_file; 00147 00148 static uint opt_protocol= 0; 00149 00150 static int get_options(int *argc,char ***argv); 00151 static uint opt_mysql_port= 0; 00152 static uint opt_use_threads; 00153 00154 static const char *load_default_groups[]= { "mysqlslap","client",0 }; 00155 00156 typedef struct statement statement; 00157 00158 struct statement { 00159 char *string; 00160 size_t length; 00161 statement *next; 00162 }; 00163 00164 typedef struct stats stats; 00165 00166 struct stats { 00167 long int timing; 00168 uint users; 00169 unsigned long long rows; 00170 }; 00171 00172 typedef struct thread_context thread_context; 00173 00174 struct thread_context { 00175 statement *stmt; 00176 ulonglong limit; 00177 bool thread; 00178 }; 00179 00180 typedef struct conclusions conclusions; 00181 00182 struct conclusions { 00183 char *engine; 00184 long int avg_timing; 00185 long int max_timing; 00186 long int min_timing; 00187 uint users; 00188 unsigned long long avg_rows; 00189 /* The following are not used yet */ 00190 unsigned long long max_rows; 00191 unsigned long long min_rows; 00192 }; 00193 00194 static statement *create_statements= NULL, 00195 *engine_statements= NULL, 00196 *query_statements= NULL; 00197 00198 /* Prototypes */ 00199 void print_conclusions(conclusions *con); 00200 void print_conclusions_csv(conclusions *con); 00201 void generate_stats(conclusions *con, statement *eng, stats *sptr); 00202 uint parse_comma(const char *string, uint **range); 00203 uint parse_delimiter(const char *script, statement **stmt, char delm); 00204 static int drop_schema(MYSQL *mysql, const char *db); 00205 uint get_random_string(char *buf); 00206 static statement *build_table_string(void); 00207 static statement *build_insert_string(void); 00208 static statement *build_query_string(void); 00209 static int create_schema(MYSQL *mysql, const char *db, statement *stmt, 00210 statement *engine_stmt); 00211 static int run_scheduler(stats *sptr, statement *stmts, uint concur, 00212 ulonglong limit); 00213 int run_task(thread_context *con); 00214 void statement_cleanup(statement *stmt); 00215 00216 static const char ALPHANUMERICS[]= 00217 "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; 00218 00219 #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) 00220 00221 00222 static long int timedif(struct timeval a, struct timeval b) 00223 { 00224 register int us, s; 00225 00226 us = a.tv_usec - b.tv_usec; 00227 us /= 1000; 00228 s = a.tv_sec - b.tv_sec; 00229 s *= 1000; 00230 return s + us; 00231 } 00232 00233 #ifdef __WIN__ 00234 static int gettimeofday(struct timeval *tp, void *tzp) 00235 { 00236 unsigned int ticks; 00237 ticks= GetTickCount(); 00238 tp->tv_usec= ticks*1000; 00239 tp->tv_sec= ticks/1000; 00240 00241 return 0; 00242 } 00243 #endif 00244 00245 int main(int argc, char **argv) 00246 { 00247 MYSQL mysql; 00248 int x; 00249 unsigned long long client_limit; 00250 statement *eptr; 00251 00252 #ifdef __WIN__ 00253 opt_use_threads= 1; 00254 #endif 00255 00256 MY_INIT(argv[0]); 00257 00258 load_defaults("my",load_default_groups,&argc,&argv); 00259 defaults_argv=argv; 00260 if (get_options(&argc,&argv)) 00261 { 00262 free_defaults(defaults_argv); 00263 my_end(0); 00264 exit(1); 00265 } 00266 00267 /* Seed the random number generator if we will be using it. */ 00268 if (auto_generate_sql) 00269 srandom((uint)time(NULL)); 00270 00271 /* globals? Yes, so we only have to run strlen once */ 00272 delimiter_length= strlen(delimiter); 00273 00274 if (argc > 2) 00275 { 00276 fprintf(stderr,"%s: Too many arguments\n",my_progname); 00277 free_defaults(defaults_argv); 00278 my_end(0); 00279 exit(1); 00280 } 00281 mysql_init(&mysql); 00282 if (opt_compress) 00283 mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); 00284 #ifdef HAVE_OPENSSL 00285 if (opt_use_ssl) 00286 mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, 00287 opt_ssl_capath, opt_ssl_cipher); 00288 #endif 00289 if (opt_protocol) 00290 mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); 00291 #ifdef HAVE_SMEM 00292 if (shared_memory_base_name) 00293 mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); 00294 #endif 00295 mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); 00296 00297 if (!opt_only_print) 00298 { 00299 if (!(mysql_real_connect(&mysql, host, user, opt_password, 00300 NULL, opt_mysql_port, 00301 opt_mysql_unix_port, connect_flags))) 00302 { 00303 fprintf(stderr,"%s: Error when connecting to server: %s\n", 00304 my_progname,mysql_error(&mysql)); 00305 free_defaults(defaults_argv); 00306 my_end(0); 00307 exit(1); 00308 } 00309 } 00310 00311 /* Main iterations loop */ 00312 eptr= engine_statements; 00313 do 00314 { 00315 /* For the final stage we run whatever queries we were asked to run */ 00316 uint *current; 00317 conclusions conclusion; 00318 00319 for (current= concurrency; current && *current; current++) 00320 { 00321 stats *head_sptr; 00322 stats *sptr; 00323 00324 head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, MYF(MY_ZEROFILL)); 00325 00326 bzero(&conclusion, sizeof(conclusions)); 00327 00328 if (num_of_query) 00329 client_limit= num_of_query / *current; 00330 else 00331 client_limit= actual_queries; 00332 00333 for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++) 00334 { 00335 /* 00336 We might not want to load any data, such as when we are calling 00337 a stored_procedure that doesn't use data, or we know we already have 00338 data in the table. 00339 */ 00340 if (!opt_preserve) 00341 drop_schema(&mysql, create_schema_string); 00342 /* First we create */ 00343 if (create_statements) 00344 create_schema(&mysql, create_schema_string, create_statements, eptr); 00345 00346 run_scheduler(sptr, query_statements, *current, client_limit); 00347 } 00348 00349 generate_stats(&conclusion, eptr, head_sptr); 00350 00351 if (!opt_silent) 00352 print_conclusions(&conclusion); 00353 if (opt_csv_str) 00354 print_conclusions_csv(&conclusion); 00355 00356 my_free((byte *)head_sptr, MYF(0)); 00357 } 00358 00359 if (!opt_preserve) 00360 drop_schema(&mysql, create_schema_string); 00361 } while (eptr ? (eptr= eptr->next) : 0); 00362 00363 if (!opt_only_print) 00364 mysql_close(&mysql); /* Close & free connection */ 00365 00366 00367 /* Remove lock file */ 00368 my_delete(lock_file_str, MYF(0)); 00369 00370 /* now free all the strings we created */ 00371 if (opt_password) 00372 my_free(opt_password, MYF(0)); 00373 00374 my_free((byte *)concurrency, MYF(0)); 00375 00376 statement_cleanup(create_statements); 00377 statement_cleanup(engine_statements); 00378 statement_cleanup(query_statements); 00379 00380 #ifdef HAVE_SMEM 00381 if (shared_memory_base_name) 00382 my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); 00383 #endif 00384 free_defaults(defaults_argv); 00385 my_end(0); 00386 00387 return 0; 00388 } 00389 00390 00391 static struct my_option my_long_options[] = 00392 { 00393 {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 00394 0, 0, 0, 0, 0, 0}, 00395 {"auto-generate-sql", 'a', 00396 "Generate SQL where not supplied by file or command line.", 00397 (gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql, 00398 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 00399 {"compress", 'C', "Use compression in server/client protocol.", 00400 (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 00401 0, 0, 0}, 00402 {"concurrency", 'c', "Number of clients to simulate for query to run.", 00403 (gptr*) &concurrency_str, (gptr*) &concurrency_str, 0, GET_STR, 00404 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00405 {"create", OPT_CREATE_SLAP_SCHEMA, "File or string to use create tables.", 00406 (gptr*) &create_string, (gptr*) &create_string, 0, GET_STR, REQUIRED_ARG, 00407 0, 0, 0, 0, 0, 0}, 00408 {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.", 00409 (gptr*) &create_schema_string, (gptr*) &create_schema_string, 0, GET_STR, 00410 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00411 {"csv", OPT_CREATE_SLAP_SCHEMA, 00412 "Generate CSV output to named file or to stdout if no file is named.", 00413 (gptr*) &opt_csv_str, (gptr*) &opt_csv_str, 0, GET_STR, 00414 OPT_ARG, 0, 0, 0, 0, 0, 0}, 00415 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 00416 (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, 00417 OPT_ARG, 0, 0, 0, 0, 0, 0}, 00418 {"delimiter", 'F', 00419 "Delimiter to use in SQL statements supplied in file or command line.", 00420 (gptr*) &delimiter, (gptr*) &delimiter, 0, GET_STR, REQUIRED_ARG, 00421 0, 0, 0, 0, 0, 0}, 00422 {"engine", 'e', "Storage engine to use for creating the table.", 00423 (gptr*) &default_engine, (gptr*) &default_engine, 0, 00424 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00425 {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, 00426 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00427 {"iterations", 'i', "Number of times too run the tests.", (gptr*) &iterations, 00428 (gptr*) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, 00429 {"lock-directory", OPT_MYSQL_LOCK_DIRECTORY, "Directory to use to keep locks.", 00430 (gptr*) &lock_directory, (gptr*) &lock_directory, 0, GET_STR, 00431 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00432 {"number-char-cols", 'x', 00433 "Number of INT columns to create table with if specifying --auto-generate-sql.", 00434 (gptr*) &num_char_cols, (gptr*) &num_char_cols, 0, GET_UINT, REQUIRED_ARG, 00435 1, 0, 0, 0, 0, 0}, 00436 {"number-int-cols", 'y', 00437 "Number of VARCHAR columns to create table with if specifying " 00438 "--auto-generate-sql.", (gptr*) &num_int_cols, (gptr*) &num_int_cols, 0, 00439 GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, 00440 {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY, 00441 "Limit each client to this number of queries (this is not exact).", 00442 (gptr*) &num_of_query, (gptr*) &num_of_query, 0, 00443 GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00444 {"only-print", OPT_MYSQL_ONLY_PRINT, 00445 "This causes mysqlslap to not connect to the databases, but instead print " 00446 "out what it would have done instead.", 00447 (gptr*) &opt_only_print, (gptr*) &opt_only_print, 0, GET_BOOL, NO_ARG, 00448 0, 0, 0, 0, 0, 0}, 00449 {"password", 'p', 00450 "Password to use when connecting to server. If password is not given it's " 00451 "asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, 00452 #ifdef __WIN__ 00453 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, 00454 NO_ARG, 0, 0, 0, 0, 0, 0}, 00455 #endif 00456 {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, 00457 (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 00458 0}, 00459 {"preserve-schema", OPT_MYSQL_PRESERVE_SCHEMA, 00460 "Preserve the schema from the mysqlslap run, this happens unless " 00461 "--auto-generate-sql or --create are used.", 00462 (gptr*) &opt_preserve, (gptr*) &opt_preserve, 0, GET_BOOL, 00463 NO_ARG, TRUE, 0, 0, 0, 0, 0}, 00464 {"protocol", OPT_MYSQL_PROTOCOL, 00465 "The protocol of connection (tcp,socket,pipe,memory).", 00466 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00467 {"query", 'q', "Query to run or file containing query to run.", 00468 (gptr*) &user_supplied_query, (gptr*) &user_supplied_query, 00469 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00470 #ifdef HAVE_SMEM 00471 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, 00472 "Base name of shared memory.", (gptr*) &shared_memory_base_name, 00473 (gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 00474 0, 0, 0, 0, 0, 0}, 00475 #endif 00476 {"silent", 's', "Run program in silent mode - no output.", 00477 (gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 00478 0, 0, 0, 0, 0, 0}, 00479 {"slave", OPT_MYSQL_SLAP_SLAVE, "Follow master locks for other slap clients", 00480 (gptr*) &opt_slave, (gptr*) &opt_slave, 0, GET_BOOL, NO_ARG, 00481 0, 0, 0, 0, 0, 0}, 00482 {"socket", 'S', "Socket file to use for connection.", 00483 (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, 00484 REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00485 #include <sslopt-longopts.h> 00486 {"use-threads", OPT_USE_THREADS, 00487 "Use pthread calls instead of fork() calls (default on Windows)", 00488 (gptr*) &opt_use_threads, (gptr*) &opt_use_threads, 0, 00489 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00490 #ifndef DONT_ALLOW_USER_CHANGE 00491 {"user", 'u', "User for login if not current user.", (gptr*) &user, 00492 (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 00493 #endif 00494 {"verbose", 'v', 00495 "More verbose output; You can use this multiple times to get even more " 00496 "verbose output.", (gptr*) &verbose, (gptr*) &verbose, 0, 00497 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 00498 {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, 00499 NO_ARG, 0, 0, 0, 0, 0, 0}, 00500 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} 00501 }; 00502 00503 00504 #include <help_start.h> 00505 00506 static void print_version(void) 00507 { 00508 printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, 00509 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); 00510 } 00511 00512 00513 static void usage(void) 00514 { 00515 print_version(); 00516 puts("Copyright (C) 2005 MySQL AB"); 00517 puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\ 00518 \nand you are welcome to modify and redistribute it under the GPL \ 00519 license\n"); 00520 puts("Run a query multiple times against the server\n"); 00521 printf("Usage: %s [OPTIONS]\n",my_progname); 00522 print_defaults("my",load_default_groups); 00523 my_print_help(my_long_options); 00524 } 00525 00526 #include <help_end.h> 00527 00528 static my_bool 00529 get_one_option(int optid, const struct my_option *opt __attribute__((unused)), 00530 char *argument) 00531 { 00532 DBUG_ENTER("get_one_option"); 00533 switch(optid) { 00534 #ifdef __NETWARE__ 00535 case OPT_AUTO_CLOSE: 00536 setscreenmode(SCR_AUTOCLOSE_ON_EXIT); 00537 break; 00538 #endif 00539 case 'v': 00540 verbose++; 00541 break; 00542 case 'p': 00543 if (argument) 00544 { 00545 char *start= argument; 00546 my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); 00547 opt_password= my_strdup(argument,MYF(MY_FAE)); 00548 while (*argument) *argument++= 'x'; /* Destroy argument */ 00549 if (*start) 00550 start[1]= 0; /* Cut length of argument */ 00551 tty_password= 0; 00552 } 00553 else 00554 tty_password= 1; 00555 break; 00556 case 'W': 00557 #ifdef __WIN__ 00558 opt_protocol= MYSQL_PROTOCOL_PIPE; 00559 #endif 00560 break; 00561 case OPT_MYSQL_PROTOCOL: 00562 { 00563 if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) 00564 { 00565 fprintf(stderr, "Unknown option to protocol: %s\n", argument); 00566 exit(1); 00567 } 00568 break; 00569 } 00570 case '#': 00571 DBUG_PUSH(argument ? argument : default_dbug_option); 00572 break; 00573 #include <sslopt-case.h> 00574 case 'V': 00575 print_version(); 00576 exit(0); 00577 break; 00578 case '?': 00579 case 'I': /* Info */ 00580 usage(); 00581 exit(0); 00582 } 00583 DBUG_RETURN(0); 00584 } 00585 00586 00587 uint 00588 get_random_string(char *buf) 00589 { 00590 char *buf_ptr= buf; 00591 int x; 00592 DBUG_ENTER("get_random_string"); 00593 for (x= RAND_STRING_SIZE; x > 0; x--) 00594 *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; 00595 DBUG_PRINT("info", ("random string: '%*s'", buf_ptr - buf, buf)); 00596 DBUG_RETURN(buf_ptr - buf); 00597 } 00598 00599 00600 /* 00601 build_table_string 00602 00603 This function builds a create table query if the user opts to not supply 00604 a file or string containing a create table statement 00605 */ 00606 static statement * 00607 build_table_string(void) 00608 { 00609 char buf[512]; 00610 int col_count; 00611 statement *ptr; 00612 DYNAMIC_STRING table_string; 00613 DBUG_ENTER("build_table_string"); 00614 00615 DBUG_PRINT("info", ("num int cols %d num char cols %d", 00616 num_int_cols, num_char_cols)); 00617 00618 init_dynamic_string(&table_string, "", 1024, 1024); 00619 00620 dynstr_append(&table_string, "CREATE TABLE `t1` ("); 00621 for (col_count= 1; col_count <= num_int_cols; col_count++) 00622 { 00623 sprintf(buf, "intcol%d INT(32)", col_count); 00624 dynstr_append(&table_string, buf); 00625 00626 if (col_count < num_int_cols || num_char_cols > 0) 00627 dynstr_append(&table_string, ","); 00628 } 00629 for (col_count= 1; col_count <= num_char_cols; col_count++) 00630 { 00631 sprintf(buf, "charcol%d VARCHAR(128)", col_count); 00632 dynstr_append(&table_string, buf); 00633 00634 if (col_count < num_char_cols) 00635 dynstr_append(&table_string, ","); 00636 } 00637 dynstr_append(&table_string, ")"); 00638 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00639 ptr->string = (char *)my_malloc(table_string.length+1, MYF(MY_WME)); 00640 ptr->length= table_string.length+1; 00641 strmov(ptr->string, table_string.str); 00642 DBUG_PRINT("info", ("create_string %s", ptr->string)); 00643 dynstr_free(&table_string); 00644 DBUG_RETURN(ptr); 00645 } 00646 00647 00648 /* 00649 build_insert_string() 00650 00651 This function builds insert statements when the user opts to not supply 00652 an insert file or string containing insert data 00653 */ 00654 static statement * 00655 build_insert_string(void) 00656 { 00657 char buf[RAND_STRING_SIZE]; 00658 int col_count; 00659 statement *ptr; 00660 DYNAMIC_STRING insert_string; 00661 DBUG_ENTER("build_insert_string"); 00662 00663 init_dynamic_string(&insert_string, "", 1024, 1024); 00664 00665 dynstr_append_mem(&insert_string, "INSERT INTO t1 VALUES (", 23); 00666 for (col_count= 1; col_count <= num_int_cols; col_count++) 00667 { 00668 sprintf(buf, "%ld", random()); 00669 dynstr_append(&insert_string, buf); 00670 00671 if (col_count < num_int_cols || num_char_cols > 0) 00672 dynstr_append_mem(&insert_string, ",", 1); 00673 } 00674 for (col_count= 1; col_count <= num_char_cols; col_count++) 00675 { 00676 int buf_len= get_random_string(buf); 00677 dynstr_append_mem(&insert_string, "'", 1); 00678 dynstr_append_mem(&insert_string, buf, buf_len); 00679 dynstr_append_mem(&insert_string, "'", 1); 00680 00681 if (col_count < num_char_cols) 00682 dynstr_append_mem(&insert_string, ",", 1); 00683 } 00684 dynstr_append_mem(&insert_string, ")", 1); 00685 00686 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00687 ptr->string= (char *)my_malloc(insert_string.length+1, MYF(MY_WME)); 00688 ptr->length= insert_string.length+1; 00689 strmov(ptr->string, insert_string.str); 00690 DBUG_PRINT("info", ("generated_insert_data %s", ptr->string)); 00691 dynstr_free(&insert_string); 00692 DBUG_RETURN(ptr); 00693 } 00694 00695 00696 /* 00697 build_query_string() 00698 00699 This function builds a query if the user opts to not supply a query 00700 statement or file containing a query statement 00701 */ 00702 static statement * 00703 build_query_string(void) 00704 { 00705 char buf[512]; 00706 int col_count; 00707 statement *ptr; 00708 static DYNAMIC_STRING query_string; 00709 DBUG_ENTER("build_query_string"); 00710 00711 init_dynamic_string(&query_string, "", 1024, 1024); 00712 00713 dynstr_append_mem(&query_string, "SELECT ", 7); 00714 for (col_count= 1; col_count <= num_int_cols; col_count++) 00715 { 00716 sprintf(buf, "intcol%d", col_count); 00717 dynstr_append(&query_string, buf); 00718 00719 if (col_count < num_int_cols || num_char_cols > 0) 00720 dynstr_append_mem(&query_string, ",", 1); 00721 00722 } 00723 for (col_count= 1; col_count <= num_char_cols; col_count++) 00724 { 00725 sprintf(buf, "charcol%d", col_count); 00726 dynstr_append(&query_string, buf); 00727 00728 if (col_count < num_char_cols) 00729 dynstr_append_mem(&query_string, ",", 1); 00730 00731 } 00732 dynstr_append_mem(&query_string, " FROM t1", 8); 00733 ptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 00734 ptr->string= (char *)my_malloc(query_string.length+1, MYF(MY_WME)); 00735 ptr->length= query_string.length+1; 00736 strmov(ptr->string, query_string.str); 00737 DBUG_PRINT("info", ("user_supplied_query %s", ptr->string)); 00738 dynstr_free(&query_string); 00739 DBUG_RETURN(ptr); 00740 } 00741 00742 static int 00743 get_options(int *argc,char ***argv) 00744 { 00745 int ho_error; 00746 char *tmp_string; 00747 MY_STAT sbuf; /* Stat information for the data file */ 00748 00749 DBUG_ENTER("get_options"); 00750 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) 00751 exit(ho_error); 00752 00753 if (!user) 00754 user= (char *)"root"; 00755 00756 if (create_string || auto_generate_sql) 00757 { 00758 if (verbose >= 1) 00759 fprintf(stderr, "Turning off preserve-schema!\n"); 00760 opt_preserve= FALSE; 00761 } 00762 00763 if (auto_generate_sql && (create_string || user_supplied_query)) 00764 { 00765 fprintf(stderr, 00766 "%s: Can't use --auto-generate-sql when create and query strings are specified!\n", 00767 my_progname); 00768 exit(1); 00769 } 00770 00771 parse_comma(concurrency_str ? concurrency_str : "1", &concurrency); 00772 00773 if (lock_directory) 00774 snprintf(lock_file_str, FN_REFLEN, "%s/%s", lock_directory, MYSLAPLOCK); 00775 else 00776 snprintf(lock_file_str, FN_REFLEN, "%s/%s", MYSLAPLOCK_DIR, MYSLAPLOCK); 00777 00778 if (opt_csv_str) 00779 { 00780 opt_silent= TRUE; 00781 00782 if (opt_csv_str[0] == '-') 00783 { 00784 csv_file= fileno(stdout); 00785 } 00786 else 00787 { 00788 if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0))) 00789 == -1) 00790 { 00791 fprintf(stderr,"%s: Could not open csv file: %sn\n", 00792 my_progname, opt_csv_str); 00793 exit(1); 00794 } 00795 } 00796 } 00797 00798 if (opt_only_print) 00799 opt_silent= TRUE; 00800 00801 if (auto_generate_sql) 00802 { 00803 create_statements= build_table_string(); 00804 query_statements= build_insert_string(); 00805 DBUG_PRINT("info", ("auto-generated insert is %s", query_statements->string)); 00806 query_statements->next= build_query_string(); 00807 DBUG_PRINT("info", ("auto-generated is %s", query_statements->next->string)); 00808 if (verbose >= 1) 00809 { 00810 fprintf(stderr, "auto-generated insert is:\n"); 00811 fprintf(stderr, "%s\n", query_statements->string); 00812 fprintf(stderr, "auto-generated is:\n"); 00813 fprintf(stderr, "%s\n", query_statements->next->string); 00814 } 00815 00816 } 00817 else 00818 { 00819 if (create_string && my_stat(create_string, &sbuf, MYF(0))) 00820 { 00821 File data_file; 00822 if (!MY_S_ISREG(sbuf.st_mode)) 00823 { 00824 fprintf(stderr,"%s: Create file was not a regular file\n", 00825 my_progname); 00826 exit(1); 00827 } 00828 if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1) 00829 { 00830 fprintf(stderr,"%s: Could not open create file\n", my_progname); 00831 exit(1); 00832 } 00833 tmp_string= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME)); 00834 my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); 00835 tmp_string[sbuf.st_size]= '\0'; 00836 my_close(data_file,MYF(0)); 00837 parse_delimiter(tmp_string, &create_statements, delimiter[0]); 00838 my_free(tmp_string, MYF(0)); 00839 } 00840 else if (create_string) 00841 { 00842 parse_delimiter(create_string, &create_statements, delimiter[0]); 00843 } 00844 00845 if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0))) 00846 { 00847 File data_file; 00848 if (!MY_S_ISREG(sbuf.st_mode)) 00849 { 00850 fprintf(stderr,"%s: User query supplied file was not a regular file\n", 00851 my_progname); 00852 exit(1); 00853 } 00854 if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1) 00855 { 00856 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname); 00857 exit(1); 00858 } 00859 tmp_string= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME)); 00860 my_read(data_file, tmp_string, sbuf.st_size, MYF(0)); 00861 tmp_string[sbuf.st_size]= '\0'; 00862 my_close(data_file,MYF(0)); 00863 if (user_supplied_query) 00864 actual_queries= parse_delimiter(tmp_string, &query_statements, 00865 delimiter[0]); 00866 my_free(tmp_string, MYF(0)); 00867 } 00868 else if (user_supplied_query) 00869 { 00870 actual_queries= parse_delimiter(user_supplied_query, &query_statements, 00871 delimiter[0]); 00872 } 00873 } 00874 00875 if (default_engine) 00876 parse_delimiter(default_engine, &engine_statements, ','); 00877 00878 if (tty_password) 00879 opt_password= get_tty_password(NullS); 00880 DBUG_RETURN(0); 00881 } 00882 00883 00884 static int run_query(MYSQL *mysql, const char *query, int len) 00885 { 00886 if (opt_only_print) 00887 { 00888 printf("%.*s;\n", len, query); 00889 return 0; 00890 } 00891 00892 if (verbose >= 2) 00893 printf("%.*s;\n", len, query); 00894 return mysql_real_query(mysql, query, len); 00895 } 00896 00897 00898 00899 static int 00900 create_schema(MYSQL *mysql, const char *db, statement *stmt, 00901 statement *engine_stmt) 00902 { 00903 char query[HUGE_STRING_LENGTH]; 00904 statement *ptr; 00905 int len; 00906 DBUG_ENTER("create_schema"); 00907 00908 len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db); 00909 DBUG_PRINT("info", ("query %s", query)); 00910 00911 if (run_query(mysql, query, len)) 00912 { 00913 fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db, 00914 mysql_error(mysql)); 00915 exit(1); 00916 } 00917 00918 if (opt_only_print) 00919 { 00920 printf("use %s;\n", db); 00921 } 00922 else 00923 { 00924 if (verbose >= 2) 00925 printf("%s;\n", query); 00926 if (mysql_select_db(mysql, db)) 00927 { 00928 fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db, 00929 mysql_error(mysql)); 00930 exit(1); 00931 } 00932 } 00933 00934 if (engine_stmt) 00935 { 00936 len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`", 00937 engine_stmt->string); 00938 if (run_query(mysql, query, len)) 00939 { 00940 fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname, 00941 mysql_error(mysql)); 00942 exit(1); 00943 } 00944 } 00945 00946 for (ptr= stmt; ptr && ptr->length; ptr= ptr->next) 00947 { 00948 if (run_query(mysql, ptr->string, ptr->length)) 00949 { 00950 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", 00951 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); 00952 exit(1); 00953 } 00954 } 00955 00956 DBUG_RETURN(0); 00957 } 00958 00959 static int 00960 drop_schema(MYSQL *mysql, const char *db) 00961 { 00962 char query[HUGE_STRING_LENGTH]; 00963 int len; 00964 DBUG_ENTER("drop_schema"); 00965 len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db); 00966 00967 if (run_query(mysql, query, len)) 00968 { 00969 fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n", 00970 my_progname, db, mysql_error(mysql)); 00971 exit(1); 00972 } 00973 00974 00975 00976 DBUG_RETURN(0); 00977 } 00978 00979 static int 00980 run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit) 00981 { 00982 uint x; 00983 File lock_file; 00984 struct timeval start_time, end_time; 00985 thread_context con; 00986 DBUG_ENTER("run_scheduler"); 00987 00988 con.stmt= stmts; 00989 con.limit= limit; 00990 con.thread= opt_use_threads ? 1 :0; 00991 00992 lock_file= my_open(lock_file_str, O_CREAT|O_WRONLY|O_TRUNC, MYF(0)); 00993 00994 if (!opt_slave) 00995 if (my_lock(lock_file, F_WRLCK, 0, F_TO_EOF, MYF(0))) 00996 { 00997 fprintf(stderr,"%s: Could not get lockfile\n", 00998 my_progname); 00999 exit(0); 01000 } 01001 01002 #ifdef HAVE_LIBPTHREAD 01003 if (opt_use_threads) 01004 { 01005 pthread_t mainthread; /* Thread descriptor */ 01006 pthread_attr_t attr; /* Thread attributes */ 01007 01008 for (x= 0; x < concur; x++) 01009 { 01010 pthread_attr_init(&attr); 01011 pthread_attr_setdetachstate(&attr, 01012 PTHREAD_CREATE_DETACHED); 01013 01014 /* now create the thread */ 01015 if (pthread_create(&mainthread, &attr, (void *)run_task, 01016 (void *)&con) != 0) 01017 { 01018 fprintf(stderr,"%s: Could not create thread\n", 01019 my_progname); 01020 exit(0); 01021 } 01022 } 01023 } 01024 #endif 01025 #if !(defined(__WIN__) || defined(__NETWARE__)) 01026 #ifdef HAVE_LIBPTHREAD 01027 else 01028 #endif 01029 { 01030 fflush(NULL); 01031 for (x= 0; x < concur; x++) 01032 { 01033 int pid; 01034 DBUG_PRINT("info", ("x %d concurrency %d", x, concurrency)); 01035 pid= fork(); 01036 switch(pid) 01037 { 01038 case 0: 01039 /* child */ 01040 DBUG_PRINT("info", ("fork returned 0, calling task(\"%s\"), pid %d gid %d", 01041 stmts ? stmts->string : "", pid, getgid())); 01042 if (verbose >= 2) 01043 fprintf(stderr, 01044 "%s: fork returned 0, calling task pid %d gid %d\n", 01045 my_progname, pid, getgid()); 01046 run_task(&con); 01047 exit(0); 01048 break; 01049 case -1: 01050 /* error */ 01051 DBUG_PRINT("info", 01052 ("fork returned -1, failing pid %d gid %d", pid, getgid())); 01053 fprintf(stderr, 01054 "%s: Failed on fork: -1, max procs per parent exceeded.\n", 01055 my_progname); 01056 /*exit(1);*/ 01057 goto WAIT; 01058 default: 01059 /* parent, forked */ 01060 DBUG_PRINT("info", ("default, break: pid %d gid %d", pid, getgid())); 01061 if (verbose >= 2) 01062 fprintf(stderr,"%s: fork returned %d, gid %d\n", 01063 my_progname, pid, getgid()); 01064 break; 01065 } 01066 } 01067 } 01068 #endif 01069 01070 /* Lets release use some clients! */ 01071 if (!opt_slave) 01072 my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0)); 01073 01074 gettimeofday(&start_time, NULL); 01075 01076 /* 01077 We look to grab a write lock at this point. Once we get it we know that 01078 all clients have completed their work. 01079 */ 01080 if (opt_use_threads) 01081 { 01082 if (my_lock(lock_file, F_WRLCK, 0, F_TO_EOF, MYF(0))) 01083 { 01084 fprintf(stderr,"%s: Could not get lockfile\n", 01085 my_progname); 01086 exit(0); 01087 } 01088 my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0)); 01089 } 01090 #ifndef __WIN__ 01091 else 01092 { 01093 WAIT: 01094 while (x--) 01095 { 01096 int status, pid; 01097 pid= wait(&status); 01098 DBUG_PRINT("info", ("Parent: child %d status %d", pid, status)); 01099 if (status != 0) 01100 printf("%s: Child %d died with the status %d\n", 01101 my_progname, pid, status); 01102 } 01103 } 01104 #endif 01105 gettimeofday(&end_time, NULL); 01106 01107 my_close(lock_file, MYF(0)); 01108 01109 sptr->timing= timedif(end_time, start_time); 01110 sptr->users= concur; 01111 sptr->rows= limit; 01112 01113 DBUG_RETURN(0); 01114 } 01115 01116 01117 int 01118 run_task(thread_context *con) 01119 { 01120 ulonglong counter= 0, queries; 01121 File lock_file= -1; 01122 MYSQL *mysql; 01123 MYSQL_RES *result; 01124 MYSQL_ROW row; 01125 statement *ptr; 01126 01127 DBUG_ENTER("run_task"); 01128 DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : "")); 01129 01130 if (!(mysql= mysql_init(NULL))) 01131 goto end; 01132 01133 if (con->thread && mysql_thread_init()) 01134 goto end; 01135 01136 DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user)); 01137 lock_file= my_open(lock_file_str, O_RDWR, MYF(0)); 01138 my_lock(lock_file, F_RDLCK, 0, F_TO_EOF, MYF(0)); 01139 if (!opt_only_print) 01140 { 01141 /* Connect to server */ 01142 static ulong connection_retry_sleep= 100000; /* Microseconds */ 01143 int i, connect_error= 1; 01144 for (i= 0; i < 10; i++) 01145 { 01146 if (mysql_real_connect(mysql, host, user, opt_password, 01147 create_schema_string, 01148 opt_mysql_port, 01149 opt_mysql_unix_port, 01150 connect_flags)) 01151 { 01152 /* Connect suceeded */ 01153 connect_error= 0; 01154 break; 01155 } 01156 my_sleep(connection_retry_sleep); 01157 } 01158 if (connect_error) 01159 { 01160 fprintf(stderr,"%s: Error when connecting to server: %d %s\n", 01161 my_progname, mysql_errno(mysql), mysql_error(mysql)); 01162 goto end; 01163 } 01164 } 01165 DBUG_PRINT("info", ("connected.")); 01166 if (verbose >= 3) 01167 fprintf(stderr, "connected!\n"); 01168 queries= 0; 01169 01170 limit_not_met: 01171 for (ptr= con->stmt; ptr && ptr->length; ptr= ptr->next) 01172 { 01173 if (run_query(mysql, ptr->string, ptr->length)) 01174 { 01175 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n", 01176 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql)); 01177 goto end; 01178 } 01179 if (mysql_field_count(mysql)) 01180 { 01181 result= mysql_store_result(mysql); 01182 while ((row = mysql_fetch_row(result))) 01183 counter++; 01184 mysql_free_result(result); 01185 } 01186 queries++; 01187 01188 if (con->limit && queries == con->limit) 01189 goto end; 01190 } 01191 01192 if (!con->stmt && con->limit && queries < con->limit) 01193 goto limit_not_met; 01194 01195 end: 01196 01197 if (lock_file != -1) 01198 { 01199 my_lock(lock_file, F_UNLCK, 0, F_TO_EOF, MYF(0)); 01200 my_close(lock_file, MYF(0)); 01201 } 01202 01203 if (!opt_only_print) 01204 mysql_close(mysql); 01205 01206 if (con->thread) 01207 my_thread_end(); 01208 DBUG_RETURN(0); 01209 } 01210 01211 01212 uint 01213 parse_delimiter(const char *script, statement **stmt, char delm) 01214 { 01215 char *retstr; 01216 char *ptr= (char *)script; 01217 statement **sptr= stmt; 01218 statement *tmp; 01219 uint length= strlen(script); 01220 uint count= 0; /* We know that there is always one */ 01221 01222 DBUG_PRINT("info", ("Parsing %s\n", script)); 01223 01224 for (tmp= *sptr= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)); 01225 (retstr= strchr(ptr, delm)); 01226 tmp->next= (statement *)my_malloc(sizeof(statement), MYF(MY_ZEROFILL)), 01227 tmp= tmp->next) 01228 { 01229 count++; 01230 tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE)); 01231 tmp->length= (size_t)(retstr - ptr); 01232 DBUG_PRINT("info", (" Creating : %.*s\n", (uint)tmp->length, tmp->string)); 01233 ptr+= retstr - ptr + 1; 01234 if (isspace(*ptr)) 01235 ptr++; 01236 count++; 01237 } 01238 01239 if (ptr != script+length) 01240 { 01241 tmp->string= my_strndup(ptr, (size_t)((script + length) - ptr), 01242 MYF(MY_FAE)); 01243 tmp->length= (size_t)((script + length) - ptr); 01244 DBUG_PRINT("info", (" Creating : %.*s\n", (uint)tmp->length, tmp->string)); 01245 count++; 01246 } 01247 01248 return count; 01249 } 01250 01251 01252 uint 01253 parse_comma(const char *string, uint **range) 01254 { 01255 uint count= 1,x; /* We know that there is always one */ 01256 char *retstr; 01257 char *ptr= (char *)string; 01258 uint *nptr; 01259 01260 for (;*ptr; ptr++) 01261 if (*ptr == ',') count++; 01262 01263 /* One extra spot for the NULL */ 01264 nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1), MYF(MY_ZEROFILL)); 01265 01266 ptr= (char *)string; 01267 x= 0; 01268 while ((retstr= strchr(ptr,','))) 01269 { 01270 nptr[x++]= atoi(ptr); 01271 ptr+= retstr - ptr + 1; 01272 } 01273 nptr[x++]= atoi(ptr); 01274 01275 return count; 01276 } 01277 01278 void 01279 print_conclusions(conclusions *con) 01280 { 01281 printf("Benchmark\n"); 01282 if (con->engine) 01283 printf("\tRunning for engine %s\n", con->engine); 01284 printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n", 01285 con->avg_timing / 1000, con->avg_timing % 1000); 01286 printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n", 01287 con->min_timing / 1000, con->min_timing % 1000); 01288 printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n", 01289 con->max_timing / 1000, con->max_timing % 1000); 01290 printf("\tNumber of clients running queries: %d\n", con->users); 01291 printf("\tAverage number of queries per client: %llu\n", con->avg_rows); 01292 printf("\n"); 01293 } 01294 01295 void 01296 print_conclusions_csv(conclusions *con) 01297 { 01298 char buffer[HUGE_STRING_LENGTH]; 01299 snprintf(buffer, HUGE_STRING_LENGTH, 01300 "%s,query,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n", 01301 con->engine ? con->engine : "", /* Storage engine we ran against */ 01302 con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */ 01303 con->min_timing / 1000, con->min_timing % 1000, /* Min time */ 01304 con->max_timing / 1000, con->max_timing % 1000, /* Max time */ 01305 con->users, /* Children used */ 01306 con->avg_rows /* Queries run */ 01307 ); 01308 my_write(csv_file, buffer, strlen(buffer), MYF(0)); 01309 } 01310 01311 void 01312 generate_stats(conclusions *con, statement *eng, stats *sptr) 01313 { 01314 stats *ptr; 01315 int x; 01316 01317 con->min_timing= sptr->timing; 01318 con->max_timing= sptr->timing; 01319 con->min_rows= sptr->rows; 01320 con->max_rows= sptr->rows; 01321 01322 /* At the moment we assume uniform */ 01323 con->users= sptr->users; 01324 con->avg_rows= sptr->rows; 01325 01326 /* With no next, we know it is the last element that was malloced */ 01327 for (ptr= sptr, x= 0; x < iterations; ptr++, x++) 01328 { 01329 con->avg_timing+= ptr->timing; 01330 01331 if (ptr->timing > con->max_timing) 01332 con->max_timing= ptr->timing; 01333 if (ptr->timing < con->min_timing) 01334 con->min_timing= ptr->timing; 01335 } 01336 con->avg_timing= con->avg_timing/iterations; 01337 01338 if (eng && eng->string) 01339 con->engine= eng->string; 01340 else 01341 con->engine= NULL; 01342 } 01343 01344 void 01345 statement_cleanup(statement *stmt) 01346 { 01347 statement *ptr, *nptr; 01348 if (!stmt) 01349 return; 01350 01351 for (ptr= stmt; ptr; ptr= nptr) 01352 { 01353 nptr= ptr->next; 01354 if (ptr->string) 01355 my_free(ptr->string, MYF(0)); 01356 my_free((byte *)ptr, MYF(0)); 01357 } 01358 }
1.4.7

