Flash makes it very easy to compress data- just call ByteArray.compress. It’s just as easy to uncompress with ByteArray.uncompress. With such convenience, it’s tempting to compress every ByteArray you send across without a second thought. But is this really a good idea? Will compressing every packet you send over a socket slow your app to a standstill? Today’s test is designed to answer just this question. Read on for the test and results!

The following test is a little different from the normal, straightforward tests you usually see in my articles. The trouble is that setting up a ByteArray to compress or uncompress is quite expensive. To keep the results clean, the test first sets up a randomized ByteArray and measures just the time taken to copy those bytes to a fresh ByteArray. Then each test proceeds to do a copy of the original ByteArray and either compress or uncompress it. That said, here’s the test app for the deflate and zlib algorithms with 1 KB and 1 MB sizes:

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class CompressionSpeed extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",") + "\n");
		}
 
		public function CompressionSpeed()
		{
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			row(
				"Size",
				"deflate (compress)",
				"zlib (compress)",
				"deflate (uncompress)",
				"zlib (uncompress)"
			);
			runTests("1 KB", 1024, 1024);
			runTests("1 MB", 1024*1024, 1);
		}
 
		private function runTests(label:String, size:int, reps:int): void
		{
			var beforeTime:int;
			var afterTime:int;
			var emptyTime:int;
			var deflateTimeCompress:int;
			var zlibTimeCompress:int;
			var deflateTimeUncompress:int;
			var zlibTimeUncompress:int;
			var bytes:ByteArray = new ByteArray();
			var originalBytes:ByteArray = new ByteArray();
			var compressedBytes:ByteArray = new ByteArray();
			var i:int;
			var zlib:String = CompressionAlgorithm.ZLIB;
			var deflate:String = CompressionAlgorithm.DEFLATE;
 
			fillBytes(originalBytes, size);
 
			// Empty
			beforeTime = getTimer();
			for (i = 0; i < reps; ++i)
			{
				copyBytes(originalBytes, bytes);
			}
			afterTime = getTimer();
			emptyTime = afterTime - beforeTime;
 
			// Compress
			beforeTime = getTimer();
			for (i = 0; i < reps; ++i)
			{
				copyBytes(originalBytes, bytes);
				bytes.compress(deflate);
			}
			afterTime = getTimer();
			deflateTimeCompress = afterTime - beforeTime - emptyTime;
 
			beforeTime = getTimer();
			for (i = 0; i < reps; ++i)
			{
				copyBytes(originalBytes, bytes);
				bytes.compress(zlib);
			}
			afterTime = getTimer();
			zlibTimeCompress = afterTime - beforeTime - emptyTime;
 
			// Uncompress
			copyBytes(originalBytes, compressedBytes);
			compressedBytes.compress(deflate);
			beforeTime = getTimer();
			for (i = 0; i < reps; ++i)
			{
				copyBytes(compressedBytes, bytes);
				bytes.uncompress(deflate);
			}
			afterTime = getTimer();
			deflateTimeUncompress = afterTime - beforeTime - emptyTime;
 
			copyBytes(originalBytes, compressedBytes);
			compressedBytes.compress(zlib);
			beforeTime = getTimer();
			for (i = 0; i < reps; ++i)
			{
				copyBytes(compressedBytes, bytes);
				bytes.uncompress(zlib);
			}
			afterTime = getTimer();
			zlibTimeUncompress = afterTime - beforeTime - emptyTime;
 
			row(
				label,
				deflateTimeCompress,
				zlibTimeCompress,
				deflateTimeUncompress,
				zlibTimeUncompress
			);
		}
 
		private function fillBytes(bytes:ByteArray, size:int): void
		{
			bytes.length = 0;
			bytes.position = 0;
			for (var i:int; i < size; ++i)
			{
				bytes.writeByte(Math.random()*256);
			}
			bytes.position = 0;
		}
 
		private function copyBytes(bytes:ByteArray, into:ByteArray): void
		{
			bytes.position = 0;
			into.position = 0;
			into.length = 0;
			into.writeBytes(bytes);
			bytes.position = 0;
			into.position = 0;
		}
	}
}

I ran this test in the following environment:

  • Flex SDK (MXMLC) 4.5.1.21328, compiling in release mode (no debugging or verbose stack traces)
  • Release version of Flash Player 11.1.102.55
  • 2.4 Ghz Intel Core i5
  • Mac OS X 10.7.3

Here are the results I got:

Size deflate (compress) zlib (compress) deflate (uncompress) zlib (uncompress)
1 KB 110 101 2 3
1 MB 60 66 2 3

Compression Speed Performance Chart

From this data we can derive a few conclusions:

  • compress is much slower than uncompress
  • deflate and zlib are about as fast as each other
  • The overhead of compressing or uncompressing on small amounts of data is large- it’s about twice as slow as larger amounts

The original question was whether your app would grind to a halt if you compressed and uncompressed every ByteArray you came across. Well, the above test is on a total of 1 MB of data: either 1024 compress/uncompress operations on a 1 KB ByteArray or 1 operation on a 1 MB block. Presumably, if you’re dealing with lots of ByteArray objects, they’re probably small. Still, on the test machine for this article that 1 KB ByteArray could be compressed about 100,000 times per second or uncompressed about 200,000 times per second. Even in a real-time game running at 60 FPS, the same ByteArray could be compressed over 1600 times per frame or uncompressed over 3200 times per frame. At an average of about one compressed network packet per frame, the compression overhead would only take up about 0.06% of the total frame time on the CPU. So will compressing everything you come across slow you down? Probably not!

Spot a bug? Have a question or suggestion? Post a comment!