Okay, now that we’ve performed some optimizations, it’s time to test and make sure these optimizations didn’t break any functionality. Given that all I did was switching around some preprocessor directives (and thus none of the code is different – just which parts of it get compiled on AArch64), I really doubt that anything will have broken. Still, it’s good practice to be absolutely certain.
Another thing that we need to test is if our optimizations affected other platforms. It’s entirely possible that a code change that makes a function run faster on AArch64 could make it run more slowly on x86_64 (or vice versa). If it does happen that a change improves things on one architecture while causing regressions on another, that doesn’t mean the change is bad either. We can simply use preprocessor directives, so that the optimal code is compiled on each architecture. The C preprocessor is a useful tool, though heavy use of it can make source code more difficult to read.
However, this doesn’t actually apply here. Since I only changed preprocessor directives to affect what code is compiled on AArch64, there’s absolutely no difference in the running code on x86_64 (or on any other architecture). This means I can save time and avoid having to run benchmarks and functionality tests on x86_64. It also means there’s no chance of the change affecting less commonly used architectures, which is good given that I lack both the time and the boxes to test on anything other than AArch64 and x86_64 (or maybe on older 32 bit ARM processors, but still).
Okay, so how do we test if the functionality is broken? There are a few ways. Given that this is a compression library, the first and most obvious is ‘after we compress/decompress a file, is the result the same?’ Testing this is very straightforward – compress a file, decompress it, then compare the output. The ‘cmp’ command (on Linux) compares two files and tells you if there’s any difference between them. So I ran the following command:
cmp testdata/9GB.avi otmp
And it gave me no results, which means the files are identical. So far, so good. What else can we do to be sure? Some projects have their own testing suites, and csnappy happens to be one of those projects. Running ‘make test’ performs a series of standard functionality tests (similar to what I just did), and then runs valgrind’s memory leak checker. Not all projects will have their own tests set up, but it’s quite helpful when they do. And in this case, the test results all look proper, so everything seems good so far.
There’s one final test I want to do before I can be absolutely certain that my changes haven’t broken anything – backwards compatibility. It’d be a problem if an update to a popular (or even somewhat popular) program meant it produced files that didn’t work with earlier programs. At the very least, if an optimization does break backwards compatibility, upstream needs to know about it so they can hold it off until a major version release.
How to test this is fairly obvious – compress something with the modified library, then see if the regular version of the library can decompress it without problems. In this case it’s all but certain that this won’t be a problem – the different code in csnappy compiled for different architectures is made to produce the same output. Otherwise, you could compress a file on an x86_64 box and would potentially be unable to decompress it on x86_64 – unacceptable behavior for a compression library.
Fortunately for us, everything seems to check out. With this, I can finally call Stage 2 complete, and move onto the third and final stage – getting my code accepted upstream. If you’ve worked with open source communities before, you’re probably familiar with the process. But if you’re not, stay tuned as I’ll be talking about it as I go along.