Tech Tips on DevCentral
   
You are here: Tutorials > Tech Tips

Current Articles | Categories | Search | Syndication

iRules Optimization 101 - #02 - Expressions and Variables

by Colin Walker - 9336 views

Building on the foundation that we laid down in last week's article, this installation of iRules Optimization 101 will focus on how to get the most out of the commands and expressions you're running within your iRules. Other articles in the series:

Two of the simplest, yet most effective ways to do this that I often discuss with people are the proper use of braces, and frugal use of variables. These are two things that are easily overlooked that can have a surprising impact on performance. As you might imagine, the more complex the rule, the more these practices matter as the performance gains are additive each time you implement the more efficient method over what might have been there otherwise. ;)

Section One: Braced Expressions

Anyone who's written code in most scripting languages is used to seeing braces "{ }" as a kind of delimiter. They're often used to delineate control structures, certain memory allocations, etc. As you've likely noticed, TCL makes liberal use of braces in many ways. Everything from defining your if statements to beginning and ending your events in your iRules (ok, that's us, not TCL...but you get the idea, and I had to make sure you were paying attention).

One of the many things that braces are used for in TCL is to encapsulate command arguments. This becomes extremely important in certain cases, as it A.) is often optional and B.) can have a huge performance impact. By making sure that we use braces when passing certain types of arguments to commands, we're able to stop the interpreter from trying to convert them, possibly multiple times, to different data types. This can be a huge performance sap depending on your code.

For example, a simple example of performing some math against an octet in an IP address might look something like:

when CLIENT_ACCEPTED {
  set newOct [expr 3 + [getfield [IP::client_addr] "." 4]]
  set total [expr 128 + $newOct]
...
}

While this is absolutely functional, and most people would look past the code without much thought, there is a huge amount of efficiency that can be gained here. By adding in braces around the values being passed to the expr command, we can stop unnecessary conversions, such as numeric -> string -> numeric, from occurring. This can mean a drastic performance difference, especially when implemented in a larger rule. The new rule would be very similar, with the addition of braces, and would read:

when CLIENT_ACCEPTED {
  set newOct [expr {3 + [getfield [IP::client_addr] "." 4]}]
  set total [expr {128 + $newOct}]
...
}

This not only allows for certain values, such as numeric values, to avoid undergoing multiple conversions out of and back to their original state, it also allows for immediate evaluation of variables by telling the interpreter that it needn't run through a second pass of evaluation as is necessary in some cases. I know it seems trivial, but this simple practice can gain you almost an order of magnitude in efficiency. I highly recommend taking a peek here for those of you who really want to delve into the nuts and bolts. The bottom line is, brace your expressions!

Section Two: Variable Allocation and Re-use

Another coding practice that will serve you well when aiming for optimal efficiency is the re-use of variables. I think it's safe to say that most people realize it is less expensive to re-use a variable than it is to allocate a new one. This common practice extends into the custom information made available to you in iRules by TMOS. The commands such as HTTP::host and IP::client_addr are not normal variable calls. They are calls to a piece of information already cached in memory by TMOS upon inspection.

This means that there is a large amount of effiency to be gained by avoiding unneeded variables by just not setting them in the first place, as well as making use of those special variables that we've made available to you, even if you're re-using it multiple times. For example:

when HTTP_REQUEST {
  set uri [HTTP::uri]
  set host [HTTP::host]
  set string "/login.php"
  if { ($host equals "bob.com") and ($uri equals $string)} {
    HTTP::redirect "https://[HTTP::host][HTTP::uri]"
  }
}

The above rule is again perfectly valid, it's just not very efficient. Notice how we set our own variables equal to information that TMOS has already cached in HTTP::uri and HTTP::host. Also, setting a variable equal to a constant string is just overhead that could be avoided. Try re-writing this kind of code like:

when HTTP_REQUEST {
  if { ([HTTP::host] equals "bob.com") and ([HTTP::uri] equals "/login.php")} {
    HTTP::redirect "https://[HTTP::host][HTTP::uri]"
  }
}

Not only is this a simpler, more elegant solution to read and debug, it's also far more efficient, as you are avoiding setting up three separate variables that really aren't needed. This means less used memory and less processing time to set/convert those values.

These tips may seem trivial, but you'll be surprised at the impact they have on your code's performance, which is especially important in a high-paced, wire-speed execution environment like iRules runs in. ;)

Get the Flash Player to see this player.


Rate This Article:

COMMENTS

posted @ Tuesday, October 02, 2007 6:11 AM by Andy Herrman   

The brace behavior in TCL is still fairly confusing to me (and I've read the TCL docs on it a few times). Your optimization example seems like a good demonstration of how braces are used (difference between {}, [], and ""), but it's still a bit hard to follow. Any chance you can give a step-by-step description of the differences in execution between the pre-optimized and post-optimized code? I think it would be incredibly useful for people new to TCL to see a nice simple example explained. Thanks!

posted @ Tuesday, October 02, 2007 4:08 PM by Colin Walker   

Thanks for the suggestion. I'll see what I can do to give a step-by-step of the execution that's occurring due to the braces or lack thereof.

#Colin

posted @ Monday, April 07, 2008 10:14 AM by Joe Hsy   

Thanks for the great tips, Colin! Are constructs like [HTTP::payload length] or [HTTP::header "Content Type] also cached? If not, is it still more efficient to call these constructs multiple times or to save the results in a variable? Thanks!

posted @ Monday, April 07, 2008 10:23 AM by Colin Walker   

As I understand it those values are indeed cached. I'll double check on that though, to refresh my memory and be sure. ;)

posted @ Monday, June 02, 2008 3:32 AM by panos   

A comment about the use of variables, or not setting variables to a string. I understand that it is faster not to use variables in that case but it is really bad programming practise to hard code strings or expressions in the code without a variable. This is because when you want to change that string you need to go through the entire code and search/replace the string and risk missing it in places. Moreover for people reading the code when you don't use variables it is not easy to figure out what the code does, especially when you use the same string multiple times in the code without a variable.

Faster yes, but a lot harder to maintain, debug and modify the code.

posted @ Monday, June 02, 2008 8:58 AM by Colin Walker   

I completely understand the normal coding practice of pre-defining variables to use throughout your script. If performance is not a concern in your deployment, then feel free to do just that.

There is a trade-off in any scripting between ease of maintenance/ledgibility and performance. I understand that it would be easier if I had things clearly defined and neat up at the top of the script for the next person to come along and look at it, but it would also be a performance hit which, in some cases, can be the difference between being able to meet the demands of your users or not.

In my past experience programming I've stuck to the rules you're talking about (and more) pretty strictly with portability and longevity in mind. The difference is most of those programs will be executed at MOST a couple hundred times per second. And that's honestly pushing it. When dealing with iRules you're talking about scoping for scripts that are being run hundreds of THOUSANDS of times per second. The tiny performance gains that wouldn't matter in, say, a perl script being executed 90 times per second make a drastic difference in an iRule being run 200,000 times per second.

So you're right, it's not "proper" coding in the sense that I wouldn't do it anywhere else, but it's darn good iRuling. ;)

#Colin

posted @ Wednesday, May 05, 2010 6:22 AM   

posted @ Wednesday, May 05, 2010 10:37 AM   

Only registered users may post comments.
  
Subscriptions: Video  |  Audio  |  Tutorials  |  Tech Tips  |  Features  | 

More...

 

 

Essentials Quick Start Guides
iRules Wiki | iControl SDK | WebAccelerator Wiki iRules | iControl
FirePass Wiki | Advanced Design & Config Wiki WebAccelerator | FirePass

 

Videos

  

Audio

Cache in with LTM and iRules
Can iRules fix my cert mismatch errors?
Concurrent iControl Programming Explained
Cookie LoJack vi iRules
Creating An iControl PowerShell Monitoring Dashboard With Google Charts
Custom SNMP Traps
Exchange Persistence Duality and iRules
FTPS Offload via iRules
Getting Started with pyControl
iControl 101 - #19 - Time Conversions
iControl 101 - #20 - Port Lockdown
iControl 101 - #21 - Rate Classes
iControl 101 - #22 - GTM Data Centers
iControl Apps - #04 - Graceful Server Shutdown
iControl Apps - #05 - Rate Based Statistics
iControl Apps - #06 - Configuration Archiving
iControl Apps - #07 - System Http Statistics
iControl Apps - #08 - System IP Statistics
iControl Apps - #09 - TMM Statistics
iControl Apps - #10 - Bigpipe List
iControl Apps - #11 - Global GTM Statistics
iControl Apps - #12 - Global SSL Statistics
iControl Apps - #13 - System PVA Statistics
iControl Apps - #14 - Global Statistics
iControl Apps - #18 - Virtual Server Reverse Lookup
Investigating the LTM TCP Profile: Acknowledgements
Investigating the LTM TCP Profile: Congestion Control Algorithms
Investigating the LTM TCP Profile: ECN & LTR
Investigating the LTM TCP Profile: Max Syn Retransmissions & Idle Timeout
Investigating the LTM TCP Profile: Nagle’s Algorithm
Investigating the LTM TCP Profile: The Finish Line
Investigating the LTM TCP Profile: Windows & Buffers
iRules 101 - #13 - TCL String Commands Part 1
iRules 101 - #14 - TCL String Commands Part 2
iRules 101 - #15 - TCL List Handling Commands
iRules Event Order
Managing The System Boot Location with iControl
Persisting SSL Connections
Replacing the WebSphere Apache Plugin with iRules
Ruby meets iControl: Creating VIPs
Ruby meets iControl: Making Wide IPs
Ruby Meets iControl: Switching Policies
Ten Steps to iRules Optimization
Unbind your LDAP servers with iRules
v.10 - A new iRules Namespace
v.10 - FastHTTP and Cookie Persistence
v.10 - iRules and the after command
v.10 - New class features in iRules
v.10 - Remote Authorization via TACACS+
v10.1 - Configuring GTM's DNS Security Extensions

  

Features

  

Tutorials

  

iControl

  

iRules

  

Monitoring & Management

  

Advanced Design & Config

  

93,050 Members in 191 Countries and Growing!

Join DevCentral Today!

About DevCentral

F5 DevCentral is your source for the best technical documentation, discussion forums, blogs, media and more related to application delivery networking.

So dive in, meet your peers, and get familiar with DevCentral. We hope it makes your job easier and helps you get more from your F5 investment. If new to DevCentral, check out the Getting Started section. And if you have any problems, or think something could be easier to use, let us know.

Got It !

We've received your comment and transmitted it directly to DevCentral HQ.

Thanks for taking time to let us know what's on your mind. At DevCentral | Community Matters!

Get In Touch With Us

Have questions, suggestions or just want to get something off your chest?

Use our handy form below to Direct Connect with DevCentral Mission Control.

Send Us Feedback      or