Running remote Unix commands from LoadRunner
If you need to run a Unix command on a remote server with a LoadRunner script (running on Windows), then there is a neat program called plink that you will find very useful.
If you use any variety of Unix, you will probably already by using PuTTY; well plink is is distributed with PuTTY, and allows you to run remote Unix commands from your DOS prompt.
In this example, I have used it to collect disk I/O metrics from a remote Solaris server.
You may need to refer to some background material for the different components that are used for this example.
- Solaris Tips
- AWK
- Running command-line programs from LoadRunner
To capture the %busy metric for each disk, I can run iostat -xc. This gives the following output:
1 2 3 4 5 6 7 8 9 10 | extended device statistics cpu device r/s w/s kr/s kw/s wait actv svc_t %w %b us sy wt id md0 0.5 0.6 8.5 0.8 0.0 0.0 19.9 0 0 1 1 0 98 md1 6.3 6.8 50.3 54.5 0.0 0.3 24.0 0 0 md3 0.2 0.7 12.7 12.6 0.0 0.0 11.0 0 1 md5 0.0 0.0 2.7 0.3 0.0 0.0 8.0 0 0 md6 0.0 0.0 0.0 0.0 0.0 0.0 3.6 0 0 md10 0.3 0.6 4.2 0.8 0.0 0.0 21.3 0 0 md11 3.1 6.8 25.1 54.5 0.0 0.3 25.6 0 0 md13 0.1 0.7 6.4 12.6 0.0 0.0 8.7 0 0 |
Using AWK to just grab the device name and the %b column can be done by running iostat -xc | awk ‘NR >2 {print $1, $9}’, which gives:
1 2 3 4 5 6 7 8 | md0 0 md1 0 md3 1 md5 0 md6 0 md10 0 md11 0 md13 0 |
Putting this in a LoadRunner script that will save the %b value for each device using lr_user_data_point() looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | /* * This script retrieves Disk IO stats from a Solaris server and plots them in the Controller using lr_user_data_point(). */ #define BUFFER_SIZE 10240 // 10 KB extern char* strtok(char *token, const char *delimiter); // Explicit declaration required for functions that do not return an int. Action() { long fp; // file/stream pointer int count; // number of characters that have been read from the stream. char buffer[BUFFER_SIZE]; // allocate memory for the output of the command. char * row_token; // for each row in the output of the command. char field_name[100]; // for the first column in the row. int field_value; // for the second column in the row. char lrudp_name[100]; // buffer to hold the LR user data point name. int rc; // return code for sscanf. lr_start_transaction("Monitor Disk IO"); // The command we want to run is: plink -ssh -l username -pw password hostname command lr_save_string("stuart", "UserName"); lr_save_string("asdf7890", "Password"); lr_save_string("sdb526.sysdomain.local", "Server"); lr_save_string("iostat -xc | awk 'NR >2 {print $1, $10}'", "Command"); // run iostat, and retrieve the "device" and "%b" column from the output. lr_save_string(lr_eval_string("C:\\Progra~1\\PuTTY\\plink -ssh -l {UserName} -pw {Password} {Server} \"{Command}\" 2>&1 0< nul:"), "CompleteCommand"); // Note: plink refuses to work without stdin redirected fp = popen(lr_eval_string("{CompleteCommand}"), "r"); if (fp == NULL) { lr_error_message("Error opening stream."); return -1; } count = fread(buffer, sizeof(char), BUFFER_SIZE, fp); // read up to 10KB if (feof(fp) == 0) { lr_error_message("Did not reach the end of the input stream when reading. Try increasing BUFFER_SIZE."); return -1; } if (ferror(fp)) { lr_error_message ("I/O error during read."); return -1; } if (count == 0) { lr_error_message("Something went wrong when running command. No output returned."); return -1; } buffer[count] = NULL; /* The command should return data formatted like this: md0 0 md1 0 md3 1 md5 0 md6 0 md10 0 md11 0 md13 0 Iterate through each row, and save the name and value. */ row_token = (char*) strtok(buffer, "\n"); // Split the buffer at each newline character if (row_token == NULL) { lr_error_message ("Something went wrong. No token found"); return -1; } while (row_token != NULL) { // While there are still rows in the buffer... rc = sscanf(row_token, "%s %d", field_name, &field_value); // Grab the field name and value. if (rc != 2) { lr_error_message("Incorrect number of items read from the row."); return -1; } // Create a user data point, so this value can be graphed in the LoadRunner Controller (and in LoadRunner Analysis). sprintf(lrudp_name, "disk_busy_%s", field_name); lr_user_data_point(lrudp_name, field_value); row_token = (char*) strtok(NULL, "\n"); } /* Output will be Notify: Data Point "disk_busy_md0" value = 0.0000. Notify: Data Point "disk_busy_md1" value = 0.0000. Notify: Data Point "disk_busy_md3" value = 1.0000. Notify: Data Point "disk_busy_md5" value = 0.0000. Notify: Data Point "disk_busy_md6" value = 0.0000. Notify: Data Point "disk_busy_md10" value = 0.0000. Notify: Data Point "disk_busy_md11" value = 0.0000. Notify: Data Point "disk_busy_md13" value = 0.0000. */ pclose(fp); lr_end_transaction("Monitor Disk IO", LR_AUTO); return 0; } |
I hope you find this useful – both for the general concept of using LoadRunner to invoke commands (or shell scripts) on a remote Unix host and retrieve the output, and for the ability to monitor disk IO on Solaris without using SiteScope.




Note that the first time you connect to a server using plink, you are likely to get a message like this:
…and you will have to add the key to the cache before you can run plink from LoadRunner.
Another hot tip:
If you use this script for monitoring, run it from a separate load generator, rather than from your Controller, because every time the DOS command is invoked, it briefly pops up an annoying cmd.exe window.
Please suggest any suitable tool for the load testing of Flex based web application?
Hi, Stuart. Nice to see your instruction on how to run UNIX command using LR controller under windows. I tried to use LR agent to run a LR script that calls system() function to run a UNIX command, and when using mdrv -usr *.usr, all seems ok. The transaction can pass. However, when I using LR controller under WINDOWS to run the compiled script under $M_LROOT/bin the transaction failed. I used the “Not to use RSH” option. Do you think I should use RSH instead? Any suggestions? Thank you in advance.
It sounds like you are running your vusers from an agent on a Linux/Unix load generator.
The example above runs the Unix command remotely from a Windows load generator.
Unfortunately I am not sure what the problem might be in your case.
On a side-note, I would not recommend that you use Unix/Linux-based load generators for LoadRunner.