пятница, 6 июня 2014 г.

Github has a great continuous integration system called Travis.CI. I use it for HyperFastCgi server to check that solution correctly builds after commit and I am going to use it for unit-tests in future. Travis.CI has a very simple configuration syntax, for example HyperFastCgi travis.yml file looks like that

Yesterday I've found, that drone (analogue of Travis.CI) made support for GitLab (analogue of Github) two month ago. So now you can run Github-like version control with Travis-like continuous integration for your private projects without using github and travis. I did not try to install drone to my gitlab server yet, but if it works without serious issues it's a really, really cool!

воскресенье, 1 июня 2014 г.

This is a quick starting guide to run "Hello, world" ASP.NET vNext app on mono/linux.

Installing mono 3.4.1

At first, you need to compile the latest mono version from sources. Sources are located at http://github.com/mono/mono. You can follow the docs on the main page, but BEWARE of using --prefix=/usr/local as option of autogen.sh file! Before doing it check where is your system mono installed. You can check it with which command.

$ which mono
/usr/bin/mono

If mono is located in /usr/bin (for example Ubuntu holds it there) then you should change prefix to --prefix=/usr otherwise you'll get two different mono installation and could run into the issues "where is the proper library located?".
If you use Ubuntu, you can run this script. It'll install mono, xsp (mono web server) and monodevelop IDE.

Running "Hello, world!" application

It will start the web application at localhost:3001. To change host and port edit the file firefly/src/main/Firefly/ServerFactory.cs at line 30. Put there your host and port. No need to compile, just run k web-firefly again

You can also try to run Nowin host with the command k web, but due to the issue with sockets, you can run only ~1000 requests to your web server

вторник, 29 апреля 2014 г.

Let's imagine that you implemented some great algorithm using C# and think about improving performance of it. You might suggest to rewrite some bottleneck part in native C/C++ and call it from managed code using PInvoke. That may look like a good idea because native code is generally faster than managed but even moon has its own dark side. In the case it will be the cost of PInvoke calls to unmanaged functions. In this post you can find speed comparison of various approaches and choose the best fitting to your needs.

PInvoke call

For example, let's take a function, which calculates the sum of char codes in the string. Something like this:
(Note: all source code you can find at github)

[DllImport] attribute tells which native library to use and the name of the function in the library (EntryPoint), [MarshalAs] attribute says that PInvoke must pass first parameter as array of two-bytes strings

If you're unfamiliar with PInvoke, you should know one thing: at every call PInvoke converts parameters from managed type to unmanaged and then convert it back on return value. The attribute [MarshalAs] of parameters tells CLR how they should be converted. Such conversions consume additional time and affects to performance as well.

Now, we can create array of strings, and call these functions ten million times to check the time execution.

Managed: 3 939 ms
PInvoke: 11 616 ms

You can see, that PInvoke is three times slower than managed function and mostly because of these managed to unmanaged conversions, so you can't improve performance with PInvoke to unmanaged function if it is called very often.

Internal call

Mono has a hidden feature which is not well-known yet. It's called Internal Calls. Primary purpose of Internal Calls are mostly provide the way to implement in native code some critical methods of corlib library (memory allocation, copiing of objects, interaction with sockets and so on). Secondary it allows native application which embeds mono calls native functions of the application. With some magic I found a way to use Internal Calls in common mono application without embedding mono or changing corlib assembly.

Difference between platform invoke method declaration and internal calls is that you place the attribute [MethodImpl(MethodImplOptions.InternalCall)] over the method. MethodCodeType field is optional and may be omitted. Also, there is another difference you don't need to specify how parameters will be marshaled, because Internal Calls don't convert parameters of method to unmanaged types and place parameter to the stack as is.

Then we have to write registration function for our internal call. Add the declaration to cs file.

You see that init() function calls mono_add_internal_call. This function is defined in mono runtime, and you have to add header <loader.h>, add to compiler options include search path and link with mono library. To know headers include path, run from command line

Function mono_add_internal_call has two parameters: CLI method name (with optional signature) and pointer to a native function, which will be called when CLR calls the declared method. The name of the method is constucted as "Namespace.ClassName::MethodName" and may be optionally added with method signature (this is usefull, when you have got overloaded methods)

Now we are ready to the final part: implementation of internalCount function. Let see at the function body

You may notice that the function has MonoArray type in the signature which represents string[] type in csharp. That is the most important difference versus standard PInvoke: Internal Calls works directly with managed types and you have to use Mono API to access parameters and return values. Header files of Mono API you can find at pkg-config --cflags mono-2 directory mentioned above.

But surprisingly for me it worked as expected only in mono AOT mode, when I run this program in normal mode I got MissingMethodException. I have to spent some time with debugger and found the interesting thing

When mono starts to execute method 'Main' JIT compiler compiles 'Main' at first and recursively all the methods which are called from the 'Main'. As 'Main' is referenced to 'InternalCount' method, JIT starts to compile 'InternalCount' method too. In compilation it searches the method name in registered internal calls, because the method has [MethodImplOption.InternalCall] attribute. But it could not find it, because 'InitInternals' function is not yet run! In this case JIT generates 'throw new MissingMethodException' in IL and all subsequent calls are throwing that exception, even when we register proper internal call later.

To avoid such behaviour I hide the method InternalCount from JIT. To do this I placed all the meaningful code out of the 'Main' function, and in 'Main' function created delegate to my function and called it. JIT compiles delegate only when it starts to run and 'MissingMethodException' goes away! The code now looks like this

Internal calls is a total winner, when the PInvoke is outsider with no chances to beat even managed code. PInvoke to Internal Call performance differs more to ten times!

And here are the results for byte buffer xoring algorithm

Method

Mono no optimizations

Mono --optimize=unsafe

Managed

2 068 ms

1 507 ms

PInvoke

4 387 ms

3 707 ms

Internal Call

1 372 ms

1 381 ms

You can see that with 'unsafe' optimization managed code executes close to Internal Calls, but without optimizations it's 50% slower. I choose 'unsafe' optimization, because it shows maximal speed boost for code working with arrays (unsafe optimization removes bounds checks). PInvoke again at the last place

Opened questions:

GC movements. Should we pin managed data or do something another to be sure, that the data is not moving by GC when we are in the internal call?

Conclusion

Mono is a powerful framework and allows you to do great things with native code as well as managed. If you want to increase performance of you managed code don't use PInvoke to unmanaged as it defeats performance, but instead you might look onto Internal Calls. But you should be aware that the internal call mechanism is platform depended and you could not run you great app on .NET if you use it. By the way you always can add conditional #ifdef and compile your app with managed method for .NET and internal for Mono