Friday, September 11, 2009

Need Editor

Re-reading the posts, I realize I need an editor.

Thursday, September 10, 2009

Persisting LR Data Using MySQL

In the beginning it was horrible: not knowing what kind of C compiler LoadRunner is using, I experience with several header files from cygwin and mingw, which I know, deep inside, won’t work.

But RTFM saved the day, by merging the header files to $LR/include MySQL C code can be compiled by only tweaking one 64 bits reference.

Below is the final code to commit unique users, I totally rely on MySQL’s ACID to do the right thing. Hopefully I put my belief at the right place.
int commit_user() {
int rc = 0;
char *exec;
int good = 0;
int available = 1;

db_connection = mysql_init(NULL);
if (db_connection == NULL) {
lr_error_message("Insufficient memory");
return -1;
}

// Connect to the database
if (mysql_real_connect(db_connection, server, user, password, database, port, NULL, 0) == NULL) {
lr_error_message("error on connect: %s", mysql_error(db_connection));
mysql_close(db_connection);
return -1;
}
lr_output_message("Connection to DB is established");

while (!good) {
available = 1;

while (available) {
exec = lr_eval_string("SELECT EXISTS (select login from LATLogin WHERE login = '{pUserName}');");
if (mysql_query(db_connection, exec)!= 0) {
lr_error_message("%s;error on query: %s", exec, mysql_error(db_connection));
mysql_close(db_connection);
return -1;
}
lr_output_message("exec: %s", exec);

if ((query_result = mysql_store_result(db_connection)) == NULL) {
lr_error_message("%s;error on store: %s", exec, mysql_error(db_connection));
mysql_close(db_connection);
return -1;
}

result_row = mysql_fetch_row(query_result);
available = atoi(result_row[0]);
lr_output_message("available=%d", available);

if (available) { //exists
lr_advance_param("pDataFileUserName");
lr_output_message("Advance pDataFileUserName = %s", lr_eval_string("{pDataFileUserName}"));
while (strcmp(lr_eval_string("{pDataFileUserName}"), lr_eval_string("{pUserName}")) == 0) {
lr_advance_param("pDataFileUserName");
lr_output_message("Advance pDataFileUserName = %s", lr_eval_string("{pDataFileUserName}"));
}
lr_save_string(lr_eval_string("{pDataFileUserName}"), "pUserName");
}
mysql_free_result(query_result);
}

exec = lr_eval_string("INSERT INTO LATLogin VALUES('{pUserName}');");
if (mysql_query(db_connection, exec)!= 0) {
rc = mysql_errno(db_connection);

if (rc == 1062) {
lr_output_message("%s is too late, duplicate exists", exec);

//when pUserName exists, probably some else took it already
lr_advance_param("pDataFileUserName");
lr_output_message("Advance pDataFileUserName = %s", lr_eval_string("{pDataFileUserName}"));
while (strcmp(lr_eval_string("{pDataFileUserName}"), lr_eval_string("{pUserName}")) == 0) {
lr_advance_param("pDataFileUserName");
lr_output_message("Advance pDataFileUserName = %s", lr_eval_string("{pDataFileUserName}"));
}
lr_save_string(lr_eval_string("{pDataFileUserName}"), "pUserName");
}
else {
lr_error_message("%s, error(%d): %s", exec, mysql_errno(db_connection), mysql_error(db_connection));
mysql_close(db_connection);
return -1;
}
}
else {
lr_output_message("exec: %s", exec);
good = 1;
user_removed = 0;
}
}
mysql_close(db_connection);
lr_output_message("Connection to DB is closed");
return 0;
}
The final result: running 90 virtual users (I ran out of login), each running 20 seconds transactions.
GetUniqueUserName
  • 75% of population: 0.028 +/- 0.02
  • 90Percentile: 0.043
The generator machine CPU consumption is hovering around 25% - I give this method of persisting LR data a stamp of approval.

Tuesday, September 8, 2009

Perl Now Runs On Android Scripting Environment (ASE)

I think I have heard about it before, but I managed to push it down to my subconscious level. Now off to figure out which android phone to throw into the ring of my gadget wishlist.

Sunday, September 6, 2009

Internet Is Humming Fine

The tech is a magician! He fixed AT&T's crappy DSL line. No red DSL light blinking this week, not once.

DSL Training Errors, Time Since Last Event: 5 days 6:51:19

House of Prime Rib

1906 Van Ness Ave
San Francisco, CA 94109
Tel:(415) 885-4605
http://houseofprimerib.net

They are doing a good imitation of Lawry's, or is it the other way around?

Friday, September 4, 2009

RTFM Saved The Day

Friday afternoon, and I am very down since nothing works.

I admit, Wilsonmar webpage's not the official one, but it's damn close. But then, I noticed this:
LoadRunner uses A website external to this site 1994 GNU C Pre-Processor options and the A website external to this site 1995 LCC-win32 Retargetable C Compiler/Linker from the Free Software Foundation via Chris Fraser of AT&T and Dave Hanson of Princeton.
MySQL C code is compiling nicely now (after one 64bits ref is tweaked).

The New Multi Protocol Script On LR9.1 Is A Useless POS

Q: Can I record ODBC traffic for Action1.c and then record Web traffic for Action2.c (or vice versa)?
A: No.

Thursday, September 3, 2009

El Burro's Mexican Restaurant

1875 S Bascom Ave # 570 (The Pruneyard #570)
Campbell, CA 95008-2389
Tel: (408) 371-5800

Not bad, not bad at all

Next Stop: SQLite

Actually no, I was thinking about something more ambitious (MySQL). The fact that I have to hunt down other C library files, forces me to consider SQLite. Just drop sqlite3.dll to $LR/bin, sqlite3.h to $LR/include and trim off the 64 bit references in sqlite3.h to make it works.

But simpler solution doesn’t make my life easier, since writing SQLite code (or any db code), in C, that doesn’t leak memory or crashes the db, is fairly hard.

But finally, I get this:
rc = sqlite3_open("test.db", &db);
if (rc) {
lr_output_message("Can't open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return -1;
}
exec = "NO RESULT QUERY SUCH AS: DELETE, INSERT”;
isPrepared = 0;
while (!isPrepared) {
rc = sqlite3_prepare(db, exec, -1, &stmt, 0);
if (rc == SQLITE_OK) { //SQLITE_OK == 0
isPrepared = 1;
isExecuted = 0;
while (!isExecuted) {
rc = sqlite3_step(stmt);
/* uncomment this section when exec is a query that return result
while ((rc == SQLITE_ROW)||(rc == SQLITE_BUSY) ) {
if (rc == SQLITE_BUSY ) {
lr_output_message("SQLITE_BUSY - wait for 0.1 seconds");
lr_think_time(0.1); // TODO: tweak the wait time to your need
}
else {
// extract data
rc = sqlite3_step(stmt);
}
}
*/
if (rc == SQLITE_DONE) {
isExecuted = 1;
sqlite3_finalize(stmt);
}
else if (rc == SQLITE_BUSY) { // DB is locked
lr_output_message("SQLITE_BUSY - wait for 0.1 seconds");
lr_think_time(0.1); // TODO: tweak the wait time to your need
}
else { // real bad stuff usually happens here
lr_output_message("Cannot execute step, rc = %d", rc);
lr_output_message("sqlite3_errmsg: %s", sqlite3_errmsg(db));
lr_output_message("sqlite3_extended_errcode, rc = %d", sqlite3_extended_errcode(db));
sqlite3_finalize(stmt);
sqlite3_close(db);
return -1;
}
}
}
else if (rc == SQLITE_BUSY) { // DB is locked
lr_output_message("SQLITE_BUSY - wait for 0.1 seconds");
lr_think_time(0.1); // TODO: tweak the wait time to your need
}
else { // real bad stuff usually happens here
lr_output_message("Could not prepare statement, rc=%d", rc);
lr_output_message("sqlite3_errmsg: %s", sqlite3_errmsg(db));
lr_output_message("sqlite3_extended_errcode, rc = %d", sqlite3_extended_errcode(db));
sqlite3_close(db);
return -1;
}
}
sqlite3_close(db);
Functionally the script works, at 50 virtual users, each running 20 seconds transactions, even the GetUniqueUserName transaction is fairly fast:
  • 75% of population: 0.269 +/- 0.731
  • 90Percentile: 0.655
But, it doesn’t work at 60 virtual users, it also locks the controller. Not good, need to look into MySQL solution.

Wednesday, September 2, 2009

ActiveState - People Don't Like You?

This is the first time I heard about people emitting strong comments against ActiveState, but I agree with Dami, ActiveState has been making my life very productive, it's products and business practices has been very satisfactory to me.