Command Performance

Problem this snippet solves:

The article Ten Steps to iRules Optimization illustrates some ways to optimize your iRules. I took a look at the control statements and built a little iRule that will test those assertions and generate performance graphs using Google Charts to present the findings.

How to use this snippet:

Dependencies

This iRule relies on external Class files for the test on the "class match" command. The class names should be in the form of "class_xxx" where xxx is the list size you want to test. Include xxx number of entries with values from 0 to xxx-1. For a list size of 10, the class should look like this:

# Snippet in bigip.conf
class calc_10 {
   "0"
   "1"
   "2"
   "3"
   "4"
   "5"
   "6"
   "7"
   "8"
   "9"
}

I used perl to generate larger classes of size 100, 1000, 5000, and 10000 for my tests.

Usage

Assign the iRule to a virtual server and then browse to the url http://virtualserver/calccommands. I've included query string arguments to override the default test parameters as follows

  • ls=nnn - List Size. You will need a class defined titled calc_10 for a value of ls=10.
  • i=nnn - Number of iterations. This will be how many times the test is performed for each list size.
  • gw=nnn - Graph Width (default value of 300)
  • gh=nnn - Graph Height (default value of 200)
  • ym=nnn - Graph Y Max value (default 500)

An example usage is: http://virtualserver/calccommands?ls=1000&i=500. This will work on a list size of 1000 with 500 iterations per test.

Code :

when HTTP_REQUEST {

  #--------------------------------------------------------------------------
  # read in parameters
  #--------------------------------------------------------------------------
  set listsize    [URI::query [HTTP::uri] "ls"];
  set iterations  [URI::query [HTTP::uri] "i"];
  set graphwidth  [URI::query [HTTP::uri] "gw"];
  set graphheight [URI::query [HTTP::uri] "gh"];
  set ymax        [URI::query [HTTP::uri] "ym"];

  #--------------------------------------------------------------------------
  # set defaults
  #--------------------------------------------------------------------------
  if { ("" == $iterations) || ($iterations > 10000) } { set iterations 500; }
  if { "" == $listsize } { set listsize 5000; }
  if { "" == $graphwidth } { set graphwidth 300; }
  if { "" == $graphheight } { set graphheight 200; }
  if { "" == $ymax } { set ymax 500; }
  
  set modulus [expr $listsize / 5];
  set autosize 0;
  
  #--------------------------------------------------------------------------
  # build lookup list
  #--------------------------------------------------------------------------
  set matchlist "0";
  for {set i 1} {$i < $listsize} {incr i} {
    lappend matchlist "$i";
  }

  set luri [string tolower [HTTP::path]]

  switch -glob $luri {
    
    "/calccommands" {
      
      #----------------------------------------------------------------------
      # check for existence of class file.  If it doesn't exist
      # print out a nice error message.  Otherwise, generate a page of
      # embedded graphs that route back to this iRule for processing
      #----------------------------------------------------------------------
      
      if { [catch { class match "1" equals calc_$listsize } ] } {
        
        
        # error
        set content "
BIG-IP Version $static::tcl_platform(tmmVersion)" append content "

ERROR: class file 'calc_$listsize' not found

"; append content ""; } else { # Build the html and send requests back in for the graphs... set content "
BIG-IP Version $static::tcl_platform(tmmVersion)" append content "

List Size: ${listsize}


" set c 0; foreach item $matchlist { set mod [expr $c % $modulus]; if { $mod == 0 } { append content ""; } incr c; } append content "

"; } HTTP::respond 200 content $content; } "/calccommands/*" { #---------------------------------------------------------------------- # Time various commands (switch, switch -glob, if/elseif, matchclass, # class match) and generate redirect to a Google Bar Chart #---------------------------------------------------------------------- set item [getfield $luri "/" 3] set labels "|" set values "" #---------------------------------------------------------------------- # Switch #---------------------------------------------------------------------- set expression "set t1 \[clock clicks -milliseconds\]; \n" append expression "for { set y 0 } { \$y < $iterations } { incr y } { " append expression "switch $item {" foreach i $matchlist { append expression "\"$i\" { } "; } append expression " } " append expression " } \n" append expression "set t2 \[clock clicks -milliseconds\]"; eval $expression; set duration [expr {$t2 - $t1}] if { [expr {$duration < 0}] } { log local0. "NEGATIVE TIME ($item, matchclass: $t1 -> $t2"; } append labels "s|"; if { $values ne "" } { append values ","; } append values "$duration"; if { $autosize && ($duration > $ymax) } { set ymax $duration } #---------------------------------------------------------------------- # Switch -glob #---------------------------------------------------------------------- set expression "set t1 \[clock clicks -milliseconds\]; \n" append expression "for { set y 0 } { \$y < $iterations } { incr y } { " append expression "switch -glob $item {" foreach i $matchlist { append expression "\"$i\" { } "; } append expression " } " append expression " } \n" append expression "set t2 \[clock clicks -milliseconds\]"; eval $expression; set duration [expr {$t2 - $t1}] if { [expr {$duration < 0}] } { log local0. "NEGATIVE TIME ($item, matchclass: $t1 -> $t2"; } append labels "s-g|"; if { $values ne "" } { append values ","; } append values "$duration"; if { $autosize && ($duration > $ymax) } { set ymax $duration } #---------------------------------------------------------------------- # If/Elseif #---------------------------------------------------------------------- set z 0; set y 0; set expression "set t1 \[clock clicks -milliseconds\]; \n" append expression "for { set y 0 } { \$y < $iterations } { incr y } { " foreach i $matchlist { if { $z > 0 } { append expression "else"; } append expression "if { $item eq \"$i\" } { } "; incr z; } append expression " } \n"; append expression "set t2 \[clock clicks -milliseconds\]"; eval $expression; set duration [expr {$t2 - $t1}] if { [expr {$duration < 0}] } { log local0. "NEGATIVE TIME ($item, matchclass: $t1 -> $t2"; } append labels "If|"; if { $values ne "" } { append values ","; } append values "$duration"; if { $autosize && ($duration > $ymax) } { set ymax $duration } #---------------------------------------------------------------------- # Matchclass on list #---------------------------------------------------------------------- set expression "set t1 \[clock clicks -milliseconds\]; \n" append expression "for { set y 0 } { \$y < $iterations } { incr y } { " append expression "if { \[matchclass $item equals \$matchlist \] } { }" append expression " } \n"; append expression "set t2 \[clock clicks -milliseconds\]"; eval $expression; set duration [expr {$t2 - $t1}] if { [expr {$duration < 0}] } { log local0. "NEGATIVE TIME ($item, matchclass: $t1 -> $t2"; } append labels "mc|"; if { $values ne "" } { append values ","; } append values "$duration"; if { $autosize && ($duration > $ymax) } { set ymax $duration } #---------------------------------------------------------------------- # class match (with class) #---------------------------------------------------------------------- set expression "set t1 \[clock clicks -milliseconds\]; \n" append expression "for { set y 0 } { \$y < $iterations } { incr y } { " append expression "if { \[class match $item equals calc_$listsize \] } { }" append expression " } \n"; append expression "set t2 \[clock clicks -milliseconds\]"; log local0. $expression; eval $expression; set duration [expr {$t2 - $t1}] if { [expr {$duration < 0}] } { log local0. "NEGATIVE TIME ($item, matchclass: $t1 -> $t2"; } append labels "c|"; if { $values ne "" } { append values ","; } append values "$duration"; if { $autosize && ($duration > $ymax) } { set ymax $duration } #---------------------------------------------------------------------- # build redirect for the google chart and issue a redirect #---------------------------------------------------------------------- set mod [expr $item % 10] set newuri "http://${mod}.chart.apis.google.com/chart?chxl=0:${labels}&chxr=1,0,${ymax}&chxt=x,y" append newuri "&chbh=a&chs=${graphwidth}x${graphheight}&cht=bvg&chco=A2C180&chds=0,${ymax}&chd=t:${values}" append newuri "&chdl=(in+ms)&chtt=Perf+(${iterations}-${item}/${listsize})&chg=0,2&chm=D,0000FF,0,0,3,1" HTTP::redirect $newuri; } } }
Published Mar 17, 2015
Version 1.0
  • Hi, after requesting an updated script, I took upon myself to make the modifications. I switched the charting engine to quickchart.io, which should be stable(ish) for the next several years. I also inserted some addition remarks with use examples.

     

    😀

  • Would it be possible to update this code for the newer Google chart apis?