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 "<CENTER>BIG-IP Version $static::tcl_platform(tmmVersion)"
append content "<H1 id="community-286142-toc-hId-1039316030"><FONT color="red">ERROR: class file 'calc_$listsize' not found</FONT></H1>";
append content "";
} else {
# Build the html and send requests back in for the graphs...
set content "<CENTER>BIG-IP Version $static::tcl_platform(tmmVersion)"
append content "<P>List Size: ${listsize}</P><P></P><HR size="3" width="75%" /><P>"
set c 0;
foreach item $matchlist {
set mod [expr $c % $modulus];
if { $mod == 0 } {
append content "<IMG src="$luri/$item"
append content "?ls=${listsize}&i=${iterations}&gw=${graphwidth}&gh=${graphheight}&ym=${ymax}" />";
}
incr c;
}
append content "</P></CENTER>";
}
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;
}
}
}
2 Comments
- keithhubb
Employee
Would it be possible to update this code for the newer Google chart apis?
- keithhubb
Employee
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.
😀