понедельник, 26 октября 2015 г.

Enable refactoring in Monodevelop 5.9.6 on Linux


After some changes in monodevelop refactoring stopped to work on Linux. After some investigation I found a way to enable it back.

For Monodevelop v 5.11 (compiled from sources)

Right click on the solution, remove check near "Enable refactoring" menu item (it is located under "Options" menu item) and then set the check again. After these manipulations refactoring starts to work.

For Monodevelop v 5.9.6 (installed from Xamarin repo)

Unfortunately, "Enable refactoring" checkbox is available only in the latest Monodevelop and does not exist in Monodevelop 5.9.6, but it can be enabled manually.

Close your solution in Monodevelop. Go to your solution folder, open <YourSolution>.userprefs file then add the attribute RefactoringSettings.EnableRefactorings="True" to the first XML element "Properties" the file.

It should look like this <Properties StartupItem="...." RefactoringSettings.EnableRefactorings="True">

Then save the file and open solution in monodevelop again. Refactoring is working now

среда, 11 февраля 2015 г.

Increase NUnit performance on AppVeyor

I think you're familiar with AppVeyor - continuous integration cloud system, which allows to make your builds and run unit-tests on windows-based VM. It's free for open-source projects and very useful when you need to be sure that your program will be compilable and runnable against Windows platform (for Linux there is Travis.CI or docker.io, for OS X you can use Travis.CI again).

When I converted MSTest to NUnit for Microsoft Bond project I have found that nunit tests run 4x-5x times slower than similar MS Tests on appveyor. That was strange because my measurements show that slowness was directly inside the tested methods, not in the nunit framework itself. I started to investigate the issue and found that there is NUnitLite nuget package which do the same things as nunit-console but much faster. What was bad that before using NUnitLite you have to create new console project and reference NUnitLite nuget package. That is not always possible if you don't want to add to your sources some unrelated to your project staff.

So at first I made an AppVeyor script which builds NUnitLite

install_script:
   - nuget install NUnitLite -version 3.0.0-alpha-5 -pre
   - mkdir nunit
   - copy NUnitLite.3.0.0-alpha-5\lib\net45\nunitlite.dll nunit 
   - copy NUnit.3.0.0-alpha-5\lib\net45\nunit.framework.dll nunit
   - csc /platform:anycpu32bitpreferred /out:nunit\nulite.exe /optimize+ NUnitLite.3.0.0-alpha-5\content\Program.cs /r:nunit\nunitlite.dll /r:nunit\nunit.framework.dll

To test with NUnitLite, you can use two ways.

test_script:
   #use this way if you installed NUnitLite version greater than 3.0.0-alpha-5
   - nunit\nulite.exe path\to\your\tests\TestAssembly.dll
   #use this way if you installed NUnitLite version 3.0.0-alpha-5 or lower
   - copy nunit\* path\to\your\tests
   - path\to\your\tests\nulite.exe TestAssembly

Please note that in the second case we start nulite.exe in the folder where your tests are located and pass an assembly name (without extension) as nulite.exe argument

What was interested that without /platform:anycpu32bitpreferred argument nulite.exe works slow on AppVeyor. This argument says to execute generated exe file in x86 mode on the systems which support 32bit. I tried to run nunit-console in x86 mode and this increased speed a lot! To do it just specify --x86 argument for nunit-console version 3.0 or run nunit-console-x86 for nunit 2.6.3 (which is preinstalled by default on AppVeyor)

вторник, 3 февраля 2015 г.

CoreCLR is on github! How to build it on linux.

Today Microsoft announced that CoreCLR (cross-platform runtime for .NET Core) is on github. At first I tried to build it on my Ubuntu 14.04 box. There was some prerequisites issues which prevented build to be completed, but after some investigation I've found the working set of packages: This is the final script:

#Installing Prerequisites
sudo apt-get install git cmake clang-3.5 make llvm-3.5 gcc
 
#build.sh is working only on 64 bit Linux!
git clone https://github.com/dotnet/coreclr
cd coreclr
./build.sh     

пятница, 23 января 2015 г.

Monodevelop and using inherited T4 templates

Introduction

I am writing BenchmarkSuite the framework which helps to write benchmark tests in the same way like NUnit unit tests. You write a method which do the benchmark of you code, then mark it with [Bench] attribute and run the bench-console application. It search all the methods marked with [Bench] in the the assembly runs them several times, measures the metrics, calculates Mean, Standard Deviation and other statistical variables and outputs the results to the console and XML file. For testing the usage of the BenchmarkSuite library I've decided to benchmark various binary serializers for some common operations.

I've created SerializersBenchmarks project on github, got some well-known and some unknown binary serializers and start to write benchmarks for them. At the start that was funny, I've written a benchmark ran the console and immediately saw its results. But when number of binary serializers became more than 3, and number of test types grew it became a pain to add almost identical lines of code (which differentiate only by name of serializer and method to serialize/deserialize data) to every project. At this stage I decided to automatize the process and use the code generation

Transforming the code to T4

Look at the benchmark code

[Bench]
[Iterations(10000)]
public void SerializeByteArray64KStream()
{
 var ser = SerializationContext.Default.GetSerializer<ByteArray64K> ();
 var arr = ByteArray64K.Create();
 var b = Benchmark.StartNew ();

 using (MemoryStream ms = new MemoryStream ()) {
  for (int i = 0; i < 10000; i++) {
   ms.Position = 0;
   ser.Pack(ms,arr);
  }
 }

 b.Stop ();
}

It creates serializer, then creates object of the serialized type and calls 10000 operation of serializing the type to a MemoryStream.

For every serializer and type it differs only few lines of code:

  • function name
  • creation of serializer
  • creation of type
  • calling method to serialize the type to a stream

To reuse common code I decided to write one base T4 precompiled template, derive from it in every benchmarking project and customize derived template for serializer needs. I used "Inheritance Pattern: Text in Base Body" from MSDN library to create base template.The code for template

<#
foreach (BenchTypeInfo typeInfo in SerializedTypes) {
#>

 [Bench]
 [Iterations(<#=typeInfo.Iterations#>)]
 public void Serialize<#=typeInfo.Name#>Stream()
 {
  <# InstantiateSerializer("ser",typeInfo.Name); #>
  var arr = <#=typeInfo.Name#>.Create();

  var b = Benchmark.StartNew ();

  using (MemoryStream ms = new MemoryStream ()) {
   for (int i = 0; i < <#=typeInfo.Iterations#>; i++) {
    ms.Position = 0;
    <# Serialize("ser","arr",typeInfo.Name,"ms"); #>
   }
  }

  b.Stop ();
 }

<#
}
#>

<#+
public virtual BenchTypeInfo[] SerializedTypes {
 get { 
  return new BenchTypeInfo[] {
    new BenchTypeInfo(typeof(ByteArray64K),10000),
    new BenchTypeInfo(typeof(PrimitiveType),1000000)
   };
 }
}

public virtual void InstantiateSerializer(string name, string type){}

public virtual void Serialize(string serName, string objName, 
                              string objType, string streamName){}

#>

What do this template do? For every type added in SerializedType array it creates text of the Serializing function, which serializes type to the memory stream. In the placeholders where Serializer should be created it calls the virtual method InstantiateSerializer(), which must be overrided in derived class and must write the code text which instantiates serializer. Then it calls virtual method Serialize() to fill the placeholder with Serialization code.

The next step was to create derived template, which would fill up all placeholders in base template. This was a little tricky. At the first, we must to say that template is ihnerited from base template with

<#@ template language="C#" inherits="BenchArrayBase" #>

Then we need to reference the base template assembly and base template namespaces in derived templates. To do it there are commands

<#@assembly name="absolute_path_to_assembly" #>
<#@import namespace="namespace_name" #>

Unfortunately, in most cases you don't know the absolute path to the referenced assembly, because you can place your project everywhere. Putting assemblies into GAC is not the good option to avoid this issue. But there is a solution. You can use project macros like ${ProjectDir} or ${TargetDir} in the assembly name and they will be evaluated into the absolute path. I added project 'SerializersBenchmarks' which contains base template as a reference to benchmarking projects and used

<#@assembly name="${TargetDir}/SerializersBenchmarks.dll" #>

as a reference in T4 template. If your base template located in the same assembly as the derived template you can use

<#@assembly name="${TargetPath}" #>

construction.

So I've added these lines at the top of the template

<#@ template language="C#" inherits="BenchArrayBase" #>
<#@ assembly name="${TargetDir}/SerializersBenchmarks.dll" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="SerializersBenchmarks.Templates" #>
 
<# base.TransformText(); #>

base.TransformText(); calls all transformations in the base template and outputs generated code. During the transformation it calls the overrided methods from the derived template, so I have to define these methods at the end of the file


<#+
public override void InstantiateSerializer(string name, string type) 
{
 base.WriteLine("var {0} = SerializationContext.Default.GetSerializer<{1}> ();",name, type);
}

public override void Serialize(string name, string objname, string objtype, string stream) 
{
 //ser.Serialize(ms,arr);
 base.WriteLine("{0}.Pack({1},{2});",name,stream,objname);
}
#>

As you guessed base.WriteLine() writes the line into the output which is generated by base template. That's all! Only few lines of code and we can add new serializer to our benchmarks without copy-pasting and replacing bunch of strings.

You can look into the sources in the real project:

Base Template
Derived Template
Generated CS File

Issues with Monodevelop

When I start to use inherited T4 templates in Monodevelop I've found that Monodevelop did not support them, it threw an exceptions on trying to use derived templates. So I made a patch with fixes for Monodevelop, which was accepted in version 5.8. Also I made a patch which allow to regenerate all T4 templates in the project or solution (very useful when you made some changes in base template and need to update generated code in the whole solution). To do it right click on the Solution and Project and go to "Tools/Generate T4 Templates" option menu. If you read the article when monodevelop 5.8 is not released yet and want to use T4 inheritance, you can use latest dev monodevelop snapshot. To do it, add the Xamarin dev repository to you repos (see the instruction), and then do the following commands from the command line:

sudo apt-get update
sudo apt-get install monodevelop-snapshot-latest
. mono-snapshot monodevelop
monodevelop

суббота, 3 января 2015 г.

Monodevelop project macros

In Visual Studio you can use macros like $(SolutionName) in *.csproj file. The full list of macros you can find in MSDN. Monodevelop also has got the macros, but the list differs from MSDN. Here is the list of the project macros I've found in Monodevelop sources. It's actual for Monodevelop 5.8, in future version the list can be changed.

  • ProjectFile
  • ProjectConfig
  • ProjectConfigName
  • ProjectConfigPlat
  • TargetPath
  • TargetFile
  • TargetName
  • TargetDir
  • TargetExt
  • ProjectName
  • ProjectDir
  • AuthorName
  • AuthorEmail
  • AuthorCopyright
  • AuthorCompany
  • AuthorTrademark
  • SolutionFile
  • SolutionName
  • SolutionDir

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

Two words about continuous integration for mono projects


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

language: c

before_install:
    #add badgerpots ppa key
    - wget http://badgerports.org/directhex.ppa.asc
    - sudo apt-key add directhex.ppa.asc
    #add bagderport repository
    - sudo apt-get install python-software-properties
    - sudo add-apt-repository "deb http://badgerports.org $(lsb_release -sc) main"
    - sudo apt-get update
    #install mono
    - sudo apt-get install mono-devel

script:
    - ./autogen.sh --prefix=/usr
    - make
    - sudo make install

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 г.

Running ASP.NET vNext on mono/linux

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.

Installing ASP.NET vNext

Run the following commands:

wget https://raw.githubusercontent.com/graemechristie/Home/KvmShellImplementation/kvmsetup.sh 
chmod a+x kvmsetup.sh
./kvmsetup.sh
source ~/.kre/kvm/kvm.sh
kvm upgrade

Running "Hello, world!" application

git clone https://github.com/davidfowl/HelloWorldVNext
cd HelloWorldVNext
git submodule update --init
kpm restore
cd src/helloworldweb
k web-firefly

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