XML Operator Speed
AS3 has always had great support for XML built right into the language, but how fast is it? Today’s article compares the performance of operators that work on XML
objects like .@x
, .x
, ..x
, and ["x"]
against their equivalents in plain Object
instances and typed class
instances. Just how slow are the XML operators? Read on to find out.
Here is the source code for the test app. It’s a very straightforward measurement of each XML operator’s speed when attributes and elements both exist and don’t exist. Plain objects and typed (class instance) objects are also tested. The only exception is with typed objects because there is no equivalent way to test when a property doesn’t exist. This is because you’ll get a compiler error with the dot (.x
) operator and a runtime error with the bracket (["x"]
) operator.
package { import flash.display.*; import flash.utils.*; import flash.text.*; public class XMLOperatorSpeed 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 XMLOperatorSpeed() { 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 = 10000000; 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", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { XML_OBJ.@c; } afterTime = getTimer(); row("XML Attribute Does Not Exist", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { XML_OBJ.d; } afterTime = getTimer(); row("XML Element Exists (dot)", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { XML_OBJ.e; } afterTime = getTimer(); row("XML Element Does Not Exist (dot)", (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) { XML_OBJ.f; } afterTime = getTimer(); row("XML Descendent Exists", (afterTime-beforeTime)); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { XML_OBJ.g; } afterTime = getTimer(); row("XML Descendent Does Not Exist", (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"; }
I ran this test in the following environment:
- Release version of Flash Player 11.9.900.170
- 2.3 Ghz Intel Core i7
- Mac OS X 10.9.1
- Google Chrome 31.0.1650.63
- 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 | 3328 |
XML Attribute Does Not Exist | 2913 |
XML Element Exists (dot) | 2704 |
XML Element Does Not Exist (dot) | 2724 |
XML Element Exists (bracket) | 3287 |
XML Element Does Not Exist (bracket) | 3164 |
XML Descendent Exists | 2719 |
XML Descendent Does Not Exist | 2716 |
Plain Object Exists | 306 |
Plain Object Does Not Exist | 477 |
Typed Object Exists | 18 |
Typed Object Does Not Exist | 0 |
With the exception of XML attributes, it doesn’t seem to make much of a difference whether the item you’re looking for exists or not. Plain objects, however, take about 50% more time when an item doesn’t exist. As mentioned earlier, typed objects don’t have equivalent functionality.
Overall, XML operators are about 10x slower than plain object operators. This will vary depending on the complexity of your XML
document as more and more attributes and elements need to be searched, especially by the descendent (..x
) operator. The above test uses the smallest possible XML
object to carry out the tests, so think of these as best-case times. Of course there is no descendent operator for plain objects, so you’d need to recursively search for its children which would also take more time.
Typed objects clearly beat both XML
and plain objects: they’re about 17x faster. However, they’re far less flexible than their competitors in this area. I’ve included them mostly as a reference point to see how much slower than “normal” class
-based code these plain objects and XML
objects are. In short, plain objects are an order of magnitude slower than typed objects and XML
objects are yet another order of magnitude slower than plain objects. Do not use them in performance-critical code.
I suppose that no article about XML would be complete without mentioning JSON. Flash’s JSON.parse
function returns a plain object and provides you with no special operators as there are with XML
. So while you lose some operator convenience, you’ll get about 10x faster access to the loaded JSON data.
Spot a bug? Have a question or suggestion? Post a comment!
#1 by henke37 on January 13th, 2014 ·
Check the resulting bytecode, some of the XML operators are secretly implemented as inlined search loops. Especially those that return XMLList instances.
#2 by jackson on January 14th, 2014 ·
Good point. I think many AS3 programmers would not expect a simple operator to trigger a whole search loop. As shown in the article, the results of the search are already quite poor even with a very small document to search. A larger document would likely scale far worse than the equivalent plain object or class instance.
#3 by rocksoccer on January 19th, 2014 ·
No surprise to see XML is slower than object, but still surprised it is so much slower.
But are there any big speed different between E4X and methods in XML class like
attribute()
,child()
and etc? Is it going to be even slower?#4 by jackson on January 19th, 2014 ·
This sounds like an excellent idea for a followup article. Stay tuned!