Alex Rønne Petersen profiler, runtime

As part of our ongoing efforts to improve Mono’s profiling infrastructure, in Mono 5.6, we will be shipping an overhaul of Mono’s profiler API. This is the part of Mono’s embedding API that deals with instrumenting managed programs for the purpose of collecting data regarding allocations, CPU usage, code coverage, and other data produced at runtime.

The old API had some limitations that prevented some features and capabilities from being implemented. The upgrade to the API will allow us to:

  • Reconfigure the profiling features at runtime
  • Look at the values of incoming parameters and return values.
  • Ability to instrument the managed allocators, thus allowing these to be profiled.

This is what we did.

Reconfigure Profiling at Runtime

We wanted the ability to reconfigure the profiling option at runtime. This was not possible with the old API because none of the API functions took an argument representing the profiler whose options should be changed.

This means that it was only possible to change options of the most recently installed profiler, and this was not guaranteed to be the one you wanted. Additionally, doing so it was not thread safe.

Why would we want to change profiling options at runtime, you might wonder? Suppose you know that only a particular area of your program has performance issues and you’re only interested in data gathered while your program is executing that code. With this capability, you can turn off profiling features such as allocations and statistical sampling until you get to the point you want to profile, and then turn them on programmatically. This can significantly reduce the noise caused by unneeded data in a profiling session.

Call Context Introspection

Call context introspection allows a profiler to instrument the prologue and/or epilogue of any method and gain access to arguments (including the this reference), local variables, and the return value.

This opens up countless possibilities for instrumenting framework methods to learn how a program is utilizing facilities like the thread pool, networking, reflection and so on. It can also be useful for debugging, especially if dealing with assemblies for which the source code is not available.

Instrumenting Managed Allocators

Another improvement we were able to make thanks to the redesigned API was to use instrumented managed allocators when profiling. In the past, we would disable managed allocators entirely when profiling. This would slow down allocation-heavy programs significantly. Now, we insert a call back to the profiler API at the end of managed allocators if profiling is enabled.

Simpler to Work With

On top of these major features, the new API is also simply more pleasant to use. In particular, you no longer have to worry about setting event flags; you simply install a callback and you will get events. Also, you no longer have to use callback installation functions which take multiple callback arguments. Every kind of callback now has exactly one function to install it. This means you will no longer have code such as mono_profiler_install_assembly (NULL, NULL, load_asm, NULL); where it can be unclear which argument corresponds to which callback. Finally, several unused, deprecated, or superseded features and callbacks have been removed.

Breaking Change

The new API completely replaces the old one, so this is a breaking change. We try very hard to not break API/ABI compatibility in Mono’s embedding API, but after much consideration and evaluation of the alternatives, a breaking change was deemed to be the most sensible way forward. To aid with the transition to the new API, Mono will detect and refuse to load profiler modules that use the old API. Developers who wish to support both the old and new APIs by compiling separate versions of their profiler module may find the new MONO_PROFILER_API_VERSION macro useful.

A presentation with more details is available in PowerPoint and PDF formats.

Alexander Köplinger releases

Mono 5.2 is out in the stable channel !

Check out our release notes for more details about what is new on Mono 5.2.

This release was made up of nearly 1000 commits since Mono 5.0 and is the result of many months of work by the Mono team and contributors!

Miguel de Icaza runtime

We have been experimenting with a couple of approaches to bring Mono to the web using WebAssembly - a technology that can efficiently and safely execute code in web browsers without being limited to Javascript. Running code written in C or C++ inside the browser has been a big motivator, but most major programming languages have plans to target WebAssembly as a platform.

WebAssembly has been out for a few months on desktop computers and Android, and with the introduction of iOS 11 it will become nearly universal.

We have done some exploratory work to identify what needs to be done to run Mono on the browser. The early experiments are promising, let me talk about those.

Mono supports various execution modes, it ranges from the traditional fully just-in-time compiled, to fully statically compiled with a couple of hybrid modes in between (statically compiled with JIT, and statically compiled with an interpreter).

Today we have two prototypes running in WebAssembly.

The first one uses the traditional full static compilation mode of Mono, this compiled both the Mono C runtime and the Mono class libraries along with the user code into WebAssembly code. It produces one large statically compiled application. You can try this fully statically compiled Hello World here. The full static compilation currently lives here.

The second prototype compiles the Mono C runtime into web assembly, and then uses Mono’s IL interpreter to run managed code. This one is a smaller download, but comes at the expense of performance. The mixed mode execution prototype currently lives here.

You can see C# Hello World, or this F# code in action:

open System
type Shape = | Circle of float | Square of float * float
let main argv =
  let s = Circle 10.
  Console.WriteLine (s)

Currently neither approach has been optimized for size, they are using the full Mono Desktop profiles. The size should come down significantly once we use a custom profile based on the mobile profile and remove many of the unnecessary features.

There are both interesting technical challenges to solve in the WebAssembly space, some hard (stack walks) and some straightforward (single threaded).

The development experience is another component that will be interesting to study. Clearly we want to have our cake and eat it too, so we desire the high performance that comes from doing full linking and statically compiling everything to WebAssembly. But for quick iterative development, clearly something like an interpreter or a JIT compiler in the browser with cached versions of libmono and the core managed libraries is desirable.

Miguel de Icaza releases

After almost 12 years, we are upgrading the guts of HttpWebRequest, the engine that powers the basic HTTP client stack in Mono.

.NET offers two sets of HTTP client APIs, the original HttpWebRequest that offers a comprehensive and configurable API that can communicate with HTTP 1.x servers using the original .NET 1.0 programming model, and a modern, pluggable and more limited API in the form of HttpClient which can also talk to HTTP 2.0 servers.

HttpClient is an interesting API as it has been designed to allow for different providers to be used and was also designed with async programming support in mind.

On each platform, HttpClient tries to use the best available transport:

Host/Runtime Backend
Windows/.NET Framework HttpWebRequest
Windows/Mono HttpWebRequest
Windows/UWP Windows native WinHttpHandler (HTTP 2.0 capable)
Windows/.NET Core Windows native WinHttpHandler (HTTP 2.0 capable)
Android/Xamarin Default to Android’s HTTP transport
Can be configured to be HttpWebRequest.
iOS, tvOS, watchOS/Xamarin Default to NSUrlSession (HTTP 2.0 capable)
Can be configured to use HttpWebRequest.
macOS/Xamarin Default to NSUrlSession (HTTP 2.0 capable)
Can be configured to use HttpWebRequest
macOS/Mono HttpWebRequest
macOS/.NET Core libcurl-based HTTP transport (HTTP 2.0 capable)
Linux/Mono HttpWebRequest
Linux/.NET Core libcurl-based HTTP transport (HTTP 2.0 capable)

As you can see, while HttpWebRequest is not the default across the board and lacks HTTP 2.0 capabilities, it is still available in various configurations in Mono-powered stacks (Mono and Xamarin).

Mono’s original HttpWebRequest stack was written in 2004 and was built using the asynchronous APIs that were available in .NET 1.0, that is the BeginInvoke / EndInvoke patterns, a pattern that was heavily based on queuing work, waiting for a result and resuming execution at a later point.

While the code grew in capabilities, features and reliability over the years, all of this was built on top of these 2004-era programming idioms. The code is difficult to read, to follow and understand. Simple bugs can take a long time to fix, and subtle problems can burn the most passionate developer. It has been a source of frustration for both us, and our users when a rare bug comes up in this stack.

At one point we tried to use the .NET Reference Source implementation, but that version was just too difficult to extract as it relies on many internals that do not exist in Mono, and in turn relies on Windows capabilities that we would have needed to support [1]. But this code also used those old idioms and while it might have fewer bugs and we might increase the compatibility of the stacks, the extraction was too complicated.

Over the years we have embraced expedience in the form of band-aids for this code, over the right fix, given just how complex the code had gotten. We are facing a couple of corner cases that are hard to fix and we wanted to fix the code for good, not apply another band aid.

So we decided to refactor the code from the old idioms from 2004 into 2017 idioms, using everything that is available to us in C# 7.

Chief among those capabilities is the use of async programming that removes both the complexity from the code and makes the code a pleasure to read and understand. It has taken us a few weeks to do the port, and we are currently validating every known scenario and test suite against it, but things are looking very promising.

You can track the state of this effort on Martin’s GitHub pull request.

[1] At one point we did write such a layer, the effort still lives dormant on a branch, for anyone that might be interested in resuming that work.

Jonathan Peppers releases

Today we are announcing the first preview release of Embeddinator-4000 for Android available on NuGet. The package also includes the previously released iOS support.

nuget install Embeddinator-4000

This will place Embeddinator-4000.exe into the packages/Embeddinator-4000/tools directory.

This release supports the following scenarios:

  • Call C# code from Java or C
  • Package a Xamarin.Android library project into an AAR package for use in Android Studio
    • Include Android layouts, drawables, assets, etc. from C# projects
    • Default linker behavior of SdkOnly
    • Generate AAR files on either Windows or OS X
  • Use Xamarin.Forms’ new embedding API to use Xamarin.Forms from Java
  • Package a .NET library project into a JAR file for use from Java on desktop platforms
  • Package a .NET library project into a dylib, so, or dll as appropriate per platform for use from C

For general usage, run Embeddinator on a compiled Android library assembly as follows:

mono Embeddinator-4000.exe -gen=Java -platform=Android -c YourAndroidLibrary.dll

This will output YourAndroidLibrary.aar for use in Android Studio.

In Android Studio, create a new module and choose Import .JAR/.AAR package: Import AAR Package

Adding a dependency to the new module, will give Java access to your .NET code: Add Module Dependency

For detailed instructions on using Embeddinator-4000 for Android see our Getting Started guide.

For a complete walkthrough, check out this video embedding Charles Petzold’s FingerPaint demo in an Android Studio project here:

Embeddinator-4000 for Android

For iOS support, you can use objcgen.exe included in the NuGet package. Additionally, you can follow the iOS Getting Started guide.