News for hackers. Stuff that matters.
Re:An Unbelievable Demo by maccard on Friday June 04, 2021 @03:32AM (#27391491)
One of the reasons games do this is the data is compressed, so a "patch" might be indistinguishable from a real update.

Also, as a dev, you have no idea what version your users are updating _from_. You either need to generate some number of patches for every version you could be updating from, and figure out if you should just download the whole thing again in any of those cases anyway.

Re:An Unbelievable Demo by kevincox on Friday June 04, 2021 @07:34AM (#27392549)
There are solutions to this!

The simplest one is generate patches for recent versions, where recent can be years in the past. It is a linear operation but you only run it on release so it probably isn't a huge cost. You can also use some heuristics such as if if diff is >20% of the file just stop and force users still on that version to do a full update.

A second option is using zsync[1]. zsync is basically a precomputed rolling checksum. The client can download this manifest and they download just the parts of the file they need. This way you don't care about the source, if there is any similarity they can save resources.

And of course these can be combined. Generate exact deltas for recent versions and a zsync manifest for fallback.

[1] http://zsync.moria.org.uk/

Side note: One nice thing about zsync is that the actual download happens from the original file using range requests. This is nice for caching as a proxy only needs to cache the new data once. Is there a diff tool that generates a similar manifest for exact diffs? So instead of storing the new data in the delta file it just references ranges of the new file.

Re:An Unbelievable Demo by mewse on Friday June 04, 2021 @05:23AM (#27391958)
We usually don’t compress the data on disk; decompression would make loading and file access slower.

Instead, we just pack the uncompressed files together (frequently using normal zip in a no-compression mode) so that we can avoid needing to ask the OS to open and close files for us or examining the contents of a directory, both of which can be kind of startlingly slow (by video game standards) on some common OSes. Instead, we will generally cache the directory data from the zip file and just use that rather than go to disk.

(of course, the whole download/patch would all be compressed for network transfer, but files would then be decompressed during the installation process)

Re:An Unbelievable Demo by maccard on Friday June 04, 2021 @05:43AM (#27392059)
> We usually don’t compress the data on disk; decompression would make loading and file access slower.

_You_ mightn't but the last three AAA games I worked on do/did. PS5 expectes compressed files, and does HW decompression (ahem, mostly) on the fly.

Re:An Unbelievable Demo by Danieru on Friday June 04, 2021 @10:03AM (#27393704)
On the switch the reads are so slow the fastest loading requires atbleast mild compression. At least it did when I was testing packaging for my latest switch release. Despite the weak cpu.

Ps4 also did the compressed packages by default thing if I remember right. The upside there being ample cpu for decompression such that no compression was never fastest.

Re:An Unbelievable Demo by sumtechguy on Friday June 04, 2021 @10:28AM (#27393950)
I could see that keeping one big file would still be advantageous too in that environment. As a fopen on a set of small sized files plus read plus close over and over does add up. Just in cpu time and memory slack. Whereas treating it as one giant packed backing store would have advantages in speed. But at a cost of dev time. Even if you are compressing it as well could be an advantage. But I would expect there to be some spot where it crosses over from being an advantage to a disadvantage. I suspect it would be on small files/objects. But that would just be for speed. You may have to optimize for size in some cases. In the end it is usually better to build some test code and find out. Sometimes the results are what you expect. Sometimes you are spending time on things that do not matter anymore but were a big deal 20 years ago.
Re:An Unbelievable Demo by mewse on Friday June 04, 2021 @08:57PM (#27400927)
Oh, definitely! I haven’t worked on anything targetting a console past the PS3 generation and it completely slipped my mind that the latest gen consoles are architected specifically for streaming compressed data.

On the Windows/Mac/Linux title I’m working on now, I definitely measure a sizeable improvement to performance when loading from an uncompressed zip rather than from a compressed one. But even that could be down to the particular set of libraries I’m using to handle it.

Re:An Unbelievable Demo by tialaramex on Friday June 04, 2021 @06:20AM (#27392221)
> We usually don’t compress the data on disk; decompression would make loading and file access slower.

Did you actually benchmark this? It probably makes sense in your head, but on any vaguely modern hardware it's very unlikely to actually be true because of how exponential the memory hierarchy is.

Re:An Unbelievable Demo by bsenftner on Friday June 04, 2021 @07:17AM (#27392461)
Console hardware tends to have fast processors & cache but extremely slow RAM. Benchmarking a console's memory vs cache access tends to be one of the first things a team of principal game devs do and that information becomes bible for their titles.
Re:An Unbelievable Demo by PeterisP on Friday June 04, 2021 @06:18AM (#27392214)
IIRC in a bunch of scenarios compression makes loading and file access faster, as you're I/O limited and it's quicker to read less data and decompress. You do need to choose simple/quick/not-that-much-compressing compression algorithms for that.
Re:An Unbelievable Demo by greyhair on Friday June 04, 2021 @07:19AM (#27392470)
I have worked on a number of embedded products which ran from compressed root file system from eMMC. The overhead was a wash because RAM is so much faster than eMMC. What you spent in decompression time was covered by reduced eMMC access time.
Re:An Unbelievable Demo by xmprt on Friday June 04, 2021 @04:00AM (#27391616)
If you know a user is on version 3 and need to update to version 5, then why not just send out all the patches between 3 and 5? Why do you need to generate a new patch for each pair of versions.

It feels a bit egregious when I have to download a 100MB update just because a few characters were buffed or nerfed. More involved changes end up being over 1GB.

Re:An Unbelievable Demo by maccard on Friday June 04, 2021 @05:30AM (#27391992)
Because it's not just version 3 to version 5, it's version 3 to version 84.

Not all versions are made equal either - one might be a character buff, another might reorder assets in the "big huge binary blob file" for performance improvements. At a certain point, rather than downloading 30MB per update for 25 versions, and applying each incrementally (remember that you have to do them in order too), just download the full 1GB once and overwrite the whole whing.

Re:An Unbelievable Demo by uuidgen on Friday June 04, 2021 @08:20AM (#27392859)
Microsoft made sure in windows 10 that it's almost unusable without SSD. SO you big binary blob file have random r/w access.

Most backup software is able to do good binary deltas of arbitrary data for decades. Even dumb checkpointing resolves problem of downloading 25 versions - you download latest checkpoint and deltas from there.

Don't excuse poor design and programming, when you know a file structure, creating a differential update should be short task. With a tiny bit of algorithmic knowledge you could even optimize the process to only download needed assets inside of you big binary blob - if the asset was changed 7 times during your last 25 version you only need to download the last one.

Re:An Unbelievable Demo by xmprt on Friday June 04, 2021 @04:54PM (#27398954)
I'd personally like to see a company put a little thought into innovating how they store data on disk so patches can be quickly applied like with git while also not requiring a full source recompilation.
Re:An Unbelievable Demo by milankragujevic on Friday June 04, 2021 @04:05AM (#27391639)
It can go worse - some cheap and badly designed Android phones which download updates from every month when you first buy it until the current month, so maybe 10+ updates, but they aren't deltas (diffs) but full images. Ridiculous on so many levels.
Re:An Unbelievable Demo by beagle3 on Friday June 04, 2021 @07:27AM (#27392514)
It’s because they only tested updates from one version to the next, and not every version to every newer version.

It is a complete image, but phones today have nontrivial state that may be a problem - e.g. your baseband processor might have its own rom with its own update protocol, which changed between image 2 and image 7, so image 10 after image 1 will be unable to update the baseband.

Re:An Unbelievable Demo by mst on Saturday June 05, 2021 @01:08PM (#27406750)
If it's a cheap phone, I'd rather them do something brute force but reliable than try and be clever when they know they don't have the budget to QA it.

I honestly consider that a pretty reasonable trade-off.

Re:An Unbelievable Demo by oblio on Friday June 04, 2021 @03:42AM (#27391543)
> One of the reasons games do this is the data is compressed, so a "patch" might be indistinguishable from a real update.

Does this happen with more advanced compression algorithms? I've rsynced zip files of different versions of internal software and the diff was always much, much smaller than the entire package.

Re:An Unbelievable Demo by sgtnoodle on Friday June 04, 2021 @04:20AM (#27391691)
Zip files have all the metadata in a footer rather than a header. As a result, compressed files can be added and overwritten by appending to the file without disturbing already compressed data. Additionally, the "deflate" compression likely does not span across files, so files that did not change from version to version would have a similar compressed byte sequence, regardless of the order they were added to the archive.

I'd argue that zip is a relatively simple compressed archive format. Its simplicity is its charm and the reason it's so popular. More space-efficient algorithms would be less likely to be "patchable" as there would be less redundancy / structure in the compressed representation to exploit (the best compression seems like it would have similar properties of random data.)

Re:An Unbelievable Demo by versteegen on Friday June 04, 2021 @05:04AM (#27391882)
> Additionally, the "deflate" compression likely does not span across files

Clarification: .zip (unlike .tar.gz for example, or "solid" .7z) compresses each file separately, that's nothing to do with the compression algorithm used. In addition, DEFLATE, the LZ77-based compression which is by far most commonly used in .zip (and also by gzip) has a window size of 32kB (uncompressed). So yes, even if you used DEFLATE on a solid stream (e.g. zipped a .tar archive) it couldn't remove any cross-file redundancy once it's gone past the first 32kB of each file.

Re:An Unbelievable Demo by beagle3 on Friday June 04, 2021 @07:32AM (#27392536)
On the other hand HIgh voltage sid collection (hvsc) distributes a zipped zip;

Each file is 1k-20k, of which there are 40,000 or so. But they are catalogued in 3-4 deep directories, so if you just zip them, the metadata takes 30% or so of the zip.

But the metadata does compress very well, so they zip it again.

Re:An Unbelievable Demo by BBC-vs-neolibs on Friday June 04, 2021 @04:45AM (#27391799)
zstd strikes a nice balance here. It can inject markers in the bytestream to make it "rsync friendly", but one could just as well say "binary diff friendly".

zstd itself also has the (pretty new) ability to use a shared file as shorthand during compression. What that means in practice is that diffs can be REALLY tiny if you have the previous archive download.

Hi dang.

Re:An Unbelievable Demo by kevincox on Friday June 04, 2021 @07:43AM (#27392595)
In general yes. After the first difference the compressed streams will be basically random compared to each other. However there are numerous things that may avoid this.

For zip files each individual file is compressed independently. So unchanged files and prefixes don't need to be resent, even if once a file changes the entire tail end of it needs to be resent.

Some times compression algorithms "reset" periodically. For example the `gzip --rsyncable` patch. This basically resets the compression stream so that a change will only affect part of the compressed file. This does have a cost in terms of compressed size because the compressor can't deduplicate across resets. However if the resets are infrequent you can maintain fairly good delta transfer with little space overhead.

Additionally some delta transfer tools detect common compression and decompress the file "in transfer", performing the delta checks on the original file.

Re:An Unbelievable Demo by whelming_wave on Friday June 04, 2021 @03:54AM (#27391587)
Kind of an aside from your question, but binary patches not being much smaller than the full thing might happen more with modern games?

Heresay, but from what I've heard modern games may ship multiple copies of some assets with different levels or features so they can be loaded as a sequential read off the disk. While a block-oriented compression algorithm might sync up more reliably, if you're packing 200MB of assets for a level and they're all compressed to take advantage of the fact they'll be read sequentially could mean a change 25MB in would still ship ~175MB of changes.

Re:An Unbelievable Demo by uuidgen on Friday June 04, 2021 @08:31AM (#27392934)
So far in in most of the world even platter disks (which have really poor performance with modern Windows) are faster than network. Which means you can download description of the difference and reorder the file locally much faster than downloading it. Yes it needs the file to made in a way that is update friendly - most current compression algorithms can be configured like that. Yes, compression will be slightly lower, but you will save on both download size AND disk space, because right now most patches require you to download patch and then apply it, requiring twice the space. If you have 5% larger asset file but can patch it with a few memcpy on a mapped file it is a win in every way imaginable.

It is just really poor programming, nothing more. And it's everywhere. If find source >/dev/null takes 6 seconds there is no reason for gradle to take 2 minutes on a rebuild. If the dev is used to that, why would they even think about patch optimisation?

Re:An Unbelievable Demo by erosenbe0 on Friday June 04, 2021 @09:23AM (#27393337)
Windows game devs just traditionally didn't treat things with such granularity as you might find in a *nix environment where every little thing is a file. Content is then managed as larger blobs and you have a database of offsets or mappings.
Re:An Unbelievable Demo by maccard on Friday June 04, 2021 @03:56AM (#27391600)
I can't say, I'm not sure what compression we used on the last two games I worked on, sorry!
Re:An Unbelievable Demo by wruza on Friday June 04, 2021 @04:52AM (#27391826)
It is very unlikely that it was a “continuous” compression anyway. Continuous archives disallow random file access property, and games require exactly that for assets. You can’t decompress few gb on average to fetch a sprite of a cat.

The reason games (and software in general) do full downloads instead of binary patches is purely overdefensive and/or stupid. Store software could just check checksums after a patch and re-download only if they fail.

Re:An Unbelievable Demo by maccard on Friday June 04, 2021 @05:31AM (#27392004)
it's a UE4 game so the code is available on Github, I believe it was a header, with an encrypted index into a large binary blob of compressed data.
Re:An Unbelievable Demo by BlueTemplar on Friday June 04, 2021 @06:12AM (#27392183)
Well, whether they use full versions or diffs is also going to depend on how much they care about bandwidth.