Developer Info

All About Strict Aliasing!

Code: void pointlessFunction( uint32_t foo ) { uint32_t* const bar = (uint32_t*)&foo; }

Code: void anotherPointlessFunction( uint32_t foo ) { uint16_t* const bar = (uint16_t*)&foo; }

Of Unicorns and Compilers...

Small but Helpful Things

Code: make -jX otapackage > buildlog.txt

Code: make -jX otapackage 1> buildstdout.txt 2> buildstderr.txt

Code: make -jX otapackage > buildlog.txt 2>&1

This is a little section I'm gonna set up explaining things in more technicalish and "down-and-dirty" details of sorts for developers interested in this project and potentially incorporating it into their projects.The only thing I ask is to make a little "Thank You" section in your main post like I have here and credit at least me and Linaro, and also credit anybody else's work I have used if you use it as well. I'd also appreciate it if you could maybe link my name to this thread or my user profile here on XDA, but that part isn't a requirement.All of my work can be found on my GitHub . Please note that any commits on my GitHub that are after the most recent build of FML should be considered experimental and potentially not working at all. I develop on the fly and often times things on my GitHub aren't finished and fully tested unless they have made their way into an official build of FML.Please pay no attention to where it says a repository was forked from. Often times I'll have forks that I just re-use to avoid duplicate and unnecessary extra repos. For example, in repos forked from CyanogenMod you might notice the default branch is actually something like "omni-4.4" indicating that branch is based from OmniROM and not CyanogenMod.The best place to keep track of what parts of the Android source code that needs patches is the manifest One of the big things Linaro does with improving Android's performance is fixing violations of what's known as "the strict aliasing rule."A pointer is said toanother pointer when they both refer to the same location of memory. This is OK and not an uncommon thing to do. The strict aliasing rule is that pointers of different types should never refer to the same location of memory (aka alias each other). Things like this are just fine and dandy:That's alright, as foo and bar are the same type. Note that it's also OK if the only difference between foo and bar is signedness (e.x. uint32_t and int32_t).Now this......this is a problem. foo and bar are NOT the same type. This is a violation of strict aliasing.Strict aliasing allows a compiler to make some assumptions when compiling and optimizing code that it otherwise couldn't. This is a good read about the benefits of it.Here's a few examples of fixing strict aliasing violations:Note that not everything is fixable, or worth fixing. Sometimes you'll just have to add -fno-strict-aliasing to the problematic section and call it a day:This section will delve into compilers and flags for them. The "Of Unicorns" part is in reference to the amount of false information, misconceptions, and mythical beliefs regarding these things. One thing in particular is the common belief that throwing every flag possible at the compiler results in better/faster binaries. That couldn't be further from the truth, and is something that actually took me quite some time to properly understand myself (in part because the misconceptions are more common than the actual truth!). In this section I will mainly be referencing the GCC compiler, as that's what is currently used for the majority of Android and most Linux systems as a whole. The other compiler that is making quite a run at GCC is Clang, so first I will talk about GCC vs Clang quickly:GCC is currently (~May 2014) the most common compiler used for Linux and Linux-based systems (which includes Android). GCC was first released in 1987, as the "GNU C Compiler." Not long after its release, it was extended to support C++ as well, and over time many different languages and platforms became supported by GCC so it is now called the "GNU Compiler Collection." Over all this time, GCC became more and more difficult to maintain. As time passes on, fewer and fewer people have been able to get their foot in the door to work on GCC as it just became so... bloated.Eventually, somebody finally got the guts (or resources, rather) to take on GCC and make a competing compiler. Clang was born.Clang is a front-end for LLVM. Initially, LLVM was going to make use of GCC's front-end for making a C/C++/etc. compiler using LLVM's back-end, however this was just too cumbersome of a task due to GCC's difficult-to-work-with codebase, which was what sparked Clang instead.Fun fact: Clang 1.0 was released in 2009. It was first open-sourced in 2007. That's 20 years after GCC's inception, but yet Clang has managed to tear GCC's usage apart. However to be fair, LLVM's initial release was 2003, but that's still a decade and a half head-start given to GCC!As of GCC 4.8 vs. LLVM/Clang 3.4, it's kind of a toss-up between the two. In some cases GCC has better binary results and in other cases Clang has better binary results, however Clang outshines GCC in areas other than the resulting compiled code:1. Clang is faster and uses fewer resources than GCC when compiling. It's usually a safe bet that Clang is going to be at least 50% (1.5x) faster than GCC when compiling, whilst also somehow using less RAM and disk space than GCC. For those of you that like being eco-friendly, just imagine the amount of energy this saves!2. Clang has generally been ahead-of-the-game when it comes to supporting C++ standards. Current example: Clang has been C++14 feature-complete since the end of 2013, while GCC (even in 4.9!) is not.Thanks to the competition from Clang, GCC has also been stepping up its game as well too. All-in-all this has been a win-win for everybody so far.Aaand here we go on compiler flags. For this I'll be referencing the GCC documentation on "GCC command options", here: https://gcc.gnu.org/onlinedocs/gcc/i...c_Invoking-GCC Of particular interest in this section will be "Options That Control Optimization", but other sections are often overlooked which can be of use, I'll explain those later though.The first thing you'll see in the "Options That Control Optimization" section are the -O options. These are general optimization levels that give you a sensible default to work with.First off is -O0. This is the default, and doesn't turn on any optimization options. This is generally only used for debugging code, as some optimizations can interfere with that.Next would be -O1. This enables some optimizations to reduce code size and improve speed, without increasing the time it takes to compile code significantly.After that is -O2. This is what is generally used for most program compiling, as it enables plenty of optimizations and these ones generally don't cause problems/bugs with the resulting binaries whilst greatly improving speed.Then there are some non-numbered ones which I'll go over:-Os is somewhere between -O1 and -O2. It enables most of -O2's options, but disables some that can increase the size of the resulting binaries. This can be of great use when dealing with smaller embedded systems where space is generally preferred over speed. It's closer to -O2 than -O1...-Og is useful for debugging purposes. It enables a few optimizations that generally don't effect ability to debug code, so devs don't have to deal with the slowness of -O0 as much as usual.And then there's the almighty -O3...-O3 enables some extra optimizations that -O2 does not. The drawbacks are increased compile time, increased binary size, and the possibility for some bugs. In many cases, -O3 might not improve speed over -O2 whatsoever. In other cases it can be helpful, but it is nothing compared to the differences between -O1 and -O2.Android generally uses -O2 by default. It's safe and fast enough for most cases. -Os is also used for any Thumb instruction-set code for ARM, as Thumb is generally meant for reduced size and complexity from what I can tell.There's also a flag kinda above -O3, which is -Ofast. The problem with -Ofast is that it can cause huge problems for any code that makes the (correct!) assumption about some math stuff, so it is generally avoided.Then there are some flags that aren't enabled byoptimization level. This is not without reason: these flags are, generally,. They increase compile time by a ridiculous amount, and their effects on the resulting binaries might be absolutely nothing. Zilch. Nadda. Even for something as large as Android, these flags can still do nothing. If these flagshave a speed-up, it's generally not without risk, and they should be kept to specific use-cases rather than used on every single thing.These flags can be considered about the equivalent of using the "placebo" profile for h264 video encoding. It has a less-than 1% improvement in the resulting quality, yet can take twice as long to render (or, in this case, compile). And they are pretty much exactly what the placebo profile for h264 encoding is,. You will not find a measurable increase in speed, and the risks associated with it are generally not worth it!Therean exception to that though: -flto. This enables Link-Time Optimization, and can have huge impacts on both the speed of the binaries as well as even a reduction in their size! LTO can be viewed as this: when the compiler is truckin along compiling things, it generally only sees bits and pieces of the project at hand. LTO allows the compiler to view how everything works together rather than just each individual part, and in doing so it can find HUGE improvements! When LTO was in its infancy with GCC, it was pretty unstable, but with GCC 4.8 and above it can be used reliably. It's also advised to use the -fuse-linker-plugin flag when using LTO as well (read the docs on that).Here is my work on using LTO with Android, it's more involved than simply adding it with all the other flags which is why you'll generally hear the people that are making use of the "unicorn flags" say it doesn't work...Ignore the things in the last couple commits there that aren't related to LTO...But like I said, it's more involved than just throwing the flags blindly at the compiler, there are a few other fixes required to get a successful build with LTO:And then it also has to be disabled in ART, that fix courtesy of @ metalspring // To be continued.I thought I'd put some simple little things here that can be immensely helpful to devs. Most of these they'll probably know already, but some won't and when I learned these things they had a profound impact on development. At the very least it can be a helpful reminder/reference sort of thing.This is something I finally figured out not long ago that has had a huge impact on debugging problems...I'm not all that great with bash but Iunderstood redirecting the output of a program to a file. However, when I tried the usual:, not everything was going to the file. Eventually I learned that just using ">" only redirects stdout, and not stderr which was where all the warnings and errors went to. To get around that, there's a couple options. One, you can redirect stdout and stderr to separate files, like so:, or the other option is to just lump them all into a single file using:This post is a WIP...