We know that the XML E4X operators are an 10x slower than plain Object, but how slow are they compared to the XML class’ methods like elements() and attributes? Today’s article finds that out.

The following test app is the same as with the last article in this series, but with two important changes. First, the E4X descendant operator test has been implemented correctly this time around. Second, and more on-topic to this article, the same XML object has been accessed in two ways. The first is the same as last time and employes the E4X operators. The second is by using the XML class’ methods: elements(), attributes(), and descendants().

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class XMLOperatorVsMethod extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",") + "\n");
		}
 
		private static var XML_OBJ:XML = <a b="x"><d><f/></d></a>;
		private static var PLAIN_OBJ:Object = { b:"x" };
		private static var TYPED_OBJ:TypedObj;
 
		public function XMLOperatorVsMethod()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			XML_OBJ = <a b="x"/>;
			PLAIN_OBJ = { b:"x" };
			TYPED_OBJ = new TypedObj();
 
			init();
		}
 
		private function init(): void
		{
			const REPS:int = 1000000;
			var i:int;
			var beforeTime:int;
			var afterTime:int;
 
			row("Operation", "Time");
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.@b;
			}
			afterTime = getTimer();
			row("XML Attribute Exists (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.@c;
			}
			afterTime = getTimer();
			row("XML Attribute Does Not Exist (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.d;
			}
			afterTime = getTimer();
			row("XML Element Exists (dot) (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.e;
			}
			afterTime = getTimer();
			row("XML Element Does Not Exist (dot) (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ..f;
			}
			afterTime = getTimer();
			row("XML Descendent Exists (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ..g;
			}
			afterTime = getTimer();
			row("XML Descendent Does Not Exist (E4X)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.attribute("b");
			}
			afterTime = getTimer();
			row("XML Attribute Exists (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.attribute("c");
			}
			afterTime = getTimer();
			row("XML Attribute Does Not Exist (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.elements("d");
			}
			afterTime = getTimer();
			row("XML Element Exists (dot) (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.elements("e");
			}
			afterTime = getTimer();
			row("XML Element Does Not Exist (dot) (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.descendants("f");
			}
			afterTime = getTimer();
			row("XML Descendent Exists (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ.descendants("g");
			}
			afterTime = getTimer();
			row("XML Descendent Does Not Exist (Method)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ["d"];
			}
			afterTime = getTimer();
			row("XML Element Exists (bracket)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				XML_OBJ["e"];
			}
			afterTime = getTimer();
			row("XML Element Does Not Exist (bracket)", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				PLAIN_OBJ.b;
			}
			afterTime = getTimer();
			row("Plain Object Exists", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				PLAIN_OBJ.c;
			}
			afterTime = getTimer();
			row("Plain Object Does Not Exist", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				TYPED_OBJ.b;
			}
			afterTime = getTimer();
			row("Typed Object Exists", (afterTime-beforeTime));
 
			row("Typed Object Does Not Exist", 0);
		}
	}
}
class TypedObj
{
	public var b:String = "x";
}

Run the test

I ran this test in the following environment:

  • Release version of Flash Player 12.0.0.41
  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.9.1
  • Google Chrome 32.0.1700.102
  • ASC 2.0.0 build 354071 (-debug=false -verbose-stacktraces=false -inline -optimize=true)

And here are the results I got:

Operation Time
XML Attribute Exists (E4X) 344
XML Attribute Does Not Exist (E4X) 304
XML Element Exists (dot) (E4X) 284
XML Element Does Not Exist (dot) (E4X) 286
XML Descendent Exists (E4X) 257
XML Descendent Does Not Exist (E4X) 262
XML Attribute Exists (Method) 688
XML Attribute Does Not Exist (Method) 668
XML Element Exists (dot) (Method) 232
XML Element Does Not Exist (dot) (Method) 239
XML Descendent Exists (Method) 262
XML Descendent Does Not Exist (Method) 266
XML Element Exists (bracket) 330
XML Element Does Not Exist (bracket) 335
Plain Object Exists 31
Plain Object Does Not Exist 53
Typed Object Exists 2
Typed Object Does Not Exist 0

XML E4X Operator vs. XML Class Method Performance Graph

Access Strategy Comparison Graph

The second graph makes the comparison very clear. XML class methods take about twice as long as E4X operators when accessing attributes. For elements, however, they are slightly faster. Descendants are a dead heat.

Even with the minor speed boost when accessing elements, the XML class methods are still an order of magnitude slower than plain objects: the Object class. Typed class instances are an order of magnitude quicker than that. So the advice from the last article still stands: do not use XML objects in performance critical code. If you need to repeatedly access an XML document, parse it into typed class instances and access those.

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