ColdFusion In Context: Connection Speed

How fast IS fast, and where should speed be measured? It's not enough to know the execution speed of your pages. To help your customers and plan for change, you have to have an idea of how long it takes your pages to load on client browsers. Here's a tool you can add to a form and its action page to estimate and log connection speed. Along the way, you'll time a process with JavaScript, do a little division, parse and format a string, find a template's physical directory, and write to a text file.

Time a Process with JavaScript

The actual timing has to take place on the browser itself. One easy way is to read a timer when the page starts loading and again when it's just about done. Here's a tiny bit of JavaScript to get the start time in milliseconds: the number of milliseconds since a reference date in the distant past. Add this script to the top of the page being timed. (If you copy and paste it in, paste as unformatted text to preserve the line endings.) The page you try this with might even be your home page, which probably already contains a form for clients to log in.
<script language="JavaScript">
now=new Date();
var startms=now.getTime();
</script>
End your form (which should be near the bottom of the page) with this code. It stuffs the start and end times into hidden fields in the form. In the "document.yourform" lines, you MUST replace "yourform" with the exact name of your form for this to work. You can actually access any field in the form this way; consider the possibilities.
<input type="hidden" name="firstms">
<input type="hidden" name="lastms">
<script language="JavaScript">
later=new Date();
var endms=later.getTime();
document.yourform.firstms.value=startms;
document.yourform.lastms.value=endms;
</script>
</form>

Do a Little Division

Since you're processing the rest of the form anyway, it's easy to add a few more lines to the action page to use this information. When the user submits the form, just subtract "startms" from "endms" like this in your action page to see how many milliseconds the page took to display on the client's browser. Force the time to be at least one millisecond to guard against division by zero later on. (If the client pushes the reload button, the start and end times may be the same; that's why the test is needed.)
<cfif form.lastms is not form.firstms>
  <cfset Loadms = form.lastms - form.firstms>
<cfelse>
  <cfset Loadms = 1>
</cfif>
You can divide the result into the size of the page in bytes to get the connection speed in bytes per millisecond which becomes KBytes per second. For example, 60000 bytes / 6000 milliseconds [that's 6 seconds] reflects a connection speed of 10KBytes per second.
<!--- Replace with the size of YOUR form page in bytes;
I hope it's smaller --->
<cfset FormBytes = 26459>

<cfset KBytesPs = FormBytes/Loadms>
Add this if you want to tell the user what you've learned.
<cfoutput><p>
The form that fed this page 
took #Loadms# milliseconds to load.<br>
If it's #FormBytes# bytes, then the 
speed was: #KBytesPs# KBytes per second.<p>
</cfoutput>

Parse and Format a String

Even if you don't have a database handy, you can log speed for a given date, time, and remote address (IP). "GetToken()" parses a string, the IP address in this case, into pieces or tokens. Just name the string, the separators, and which piece you want, and this function does the rest. Use "numberFormat()" to make each element the same length (through the use of leading zeroes). This simplifies sorting in a spreadsheet. Then paste everything together into a single line.
<cfset NowDt = now()>
<cfset NowDts = DateFormat(NowDt,"YYYY/MM/DD")&"  "&TimeFormat(NowDt,"HH:mm:ss")>
<cfset RA = "#CGI.remote_addr#">
<cfset RA1 = numberFormat(getToken(#RA#,1,"."),000)>
<cfset RA2 = numberFormat(getToken(#RA#,2,"."),000)>
<cfset RA3 = numberFormat(getToken(#RA#,3,"."),000)>
<cfset RA4 = numberFormat(getToken(#RA#,4,"."),000)>
<cfset IP = #RA1#&"."&#RA2#&"."&#RA3#&"."&#RA4#>
<cfset Tab = chr(9)>

<cfset doline = "#KBytesPs##Tab##NowDts##Tab##IP#">

Find a template's physical directory and write to a text file

This code will create and add to a text file that you can always read into a spreadsheet later for analysis. To help keep this example from breaking when you try it on your server, I've added a line that gets the directory of this script and puts the log in that same directory. You might want to hard code the file location after you're comfortable with this example.
<cfset YourLog="#getDirectoryFromPath(cf_template_path)#"&"YourLog.txt">
<cfoutput>#YourLog#</cfoutput>
This single line creates the file if it doesn't exist adds text to it.
<cffile action="append" file="#YourLog#"
output="#doline#" addnewline attributes="normal">
In this example, the first column is the speed in KBytes per second, the second is the date/time with just a space separating them, and the third is the IP address. You can read the text file into Excel or copy it into an open spreadsheet. If you highlight and copy the text, go to Excel's menu to keep it from being pasted as HTML by selecting "edit; paste-special; text". If you want people to be able to paste it without going through this step, format the log as a table instead of using tabs. You might also want to round up the speeds to get rid of those long decimals.
92.9752066116	2001/01/08  16:10:06	143.158.254.007
113.255033557	2001/01/08  16:20:20	209.235.109.009
84.5070422535	2001/01/08  16:21:27	207.230.075.195
112.333333333	2001/02/25  15:01:30	127.000.000.001
262.245454545	2001/02/25  15:06:18	127.000.000.001
90.9090909091	2001/02/25  15:56:30	024.214.065.188
83.3333333333	2001/02/25  15:57:27	024.214.065.188
Here's an example on this host that shows these techniques at work: YourHome.htm. Once you've seen this, browse yourlog.txt.

A 56Kbit dial-up modem can pass about 5KBytes per second; a T1 connection can pass about 180KBytes per second. The speeds shown here are more typical of a cable modem connection or of a browser that actually resides on the server while you're checking your code (grin). =Marty=

[The offer to browse yourlog.txt was added after publication. The code, except for hidden modifications to satisfy the ISP, remains the same.]