Friday, October 5, 2012

IBM HeapAnalyzer java.lang.OutOfMemory

You might get java.lang.OutOfMemory error in IBM HeapAnalyzer while processing heapdumps.
Try increasing the JVM heap size and see whether it fixes your OutOfMemory issue before trying other options.



 Following is how you invoke HeapAnalyzer with a heap size parameter in windows.


Finally if your OutOfMemory Issue is fixed, you should able to see the heap dump analysis in HeapAnalyzer.

 

Thursday, October 4, 2012

Chrome About URL

I was playing around with Chrome's about feature few days ago but forgot the actual URL. Therefore this post is to remind me the actual URL. The URL is chrome://about/. There are some useful URLs to know in the list and they are:
  • chrome://dns/
  • chrome://tracing/
  • chrome://profiler/
  • chrome://net-internals/
  • chrome://memory-redirect/
  • chrome://flags/

Tuesday, September 18, 2012

Copying parameters in LoadRunner

Scenario:
You are using same parameter(s) in more than one script and you don't want to manually create them again for each script. So how do you go about copying the parameters from an existing script.

For example:
The following parameters have already been manually created in Script 1 and same parameters are also required for Script 2.
  • DateTime
  • IterationNo
  • RandNo
  • VuserID

Rather than manually creating them, you can copy these parameters from Script 1 and this is how you do it.

Steps:
1: Navigate to Script 1 folder and open file that ends with "prm" extension. This file defines all the parameters and their attributes.


2: Copy the parameters & their attributes and paste into the parameter file of script 2.


3: Save the parameter file. Now open script 2 and navigate to parameter list. You will now noticed that the parameters have been successfully copied.





Saturday, September 8, 2012

Generating UUID in Loadrunner

There have been multiple times where I needed to generate UUID (Verion 4) in Loadrunner but there is no inbuild function to do so. Therefore, I had to either create or modify functions to satisfy my need.

NOTE: Loadrunner does have a function(lr_generate_uuid) for UUID but it does not generate your standard UUID.

Below are three different UUID functions that I normally use depending on the requirement.

For example, If only requirement is that UUID be 32 hexadecimal digits then I will use simple LR UUID to generate it. If there are proper checks in place to see the UUID generated is valid then I will use a proper UUID function's. Therefore you can select which one you want to use depending on your requirement.

Simple UUID - this is a simple 32 hexadecimal digits. You can generate hexaadecimal in Loadrunner using %x or %X Random number.

Following screenshot shows how to generate a random Hexadecimal.


Lr UUID - this function generates 32 hexadecimal digits UUID using Version 4(random) variant. This is the most common format I have seen applications use.

Win UUID - this function uses windows inbuild CoCreateGuid function (ole32.dll). The original code is written by Scott Moore and I have modified it a little bit.

NOTE: I have left the deallocation of pointer for you to do in the code.

#define Hexlength 50  //Max length

char *lr_guid_gen(); //explicitely declare the function
char *lr_uuid_gen(); //explicitely declare the function

Action()
{   

  char *Win_UUID=0; //declare window function UUID variable 
  char *slr_UUID=0; //declare loadrunner function UUID variable
  char *lr_uuid;  //declare UUID variable

  Win_UUID=(char *)malloc(sizeof(char)); //allocate dynamic memory
  slr_UUID=(char *)malloc(sizeof(char)); //allocate dynamic memory

  Win_UUID=lr_guid_gen(); //execute Window UUID function
  slr_UUID=lr_uuid_gen(); //execute LR UUID function
  lr_uuid=lr_generate_uuid(); //assign result generated by loadrunner internal
  function to lr_uuid

  /*output a simple UUID*/
   lr_output_message("smp_UUID: %s",lr_eval_string("{sHex}{sHex}-{sHex}-{sHex}-{sHex}-{sHex}{sHex}{sHex}"));
 //you could use something like this as well -> lr_output_message("smp_UUID: %s",lr_eval_string("{sHex}{sHex}-{sHex}-{FourHex}-{sHex}-{sHex}{sHex}{sHex}"));

  /*output loadrunner UUID*/
  lr_output_message("slr_UUID: %s",lr_eval_string(slr_UUID));

  /*output window generated UUID*/
  lr_output_message("Win_UUID: %s",lr_eval_string(Win_UUID));

  /*output base64 UUID*/
  lr_output_message("%s",lr_uuid);
 
 /*frees uuid created by lr_generarte_uuid*/
 lr_generate_uuid_free(lr_uuid);
 
 return 0;

}

 

/*This function uses windows ole32 CoCreateGuid function to generate UUID*/
char *lr_guid_gen()

{

    typedef struct _GUID

    {

        unsigned long Data1;

        unsigned short Data2;

        unsigned short Data3;

        unsigned char Data4[4];

    } GUID;

    char guid[Hexlength];
    GUID m_guid;

    lr_load_dll ("ole32.dll");

    CoCreateGuid(&m_guid);

    sprintf (guid, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",

    m_guid.Data1, m_guid.Data2, m_guid.Data3,

    m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],

    m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);


    return guid;
}


/*This function uses loadrunner random numbers to generate version 4 UUID*/
char *lr_uuid_gen()
{
  char uuid[Hexlength];
  switch (atoi(lr_eval_string("{RandNo}")))
  {
   case 1:
    sprintf(uuid,lr_eval_string("{Hex}{Hex}-{Hex}-{FourHex}-{aHex}-{Hex}{Hex}{Hex}"));
    break;
   case 2:
    sprintf(uuid,lr_eval_string("{Hex}{Hex}-{Hex}-{FourHex}-{bHex}-{Hex}{Hex}{Hex}"));
    break;
   case 3:
    sprintf(uuid,lr_eval_string("{Hex}{Hex}-{Hex}-{FourHex}-{EightHex}-{Hex}{Hex}{Hex}"));
    break;
   case 4:
    sprintf(uuid,lr_eval_string("{Hex}{Hex}-{Hex}-{FourHex}-{NineHex}-{Hex}{Hex}{Hex}"));
    break;
   default:
    break;
  }
 return uuid;
}




Output:
Action.c(23): smp_UUID: 492ec6db-dcaf-fb6d-1009-72a542e26ee7
Action.c(26): slr_UUID: c4fbde14-4f41-4963-8400-32f77f6e0633
Action.c(29): Win_UUID: cee9f8fd-3715-4183-b367-a4c13b84a7c8
Action.c(32): LBase_64: J3+Lpj2t20KzpBSgg0e5Bg==

Action.c(23): smp_UUID: 65ea1bc1-8434-e05b-92f5-7e23a0f7e253
Action.c(26): slr_UUID: 358390f7-2405-4b03-8be4-b8c61b90a2b6
Action.c(29): Win_UUID: 75d74eb9-a2bf-42b4-b114-61d634a2c7db
Action.c(32): LBase_64: uzxvhpLXP0ifUjMSqzngCQ==

Action.c(23): smp_UUID: 0a86ce02-7413-1da3-bd39-63fc4cb9d60e
Action.c(26): slr_UUID: 726546c5-500d-4ef2-a27e-f447bb925143
Action.c(29): Win_UUID: db65a02f-1ca1-4fb3-ab22-0e41088b1633
Action.c(32): LBase_64: IJV65qREQUOe5CVwcE5aVQ==
 
Action.c(23): smp_UUID: 6678a6ac-3356-eb2f-63e6-02fe5a5185f2
Action.c(26): slr_UUID: acddc8f9-746d-4655-838c-7802483e06bb
Action.c(29): Win_UUID: e7a7ff1c-4019-4053-a51a-7567582d825c
Action.c(32): LBase_64: i+b5VpgA7Ueis8r1bxBTJg==
 
Action.c(23): smp_UUID: 3f8eb05e-9936-b5fc-6be9-454fd8fb9ab5
Action.c(26): slr_UUID: cc835158-9e86-4df5-8a4e-1e3f25808754
Action.c(29): Win_UUID: 3d604abe-046b-43dc-a5c4-e759fb04f960
Action.c(32): LBase_64: Rk2mSYUuOUmU0Yti_W+a5Q==

If you have a different function to generate UUID in Loadrunner, I would love to know about it.

Thursday, June 7, 2012

Plagiarizing someone else experience

Whenever I get a "Join my network on LinkediIn" message from someone on LinkedIn, I always try to view their profile before accepting it. This is because I just like to know a little bit more about them.

Recently, I received a join message from Manish Sinha(works for Accenture(Bengaluru - India) as a performance test lead) and as always, before accepting it, I viewed his profile and what I found was bit of a surprise. He was plagiarizing someone else experience on his profile as his own and guess what, that was my experience he was plagiarizing.

I emailed him couple of times to remove the experience from his profile but so far no luck. Therefore, I thought, I blog about it.

His Experience as ASc Consultant at Capgemini.


Can you see the similarity with my experience.

Friday, June 1, 2012

Publishing result in Silkperformer

SilkPerformer reports percentiles in a different section than the main table and it can be time consuming, if you want to publish all the metrics in a single table. Therefore to solve this issue, a colleague (Murray Wardle) of mine wrote a visual basic script that generates a table with all the metrics.

He has kindly allowed me to share it here and below is his description on how to use it.

"Publishing results from SilkPerformer can sometimes be very time consuming. Most projects will have requirements involving the 90th or 95th percentiles and for some reason SilkPerformer reports percentiles in a different section of the report and not in the main table I wish to publish.

Generally in my scripts I’ll use Timers for measuring response times (I’m not too keen of the automatic page and form timers) for timers controlled with the MeasureStart() and MeasureStop() functions, Inserting the following into the TInit will enable percentiles to be calculated for the Timers.

MeasureCalculatePercentiles(NULL,MEASURE_TIMER_RESPONSETIME);

Unfortunately percentiles are displayed in a different section of the report to the Min, Avg, Max, StdDev, Count, and it’s a waste of time trying to copy and paste the values into a spreadsheet.

So, here is a simple little script which does the work. Just drag and drop the OverviewReport.xml file onto the script and it will create a csv file with the following:

ScriptName, TimerName, Min, Avg, Max, StDev, Count, 50th Perc, 90th Perc, 95th Perc, 99th Perc"


NOTE: You are allowed to use the code as long as you acknowledge the author.

'Copyright (c) 2012 Murray Wardle, murray.wardle@advancedperformance.com.au
'Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
'The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
'THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

Option Explicit

Dim xmlDoc
Dim scriptName, scriptNodes, SNode, TNode, timerNodes, timerName
Dim reportFile, outputFile
Dim myFSO, fileHandle
Dim min, avg, max, stDev, count, p50, p90, p95, p99
Set xmlDoc = CreateObject("Microsoft.XMLDOM") 

Const ForReading = 1, ForWriting = 2, ForAppending = 8 

If Wscript.Arguments.Count = 0 Then
    msgbox "Please specify the overview Report file to process"
Else

 ' Get report file name & set output filename
    reportFile = Wscript.Arguments(0) 
 outputFile = Left(reportFile, Len(reportFile)-3) + "csv"

 xmlDoc.async = false 
 xmlDoc.SetProperty "SelectionLanguage", "XPath" 
 xmlDoc.SetProperty "ServerHTTPRequest", True
 xmlDoc.validateOnParse = False 
 xmlDoc.resolveExternals = False

 'load overview report
 xmlDoc.load(reportFile)
 xmlDoc.setProperty "SelectionLanguage", "XPath"  

 'open csv file to dump results into
 Set myFSO = CreateObject("Scripting.FileSystemObject")
 Set fileHandle = myFSO.OpenTextFile(outputFile, ForWriting, True)
 fileHandle.WriteLine("Script,Timer,Min,Avg,Max,StDev,Count,50th Perc,90th Perc,95th Perc,99th Perc")

 'For each script
 Set scriptNodes = xmlDoc.selectNodes("/Overview_Report_Data/UserGroups/Group") 
 For Each SNode in scriptNodes 
  scriptName = SNode.SelectSingleNode("Name").text

  'For each measure of type Timer
  Set timerNodes = SNode.selectNodes("Measures/Measure") 
  For Each TNode in timerNodes 
   If TNode.SelectSingleNode("Class").text = "Timer" then
   
    ' Extract the timer data
    timerName = TNode.SelectSingleNode("Name").text
    min = TNode.SelectSingleNode("MinMin").text
    avg = TNode.SelectSingleNode("Avg").text
    max = TNode.SelectSingleNode("MaxMax").text
    stDev = TNode.SelectSingleNode("Stdd").text
    count = TNode.SelectSingleNode("SumCount2").text
    p50 = TNode.SelectSingleNode("Percentiles/Values/Value[1]/Value").text
    p90 = TNode.SelectSingleNode("Percentiles/Values/Value[2]/Value").text
    p95 = TNode.SelectSingleNode("Percentiles/Values/Value[3]/Value").text
    p99 = TNode.SelectSingleNode("Percentiles/Values/Value[4]/Value").text

    'Write to File
    fileHandle.WriteLine(scriptName+","+timerName+","+min+","+avg+","+max+","+stDev+","+count+","+p50+","+p90+","+p95+","+p99)
   
   end if
  
  Next 'TNode in timerNodes 

 Next 'SNode in scriptNodes
 
 fileHandle.Close
 
End If


Example:
1: Save the above code as a visual basic script into a folder. Lets call this script as "ExtractOverviewReportData.vbs".
2: Navigate to you SilkPerformer project and copy OverviewReport.xml into the folder where you have saved vbs script. See the screenshot below.
When you open the xml file, it would look something like this:




  1.100000000
  ABCDEFG
   ForMyBlog.tsd (D:\Silkperformer_Projects\ABCDEF\) 
  Silk Performance Explorer
  Monday, 20 April 2012 - 3:00:00 AM
  1
  
Header ABCD 8 None 1 28/05/2012 1:00:12 AM 6280.000000000 4 Merged MPPO SVT 23
... Timer #Overall Response Time# Response time[s] Seconds 0.000000000 0.000000000 3 2 Response time[s] 200.000000000 100.000000000 830.000000000 35000.000000000 0.500000000 60.00000000 6.412345678 11.123456789 0.000000000 0 0.000000000 0 0 0 50 1.123456789 90 22.123456789 95 60.00000000 99 60.00000000 ...
3:Now drag and drop the OverviewReport.xml file onto the script and it will create a csv file.
4: Now open up the csv file in excel and you should have all the necessary metric. You will see something like this:

Monday, May 21, 2012

Querying and Inserting records into MongoDB using LoadRunner

This simple LR script inserts and retrieves a record from mongoDB. You can modify it to accommodate your own need.

Requirement:
Download Java driver for mongoDB and add it to the classpath in the java script.



import java.lang.String;
import java.net.UnknownHostException;
import java.util.Set;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

import lrapi.lr;
public class Actions
{ 
    static String HostName ="localhost";  
    static Integer Port = 27017;
    static String Username ="Harinder";
    static String Password ="Password";
    Mongo mDB;
    DB db;

 public int init() throws Throwable{
    try { 
        mDB= new Mongo( HostName , Port ); //connect to MongoDB using HostName and Port
        db = mDB.getDB("test"); // get test database from MongoDB
        boolean auth = db.authenticate(Username, Password.toCharArray()); //authenticate user access to test database
        if (auth = true) 
           lr.output_message("Successfully Authenticated");
        else
           lr.output_message("Incorrect Username/Password");

     }catch (UnknownHostException e) {
        e.printStackTrace();
    }
     return 0;
   }//end of init function

 public int action() throws Throwable {
     try { 
          InsertInToMongoDB("Harinder1", "Seera1", "ThisIsMongoDB1@gmail.com");
 
         }catch (MongoException e){
          e.printStackTrace();
         }

     try { 
         SearchMongoDB("Harinder");
 
         }catch (MongoException e){
          e.printStackTrace();
        }
 return 0;
 }//end of action function


 public int end() throws Throwable {
     mDB.close();
  return 0;
 }//end of end function


   public void InsertInToMongoDB(String FirstName, String LastName, String Email)
   { 
       // Get collection from mongoDB.
       // If collection doesn't exist, mongoDB will create it automatically
       DBCollection collection = db.getCollection("MyCollection");
       BasicDBObject document = new BasicDBObject();  // create a document to store key and value
       document.put("FirstName",FirstName);
       document.put("LastName", LastName);
       document.put("Email", Email);
       collection.insert(document);   //save the document into collection
   }


   public void SearchMongoDB(String FirstName)
   { 
       DBCollection collection = db.getCollection("MyCollection");
       BasicDBObject srchQuery = new BasicDBObject(); // search query
       srchQuery.put("FirstName", FirstName);
       DBCursor cur = collection.find(srchQuery); // query it
 
       // loop over the cursor and display the retrieved result
       while (cur.hasNext()) {
         System.out.println(cur.next()); //I am using it only for the blog purpose to show the output.
   }
 }
}

mongoDB output:

Sunday, April 1, 2012

How to alter "System" password in Oracle database express edition

Oracle database express edition is installed as part of OATS(Oracle Application Testing Suite) installation and during installation, I don't recall been asked to setup database administrator username and password, which is required to login to the Database Home page. However, you can login as a "SYSTEM" user but before that, you will need to setup the password for this user. Sorry, don't know the default password for "SYSTEM" user.

Following steps show how to setup the password for “SYSTEM” user.

NOTE: This was tested on Windows 7.

1: Make sure the database service is running. This can be checked by running "Start Database" option. If it is running, you will see following output.

2: Type following commands to connect to the database without using password.
sqlplus /nolog
connect / as sysdba
Now you are connected as "SYSTEM" user with full DBA rights. Therefore, you can go ahead and change the password of "SYSTEM" user.

3: Type in the following command to change the password.
alter user {username} identified by {password};
Example:
alter user system identified by oatsystem;

4: Now you should be able to login to Database homepage as "system" user with the new password.

Saturday, March 24, 2012

How to save mongoDB server status into a file

MongoDB serverStatus command provides a useful information about mongod instance. This information includes fields such as mem.virtual, globalLock.currentQueue.writers, extra_info.page_faults. This information can be accessed by executing db.serverStatus() command from the shell.

If you want to save the above result into a file, you can do as follows:

>mongo --eval "printjson(db.serverStatus())" >>{outfile path}

e.g.
>mongo --eval "printjson(db.serverStatus())" >>C:\harinder\log.txt

You can also execute the same using javascript file as an argument. The advantage of this approach is that you can have multiple commands in the file.

>mongo <{Javascript path} >>{Outfile path}

e.g.
>mongo < C:\harinder\mongo.js >>C:\harinder\log.txt

Example of Javascript file:
db.getProfilingLevel()
db.getLastError()
db.foo.find()

Output example:
MongoDB shell version: 2.0.4
connecting to: test
> 0
> null
> { "_id" : ObjectId("4f6e92311c7ef28999436998"), "a" : 1 }
> bye

Thursday, March 8, 2012

Saving vmstat with timestamp into a file on Redhat Linux Machine

By default vmstat output doesnot include timestamp and therefore, if you want to save it with the timestamp into a file on Redhat Linux machine, you can use following command.

$vmstat -n [delay [count]] | awk '{now=strftime("%Y-%m-%d %T "); print now $0}'>{file path}

e.g. vmstat -n 1 30 | awk '{now=strftime("%Y-%m-%d %T "); print now $0}'>/tmp/vmstat.txt
where:
  • n -> display vmstat header once
  • 1 -> update vmstat every second
  • 30 ->only display 30 records
  • awk '{now=strftime("%Y-%m-%d %T "); print now $0}' -> print timestamp
  • >/tmp/vmstat.txt -> path where the vmstat is saved


Final result:
2012-03-09 12:05:25 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
2012-03-09 12:05:25  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
2012-03-09 12:05:25  1  0      0 23199964 473756 6719956    0    0     0     2    0    0  0  0 100  0  0
2012-03-09 12:05:26  0  0      0 23199964 473756 6719956    0    0     0     0  118  232  0  0 100  0  0
2012-03-09 12:05:27  0  0      0 23199964 473756 6719956    0    0     0     0  123  260  0  0 100  0  0
2012-03-09 12:05:28  0  0      0 23199964 473756 6719956    0    0     0     0  111  234  0  0 100  0  0
2012-03-09 12:05:29  0  0      0 23199964 473756 6719956    0    0     0     0  133  276  0  0 100  0  0
2012-03-09 12:05:30  1  0      0 23200088 473756 6719956    0    0     0    88  115  263  0  0 100  0  0
2012-03-09 12:05:31  1  0      0 23200088 473756 6719956    0    0     0    12  135  251  0  0 100  0  0
2012-03-09 12:05:32  0  0      0 23200088 473756 6719964    0    0     0     0  113  313  0  0 100  0  0
2012-03-09 12:05:33  0  0      0 23200088 473756 6719964    0    0     0     0  127  270  0  0 100  0  0
2012-03-09 12:05:34  0  0      0 23200088 473756 6719964    0    0     0     0  110  271  0  0 100  0  0
2012-03-09 12:05:35  1  0      0 23200088 473756 6719964    0    0     0     0  142  297  0  0 100  0  0
2012-03-09 12:05:36  0  0      0 23200088 473756 6719964    0    0     0    44  127  264  0  0 100  0  0
2012-03-09 12:05:37  0  0      0 23200088 473756 6719968    0    0     0    12  144  349  0  0 100  0  0
2012-03-09 12:05:38  0  0      0 23200088 473756 6719928    0    0     0     0  143  259  0  0 100  0  0
2012-03-09 12:05:39  0  0      0 23200088 473756 6719928    0    0     0     0  137  273  0  0 100  0  0
2012-03-09 12:05:40  0  0      0 23200088 473756 6719928    0    0     0     0  123  252  0  0 100  0  0
2012-03-09 12:05:41  0  0      0 23200088 473756 6719928    0    0     0   104  198  269  0  0 100  0  0
2012-03-09 12:05:42  0  0      0 23200088 473756 6719928    0    0     0     0  166  280  0  0 100  0  0
2012-03-09 12:05:43  0  0      0 23200088 473756 6719928    0    0     0     0  183  322  0  0 100  0  0
2012-03-09 12:05:44  0  0      0 23200088 473756 6719932    0    0     0     0  205  330  0  0 100  0  0
2012-03-09 12:05:45  0  0      0 23200088 473756 6719932    0    0     0     0  157  260  0  0 100  0  0
2012-03-09 12:05:46  0  0      0 23200088 473756 6719932    0    0     0     0  112  219  0  0 100  0  0
2012-03-09 12:05:47  0  0      0 23200088 473756 6719932    0    0     0    52  144  304  0  0 100  0  0
2012-03-09 12:05:48  0  0      0 23200088 473756 6719932    0    0     0     0  117  230  0  0 100  0  0
2012-03-09 12:05:49  0  0      0 23200088 473756 6719932    0    0     0     0  139  280  0  0 100  0  0
2012-03-09 12:05:50  0  0      0 23200088 473756 6719932    0    0     0     0  126  241  0  0 100  0  0
2012-03-09 12:05:51  0  0      0 23200088 473756 6719932    0    0     0     0  129  243  0  0 100  0  0
2012-03-09 12:05:52  0  0      0 23200088 473756 6719932    0    0     0     0  111  237  0  0 100  0  0
2012-03-09 12:05:53  0  0      0 23200088 473756 6719932    0    0     0    32  132  265  0  0 100  0  0
2012-03-09 12:05:54  0  0      0 23200088 473756 6719932    0    0     0    16  119  260  0  0 100  0  0

Saturday, March 3, 2012

Runtime Statistics in CouchDB


CouchDB  is an open source document-oriented database. More information on CouchDB is available here

CouchDB 0.9 and above comes with a list of counters that lets you inspect how CouchDB performs. On windows (local machine where CouchDB is installed), you can view these counters by navigating to the following URL: http://localhost:5984/_stats. More information is available here.

The information returned is in JSON format. There are free tools and websites available to display the stats in a more user friendly format.


GroupKeyDescription
Couchdbdatabase_writesNumber  of times a database was changed
open_databasesNumber  of open databases
auth_cache_hitsNumber  of authentication cache hits
auth_cache_missesNumber  of authentication cache misses
database_readsNumber  of times a document was read from a database
request_timeLength of a request inside CouchDB without MochiWeb
open_os_filesNumber  of file descriptors CouchDB has open
httpdRequestsNumber  of HTTP requests
bulk_requestsNumber  of bulk requests
view_readsNumber  of view reads
clients_requesting_changesNumber  of clients for continuous _changes
temporary_view_readsNumber  of temporary view reads
httpd_request_methodsDELETENumber  of HTTP DELETE requests
HEADNumber  of HTTP HEAD requests
POSTNumber  of HTTP POST requests
PUTNumber  of HTTP PUT requests
GETNumber  of HTTP GET requests
COPYNumber  of HTTP COPY requests
httpd_status_codes400Number  of HTTP 400 Bad Request responses
201Number  of HTTP 201 Created responses
403Number  of HTTP 403 Forbidden responses
409Number  of HTTP 409 Conflict responses
200Number  of HTTP 200 OK responses
202Number  of HTTP 202 Accepted responses
404Number  of HTTP 404 Not Found responses
301Number  of HTTP 301 Moved Permanently responses
405Number  of HTTP 405 Method Not Allowed responses
500Number  of HTTP 500 Internal Server Error responses
401Number  of HTTP 401 Unauthorized responses
304Number  of HTTP 304 Not Modified responses
412Number  of HTTP 412 Precondition Failed responses

Below is a formated JSON output example:

{ "couchdb" : { "auth_cache_hits" : { "current" : 2089.0,
          "description" : "number of authentication cache hits",
          "max" : 222,
          "mean" : 0.83199999999999996,
          "min" : 0,
          "stddev" : 10.222,
          "sum" : 2089.0
        },
      "auth_cache_misses" : { "current" : 12.0,
          "description" : "number of authentication cache misses",
          "max" : 3,
          "mean" : 0.0050000000000000001,
          "min" : 0,
          "stddev" : 0.113,
          "sum" : 12.0
        },
      "database_reads" : { "current" : 643.0,
          "description" : "number of times a document was read from a database",
          "max" : 131,
          "mean" : 0.25700000000000001,
          "min" : 0,
          "stddev" : 4.1050000000000004,
          "sum" : 643.0
        },
      "database_writes" : { "current" : 205.0,
          "description" : "number of times a database was changed",
          "max" : 28,
          "mean" : 0.082000000000000003,
          "min" : 0,
          "stddev" : 1.056,
          "sum" : 205.0
        },
      "open_databases" : { "current" : 10.0,
          "description" : "number of open databases",
          "max" : 7,
          "mean" : 0.0040000000000000001,
          "min" : -5,
          "stddev" : 0.21099999999999999,
          "sum" : 10.0
        },
      "open_os_files" : { "current" : 10.0,
          "description" : "number of file descriptors CouchDB has open",
          "max" : 7,
          "mean" : 0.0040000000000000001,
          "min" : -5,
          "stddev" : 0.28699999999999998,
          "sum" : 10.0
        },
      "request_time" : { "current" : 13881.477999999999,
          "description" : "length of a request inside CouchDB without MochiWeb",
          "max" : 12043.0,
          "mean" : 115.679,
          "min" : 0.0,
          "stddev" : 1098.511,
          "sum" : 13881.477999999999
        }
    },
  "httpd" : { "bulk_requests" : { "current" : 27.0,
          "description" : "number of bulk requests",
          "max" : 10,
          "mean" : 0.010999999999999999,
          "min" : 0,
          "stddev" : 0.253,
          "sum" : 27.0
        },
      "clients_requesting_changes" : { "current" : null,
          "description" : "number of clients for continuous _changes",
          "max" : null,
          "mean" : null,
          "min" : null,
          "stddev" : null,
          "sum" : null
        },
      "requests" : { "current" : 2395.0,
          "description" : "number of HTTP requests",
          "max" : 221,
          "mean" : 0.95299999999999996,
          "min" : 0,
          "stddev" : 10.359999999999999,
          "sum" : 2395.0
        },
      "temporary_view_reads" : { "current" : 92.0,
          "description" : "number of temporary view reads",
          "max" : 33,
          "mean" : 0.036999999999999998,
          "min" : 0,
          "stddev" : 0.94199999999999995,
          "sum" : 92.0
        },
      "view_reads" : { "current" : 144.0,
          "description" : "number of view reads",
          "max" : 37,
          "mean" : 0.058000000000000003,
          "min" : 0,
          "stddev" : 1.1579999999999999,
          "sum" : 144.0
        }
    },
  "httpd_request_methods" : { "COPY" : { "current" : 1.0,
          "description" : "number of HTTP COPY requests",
          "max" : 1,
          "mean" : 0.0,
          "min" : 0,
          "stddev" : 0.02,
          "sum" : 1.0
        },
      "DELETE" : { "current" : 187.0,
          "description" : "number of HTTP DELETE requests",
          "max" : 81,
          "mean" : 0.074999999999999997,
          "min" : 0,
          "stddev" : 1.6919999999999999,
          "sum" : 187.0
        },
      "GET" : { "current" : 1672.0,
          "description" : "number of HTTP GET requests",
          "max" : 222,
          "mean" : 0.66600000000000004,
          "min" : 0,
          "stddev" : 9.1310000000000002,
          "sum" : 1672.0
        },
      "HEAD" : { "current" : null,
          "description" : "number of HTTP HEAD requests",
          "max" : null,
          "mean" : null,
          "min" : null,
          "stddev" : null,
          "sum" : null
        },
      "POST" : { "current" : 190.0,
          "description" : "number of HTTP POST requests",
          "max" : 35,
          "mean" : 0.075999999999999998,
          "min" : 0,
          "stddev" : 1.1719999999999999,
          "sum" : 190.0
        },
      "PUT" : { "current" : 345.0,
          "description" : "number of HTTP PUT requests",
          "max" : 85,
          "mean" : 0.13700000000000001,
          "min" : 0,
          "stddev" : 2.1110000000000002,
          "sum" : 345.0
        }
    },
  "httpd_status_codes" : { "200" : { "current" : 1734.0,
          "description" : "number of HTTP 200 OK responses",
          "max" : 221,
          "mean" : 0.68999999999999995,
          "min" : 0,
          "stddev" : 9.2690000000000001,
          "sum" : 1734.0
        },
      "201" : { "current" : 245.0,
          "description" : "number of HTTP 201 Created responses",
          "max" : 31,
          "mean" : 0.098000000000000004,
          "min" : 0,
          "stddev" : 1.2170000000000001,
          "sum" : 245.0
        },
      "202" : { "current" : 3.0,
          "description" : "number of HTTP 202 Accepted responses",
          "max" : 1,
          "mean" : 0.001,
          "min" : 0,
          "stddev" : 0.035000000000000003,
          "sum" : 3.0
        },
      "301" : { "current" : 3.0,
          "description" : "number of HTTP 301 Moved Permanently responses",
          "max" : 1,
          "mean" : 0.001,
          "min" : 0,
          "stddev" : 0.035000000000000003,
          "sum" : 3.0
        },
      "304" : { "current" : 25.0,
          "description" : "number of HTTP 304 Not Modified responses",
          "max" : 8,
          "mean" : 0.01,
          "min" : 0,
          "stddev" : 0.215,
          "sum" : 25.0
        },
      "400" : { "current" : 23.0,
          "description" : "number of HTTP 400 Bad Request responses",
          "max" : 8,
          "mean" : 0.0089999999999999993,
          "min" : 0,
          "stddev" : 0.22900000000000001,
          "sum" : 23.0
        },
      "401" : { "current" : 5.0,
          "description" : "number of HTTP 401 Unauthorized responses",
          "max" : 2,
          "mean" : 0.002,
          "min" : 0,
          "stddev" : 0.059999999999999998,
          "sum" : 5.0
        },
      "403" : { "current" : 14.0,
          "description" : "number of HTTP 403 Forbidden responses",
          "max" : 6,
          "mean" : 0.0060000000000000001,
          "min" : 0,
          "stddev" : 0.156,
          "sum" : 14.0
        },
      "404" : { "current" : 100.0,
          "description" : "number of HTTP 404 Not Found responses",
          "max" : 80,
          "mean" : 0.040000000000000001,
          "min" : 0,
          "stddev" : 1.6220000000000001,
          "sum" : 100.0
        },
      "405" : { "current" : 3.0,
          "description" : "number of HTTP 405 Method Not Allowed responses",
          "max" : 1,
          "mean" : 0.001,
          "min" : 0,
          "stddev" : 0.035000000000000003,
          "sum" : 3.0
        },
      "409" : { "current" : 3.0,
          "description" : "number of HTTP 409 Conflict responses",
          "max" : 1,
          "mean" : 0.001,
          "min" : 0,
          "stddev" : 0.035000000000000003,
          "sum" : 3.0
        },
      "412" : { "current" : null,
          "description" : "number of HTTP 412 Precondition Failed responses",
          "max" : null,
          "mean" : null,
          "min" : null,
          "stddev" : null,
          "sum" : null
        },
      "500" : { "current" : 87.0,
          "description" : "number of HTTP 500 Internal Server Error responses",
          "max" : 75,
          "mean" : 0.035000000000000003,
          "min" : 0,
          "stddev" : 1.508,
          "sum" : 87.0
        }
    }
} 

Friday, March 2, 2012

Monitoring specific MySQL counters using LoadRunner

You can monitor MySQL database using Sitescope. However, if you don't have access to the Sitescope application then you can write a simple LoadRunner script to monitor specific MySQL counters and plot the values using lr_user_data_point LR function. The following script is an enhancement to MySQL script detailed in my earlier post.

NOTE:
All session related information in MySQL is stored in a table called "SESSION_STATUS". Therefore, we will be querying this table for MySQL counter values.

For demonstration purpose, the script below will query the values for LAST_QUERY_COST, OPENED_TABLES, QCACHE_HITS, SELECT_FULL_JOIN and SELECT_SCAN counters.

Global declaration
#include "C:\\Program Files\\MySQL\\oldfiles\\include\\mysql.h" //mySQL.h path is included 

/*MySQL structure defined*/
MYSQL *mySQL;
MYSQL_ROW row;
MYSQL_RES *result;
int MyRC;

char *MySQLserver = "localhost"; // Location where server is running
char *MySQLuser = "root"; // User name used to connect to the database
char *MySQLpassword = ""; // Not a good idea to leave password empty
char *MySQLdatabase = "information_schema"; //Database name 
int MySQLport = 3306; // Database port

Vvuser_int
//libmysql.dll file loaded using lr_load_dll function
 MyRC= lr_load_dll("C:\\Program Files\\MySQL\\MySQL Connector C 6.0.2\\lib\\opt\\libmysql.dll"); 

 //Initialise mySQL connection handler
 mySQL= mysql_init(NULL);

 // Connect to the database
 mysql_real_connect(mySQL,MySQLserver, MySQLuser, MySQLpassword, MySQLdatabase, MySQLport,NULL,0);

 return 0;

Query Function
double atof(const char *string); // Explicit declaration
Query()
{  
    int i=0;
    float VarValue[5]; //Float variable array
    /*Save SQL statement into variable into sqlQuery.
     This query returns values for the variable name ={LAST_QUERY_COST,OPENED_TABLES,QCACHE_HITS,SELECT_FULL_JOIN,SELECT_SCAN}*/ 
 lr_param_sprintf("sqlQuery","select variable_value from session_status where variable_name IN"
      "('LAST_QUERY_COST','OPENED_TABLES','QCACHE_HITS','SELECT_FULL_JOIN','SELECT_SCAN')");

 mysql_query(mySQL, lr_eval_string ("{sqlQuery}")); //Execute SQL statement

 result = mysql_store_result(mySQL);   //Result of the sql statement is placed into MYSQL_RES result structure
  
 row=mysql_fetch_row(result);   
     
 while(row!=NULL) //Iterate through to last row
 {
  VarValue[i]=atof(row[0]);  //Save float row value to VarValue
  row=mysql_fetch_row(result);  //Retrive next row of the fetched result
  i++;
 }

/*Use lr_user_data_point function to generate the graph*/
 lr_user_data_point("LAST_QUERY_COST", VarValue[0]);
 lr_user_data_point("OPEN_TABLES", VarValue[1]);
 lr_user_data_point("QCACHE_HITS", VarValue[2]);
 lr_user_data_point("SELECT_FULL_JOIN", VarValue[3]);
 lr_user_data_point("SELECT_SCAN", VarValue[4]);

 return 0;
}

vuser_end
/*Free the memory allocated to result structure and close the database connection*/
 mysql_free_result(result);
 mysql_close(mySQL);
 return 0;



NOTE: Make sure you are explicitly declaring the atof function before using it or else you will get totally different values. See the screenshot of the values received for the above counters when atof was not declared explicitly before using it.