How does game optimization work, particularly for PCs where you can never know what combination of specs the player has? Is it interwoven to every stage of game development or is it only done at the very end right before the game is published?

Optimization generally comes in two flavors: speed and size. Since we have finite time to do things, we want things to run faster in order to do more things in the same amount of time. Similarly, we have finite memory to hold data so we want to make as much use of the limited memory we have as possible by keeping the things we load as small as possible. Most of the time optimizing for speed trumps size because disk space and memory is easier to add than computing speed… but we always want to pack as much as we can into both, so that we can deliver the most game that we can.

At its core, optimization is a question of avoiding unnecessary work. For example, let’s say that we’re working on a first person shooter and the player turns to change the camera. We have a list of all of the entities that exist in the world. We need to figure out whether each entity needs to be drawn. We can simply go through the list and ask “Is there anything in between you and me to stop me from seeing you?” and get an answer, but let’s say that doing the specific check takes a while. If we have to do it for every entity in the game every frame, this can eat up a lot of resources.

But let’s say that we also have a pretty fast condition we can check - let’s say we can ask the entity “Are you behind the player character?” and it will have to answer “yes” or “no”. Suddenly, we can start ignoring a lot of these world entities. After all, if our player can only see what’s in front of her, there is no way that she could see something behind her, right? This means that we should ask this question to every entity that we might see, because it will avoid doing the more expensive “check whether anything is in between us” operation when we don’t have to do it.

Let’s extrapolate on this concept further. One common optimization is using “LoDs” - levels of detail. The idea is that an object that’s very far away from the viewer is hard to see and is only a speck on screen, so we don’t have to render it at full detail because the player can’t see those details anyway. Therefore, we can get away with rendering fewer polygons on the far-away models, and a lot more on the up-close ones. This means that we have to load multiple models for the same entity (each level of detail needs one), but it also means that we are cutting down on the number of polygons the system needs to draw at any given time.

Let’s take this further. Another way of optimization is by minimizing the number of loads we have to do from disk. Hard drives hold a lot of data, but it takes time for the cpu to load the data from them. The reader in the hard drive needs to seek the right position, magnetic disk needs to spin to the right place to be read, then the data needs to be read from the spinning disk and written into memory. This can take a relatively long time. Let’s say that we have our LODs, but we need to load textures for them. Low detail models only need low detail textures, after all. But we want to avoid the set amount of time it takes to load a file. How do we speed it up? What we can do is take all of the textures for the all of the different LOD models and put them all into one big texture. Since we know we’re probably going to use all of the different LOD models, we might as well load all of their textures at the same time too. This means we don’t have to wait for multiple separate loads. These are called Mipmaps.

If you haven’t noticed, these kinds of optimizations apply to all platforms because they are all computers and generally behave the same way. Whether it’s a PC, mobile device, or console, it still has to load stuff from disk, it still has a CPU that runs at a certain speed, and it still uses main memory to load stuff. Don’t get me wrong, there are optimizations we do that are specific to the platform as well, but those tend to be more specific. Most dev teams start optimizing the general stuff as soon as they can, because optimization is part of the planning process too. The goal of optimization is to minimize the resources we use in an intelligent manner. That way things can run faster. Sometimes it means being smart about where to spend our time, and avoiding the expensive operations if we don’t need to do them. Sometimes it’s about using up resources we can spare (such as memory) to save time from loading. Sometimes it’s about trading resources we can spare (like memory) for resource we need (like lowering the number of polygons we have to draw each frame). But it’s all to make things perform more efficiently and that’s always a worthy goal.

Got a burning question you want answered?

PHP 7 at Tumblr

At Tumblr, we’re always looking for new ways to improve the performance of the site. This means things like adding caching to heavily used codepaths, testing out new CDN configurations, or upgrading underlying software.

Recently, in a cross-team effort, we upgraded our full web server fleet from PHP 5 to PHP 7. The whole upgrade was a fun project with some very cool results, so we wanted to share it with you.

## Timeline

It all started as a hackday project in the fall of 2015. @oli and @trav got Tumblr running on one of the PHP 7 release candidates. At this point in time, quite a few PHP extensions did not have support for version 7 yet, but there were unofficial forks floating around with (very) experimental support. Nevertheless, it actually ran!

This spring, things were starting to get more stable and we decided it was time to start looking in to upgrading more closely. One of the first things we did was package the new version up so that installation would be easy and consistent. In parallel, we ported our in-house PHP extensions to the new version so everything would be ready and available from the get-go.

A small script was written that would upgrade (or downgrade) a developer’s server. Then, during the late spring and the summer, tests were run (more on this below), PHP package builds iterated on and performance measured and evaluated. As things stabilized we started roping in more developers to do their day-to-day work on PHP 7-enabled machines.

Finally, in the end of August we felt confident in our testing and rolled PHP 7 out to a small percentage of our production servers. Two weeks later, after incrementally ramping up, every server responding to user requests was updated!

## Testing

When doing upgrades like this it’s of course very important to test everything to make sure that the code behaves in the same way, and we had a couple of approaches to this.

Phan. In this project, we used it to find code in our codebase that would be incompatible with PHP 7. It made it very easy to find the low-hanging fruit and fix those issues.

We also have a suite of unit and integration tests that helped a lot in identifying what wasn’t working the way it used to. And since normal development continued alongside this project, we needed to make sure no new code was added that wasn’t PHP 7-proof, so we set up our CI tasks to run all tests on both PHP 5 and PHP 7.

## Results

So at the end of this rollout, what were the final results? Well, two things stand out as big improvements for us; performance and language features.

## Performance

When we rolled PHP 7 out to the first batch of servers we obviously kept a very close eye at the various graphs we have to make sure things are running smoothly. As we mentioned above, we were looking for performance improvements, but the real-world result was striking. Almost immediately saw the latency drop by half, and the CPU load on the servers decrease at least 50%, often more. Not only were our servers serving pages twice as fast, they were doing it using half the amount of CPU resources.

These are graphs from one of the servers that handle our API. As you can see, the latency dropped to less than half, and the load average at peak is now lower than it’s previous lowest point!

## Language features

PHP 7 also brings a lot of fun new features that can make the life of the developers at Tumblr a bit easier. Some highlights are:

• Scalar type hints: PHP has historically been fairly poor for type safety, PHP 7 introduces scalar type hints which ensures values passed around conform to specific types (string, bool, int, float, etc).
• Return type declarations: Now, with PHP 7, functions can have explicit return types that the language will enforce. This reduces the need for some boilerplate code and manually checking the return values from functions.
• Anonymous classes: Much like anonymous functions (closures), anonymous classes are constructed at runtime and can simulate a class, conforming to interfaces and even extending other classes. These are great for utility objects like logging classes and useful in unit tests.
• Various security & performance enhancements across the board.