Slow loading xml/xnb as data type on PS Vita

Started by
5 comments, last by DapperDave 10 years, 5 months ago

I'm having trouble with loading times on the Vita and was looking for general suggestions. I'm sort of stuck as I lack competency in xml reader coding and have a tenuous grasp of content loading in general.

Some background, I'm porting a game from XNA to PSM using Monogame. So my XMLs are being loaded as XNB custom data types like so:


MapData mapData = Content.Load<MapData>(@"Game\Levels\Maps\" + name);

Now to be fair, the xmls for these maps are enormous to begin with. One of my larger maps is 4.87 mb as an XML, 257 KB as an XNB and takes about 35 seconds to load (which is way too long for a 2D RPG).

I'll show you a typical map data xml file so you can get an idea of what these long loading files look like http://pastebin.com/raw.php?i=rs6SqTd5

I suppose I either need to find to find a faster way to load them or else find smaller way to represent map data. I'm hoping there's an solution for the former.

Advertisement

Working with XML by itself can be slow. The format is verbose. The format is inefficient. The format requires parsing.

While XML is wonderful for passing data between tools, when you build your compiled game it is often best to parse it and dump it to data structure that can just be loaded into memory and used directly.

That in mind, there are many high performance XML libraries out there. They do smart things like reading the entire file into memory and process branches in parallel. These libraries also use smarter memory allocation rather than using one globally-new'd object per node, which is extremely slow and wasteful. There are hundreds of them, and I won't recommend one over the others because each has their own benefits and drawbacks that may be important in your project.

Working with XML by itself can be slow. The format is verbose. The format is inefficient. The format requires parsing.

While XML is wonderful for passing data between tools, when you build your compiled game it is often best to parse it and dump it to data structure that can just be loaded into memory and used directly.



If I understand you correctly, I may already be doing this. If my MapData is a data structure. When the game is run, this data (in XNB) format is loaded into MapData.

That in mind, there are many high performance XML libraries out there. They do smart things like reading the entire file into memory and process branches in parallel. These libraries also use smarter memory allocation rather than using one globally-new'd object per node, which is extremely slow and wasteful. There are hundreds of them, and I won't recommend one over the others because each has their own benefits and drawbacks that may be important in your project.


Thanks, I will look into this. Although, I'm not sure if it applies since I'm loading XNBs. I don't fully understand how it all works but you've given me something to go on.

XNB is just an encoding format. You still need to deserialize everything.

Going over your data it is quite likely you are running 4200 allocations, calling roughly 4200 constructors, and otherwise doing a lot of work. Even if you aren't doing all those allocations you still must deserialize each one of the 4200 items one at a time, sequentially, reading in that the element is a single item, storing the value (almost always the value -1), then advancing to the next item.

Look for ways to not do that. See if you can do ONE allocation, then push all that data into that one big allocation.

Even if you broke that down into just the 8 map layers listed in your xml, that is 8 allocations, reading 8 small blocks of 53x20=1060 integers rather than reading in the same data with 1060 entries that must be parsed individually.

Do everything you can to get your serialized data into the most usable format. Instead of 1060 blocks of data, make one big block of data that can be read without parsing.

XNB is just an encoding format. You still need to deserialize everything.

Going over your data it is quite likely you are running 4200 allocations, calling roughly 4200 constructors, and otherwise doing a lot of work. Even if you aren't doing all those allocations you still must deserialize each one of the 4200 items one at a time, sequentially, reading in that the element is a single item, storing the value (almost always the value -1), then advancing to the next item.

Look for ways to not do that. See if you can do ONE allocation, then push all that data into that one big allocation.

Even if you broke that down into just the 8 map layers listed in your xml, that is 8 allocations, reading 8 small blocks of 53x20=1060 integers rather than reading in the same data with 1060 entries that must be parsed individually.


Do everything you can to get your serialized data into the most usable format. Instead of 1060 blocks of data, make one big block of data that can be read without parsing.


Thank you for the insight. I have one idea I was considering so maybe you can give me your opinion on whether you think it will help the situation.

I'm wondering if instead of using these enormous xml/xnb files I could instead represent the same data in a much smaller text file like this http://pastebin.com/raw.php?i=czJk6pbv

In that example of a 6x4 map, the tiles are delimited by commas, the rows of tiles are delimited by line breaks, and the map layers are delimited by double line breaks.

It's the same amount of data, but it's represented in far fewer characters. So the questions is, do you think this would load any faster if I did it this way?
Again, put it into directly usable data. By the time it gets to the game there should be no parsing of data involved. You should be able to directly load the data.

The data is an array of integers. The data does not have commas or line breaks. It is fine to have that sort of thing as an intermediate data format for your tools. There is a place for systems like your xml file and have 200 bytes of structural data to encode a 4-byte integer. That might be what you need for a tool, but not for your game.

By the time it gets to your game it should be raw data: two integers to denote x and y, followed by x*y integers of data. You can read two integers in a single read, put them in x and y, then read an x*y integer array. That is two data reads with no extra bytes and only a minimal amount of parsing.
Thanks. I'll let you know how it goes.

This topic is closed to new replies.

Advertisement