[mtouch] Add support for specifying how to optimize LLVM output. (#1532)

Performance tests
-----------------

This is for a new watchOS extension project, built for release.

* The default (currently -O2) optimizations:      41s (  baseline )  30.027.060 bytes (     baseline    )
* All optimizations disabled (`--llvm-opt=all=`): 17s (-24s = -59%)  32.978.312 bytes (+2.951.252 = +10%)
* Optimized for size (`--llvm-opt=all=-Os`):      36s ( -5s = -12%)  28.617.408 bytes (-1.409.652 =  -5%)
* Optimized for more size (`--llvm-opt=all=-Oz`): 35s ( -6s = -15%)  28.601.016 bytes (-1.426.044 =  -5%)
* Optimized slightly (`--llvm-opt=all=-O1`):      35s ( -6s = -15%)  28.666.556 bytes (-1.360.504 =  -5%)
* Optimized a lot (`--llvm-opt=all=-O3`):         41s (  0s =   0%)  30.403.996 bytes (+  376.936 =  +1%)

Conclusions
-----------

* The fastest build by far (less than twice as fast) is if optimizations are
  disabled, but this adds a 10% size penalty (~3 MB in this test case),
  compared to the baseline, and 15% size penalty (4.3 MB) compared to -Oz.
* -Oz seems to have the best overall results: at least as fast as any other
  optimized build, and the smallest app as well.

Caveats
-------

Some optimizations might not work the AOT compiled code. The resulting
binaries have not been tested.
This commit is contained in:
Rolf Bjarne Kvinge 2017-01-20 16:11:48 +01:00 коммит произвёл GitHub
Родитель 834f3e3be5
Коммит 1a7a4ab463
6 изменённых файлов: 47 добавлений и 4 удалений

Просмотреть файл

@ -431,6 +431,17 @@ namespace Xamarin
mtouch.AssertError (25, $"No SDK version was provided. Please add --sdk=X.Y to specify which {GetPlatformSimpleName (profile)} SDK should be used to build your application.");
}
}
[Test]
public void MT0026 ()
{
using (var mtouch = new MTouchTool ()) {
mtouch.CreateTemporaryApp ();
mtouch.LLVMOptimizations = "-O2";
mtouch.AssertExecuteFailure (MTouchAction.BuildDev, "build");
mtouch.AssertError (26, "Could not parse the command line argument '--llvm-opt=-O2': Both assembly and optimization must be specified (assembly=optimization)");
}
}
[Test]
public void MT0051 ()

Просмотреть файл

@ -84,6 +84,7 @@ namespace Xamarin
public Profile Profile = Profile.iOS;
public bool NoPlatformAssemblyReference;
static XmlDocument device_list_cache;
public string LLVMOptimizations;
public string [] CustomArguments; // Sometimes you want to pass invalid arguments to mtouch, in this case this array is used. No processing will be done, if quotes are required, they must be added to the arguments in the array.
public class DeviceInfo
@ -310,6 +311,9 @@ namespace Xamarin
if (!string.IsNullOrEmpty (Device))
sb.Append (" --device:").Append (MTouch.Quote (Device));
if (!string.IsNullOrEmpty (LLVMOptimizations))
sb.Append (" --llvm-opt=").Append (MTouch.Quote (LLVMOptimizations));
if (CustomArguments != null) {
foreach (var arg in CustomArguments) {
sb.Append (" ").Append (arg);

Просмотреть файл

@ -131,6 +131,7 @@ namespace Xamarin.Bundler {
public string AotArguments = "static,asmonly,direct-icalls,";
public string AotOtherArguments = string.Empty;
public bool? LLVMAsmWriter;
public Dictionary<string, string> LLVMOptimizations = new Dictionary<string, string> ();
public Dictionary<string, string> EnvironmentVariables = new Dictionary<string, string> ();
@ -158,6 +159,16 @@ namespace Xamarin.Bundler {
List<Abi> abis;
HashSet<Abi> all_architectures; // all Abis used in the app, including extensions.
public string GetLLVMOptimizations (Assembly assembly)
{
string opt;
if (LLVMOptimizations.TryGetValue (assembly.FileName, out opt))
return opt;
if (LLVMOptimizations.TryGetValue ("all", out opt))
return opt;
return null;
}
public void SetDlsymOption (string asm, bool dlsym)
{
if (DlsymAssemblies == null)

Просмотреть файл

@ -337,6 +337,17 @@ namespace Xamarin.Bundler {
compiler_flags.ReferenceSymbols (Target.GetRequiredSymbols (this, true));
}
if (App.EnableLLVMOnlyBitCode) {
// The AOT compiler doesn't optimize the bitcode so clang will do it
compiler_flags.AddOtherFlag ("-fexceptions");
var optimizations = App.GetLLVMOptimizations (this);
if (optimizations == null) {
compiler_flags.AddOtherFlag ("-O2");
} else if (optimizations.Length > 0) {
compiler_flags.AddOtherFlag (optimizations);
}
}
link_task = new LinkTask ()
{
Target = Target,

Просмотреть файл

@ -349,10 +349,6 @@ namespace Xamarin.Bundler
GetCompilerFlags (App, flags, ifile, Language);
flags.AddOtherFlag ($"-m{Driver.GetTargetMinSdkName (App)}-version-min={App.DeploymentTarget.ToString ()}");
if (App.EnableLLVMOnlyBitCode)
// The AOT compiler doesn't optimize the bitcode so clang will do it
flags.AddOtherFlag ("-O2 -fexceptions");
}
void GetSharedCompilerFlags (CompilerFlags flags, string install_name)

Просмотреть файл

@ -1258,6 +1258,16 @@ namespace Xamarin.Bundler
}
},
{ "llvm-asm", "Make the LLVM compiler emit assembly files instead of object files. [Deprecated]", v => { app.LLVMAsmWriter = true; }, true},
{ "llvm-opt=", "Specify how to optimize the LLVM output (only applicable when using LLVM to compile to bitcode), per assembly: 'assembly'='optimizations', where 'assembly is the filename (including extension) of the assembly (the special value 'all' can be passed to set the same optimization for all assemblies), and 'optimizations' are optimization arguments. Valid optimization flags are Clang optimization flags.", v =>
{
var equals = v.IndexOf ('=');
if (equals == -1)
throw ErrorHelper.CreateError (26, "Could not parse the command line argument '{0}': {1}", "--llvm-opt=" + v, "Both assembly and optimization must be specified (assembly=optimization)");
var asm = v.Substring (0, equals);
var opt = v.Substring (equals + 1); // An empty string is valid here, meaning 'no optimizations'
app.LLVMOptimizations [asm] = opt;
}
},
{ "http-message-handler=", "Specify the default HTTP message handler for HttpClient", v => { http_message_handler = v; }},
{ "output-format=", "Specify the output format for some commands. Possible values: Default, XML", v =>
{