How to Use CPUTYPE successfully on your machine
This how-to explains how to use CPUTYPE based on one user's experience with it. It is written in a conversational style, where questions are written in bold and answers in normal text.
What is CPUTYPE?
CPUTYPE is a variable that you can define in your make.conf (or on the command line) when you build ports or the base system. It asks your compiler to compile optimized code for the specified processor family. The optimized code is not guaranteed to work on other processor families.
What can I expect from defining CPUTYPE on my system?
Problems. It is not always straightforward to use this variable and, if you manage to use it successfully, you probably will not gain much in performance: indeed, very often, the bottlenecks in a long operation involve low memory, disk i/o or a combination of both (swapping), not the CPU. However, if you think that your bottleneck is due to underperformance of your CPU, CPUTYPE can help.
All right, I want to give it a try. How do I know which value should I put in there?
There are many ways. I recommend to set CPUTYPE?=native, but some people discourage it because it fails to set the variable MACHINE_CPU properly: I will tell you in a minute how to fix this issue, but let us see the standard solution first. You need to get the cpu family for your processor; here are some ways to find it:
- run "llvm-tblgen -version": you will get your answer in the last line "Host CPU: ...";
- run "cc -v -x c -E -march=native /dev/null -o /dev/null": you will get your answer after the -target-cpu word (clang) or -march= or -mtune= word (gcc);
- read the documentation about your processor;
- read the beginning of dmesg: run "dmesg | head -n 25". Do not trust the "CPU: ..." line: in my case it tells me that my CPU is a k-8 family processor, but it is an ivybridge. Read on the next line the Family and Model variables and search the web to understand them.
In this guide I will assume your CPU family is <cpu_arch>.
Then you set CPUTYPE?=<cpu_arch>.
Why should I use ?= ?
Because some day you might compile code for a different CPU. Maybe you want to share with the world a packages repository built with your own options? In that case having it working only on your processor family is a bad idea.
But you said before that you recommend to use CPUTYPE?=native instead. What's the difference?
The difference is that CPUTYPE sometimes is broken and, if it is, setting native works, while setting the theoretically correct value does not. For example, it does not work for an Intel Core 1007U processor, which is what I have and is an ivybridge. According to gcc8 manual and /usr/share/mk/bsd.cpu.mk ivybridge supports avx instructions, but it does not, at least not on my specific processor. If I set CPUTYPE?=ivybridge my compiler will generate invalid instructions for my cpu, while if I set CPUTYPE?=native it works: the output of "cc -v -x c -E -march=native /dev/null -o /dev/null" explains why (the compiler correctly sees that my processor does not support avx).
On the other hand, setting CPUTYPE?=native does not set properly the MACHINE_CPU variable, which is defined in bsd.cpu.mk: if you want to use native, then you must set MACHINE_CPU manually (either in your make.conf or on the command line): if you do not you will miss some optimization, at least in the base system.
But I do not have an ivybridge, maybe in my case I can just set CPUTYPE?=<cpu_arch>. How do I know?
Set CPUTYPE?=<cpu_arch> and try the following tests:
- enter in a directory with something to build (a port, the base sources) and run "make -V MACHINE_CPU": you will get the list of features that your system and your compiler believe your processor supports. Check if all of them are really supported by your CPU: the output of "dmesg | head -n 25" can help you. If your system and compiler are wrong, then you should use native;
- try compiling a small port (for example devel/ccache) and try to use it: if you get an invalid instruction error, then you should use native.
I need to use CPUTYPE?=native. How do I set properly MACHINE_CPU?
Enter in a directory with something to build (a port, the base sources). Run "make -V MACHINE_CPU CPUTYPE=<cpu_arch>" and "make -V MACHINE_CPU CPUTYPE=": define MACHINE_CPU+=<opt_features>, where <opt_features> is the list of the features given by the first command which is not in the second command output too and that are really supported by your CPU (again, the output of "dmesg | head -n 25" can help). You might also want to add some features that are not reported by the first command but you know are supported by your CPU: see /usr/share/mk/bsd.cpu.mk for a list of recognized features.
Once you have defined MACHINE_CPU+=<opt_features>, check that you get indeed what you want with "make -V MACHINE_CPU".
Thanks! Is that all?
Not yet. You still need to know what to do when something goes wrong.
What can go wrong now? And what should I do?
Some ports can still generate invalid code. I experience this issue with ports involving rust. If you happen to generate some invalid code with some port, then you can fix it by defining on the command line, only for the problematic build, NO_CPU_CFLAGS=yes: this will disable the optimization due to CPUTYPE.
I never experienced problems with the base system, but if you do, defining the same variable can fix them.