Photo by @caraventurera / Unsplash.com

Building a simple speed test solution using Microsoft Azure

In Finland, we have a ubiquitous and affordable Internet connectivity available. Almost everywhere. At home, I have a 1 Gb fiber, with 500 Mbit upload speeds. On my phone and iPad, I have separate 4G LTE connections, which usually provide me speeds north of 100 Mbit throughout the capital area where I spend most of my time these days.

But, I often want to test connectivity. I have the Speedtest app on my phone, which is great. I can also use AzureSpeed.com to verify latency between my current location and a chosen Azure datacenter. What I lack, though, is a quick way to check for download speeds. Granted, the Azure Speed site has a download test, but that’s downloading a file using my browser – and I have to check the speed myself!

Would it not be amazing if there was a command-line utility to check for speeds from Azure? Why yes, yes it would. So I set out to build a simple speed test solution.

Preparing Azure

For my speed test solution to work, I need a test file in Azure. I provisioned a new resource group and created a regular Storage Account to hold my test files.

I need three files – a 10 MB, 100 MB, and 1 GB in size. But wait, where did I get these files from? I created them with C#, using a simple method:

public static void createTestFile(long size, string path)
{
	byte[] data = new byte[size * 1024 * 1024];
	Random rng = new Random();
	rng.NextBytes(data);
	File.WriteAllBytes(path, data);
}

I called this method three times:

createTestFile(10, "d:\\temp\\speedtest10MB.bin");
createTestFile(100, "d:\\temp\\speedtest100MB.bin");
createTestFile(1024, "d:\\temp\\speedtest1024MB.bin");

I then uploaded these files to my Azure Storage account. The container within the Storage Account is set to anonymous so that I can access these files directly.

Creating the Speed Test command-line utility

Next, I need to create a small command-line utility to download these files. It’s as simple as utilizing .NET’s HttpClient. The trick is that I want to measure how long it takes to download each file, but I’d also like to show progress in case the connection is slow.

First, let’s define the three files and their respective URIs:

var testfile10MB = "https://<storageaccount>.blob.core.windows.net/speedfiles/speedtest10MB.bin";
var testfile100MB = "https://<storageaccount>.blob.core.windows.net/speedfiles/speedtest100MB.bin";
var testfile1024MB = "https://<storageaccount>.blob.core.windows.net/speedfiles/speedtest1024MB.bin";

I then spent a few moments to try out different approaches. Download a file is trivial with HttpClient, but it just.. downloads it. And I need to poll the task asynchronously to figure out the progress. As this is a command-line tool, I don’t have any graphical capabilities to help me out.

I found a useful method from a Stack Overflow thread contributed by Hitesh Thakor. I modified it slightly by adding a stopwatch to track elapsed time and remove the things I didn’t need.

The essence of the method is as follows:

static async Task GetFileAsync(string file, int size)
{
	HttpClient client = new HttpClient();

	Stopwatch sw = new Stopwatch();
	sw.Start();
	using (var stream = await client.GetStreamAsync(file))
	{
		using (MemoryStream ms = new MemoryStream())
		{
			byte[] buffer = new byte[1024];
			var totalBytes = client.MaxResponseContentBufferSize;
			var receivedBytes = 0;

			for (; ; )
			{
				int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
				if (bytesRead == 0)
				{
					await Task.Yield();
					break;
				}

				receivedBytes += bytesRead;

				int received = unchecked((int)receivedBytes);

				Console.Write("\r" + received / (1024) + "Kb");
			}
			sw.Stop();
			var speed = size / sw.Elapsed.TotalSeconds;
			Console.Write("\t[" + Math.Round(speed / 1024, 2) + " MB/s]");
			Console.WriteLine("\n");
		}
	}

So, what happens here is that first a new HttpClient instance is created. Then, the stopwatch is initialized. A file is passed for the client, and while it’s downloading it (with GetStreamAsync), we poll for the bytes read. In order to not flood the screen, I’m using the \r string escape sequence to rewrite to the same line. Finally, I’m stopping the stopwatch and checking the speed.

What I did not build was a real-time speed meter, as I was happy enough with the average speed.

Testing the tool

Let’s give it a test! I ran the tool using my home connection.

I get about 17 MB/s for the larger files. Perhaps the 1 GB file is a bit overkill, and a 256 MB would suffice. Download the largest file in browser, I seem to be able to replicate the speeds:

Obviously as I am not printing out the speed during each tick, I only get the final average speed. Perhaps a 2.0 version of this tool could show the real-time download speed also!