Commit 8bea3d22 authored by Alvaro Herrera's avatar Alvaro Herrera

pgbench: improve multi-script support

Previously, it was possible to specify one or several custom scripts to
run, or only one of the builtin scripts.  With this patch it is also
possible to specify to run the builtin scripts multiple times, using the
new -b option.  Also, unify the code for both cases; this eases future
pgbench improvements.

Author: Fabien Coelho
Review: Michaël Paquier, Álvaro Herrera
parent 5b3cc1af
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
Typical output from <application>pgbench</application> looks like: Typical output from <application>pgbench</application> looks like:
<screen> <screen>
transaction type: TPC-B (sort of) transaction type: &lt;builtin: TPC-B (sort of)&gt;
scaling factor: 10 scaling factor: 10
query mode: simple query mode: simple
number of clients: 10 number of clients: 10
...@@ -261,6 +261,20 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -261,6 +261,20 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
benchmarking arguments: benchmarking arguments:
<variablelist> <variablelist>
<varlistentry>
<term><option>-b</> <replaceable>scriptname</></term>
<term><option>--builtin</> <replaceable>scriptname</></term>
<listitem>
<para>
Add the specified builtin script to the list of executed scripts.
Available builtin scripts are: <literal>tpcb-like</>,
<literal>simple-update</> and <literal>select-only</>.
With special name <literal>list</>, show the list of builtin scripts
and exit immediately.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-c</option> <replaceable>clients</></term> <term><option>-c</option> <replaceable>clients</></term>
...@@ -307,14 +321,13 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -307,14 +321,13 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-f</option> <replaceable>filename</></term> <term><option>-f</> <replaceable>filename</></term>
<term><option>--file=</option><replaceable>filename</></term> <term><option>--file=</><replaceable>filename</></term>
<listitem> <listitem>
<para> <para>
Read transaction script from <replaceable>filename</>. Add a transaction script read from <replaceable>filename</> to
the list of executed scripts.
See below for details. See below for details.
<option>-N</option>, <option>-S</option>, and <option>-f</option>
are mutually exclusive.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -404,10 +417,8 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -404,10 +417,8 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
<term><option>--skip-some-updates</option></term> <term><option>--skip-some-updates</option></term>
<listitem> <listitem>
<para> <para>
Do not update <structname>pgbench_tellers</> and Run builtin simple-update script.
<structname>pgbench_branches</>. Shorthand for <option>-b simple-update</>.
This will avoid update contention on these tables, but
it makes the test case even less like TPC-B.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -512,9 +523,9 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -512,9 +523,9 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
Report the specified scale factor in <application>pgbench</>'s Report the specified scale factor in <application>pgbench</>'s
output. With the built-in tests, this is not necessary; the output. With the built-in tests, this is not necessary; the
correct scale factor will be detected by counting the number of correct scale factor will be detected by counting the number of
rows in the <structname>pgbench_branches</> table. However, when testing rows in the <structname>pgbench_branches</> table.
custom benchmarks (<option>-f</> option), the scale factor However, when testing only custom benchmarks (<option>-f</> option),
will be reported as 1 unless this option is used. the scale factor will be reported as 1 unless this option is used.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -524,7 +535,8 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -524,7 +535,8 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
<term><option>--select-only</option></term> <term><option>--select-only</option></term>
<listitem> <listitem>
<para> <para>
Perform select-only transactions instead of TPC-B-like test. Run built-in select-only script.
Shorthand for <option>-b select-only</>.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -674,7 +686,17 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -674,7 +686,17 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
<title>What is the <quote>Transaction</> Actually Performed in <application>pgbench</application>?</title> <title>What is the <quote>Transaction</> Actually Performed in <application>pgbench</application>?</title>
<para> <para>
The default transaction script issues seven commands per transaction: Pgbench executes test scripts chosen randomly from a specified list.
They include built-in scripts with <option>-b</> and
user-provided custom scripts with <option>-f</>.
</para>
<para>
The default builtin transaction script (also invoked with <option>-b tpcb-like</>)
issues seven commands per transaction over randomly chosen <literal>aid</>,
<literal>tid</>, <literal>bid</> and <literal>balance</>.
The scenario is inspired by the TPC-B benchmark, but is not actually TPC-B,
hence the name.
</para> </para>
<orderedlist> <orderedlist>
...@@ -688,9 +710,15 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -688,9 +710,15 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
</orderedlist> </orderedlist>
<para> <para>
If you specify <option>-N</>, steps 4 and 5 aren't included in the If you select the <literal>simple-update</> builtin (also <option>-N</>),
transaction. If you specify <option>-S</>, only the <command>SELECT</> is steps 4 and 5 aren't included in the transaction.
issued. This will avoid update contention on these tables, but
it makes the test case even less like TPC-B.
</para>
<para>
If you select the <literal>select-only</> builtin (also <option>-S</>),
only the <command>SELECT</> is issued.
</para> </para>
</refsect2> </refsect2>
...@@ -702,10 +730,7 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</> ...@@ -702,10 +730,7 @@ pgbench <optional> <replaceable>options</> </optional> <replaceable>dbname</>
benchmark scenarios by replacing the default transaction script benchmark scenarios by replacing the default transaction script
(described above) with a transaction script read from a file (described above) with a transaction script read from a file
(<option>-f</option> option). In this case a <quote>transaction</> (<option>-f</option> option). In this case a <quote>transaction</>
counts as one execution of a script file. You can even specify counts as one execution of a script file.
multiple scripts (multiple <option>-f</option> options), in which
case a random one of the scripts is chosen each time a client session
starts a new transaction.
</para> </para>
<para> <para>
...@@ -1103,7 +1128,7 @@ END; ...@@ -1103,7 +1128,7 @@ END;
For the default script, the output will look similar to this: For the default script, the output will look similar to this:
<screen> <screen>
starting vacuum...end. starting vacuum...end.
transaction type: TPC-B (sort of) transaction type: &lt;builtin: TPC-B (sort of)&gt;
scaling factor: 1 scaling factor: 1
query mode: simple query mode: simple
number of clients: 10 number of clients: 10
...@@ -1112,7 +1137,8 @@ number of transactions per client: 1000 ...@@ -1112,7 +1137,8 @@ number of transactions per client: 1000
number of transactions actually processed: 10000/10000 number of transactions actually processed: 10000/10000
tps = 618.764555 (including connections establishing) tps = 618.764555 (including connections establishing)
tps = 622.977698 (excluding connections establishing) tps = 622.977698 (excluding connections establishing)
statement latencies in milliseconds: SQL script 1: &lt;builtin: TPC-B (sort of)&gt;
- statement latencies in milliseconds:
0.004386 \set nbranches 1 * :scale 0.004386 \set nbranches 1 * :scale
0.001343 \set ntellers 10 * :scale 0.001343 \set ntellers 10 * :scale
0.001212 \set naccounts 100000 * :scale 0.001212 \set naccounts 100000 * :scale
......
...@@ -189,13 +189,12 @@ typedef struct ...@@ -189,13 +189,12 @@ typedef struct
char *value; /* its value */ char *value; /* its value */
} Variable; } Variable;
#define MAX_FILES 128 /* max number of SQL script files allowed */ #define MAX_SCRIPTS 128 /* max number of SQL scripts allowed */
#define SHELL_COMMAND_SIZE 256 /* maximum size allowed for shell command */ #define SHELL_COMMAND_SIZE 256 /* maximum size allowed for shell command */
/* /*
* structures used in custom query mode * Connection state
*/ */
typedef struct typedef struct
{ {
PGconn *con; /* connection handle to DB */ PGconn *con; /* connection handle to DB */
...@@ -210,8 +209,8 @@ typedef struct ...@@ -210,8 +209,8 @@ typedef struct
int64 txn_scheduled; /* scheduled start time of transaction (usec) */ int64 txn_scheduled; /* scheduled start time of transaction (usec) */
instr_time txn_begin; /* used for measuring schedule lag times */ instr_time txn_begin; /* used for measuring schedule lag times */
instr_time stmt_begin; /* used for measuring statement latencies */ instr_time stmt_begin; /* used for measuring statement latencies */
int use_file; /* index in sql_files for this client */ int use_file; /* index in sql_scripts for this client */
bool prepared[MAX_FILES]; bool prepared[MAX_SCRIPTS]; /* whether client prepared the script */
/* per client collected stats */ /* per client collected stats */
int cnt; /* xacts count */ int cnt; /* xacts count */
...@@ -295,13 +294,29 @@ typedef struct ...@@ -295,13 +294,29 @@ typedef struct
double sum2_lag; /* sum(lag*lag) */ double sum2_lag; /* sum(lag*lag) */
} AggVals; } AggVals;
static Command **sql_files[MAX_FILES]; /* SQL script files */ static struct
static int num_files; /* number of script files */ {
const char *name;
Command **commands;
} sql_script[MAX_SCRIPTS]; /* SQL script files */
static int num_scripts; /* number of scripts in sql_script[] */
static int num_commands = 0; /* total number of Command structs */ static int num_commands = 0; /* total number of Command structs */
static int debug = 0; /* debug flag */ static int debug = 0; /* debug flag */
/* default scenario */ /* Define builtin test scripts */
static char *tpc_b = { #define N_BUILTIN 3
static struct
{
char *name; /* very short name for -b ... */
char *desc; /* short description */
char *commands; /* actual pgbench script */
}
builtin_script[] =
{
{
"tpcb-like",
"<builtin: TPC-B (sort of)>",
"\\set nbranches " CppAsString2(nbranches) " * :scale\n" "\\set nbranches " CppAsString2(nbranches) " * :scale\n"
"\\set ntellers " CppAsString2(ntellers) " * :scale\n" "\\set ntellers " CppAsString2(ntellers) " * :scale\n"
"\\set naccounts " CppAsString2(naccounts) " * :scale\n" "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
...@@ -316,10 +331,10 @@ static char *tpc_b = { ...@@ -316,10 +331,10 @@ static char *tpc_b = {
"UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n" "UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n" "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
"END;\n" "END;\n"
}; },
{
/* -N case */ "simple-update",
static char *simple_update = { "<builtin: simple update>",
"\\set nbranches " CppAsString2(nbranches) " * :scale\n" "\\set nbranches " CppAsString2(nbranches) " * :scale\n"
"\\set ntellers " CppAsString2(ntellers) " * :scale\n" "\\set ntellers " CppAsString2(ntellers) " * :scale\n"
"\\set naccounts " CppAsString2(naccounts) " * :scale\n" "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
...@@ -332,15 +347,17 @@ static char *simple_update = { ...@@ -332,15 +347,17 @@ static char *simple_update = {
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n" "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
"INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n" "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
"END;\n" "END;\n"
}; },
{
/* -S case */ "select-only",
static char *select_only = { "<builtin: select only>",
"\\set naccounts " CppAsString2(naccounts) " * :scale\n" "\\set naccounts " CppAsString2(naccounts) " * :scale\n"
"\\setrandom aid 1 :naccounts\n" "\\setrandom aid 1 :naccounts\n"
"SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n" "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
}
}; };
/* Function prototypes */ /* Function prototypes */
static void setalarm(int seconds); static void setalarm(int seconds);
static void *threadRun(void *arg); static void *threadRun(void *arg);
...@@ -365,24 +382,29 @@ usage(void) ...@@ -365,24 +382,29 @@ usage(void)
" create indexes in the specified tablespace\n" " create indexes in the specified tablespace\n"
" --tablespace=TABLESPACE create tables in the specified tablespace\n" " --tablespace=TABLESPACE create tables in the specified tablespace\n"
" --unlogged-tables create tables as unlogged tables\n" " --unlogged-tables create tables as unlogged tables\n"
"\nOptions to select what to run:\n"
" -b, --builtin=NAME add buitin script (use \"-b list\" to display\n"
" available scripts)\n"
" -f, --file=FILENAME add transaction script from FILENAME\n"
" -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
" (same as \"-b simple-update\")\n"
" -S, --select-only perform SELECT-only transactions\n"
" (same as \"-b select-only\")\n"
"\nBenchmarking options:\n" "\nBenchmarking options:\n"
" -c, --client=NUM number of concurrent database clients (default: 1)\n" " -c, --client=NUM number of concurrent database clients (default: 1)\n"
" -C, --connect establish new connection for each transaction\n" " -C, --connect establish new connection for each transaction\n"
" -D, --define=VARNAME=VALUE\n" " -D, --define=VARNAME=VALUE\n"
" define variable for use by custom script\n" " define variable for use by custom script\n"
" -f, --file=FILENAME read transaction script from FILENAME\n"
" -j, --jobs=NUM number of threads (default: 1)\n" " -j, --jobs=NUM number of threads (default: 1)\n"
" -l, --log write transaction times to log file\n" " -l, --log write transaction times to log file\n"
" -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n" " -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n"
" -M, --protocol=simple|extended|prepared\n" " -M, --protocol=simple|extended|prepared\n"
" protocol for submitting queries (default: simple)\n" " protocol for submitting queries (default: simple)\n"
" -n, --no-vacuum do not run VACUUM before tests\n" " -n, --no-vacuum do not run VACUUM before tests\n"
" -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
" -P, --progress=NUM show thread progress report every NUM seconds\n" " -P, --progress=NUM show thread progress report every NUM seconds\n"
" -r, --report-latencies report average latency per command\n" " -r, --report-latencies report average latency per command\n"
" -R, --rate=NUM target rate in transactions per second\n" " -R, --rate=NUM target rate in transactions per second\n"
" -s, --scale=NUM report this scale factor in output\n" " -s, --scale=NUM report this scale factor in output\n"
" -S, --select-only perform SELECT-only transactions\n"
" -t, --transactions=NUM number of transactions each client runs (default: 10)\n" " -t, --transactions=NUM number of transactions each client runs (default: 10)\n"
" -T, --time=NUM duration of benchmark test in seconds\n" " -T, --time=NUM duration of benchmark test in seconds\n"
" -v, --vacuum-all vacuum all four standard tables before tests\n" " -v, --vacuum-all vacuum all four standard tables before tests\n"
...@@ -1123,6 +1145,15 @@ agg_vals_init(AggVals *aggs, instr_time start) ...@@ -1123,6 +1145,15 @@ agg_vals_init(AggVals *aggs, instr_time start)
aggs->start_time = INSTR_TIME_GET_DOUBLE(start); aggs->start_time = INSTR_TIME_GET_DOUBLE(start);
} }
static int
chooseScript(TState *thread)
{
if (num_scripts == 1)
return 0;
return getrand(thread, 0, num_scripts - 1);
}
/* return false iff client should be disconnected */ /* return false iff client should be disconnected */
static bool static bool
doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVals *agg) doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVals *agg)
...@@ -1143,7 +1174,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa ...@@ -1143,7 +1174,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa
top: top:
INSTR_TIME_SET_ZERO(now); INSTR_TIME_SET_ZERO(now);
commands = sql_files[st->use_file]; commands = sql_script[st->use_file].commands;
/* /*
* Handle throttling once per transaction by sleeping. It is simpler to * Handle throttling once per transaction by sleeping. It is simpler to
...@@ -1328,8 +1359,11 @@ top: ...@@ -1328,8 +1359,11 @@ top:
if (commands[st->state] == NULL) if (commands[st->state] == NULL)
{ {
st->state = 0; st->state = 0;
st->use_file = (int) getrand(thread, 0, num_files - 1); st->use_file = chooseScript(thread);
commands = sql_files[st->use_file]; commands = sql_script[st->use_file].commands;
if (debug)
fprintf(stderr, "client %d executing script \"%s\"\n", st->id,
sql_script[st->use_file].name);
st->is_throttled = false; st->is_throttled = false;
/* /*
...@@ -2239,7 +2273,6 @@ static Command * ...@@ -2239,7 +2273,6 @@ static Command *
process_commands(char *buf, const char *source, const int lineno) process_commands(char *buf, const char *source, const int lineno)
{ {
const char delim[] = " \f\n\r\t\v"; const char delim[] = " \f\n\r\t\v";
Command *my_commands; Command *my_commands;
int j; int j;
char *p, char *p,
...@@ -2489,7 +2522,11 @@ read_line_from_file(FILE *fd) ...@@ -2489,7 +2522,11 @@ read_line_from_file(FILE *fd)
return NULL; return NULL;
} }
static int /*
* Given a file name, read it and return the array of Commands contained
* therein. "-" means to read stdin.
*/
static Command **
process_file(char *filename) process_file(char *filename)
{ {
#define COMMANDS_ALLOC_NUM 128 #define COMMANDS_ALLOC_NUM 128
...@@ -2501,12 +2538,6 @@ process_file(char *filename) ...@@ -2501,12 +2538,6 @@ process_file(char *filename)
char *buf; char *buf;
int alloc_num; int alloc_num;
if (num_files >= MAX_FILES)
{
fprintf(stderr, "at most %d SQL files are allowed\n", MAX_FILES);
exit(1);
}
alloc_num = COMMANDS_ALLOC_NUM; alloc_num = COMMANDS_ALLOC_NUM;
my_commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num); my_commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
...@@ -2517,7 +2548,7 @@ process_file(char *filename) ...@@ -2517,7 +2548,7 @@ process_file(char *filename)
fprintf(stderr, "could not open file \"%s\": %s\n", fprintf(stderr, "could not open file \"%s\": %s\n",
filename, strerror(errno)); filename, strerror(errno));
pg_free(my_commands); pg_free(my_commands);
return false; return NULL;
} }
lineno = 0; lineno = 0;
...@@ -2549,13 +2580,11 @@ process_file(char *filename) ...@@ -2549,13 +2580,11 @@ process_file(char *filename)
my_commands[index] = NULL; my_commands[index] = NULL;
sql_files[num_files++] = my_commands; return my_commands;
return true;
} }
static Command ** static Command **
process_builtin(char *tb, const char *source) process_builtin(const char *tb, const char *source)
{ {
#define COMMANDS_ALLOC_NUM 128 #define COMMANDS_ALLOC_NUM 128
...@@ -2609,9 +2638,60 @@ process_builtin(char *tb, const char *source) ...@@ -2609,9 +2638,60 @@ process_builtin(char *tb, const char *source)
return my_commands; return my_commands;
} }
static void
listAvailableScripts(void)
{
int i;
fprintf(stderr, "Available builtin scripts:\n");
for (i = 0; i < N_BUILTIN; i++)
fprintf(stderr, "\t%s\n", builtin_script[i].name);
fprintf(stderr, "\n");
}
static char *
findBuiltin(const char *name, char **desc)
{
int i;
for (i = 0; i < N_BUILTIN; i++)
{
if (strncmp(builtin_script[i].name, name,
strlen(builtin_script[i].name)) == 0)
{
*desc = builtin_script[i].desc;
return builtin_script[i].commands;
}
}
fprintf(stderr, "no builtin script found for name \"%s\"\n", name);
listAvailableScripts();
exit(1);
}
static void
addScript(const char *name, Command **commands)
{
if (commands == NULL)
{
fprintf(stderr, "empty command list for script \"%s\"\n", name);
exit(1);
}
if (num_scripts >= MAX_SCRIPTS)
{
fprintf(stderr, "at most %d SQL scripts are allowed\n", MAX_SCRIPTS);
exit(1);
}
sql_script[num_scripts].name = name;
sql_script[num_scripts].commands = commands;
num_scripts++;
}
/* print out results */ /* print out results */
static void static void
printResults(int ttype, int64 normal_xacts, int nclients, printResults(int64 normal_xacts, int nclients,
TState *threads, int nthreads, TState *threads, int nthreads,
instr_time total_time, instr_time conn_total_time, instr_time total_time, instr_time conn_total_time,
int64 total_latencies, int64 total_sqlats, int64 total_latencies, int64 total_sqlats,
...@@ -2621,23 +2701,14 @@ printResults(int ttype, int64 normal_xacts, int nclients, ...@@ -2621,23 +2701,14 @@ printResults(int ttype, int64 normal_xacts, int nclients,
double time_include, double time_include,
tps_include, tps_include,
tps_exclude; tps_exclude;
char *s;
time_include = INSTR_TIME_GET_DOUBLE(total_time); time_include = INSTR_TIME_GET_DOUBLE(total_time);
tps_include = normal_xacts / time_include; tps_include = normal_xacts / time_include;
tps_exclude = normal_xacts / (time_include - tps_exclude = normal_xacts / (time_include -
(INSTR_TIME_GET_DOUBLE(conn_total_time) / nclients)); (INSTR_TIME_GET_DOUBLE(conn_total_time) / nclients));
if (ttype == 0) printf("transaction type: %s\n",
s = "TPC-B (sort of)"; num_scripts == 1 ? sql_script[0].name : "multiple scripts");
else if (ttype == 2)
s = "Update only pgbench_accounts";
else if (ttype == 1)
s = "SELECT only";
else
s = "Custom query";
printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", scale); printf("scaling factor: %d\n", scale);
printf("query mode: %s\n", QUERYMODE[querymode]); printf("query mode: %s\n", QUERYMODE[querymode]);
printf("number of clients: %d\n", nclients); printf("number of clients: %d\n", nclients);
...@@ -2706,16 +2777,14 @@ printResults(int ttype, int64 normal_xacts, int nclients, ...@@ -2706,16 +2777,14 @@ printResults(int ttype, int64 normal_xacts, int nclients,
{ {
int i; int i;
for (i = 0; i < num_files; i++) for (i = 0; i < num_scripts; i++)
{ {
Command **commands; Command **commands;
if (num_files > 1) printf("SQL script %d: %s\n", i + 1, sql_script[i].name);
printf("statement latencies in milliseconds, file %d:\n", i + 1); printf(" - statement latencies in milliseconds:\n");
else
printf("statement latencies in milliseconds:\n");
for (commands = sql_files[i]; *commands != NULL; commands++) for (commands = sql_script[i].commands; *commands != NULL; commands++)
{ {
Command *command = *commands; Command *command = *commands;
int cnum = command->command_num; int cnum = command->command_num;
...@@ -2753,6 +2822,7 @@ main(int argc, char **argv) ...@@ -2753,6 +2822,7 @@ main(int argc, char **argv)
{ {
static struct option long_options[] = { static struct option long_options[] = {
/* systematic long/short named options */ /* systematic long/short named options */
{"tpc-b", no_argument, NULL, 'b'},
{"client", required_argument, NULL, 'c'}, {"client", required_argument, NULL, 'c'},
{"connect", no_argument, NULL, 'C'}, {"connect", no_argument, NULL, 'C'},
{"debug", no_argument, NULL, 'd'}, {"debug", no_argument, NULL, 'd'},
...@@ -2795,14 +2865,12 @@ main(int argc, char **argv) ...@@ -2795,14 +2865,12 @@ main(int argc, char **argv)
int is_init_mode = 0; /* initialize mode? */ int is_init_mode = 0; /* initialize mode? */
int is_no_vacuum = 0; /* no vacuum at all before testing? */ int is_no_vacuum = 0; /* no vacuum at all before testing? */
int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */ int do_vacuum_accounts = 0; /* do vacuum accounts before testing? */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
* 2: skip update of branches and tellers */
int optindex; int optindex;
char *filename = NULL;
bool scale_given = false; bool scale_given = false;
bool benchmarking_option_set = false; bool benchmarking_option_set = false;
bool initialization_option_set = false; bool initialization_option_set = false;
bool internal_script_used = false;
CState *state; /* status of clients */ CState *state; /* status of clients */
TState *threads; /* array of thread */ TState *threads; /* array of thread */
...@@ -2817,6 +2885,7 @@ main(int argc, char **argv) ...@@ -2817,6 +2885,7 @@ main(int argc, char **argv)
int64 throttle_lag_max = 0; int64 throttle_lag_max = 0;
int64 throttle_latency_skipped = 0; int64 throttle_latency_skipped = 0;
int64 latency_late = 0; int64 latency_late = 0;
char *desc;
int i; int i;
int nclients_dealt; int nclients_dealt;
...@@ -2862,7 +2931,7 @@ main(int argc, char **argv) ...@@ -2862,7 +2931,7 @@ main(int argc, char **argv)
state = (CState *) pg_malloc(sizeof(CState)); state = (CState *) pg_malloc(sizeof(CState));
memset(state, 0, sizeof(CState)); memset(state, 0, sizeof(CState));
while ((c = getopt_long(argc, argv, "ih:nvp:dqSNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1) while ((c = getopt_long(argc, argv, "ih:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
{ {
switch (c) switch (c)
{ {
...@@ -2884,14 +2953,6 @@ main(int argc, char **argv) ...@@ -2884,14 +2953,6 @@ main(int argc, char **argv)
case 'd': case 'd':
debug++; debug++;
break; break;
case 'S':
ttype = 1;
benchmarking_option_set = true;
break;
case 'N':
ttype = 2;
benchmarking_option_set = true;
break;
case 'c': case 'c':
benchmarking_option_set = true; benchmarking_option_set = true;
nclients = atoi(optarg); nclients = atoi(optarg);
...@@ -2994,12 +3055,36 @@ main(int argc, char **argv) ...@@ -2994,12 +3055,36 @@ main(int argc, char **argv)
initialization_option_set = true; initialization_option_set = true;
use_quiet = true; use_quiet = true;
break; break;
case 'b':
if (strcmp(optarg, "list") == 0)
{
listAvailableScripts();
exit(0);
}
addScript(desc,
process_builtin(findBuiltin(optarg, &desc), desc));
benchmarking_option_set = true;
internal_script_used = true;
break;
case 'S':
addScript(desc,
process_builtin(findBuiltin("select-only", &desc),
desc));
benchmarking_option_set = true;
internal_script_used = true;
break;
case 'N':
addScript(desc,
process_builtin(findBuiltin("simple-update", &desc),
desc));
benchmarking_option_set = true;
internal_script_used = true;
break;
case 'f': case 'f':
addScript(optarg, process_file(optarg));
benchmarking_option_set = true; benchmarking_option_set = true;
ttype = 3;
filename = pg_strdup(optarg);
if (process_file(filename) == false || *sql_files[num_files - 1] == NULL)
exit(1);
break; break;
case 'D': case 'D':
{ {
...@@ -3030,9 +3115,9 @@ main(int argc, char **argv) ...@@ -3030,9 +3115,9 @@ main(int argc, char **argv)
break; break;
case 'M': case 'M':
benchmarking_option_set = true; benchmarking_option_set = true;
if (num_files > 0) if (num_scripts > 0)
{ {
fprintf(stderr, "query mode (-M) should be specified before any transaction scripts (-f)\n"); fprintf(stderr, "query mode (-M) should be specified before any transaction scripts (-f or -b)\n");
exit(1); exit(1);
} }
for (querymode = 0; querymode < NUM_QUERYMODE; querymode++) for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
...@@ -3133,6 +3218,15 @@ main(int argc, char **argv) ...@@ -3133,6 +3218,15 @@ main(int argc, char **argv)
} }
} }
/* set default script if none */
if (num_scripts == 0 && !is_init_mode)
{
addScript(desc,
process_builtin(findBuiltin("tpcb-like", &desc), desc));
benchmarking_option_set = true;
internal_script_used = true;
}
/* /*
* Don't need more threads than there are clients. (This is not merely an * Don't need more threads than there are clients. (This is not merely an
* optimization; throttle_delay is calculated incorrectly below if some * optimization; throttle_delay is calculated incorrectly below if some
...@@ -3261,7 +3355,7 @@ main(int argc, char **argv) ...@@ -3261,7 +3355,7 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
if (ttype != 3) if (internal_script_used)
{ {
/* /*
* get the scaling factor that should be same as count(*) from * get the scaling factor that should be same as count(*) from
...@@ -3345,31 +3439,6 @@ main(int argc, char **argv) ...@@ -3345,31 +3439,6 @@ main(int argc, char **argv)
INSTR_TIME_SET_CURRENT(start_time); INSTR_TIME_SET_CURRENT(start_time);
srandom((unsigned int) INSTR_TIME_GET_MICROSEC(start_time)); srandom((unsigned int) INSTR_TIME_GET_MICROSEC(start_time));
/* process builtin SQL scripts */
switch (ttype)
{
case 0:
sql_files[0] = process_builtin(tpc_b,
"<builtin: TPC-B (sort of)>");
num_files = 1;
break;
case 1:
sql_files[0] = process_builtin(select_only,
"<builtin: select only>");
num_files = 1;
break;
case 2:
sql_files[0] = process_builtin(simple_update,
"<builtin: simple update>");
num_files = 1;
break;
default:
break;
}
/* set up thread data structures */ /* set up thread data structures */
threads = (TState *) pg_malloc(sizeof(TState) * nthreads); threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
nclients_dealt = 0; nclients_dealt = 0;
...@@ -3500,7 +3569,7 @@ main(int argc, char **argv) ...@@ -3500,7 +3569,7 @@ main(int argc, char **argv)
*/ */
INSTR_TIME_SET_CURRENT(total_time); INSTR_TIME_SET_CURRENT(total_time);
INSTR_TIME_SUBTRACT(total_time, start_time); INSTR_TIME_SUBTRACT(total_time, start_time);
printResults(ttype, total_xacts, nclients, threads, nthreads, printResults(total_xacts, nclients, threads, nthreads,
total_time, conn_total_time, total_latencies, total_sqlats, total_time, conn_total_time, total_latencies, total_sqlats,
throttle_lag, throttle_lag_max, throttle_latency_skipped, throttle_lag, throttle_lag_max, throttle_latency_skipped,
latency_late); latency_late);
...@@ -3584,10 +3653,14 @@ threadRun(void *arg) ...@@ -3584,10 +3653,14 @@ threadRun(void *arg)
for (i = 0; i < nstate; i++) for (i = 0; i < nstate; i++)
{ {
CState *st = &state[i]; CState *st = &state[i];
Command **commands = sql_files[st->use_file];
int prev_ecnt = st->ecnt; int prev_ecnt = st->ecnt;
Command **commands;
st->use_file = getrand(thread, 0, num_files - 1); st->use_file = chooseScript(thread);
commands = sql_script[st->use_file].commands;
if (debug)
fprintf(stderr, "client %d executing script \"%s\"\n", st->id,
sql_script[st->use_file].name);
if (!doCustom(thread, st, &thread->conn_time, logfile, &aggs)) if (!doCustom(thread, st, &thread->conn_time, logfile, &aggs))
remains--; /* I've aborted */ remains--; /* I've aborted */
...@@ -3615,7 +3688,7 @@ threadRun(void *arg) ...@@ -3615,7 +3688,7 @@ threadRun(void *arg)
for (i = 0; i < nstate; i++) for (i = 0; i < nstate; i++)
{ {
CState *st = &state[i]; CState *st = &state[i];
Command **commands = sql_files[st->use_file]; Command **commands = sql_script[st->use_file].commands;
int sock; int sock;
if (st->con == NULL) if (st->con == NULL)
...@@ -3721,7 +3794,7 @@ threadRun(void *arg) ...@@ -3721,7 +3794,7 @@ threadRun(void *arg)
for (i = 0; i < nstate; i++) for (i = 0; i < nstate; i++)
{ {
CState *st = &state[i]; CState *st = &state[i];
Command **commands = sql_files[st->use_file]; Command **commands = sql_script[st->use_file].commands;
int prev_ecnt = st->ecnt; int prev_ecnt = st->ecnt;
if (st->con && (FD_ISSET(PQsocket(st->con), &input_mask) if (st->con && (FD_ISSET(PQsocket(st->con), &input_mask)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment