You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2015/10/02 10:37:30 UTC

[2/2] ignite git commit: IGNITE-1570: Moved local benchmarks project from GG to Ignite.

IGNITE-1570: Moved local benchmarks project from GG to Ignite.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3852b0b6
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3852b0b6
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3852b0b6

Branch: refs/heads/ignite-1282
Commit: 3852b0b65fdcfeedd785405650f522e4b31865ff
Parents: c2a1631
Author: Pavel Tupitsyn <pt...@gridgain.com>
Authored: Fri Oct 2 11:38:11 2015 +0300
Committer: vozerov-gridgain <vo...@gridgain.com>
Committed: Fri Oct 2 11:38:11 2015 +0300

----------------------------------------------------------------------
 .../Apache.Ignite.Benchmarks.csproj             |  83 ++
 .../dotnet/Apache.Ignite.Benchmarks/App.config  |  24 +
 .../Apache.Ignite.Benchmarks/BenchmarkBase.cs   | 931 +++++++++++++++++++
 .../BenchmarkOperationDescriptor.cs             |  68 ++
 .../Apache.Ignite.Benchmarks/BenchmarkRunner.cs |  94 ++
 .../Apache.Ignite.Benchmarks/BenchmarkState.cs  | 106 +++
 .../Apache.Ignite.Benchmarks/BenchmarkUtils.cs  | 236 +++++
 .../Config/benchmark.xml                        |  57 ++
 .../Interop/ClosureBenchmark.cs                 |  66 ++
 .../Interop/GetAsyncBenchmark.cs                |  66 ++
 .../Interop/GetBenchmark.cs                     |  62 ++
 .../Interop/PlatformBenchmarkBase.cs            | 122 +++
 .../Interop/PutAsyncBenchmark.cs                |  60 ++
 .../Interop/PutBenchmark.cs                     |  58 ++
 .../Interop/TaskBenchmark.cs                    | 100 ++
 .../Interop/TxBenchmark.cs                      |  65 ++
 .../Apache.Ignite.Benchmarks/Model/Address.cs   |  80 ++
 .../Apache.Ignite.Benchmarks/Model/Company.cs   |  89 ++
 .../Model/Department.cs                         |  40 +
 .../Apache.Ignite.Benchmarks/Model/Employee.cs  | 136 +++
 .../Apache.Ignite.Benchmarks/Model/Sex.cs       |  31 +
 .../Portable/PortableWriteBenchmark.cs          |  83 ++
 .../Properties/AssemblyInfo.cs                  |  35 +
 .../Result/BenchmarkConsoleResultWriter.cs      |  68 ++
 .../Result/BenchmarkFileResultWriter.cs         | 323 +++++++
 .../Result/IBenchmarkResultWriter.cs            |  55 ++
 .../Compute/ComputeApiTest.cs                   |   3 +-
 .../Examples/PathUtil.cs                        |   2 +-
 .../IgniteManagerTest.cs                        |  11 +-
 .../Process/IgniteProcess.cs                    |   7 +-
 .../Apache.Ignite.Core.Tests/TestUtils.cs       |   3 +-
 .../Apache.Ignite.Core.csproj                   |   2 +
 .../Apache.Ignite.Core/Impl/Common/Classpath.cs | 159 ++++
 .../Impl/Common/IgniteHome.cs                   |  97 ++
 .../Apache.Ignite.Core/Impl/IgniteManager.cs    | 206 +---
 .../Properties/AssemblyInfo.cs                  |   1 +
 modules/platforms/dotnet/Apache.Ignite.sln      |  10 +
 37 files changed, 3425 insertions(+), 214 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
new file mode 100644
index 0000000..19f2724
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Apache.Ignite.Benchmarks.csproj
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{8F507DBE-56F9-437F-82D4-74C02EC44E41}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Apache.Ignite.Benchmarks</RootNamespace>
+    <AssemblyName>Apache.Ignite.Benchmarks</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject>Apache.Ignite.Benchmarks.BenchmarkRunner</StartupObject>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <PlatformTarget>x86</PlatformTarget>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <PlatformTarget>x86</PlatformTarget>
+    <OutputPath>bin\x86\Release\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <PlatformTarget>x64</PlatformTarget>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <PlatformTarget>x64</PlatformTarget>
+    <OutputPath>bin\x64\Release\</OutputPath>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BenchmarkBase.cs" />
+    <Compile Include="BenchmarkOperationDescriptor.cs" />
+    <Compile Include="BenchmarkRunner.cs" />
+    <Compile Include="BenchmarkState.cs" />
+    <Compile Include="BenchmarkUtils.cs" />
+    <Compile Include="Interop\PlatformBenchmarkBase.cs" />
+    <Compile Include="Interop\ClosureBenchmark.cs" />
+    <Compile Include="Interop\GetAsyncBenchmark.cs" />
+    <Compile Include="Interop\GetBenchmark.cs" />
+    <Compile Include="Interop\PutAsyncBenchmark.cs" />
+    <Compile Include="Interop\PutBenchmark.cs" />
+    <Compile Include="Interop\TaskBenchmark.cs" />
+    <Compile Include="Interop\TxBenchmark.cs" />
+    <Compile Include="Model\Address.cs" />
+    <Compile Include="Model\Company.cs" />
+    <Compile Include="Model\Department.cs" />
+    <Compile Include="Model\Employee.cs" />
+    <Compile Include="Model\Sex.cs" />
+    <Compile Include="Portable\PortableWriteBenchmark.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Result\BenchmarkConsoleResultWriter.cs" />
+    <Compile Include="Result\BenchmarkFileResultWriter.cs" />
+    <Compile Include="Result\IBenchmarkResultWriter.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj">
+      <Project>{4CD2F726-7E2B-46C4-A5BA-057BB82EECB6}</Project>
+      <Name>Apache.Ignite.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="Config\benchmark.xml" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/App.config
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/App.config b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/App.config
new file mode 100644
index 0000000..f21105a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/App.config
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<configuration>
+    <runtime>
+        <gcServer enabled="true"/>
+    </runtime>
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkBase.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkBase.cs
new file mode 100644
index 0000000..8921aef
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkBase.cs
@@ -0,0 +1,931 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Diagnostics;
+    using System.Linq;
+    using System.Text;
+    using System.Threading;
+    using Apache.Ignite.Benchmarks.Result;
+
+    /// <summary>
+    /// Benchmark base class.
+    /// </summary>
+    internal abstract class BenchmarkBase
+    {
+        /** Result writer type: console. */
+        private const string ResultWriterConsole = "console";
+
+        /** Result writer type: file. */
+        private const string ResultWriterFile = "file";
+
+        /** Default duration. */
+        private const int DefaultDuration = 60;
+
+        /** Default maximum errors count. */
+        private const int DefaultMaxErrors = 100;
+
+        /** Default percentile result buckets count. */
+        private const int DEfaultResultBucketCount = 10000;
+
+        /** Default percentile result bucket interval. */
+        private const int DefaultResultBucketInterval = 100;
+
+        /** Default batch size. */
+        private const int DefaultBatchSize = 1;
+
+        /** Default result wrier. */
+        private const string DefaultResultWriter = ResultWriterConsole;
+
+        /** Start flag. */
+        private volatile bool _start;
+
+        /** Stop flag. */
+        private volatile bool _stop;
+
+        /** Warmup flag. */
+        private volatile bool _warmup = true;
+
+        /** Ready threads. */
+        private int _readyThreads;
+
+        /** Finished threads. */
+        private volatile int _finishedThreads;
+
+        /** Descriptors. */
+        private volatile ICollection<BenchmarkOperationDescriptor> _descs;
+
+        /** Benchmark tasks. */
+        private volatile ICollection<BenchmarkTask> _tasks;
+
+        /** Percentile results. */
+        private volatile IDictionary<string, long[]> _percentiles;
+
+        /** Currently completed operations. */
+        private long _curOps;
+
+        /** Error count. */
+        private long _errorCount;
+
+        /** Watches to count total execution time. */
+        private readonly Stopwatch _totalWatch = new Stopwatch();
+
+        /** Warmup barrier. */
+        private Barrier _barrier;
+
+        /** Benchmark result writer. */
+        private IBenchmarkResultWriter _writer;
+
+        /// <summary>
+        /// Default constructor.
+        /// </summary>
+        protected BenchmarkBase()
+        {
+            Duration = DefaultDuration;
+            MaxErrors = DefaultMaxErrors;
+            ResultBucketCount = DEfaultResultBucketCount;
+            ResultBucketInterval = DefaultResultBucketInterval;
+            BatchSize = DefaultBatchSize;
+            ResultWriter = DefaultResultWriter;
+        }
+
+        /// <summary>
+        /// Run the benchmark.
+        /// </summary>
+        public void Run()
+        {
+            PrintDebug("Started benchmark: " + this);
+
+            ValidateArguments();
+
+            if (ResultWriter.ToLower().Equals(ResultWriterConsole))
+                _writer = new BenchmarkConsoleResultWriter();
+            else
+                _writer = new BenchmarkFileResultWriter();
+
+            OnStarted();
+
+            PrintDebug("Benchmark setup finished.");
+
+            try
+            {
+                _descs = new List<BenchmarkOperationDescriptor>();
+
+                GetDescriptors(_descs);
+
+                if (_descs.Count == 0)
+                    throw new Exception("No tasks provided for benchmark.");
+
+                // Initialize writer.
+                var opNames = new List<string>(_descs.Select(desc => desc.Name));
+
+                PrintDebug(() =>
+                {
+                    var sb = new StringBuilder("Operations: ");
+
+                    foreach (var opName in opNames)
+                        sb.Append(opName).Append(" ");
+
+                    return sb.ToString();
+                });
+
+                _writer.Initialize(this, opNames);
+
+                PrintDebug("Initialized result writer.");
+
+                // Start worker threads.
+                _tasks = new List<BenchmarkTask>(Threads);
+
+                PrintDebug("Starting worker threads: " + Threads);
+
+                for (var i = 0; i < Threads; i++)
+                {
+                    var task = new BenchmarkTask(this, _descs);
+
+                    _tasks.Add(task);
+
+                    new Thread(task.Run).Start();
+                }
+
+                PrintDebug("Waiting worker threads to start: " + Threads);
+
+                // Await for all threads to start in spin loop.
+                while (Thread.VolatileRead(ref _readyThreads) < Threads)
+                    Thread.Sleep(10);
+
+                PrintDebug("Worker threads started: " + Threads);
+
+                // Start throughput writer thread.
+                var writerThread = new Thread(new ThroughputTask(this).Run) {IsBackground = true};
+
+                writerThread.Start();
+
+                PrintDebug("Started throughput writer thread.");
+
+                // Start warmup thread if needed.
+                if (Warmup > 0)
+                {
+                    var thread = new Thread(new WarmupTask(this, Warmup).Run) {IsBackground = true};
+
+                    thread.Start();
+
+                    PrintDebug("Started warmup timeout thread: " + Warmup);
+                }
+                else
+                    _warmup = false;
+
+                _barrier = new Barrier(Threads, b =>
+                {
+                    Console.WriteLine("Warmup finished.");
+
+                    _totalWatch.Start();
+                });
+
+                // Start timeout thread if needed.
+                if (Duration > 0)
+                {
+                    if (Operations > 0)
+                        PrintDebug("Duration argument is ignored because operations number is set: " +
+                                   Operations);
+                    else
+                    {
+                        var thread = new Thread(new TimeoutTask(this, Warmup + Duration).Run) {IsBackground = true};
+
+                        thread.Start();
+
+                        PrintDebug("Started duration timeout thread: " + Duration);
+                    }
+                }
+
+                // Let workers start execution.
+                _start = true;
+
+                // Await workers completion.
+                PrintDebug("Awaiting worker threads completion.");
+
+                Monitor.Enter(this);
+
+                try
+                {
+                    while (_finishedThreads < Threads)
+                        Monitor.Wait(this);
+                }
+                finally
+                {
+                    Monitor.Exit(this);
+                }
+
+                PrintDebug("Worker threads completed.");
+            }
+            finally
+            {
+                OnFinished();
+
+                _totalWatch.Stop();
+
+                PrintDebug("Tear down invoked.");
+
+                if (PrintThroughputInfo())
+                {
+                    var avgThroughput = _totalWatch.ElapsedMilliseconds == 0
+                        ? 0
+                        : _curOps*1000/_totalWatch.ElapsedMilliseconds;
+
+                    var avgLatency = _curOps == 0
+                        ? 0
+                        : (double) _totalWatch.ElapsedMilliseconds*Threads/_curOps;
+
+                    Console.WriteLine("Finishing benchmark [name=" + GetType().Name +
+                                      ", time=" + _totalWatch.ElapsedMilliseconds +
+                                      "ms, ops=" + _curOps +
+                                      ", threads=" + Threads +
+                                      ", avgThroughput=" + avgThroughput +
+                                      ", avgLatency=" + string.Format("{0:0.000}ms", avgLatency) + ']');
+                }
+                else
+                {
+                    Console.WriteLine("Finishing benchmark [name=" + GetType().Name +
+                                      ", time=" + _totalWatch.ElapsedMilliseconds +
+                                      "ms, ops=" + Operations +
+                                      ", threads=" + Threads + ']');
+                }
+            }
+
+            _percentiles = new Dictionary<string, long[]>(_descs.Count);
+
+            foreach (var desc in _descs)
+                _percentiles[desc.Name] = new long[ResultBucketCount];
+
+            foreach (var task in _tasks)
+                task.CollectPercentiles(_percentiles);
+
+            foreach (var percentile in _percentiles)
+                _writer.WritePercentiles(percentile.Key, ResultBucketInterval, percentile.Value);
+
+            _writer.Commit();
+
+            PrintDebug("Results committed to output writer.");
+        }
+
+        /// <summary>
+        /// Consumes passed argument.
+        /// </summary>
+        /// <param name="name">Argument name.</param>
+        /// <param name="val">Value.</param>
+        /// <returns>True if argument was consumed.</returns>
+        public void Configure(string name, string val)
+        {
+            var prop = BenchmarkUtils.GetProperty(this, name);
+
+            if (prop != null)
+                BenchmarkUtils.SetProperty(this, prop, val);
+        }
+
+        /// <summary>
+        /// Start callback.
+        /// </summary>
+        protected virtual void OnStarted()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Warmup finished callback. Executed by each worker thread once.
+        /// </summary>
+        protected virtual void OnWarmupFinished()
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Batch execution started callback.
+        /// </summary>
+        /// <param name="state">State.</param>
+        protected virtual void OnBatchStarted(BenchmarkState state)
+        {
+            // No-op.
+        }
+
+        /// <summary>
+        /// Batch execution finished callback.
+        /// </summary>
+        /// <param name="state">State.</param>
+        /// <param name="duration">Duration.</param>
+        /// <returns>True if this result must be counted.</returns>
+        protected virtual bool OnBatchFinished(BenchmarkState state, long duration)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Benchmarh finished callback.
+        /// </summary>
+        protected virtual void OnFinished()
+        {
+            // No-op.
+        }
+
+        /// <returns>Flag indicating whether benchmark should print throughput information.</returns>
+        protected virtual bool PrintThroughputInfo()
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Internal arguments validation routine.
+        /// </summary>
+        /// <returns>True if base class must validate common arguments, false otherwise.</returns>
+        protected virtual bool ValidateArgumentsEx()
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Print debug to console.
+        /// </summary>
+        /// <param name="msg">Message</param>
+        protected void PrintDebug(string msg)
+        {
+            if (Debug)
+                Console.WriteLine("[DEBUG] " + Thread.CurrentThread.ManagedThreadId + ": " + msg);
+        }
+
+        /// <summary>
+        /// Print debug to console.
+        /// </summary>
+        /// <param name="msgFunc">Message delegate.</param>
+        protected void PrintDebug(Func<string> msgFunc)
+        {
+            if (Debug)
+                PrintDebug(msgFunc.Invoke());
+        }
+
+        /// <summary>
+        /// Add operation descriptors.
+        /// </summary>
+        /// <param name="descs">Collection where operation descriptors must be added.</param>
+        protected abstract void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs);
+
+        /// <summary>
+        /// Invoked when single thread is ready to actual execution.
+        /// </summary>
+        private void OnThreadReady()
+        {
+            Interlocked.Increment(ref _readyThreads);
+        }
+
+        /// <summary>
+        /// Invoked when single thread finished execution.
+        /// </summary>
+        private void OnThreadFinished()
+        {
+            Monitor.Enter(this);
+
+            try
+            {
+                _finishedThreads++;
+
+                Monitor.PulseAll(this);
+            }
+            finally
+            {
+                Monitor.Exit(this);
+            }
+
+            PrintDebug("Worker thread finished.");
+        }
+
+        /// <summary>
+        /// Validate arguments.
+        /// </summary>
+        private void ValidateArguments()
+        {
+            if (ValidateArgumentsEx())
+            {
+                if (Threads <= 0)
+                    throw new Exception("Threads must be positive: " + Threads);
+
+                if (Warmup < 0)
+                    throw new Exception("Warmup cannot be negative: " + Warmup);
+
+                if (Duration < 0)
+                    throw new Exception("Duration cannot be negative: " + Duration);
+
+                if (BatchSize <= 0)
+                    throw new Exception("BatchSize must be positive: " + BatchSize);
+
+                if (MaxErrors < 0)
+                    throw new Exception("MaxErrors cannot be negative: " + MaxErrors);
+
+                if (ResultWriter == null || !ResultWriter.ToLower().Equals(ResultWriterConsole)
+                    && !ResultWriter.ToLower().Equals(ResultWriterFile))
+                    throw new Exception("Invalid ResultWriter: " + ResultWriter);
+
+                if (ResultWriter.ToLower().Equals(ResultWriterFile) && ResultFolder == null)
+                    throw new Exception("ResultFolder must be set for file result writer.");
+
+                if (ResultBucketCount <= 0)
+                    throw new Exception("ResultBucketCount must be positive: " + ResultBucketCount);
+
+                if (ResultBucketInterval <= 0)
+                    throw new Exception("ResultBucketInterval must be positive: " + ResultBucketInterval);
+            }
+        }
+
+        /// <summary>
+        /// Get current throughput across all currenlty running threads.
+        /// </summary>
+        /// <returns>Current throughput.</returns>
+        private IDictionary<string, Tuple<long, long>> GetCurrentThroughput()
+        {
+            var total = new Dictionary<string, Tuple<long, long>>(_descs.Count);
+
+            foreach (var desc in _descs)
+                total[desc.Name] = new Tuple<long, long>(0, 0);
+
+            foreach (var task in _tasks)
+                task.CollectThroughput(total);
+
+            return total;
+        }
+
+        /** <inheritDoc /> */
+        public override string ToString()
+        {
+            var sb = new StringBuilder(GetType().Name).Append('[');
+
+            var first = true;
+
+            var props = BenchmarkUtils.GetProperties(this);
+
+            foreach (var prop in props)
+            {
+                if (first)
+                    first = false;
+                else
+                    sb.Append(", ");
+
+                sb.Append(prop.Name).Append('=').Append(prop.GetValue(this, null));
+            }
+
+            sb.Append(']');
+
+            return sb.ToString();
+        }
+
+        /* COMMON PUBLIC PROPERTIES. */
+
+        /// <summary>
+        /// Amount of worker threads.
+        /// </summary>
+        public int Threads { get; set; }
+
+        /// <summary>
+        /// Warmup duration in secnods.
+        /// </summary>
+        public int Warmup { get; set; }
+
+        /// <summary>
+        /// Duration in seconds.
+        /// </summary>
+        public int Duration { get; set; }
+
+        /// <summary>
+        /// Maximum amount of operations to perform.
+        /// </summary>
+        public int Operations { get; set; }
+
+        /// <summary>
+        /// Single measurement batch size.
+        /// </summary>
+        public int BatchSize { get; set; }
+
+        /// <summary>
+        /// Maximum amount of errors before benchmark exits.
+        /// </summary>
+        public int MaxErrors { get; set; }
+
+        /// <summary>
+        /// Debug flag.
+        /// </summary>
+        public bool Debug { get; set; }
+
+        /// <summary>
+        /// Result writer type.
+        /// </summary>
+        public string ResultWriter { get; set; }
+
+        /// <summary>
+        /// Result output folder.
+        /// </summary>
+        public string ResultFolder { get; set; }
+
+        /// <summary>
+        /// Percentile result buckets count.
+        /// </summary>
+        public int ResultBucketCount { get; set; }
+
+        /// <summary>
+        /// Percnetile result bucket interval in microseconds.
+        /// </summary>
+        public long ResultBucketInterval { get; set; }
+
+        /* INNER CLASSES. */
+
+        /// <summary>
+        /// Benchmark worker task.
+        /// </summary>
+        private class BenchmarkTask
+        {
+            /** Benchmark. */
+            private readonly BenchmarkBase _benchmark;
+
+            /** Descriptors. */
+            private readonly BenchmarkOperationDescriptor[] _descs;
+
+            /** Results. */
+            private readonly IDictionary<string, Result> _results;
+
+            /** Stop watch. */
+            private readonly Stopwatch _watch = new Stopwatch();
+
+            /** Benchmark state. */
+            private readonly BenchmarkState _state;
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="benchmark">Benchmark.</param>
+            /// <param name="descList">Descriptor list.</param>
+            public BenchmarkTask(BenchmarkBase benchmark,
+                ICollection<BenchmarkOperationDescriptor> descList)
+            {
+                _benchmark = benchmark;
+
+                _state = new BenchmarkState();
+
+                _results = new Dictionary<string, Result>(descList.Count);
+
+                var totalWeight = 0;
+
+                var ticksPerSlot = benchmark.ResultBucketInterval*Stopwatch.Frequency/1000000;
+
+                if (ticksPerSlot == 0)
+                    throw new Exception("Too low bucket interval: " + benchmark.ResultBucketInterval);
+
+                foreach (var desc in descList)
+                {
+                    _results[desc.Name] = new Result(benchmark.ResultBucketCount, ticksPerSlot);
+
+                    totalWeight += desc.Weight;
+                }
+
+                _descs = new BenchmarkOperationDescriptor[totalWeight];
+
+                var idx = 0;
+
+                foreach (var desc in descList)
+                {
+                    for (var i = 0; i < desc.Weight; i++)
+                        _descs[idx++] = desc;
+                }
+            }
+
+            /// <summary>
+            /// Task routine.
+            /// </summary>
+            public void Run()
+            {
+                try
+                {
+                    _benchmark.OnThreadReady();
+
+                    _benchmark.PrintDebug("Worker thread ready.");
+
+                    while (!_benchmark._start)
+                        Thread.Sleep(10);
+
+                    _benchmark.PrintDebug("Worker thread started benchmark execution.");
+
+                    var warmupIteration = true;
+
+                    long maxDur = 0;
+
+                    long maxOps = _benchmark.Operations;
+
+                    while (!_benchmark._stop)
+                    {
+                        if (warmupIteration && !_benchmark._warmup)
+                        {
+                            warmupIteration = false;
+
+                            _benchmark.OnWarmupFinished();
+
+                            _state.StopWarmup();
+
+                            _benchmark._barrier.SignalAndWait();
+                        }
+
+                        if (!warmupIteration)
+                        {
+                            if (maxOps > 0 && Interlocked.Read(ref _benchmark._curOps) > maxOps)
+                                break;
+                        }
+
+                        var desc = _descs.Length == 1
+                            ? _descs[0]
+                            : _descs[BenchmarkUtils.GetRandomInt(_descs.Length)];
+
+                        var res = true;
+
+                        _benchmark.OnBatchStarted(_state);
+
+                        _watch.Start();
+
+                        try
+                        {
+                            for (var i = 0; i < _benchmark.BatchSize; i++)
+                            {
+                                desc.Operation(_state);
+
+                                _state.IncrementCounter();
+                            }
+
+                            if (!warmupIteration)
+                                Interlocked.Add(ref _benchmark._curOps, _benchmark.BatchSize);
+                        }
+                        catch (Exception e)
+                        {
+                            Console.WriteLine("Exception: " + e);
+
+                            res = false;
+
+                            if (_benchmark.MaxErrors > 0 &&
+                                Interlocked.Increment(ref _benchmark._errorCount) > _benchmark.MaxErrors)
+                            {
+                                lock (_benchmark)
+                                {
+                                    Console.WriteLine("Benchmark is stopped due to too much errors: " +
+                                                      _benchmark.MaxErrors);
+
+                                    Environment.Exit(-1);
+                                }
+                            }
+                        }
+                        finally
+                        {
+                            _watch.Stop();
+
+                            var curDur = _watch.ElapsedTicks;
+
+                            if (res)
+                                res = _benchmark.OnBatchFinished(_state, curDur);
+
+                            _state.Reset();
+
+                            if (curDur > maxDur)
+                            {
+                                maxDur = curDur;
+
+                                _benchmark.PrintDebug("The longest execution [warmup=" + warmupIteration +
+                                                     ", dur(nsec)=" + maxDur*1000000000/Stopwatch.Frequency + ']');
+                            }
+
+                            _watch.Reset();
+
+                            if (!warmupIteration && res)
+                                _results[desc.Name].Add(curDur);
+                        }
+                    }
+                }
+                finally
+                {
+                    _benchmark.PrintDebug("Worker thread stopped.");
+
+                    _benchmark.OnThreadFinished();
+                }
+            }
+
+            /// <summary>
+            /// Collect throughput for the current task.
+            /// </summary>
+            /// <param name="total">Total result.</param>
+            public void CollectThroughput(IDictionary<string, Tuple<long, long>> total)
+            {
+                foreach (var result in _results)
+                {
+                    var old = total[result.Key];
+
+                    total[result.Key] = new Tuple<long, long>(old.Item1 + result.Value.Duration,
+                        old.Item2 + result.Value.OpCount);
+                }
+            }
+
+            /// <summary>
+            /// Collect percnetiles for the current task.
+            /// </summary>
+            /// <param name="total"></param>
+            public void CollectPercentiles(IDictionary<string, long[]> total)
+            {
+                foreach (var result in _results)
+                {
+                    var arr = total[result.Key];
+
+                    for (var i = 0; i < arr.Length; i++)
+                        arr[i] += result.Value.Slots[i];
+                }
+            }
+        }
+
+        /// <summary>
+        /// Timeout task to stop execution.
+        /// </summary>
+        private class TimeoutTask
+        {
+            /** Benchmark. */
+            private readonly BenchmarkBase _benchmark;
+
+            /** Duration. */
+            private readonly long _dur;
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="benchmark">Benchmark.</param>
+            /// <param name="dur">Duration.</param>
+            public TimeoutTask(BenchmarkBase benchmark, long dur)
+            {
+                _benchmark = benchmark;
+                _dur = dur;
+            }
+
+            /// <summary>
+            /// Task routine.
+            /// </summary>
+            public void Run()
+            {
+                try
+                {
+                    Thread.Sleep(TimeSpan.FromSeconds(_dur));
+                }
+                finally
+                {
+                    _benchmark._stop = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Warmup task to clear warmup flag.
+        /// </summary>
+        private class WarmupTask
+        {
+            /** Benchmark. */
+            private readonly BenchmarkBase _benchmark;
+
+            /** Duration. */
+            private readonly long _dur;
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="benchmark">Benchmark.</param>
+            /// <param name="dur">Duration.</param>
+            public WarmupTask(BenchmarkBase benchmark, long dur)
+            {
+                _benchmark = benchmark;
+                _dur = dur;
+            }
+
+            /// <summary>
+            /// Task routine.
+            /// </summary>
+            public void Run()
+            {
+                try
+                {
+                    Thread.Sleep(TimeSpan.FromSeconds(_dur));
+                }
+                finally
+                {
+                    _benchmark._warmup = false;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Throughput write task.
+        /// </summary>
+        private class ThroughputTask
+        {
+            /** Benchmark. */
+            private readonly BenchmarkBase _benchmark;
+
+            /** Last recorded result. */
+            private IDictionary<string, Tuple<long, long>> _lastResults;
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="benchmark">Benchmark.</param>
+            public ThroughputTask(BenchmarkBase benchmark)
+            {
+                _benchmark = benchmark;
+            }
+
+            public void Run()
+            {
+                while (!_benchmark._stop)
+                {
+                    Thread.Sleep(1000);
+
+                    if (_benchmark._start && !_benchmark._warmup)
+                    {
+                        var results = _benchmark.GetCurrentThroughput();
+
+                        if (_benchmark._finishedThreads > 0)
+                            return; // Threads are stopping, do not collect any more.
+
+                        foreach (var pair in results)
+                        {
+                            Tuple<long, long> old;
+
+                            if (_lastResults != null && _lastResults.TryGetValue(pair.Key, out old))
+                                _benchmark._writer.WriteThroughput(pair.Key, pair.Value.Item1 - old.Item1,
+                                    pair.Value.Item2 - old.Item2);
+                            else
+                                _benchmark._writer.WriteThroughput(pair.Key, pair.Value.Item1,
+                                    pair.Value.Item2);
+                        }
+
+                        _lastResults = results;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Benchmark result. Specific for each operation.
+        /// </summary>
+        private class Result
+        {
+            /** Slots. */
+            public readonly long[] Slots;
+
+            /** Slot duration in ticks. */
+            private readonly long _slotDuration;
+
+            /** Total operations count. */
+            public long OpCount;
+
+            /** Total duration. */
+            public long Duration;
+
+            /// <summary>
+            /// Constructor.
+            /// </summary>
+            /// <param name="slotCnt">Slot count.</param>
+            /// <param name="slotDuration">Slot duration in ticks.</param>
+            public Result(long slotCnt, long slotDuration)
+            {
+                Slots = new long[slotCnt];
+
+                _slotDuration = slotDuration;
+            }
+
+            /// <summary>
+            /// Add result.
+            /// </summary>
+            /// <param name="curDur">Current duration in ticks.</param>
+            public void Add(long curDur)
+            {
+                var idx = (int) (curDur/_slotDuration);
+
+                if (idx >= Slots.Length)
+                    idx = Slots.Length - 1;
+
+                Slots[idx] += 1;
+
+                OpCount++;
+                Duration += curDur;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkOperationDescriptor.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkOperationDescriptor.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkOperationDescriptor.cs
new file mode 100644
index 0000000..1233b4c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkOperationDescriptor.cs
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks
+{
+    using System;
+
+    /// <summary>
+    /// Benchmark operation descriptor.
+    /// </summary>
+    internal class BenchmarkOperationDescriptor
+    {
+        /// <summary>
+        /// Create new operation descriptor.
+        /// </summary>
+        /// <param name="name">Name.</param>
+        /// <param name="operation">Operation.</param>
+        /// <param name="weight">Weight.</param>
+        /// <returns>Operation descriptor.</returns>
+        public static BenchmarkOperationDescriptor Create(string name, Action<BenchmarkState> operation, int weight)
+        {
+            if (string.IsNullOrEmpty(name))
+                throw new Exception("Operation name cannot be null or empty.");
+
+            if (operation == null)
+                throw new Exception("Operation cannot be null: " + name);
+
+            if (weight <= 0)
+                throw new Exception("Operation weight cannot be negative [name=" + name + ", weight=" + weight + ']');
+
+            return new BenchmarkOperationDescriptor
+            {
+                Name = name,
+                Operation = operation,
+                Weight = weight
+            };
+        }
+
+        /// <summary>
+        /// Unique operation name.
+        /// </summary>
+        public string Name { get; private set; }
+
+        /// <summary>
+        /// Operation delegate.
+        /// </summary>
+        public Action<BenchmarkState> Operation { get; private set; }
+
+        /// <summary>
+        /// Weight.
+        /// </summary>
+        public int Weight { get; private set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkRunner.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkRunner.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkRunner.cs
new file mode 100644
index 0000000..506106e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkRunner.cs
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks
+{
+    using System;
+    using System.Diagnostics;
+    using System.Text;
+    using Apache.Ignite.Benchmarks.Portable;
+
+    /// <summary>
+    /// Benchmark runner.
+    /// </summary>
+    internal class BenchmarkRunner
+    {
+        /// <summary>
+        /// Entry point.
+        /// </summary>
+        /// <param name="args">Arguments.</param>
+        // ReSharper disable once RedundantAssignment
+        public static void Main(string[] args)
+        {
+            args = new[] { 
+                typeof(PortableWriteBenchmark).FullName,
+                "-ConfigPath", @"modules\platforms\dotnet\Apache.Ignite.Benchmarks\Config\benchmark.xml",
+                "-Threads", "1",
+                "-Warmup", "0",
+                "-Duration", "60",
+                "-BatchSize", "1000"
+            };
+
+            var gcSrv = System.Runtime.GCSettings.IsServerGC;
+
+            Console.WriteLine("GC Server: " + gcSrv);
+
+            if (!gcSrv)
+                Console.WriteLine("WARNING! GC server mode is disabled. This could yield in bad preformance.");
+
+            Console.WriteLine("DotNet benchmark process started: " + Process.GetCurrentProcess().Id);
+
+            var argsStr = new StringBuilder();
+
+            foreach (var arg in args)
+                argsStr.Append(arg + " ");
+            
+            if (args.Length < 1)
+                throw new Exception("Not enough arguments: " + argsStr);
+            
+            Console.WriteLine("Arguments: " + argsStr);
+
+            var benchmarkType = Type.GetType(args[0]);
+
+            if (benchmarkType == null)
+                throw new InvalidOperationException("Could not find benchmark type: " + args[0]);
+
+            var benchmark = (BenchmarkBase)Activator.CreateInstance(benchmarkType);
+
+            for (var i = 1; i < args.Length; i++)
+            {
+                var arg = args[i];
+
+                if (arg.StartsWith("-"))
+                    arg = arg.Substring(1);
+                else
+                    continue;
+
+                var prop = BenchmarkUtils.GetProperty(benchmark, arg);
+
+                if (prop != null)
+                    benchmark.Configure(prop.Name, prop.PropertyType == typeof(bool) ? bool.TrueString : args[++i]);
+            }
+
+            benchmark.Run();
+
+#if (DEBUG)
+            Console.ReadLine();
+#endif
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkState.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkState.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkState.cs
new file mode 100644
index 0000000..cc05c15
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkState.cs
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks
+{
+    using System;
+
+    /// <summary>
+    /// Benchmark state.
+    /// </summary>
+    internal class BenchmarkState
+    {
+        /** Warmup flag. */
+        private bool _warmup = true;
+
+        /** Counter within the batch. */
+        private int _counter;
+
+        /** Array of attached objects. */
+        private object[] _attachedObjects;
+
+        /// <summary>
+        /// Reset state.
+        /// </summary>
+        public void Reset()
+        {
+            _counter = 0;
+            _attachedObjects = null;
+        }
+
+        /// <summary>
+        /// Clear warmup flag.
+        /// </summary>
+        public void StopWarmup()
+        {
+            _warmup = false;
+        }
+
+        /// <summary>
+        /// Increment counter.
+        /// </summary>
+        public void IncrementCounter()
+        {
+            _counter++;
+        }
+
+        /// <summary>
+        /// Warmup flag.
+        /// </summary>
+        public bool Warmup
+        {
+            get { return _warmup; }
+        }
+
+        /// <summary>
+        /// Counter within the batch.
+        /// </summary>
+        public int Counter
+        {
+            get { return _counter; }
+        }
+
+        /// <summary>
+        /// Get/set attached object.
+        /// </summary>
+        /// <param name="idx">Index.</param>
+        /// <returns>Attahced object.</returns>
+        public object this[int idx]
+        {
+            get
+            {
+                return (_attachedObjects == null || idx >= _attachedObjects.Length) ? null : _attachedObjects[idx];
+            }
+
+            set
+            {
+                if (_attachedObjects == null)
+                    _attachedObjects = new object[idx + 1];
+                else if (idx >= _attachedObjects.Length)
+                {
+                    var arr0 = new object[idx + 1];
+
+                    Array.Copy(_attachedObjects, 0, arr0, 0, arr0.Length);
+
+                    _attachedObjects = arr0;
+                }
+
+                _attachedObjects[idx] = value;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkUtils.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkUtils.cs
new file mode 100644
index 0000000..e2543af
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/BenchmarkUtils.cs
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks
+{
+    using System;
+    using System.Linq;
+    using System.Reflection;
+    using System.Text;
+    using System.Threading;
+    using Apache.Ignite.Benchmarks.Model;
+
+    /// <summary>
+    /// Utility methods for benchmarks.
+    /// </summary>
+    internal static class BenchmarkUtils
+    {
+        /** Property binding flags. */
+        private static readonly BindingFlags PropFlags = BindingFlags.Instance | BindingFlags.Public;
+
+        /** Thread-local random. */
+        private static readonly ThreadLocal<Random> Rand;
+
+        /** Cached ANSI chcracters. */
+        private static readonly char[] Chars;
+
+        /** Seed to randoms. */
+        private static int _seedCtr;
+
+        /// <summary>
+        /// Static initializer.
+        /// </summary>
+        static BenchmarkUtils()
+        {
+            Rand = new ThreadLocal<Random>(() =>
+            {
+                var seed = Interlocked.Add(ref _seedCtr, 100);
+
+                return new Random(seed);
+            });
+
+            Chars = new char[10 + 26 + 26];
+
+            var pos = 0;
+
+            for (var i = '0'; i < '0' + 10; i++)
+                Chars[pos++] = i;
+
+            for (var i = 'A'; i < 'A' + 26; i++)
+                Chars[pos++] = i;
+
+            for (var i = 'a'; i < 'a' + 26; i++)
+                Chars[pos++] = i;
+        }
+
+        /// <summary>
+        /// Generate random integer.
+        /// </summary>
+        /// <param name="max">Maximum value (exclusive).</param>
+        /// <returns></returns>
+        public static int GetRandomInt(int max)
+        {
+            return GetRandomInt(0, max);
+        }
+
+        /// <summary>
+        /// Generate random integer.
+        /// </summary>
+        /// <param name="min">Minimum value (inclusive).</param>
+        /// <param name="max">Maximum value (exclusive).</param>
+        /// <returns></returns>
+        public static int GetRandomInt(int min, int max)
+        {
+            return Rand.Value.Next(min, max);
+        }
+
+        /// <summary>
+        /// Generate random string.
+        /// </summary>
+        /// <param name="len">Length.</param>
+        /// <returns>String.</returns>
+        public static string GetRandomString(int len)
+        {
+            var rand = Rand.Value;
+
+            var sb = new StringBuilder();
+
+            for (var i = 0; i < len; i++)
+                sb.Append(Chars[rand.Next(Chars.Length)]);
+
+            return sb.ToString();
+        }
+
+        /// <summary>
+        /// Generate random address.
+        /// </summary>
+        /// <returns>Address.</returns>
+        public static Address GetRandomAddress()
+        {
+            return new Address(
+                GetRandomString(15),
+                GetRandomString(20),
+                GetRandomInt(1, 500),
+                GetRandomInt(1, 35)
+            );
+        }
+
+        /// <summary>
+        /// Generate random company.
+        /// </summary>
+        /// <returns>Company.</returns>
+        public static Company GetRandomCompany()
+        {
+            return new Company(
+                GetRandomInt(0, 100),
+                GetRandomString(20),
+                GetRandomInt(100, 3000),
+                GetRandomAddress(),
+                GetRandomString(20)
+            );
+        }
+
+        /// <summary>
+        /// Generate random employee.
+        /// </summary>
+        /// <param name="payload">Payload size.</param>
+        /// <returns>Employee.</returns>
+        public static Employee GetRandomEmployee(int payload)
+        {
+            return new Employee(
+                GetRandomInt(0, 1000),
+                GetRandomString(15),
+                GetRandomInt(0, 1000),
+                GetRandomInt(18, 60),
+                (Sex)GetRandomInt(0, 1),
+                GetRandomInt(10000, 30000),
+                GetRandomAddress(),
+                (Department)GetRandomInt(0, 5),
+                payload
+            );
+        }
+
+        /// <summary>
+        /// List all properties present in the given object.
+        /// </summary>
+        /// <param name="obj">Object.</param>
+        /// <returns>Properties.</returns>
+        public static PropertyInfo[] GetProperties(object obj)
+        {
+            return obj.GetType().GetProperties(PropFlags);
+        }
+
+        /// <summary>
+        /// Find property with the given name in the object.
+        /// </summary>
+        /// <param name="obj">Object.</param>
+        /// <param name="name">Name.</param>
+        /// <returns>Property.</returns>
+        public static PropertyInfo GetProperty(object obj, string name)
+        {
+            return GetProperties(obj)
+                .FirstOrDefault(prop => prop.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
+        }
+
+        /// <summary>
+        /// Set property on the given object.
+        /// </summary>
+        /// <param name="obj">Object.</param>
+        /// <param name="prop">Property.</param>
+        /// <param name="val">Value.</param>
+        public static void SetProperty(object obj, PropertyInfo prop, string val)
+        {
+            object val0;
+
+            var propType = prop.PropertyType;
+
+            if (propType == typeof(int))
+            {
+                try
+                {
+                    val0 = int.Parse(val);
+                }
+                catch (Exception e)
+                {
+                    throw new Exception("Failed to parse property value [property=" + prop.Name +
+                        ", value=" + val + ']', e);
+                }
+            }
+            else if (propType == typeof(long))
+            {
+                try
+                {
+                    val0 = long.Parse(val);
+                }
+                catch (Exception e)
+                {
+                    throw new Exception("Failed to parse property value [property=" + prop.Name +
+                        ", value=" + val + ']', e);
+                }
+            }
+            else if (propType == typeof(bool))
+            {
+                try
+                {
+                    val0 = bool.Parse(val);
+                }
+                catch (Exception e)
+                {
+                    throw new Exception("Failed to parse property value [property=" + prop.Name +
+                        ", value=" + val + ']', e);
+                }
+            }
+            else if (propType == typeof(string))
+                val0 = val;                            
+            else
+                throw new Exception("Unsupported property type [property=" + prop.Name +
+                    ", type=" + propType.Name + ']');
+
+            prop.SetValue(obj, val0, null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Config/benchmark.xml
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Config/benchmark.xml b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Config/benchmark.xml
new file mode 100644
index 0000000..8bda9e8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Config/benchmark.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="localHost" value="127.0.0.1"/>
+
+        <property name="metricsLogFrequency" value="0"/>
+
+        <property name="cacheConfiguration">
+            <list>
+                <bean id="cache" class="org.apache.ignite.configuration.CacheConfiguration">
+                    <property name="name" value="cache"/>
+                    <property name="cacheMode" value="PARTITIONED"/>
+                    <property name="writeSynchronizationMode" value="FULL_SYNC"/>
+                    <property name="rebalanceMode" value="SYNC"/>
+                    <property name="backups" value="0"/>
+                    <property name="atomicityMode" value="ATOMIC"/>
+                </bean>
+            </list>
+        </property>
+
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="ipFinder">
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+                        <property name="addresses">
+                            <list>
+                                <value>127.0.0.1:47500</value>
+                            </list>
+                        </property>
+                    </bean>
+                </property>
+            </bean>
+        </property>
+    </bean>
+</beans>

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/ClosureBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/ClosureBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/ClosureBenchmark.cs
new file mode 100644
index 0000000..a6eb244
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/ClosureBenchmark.cs
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Compute;
+
+    /// <summary>
+    /// Compute func benchmark.
+    /// </summary>
+    internal class ClosureBenchmark : PlatformBenchmarkBase
+    {
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("ExecuteClosureTask", ExecuteClosureTask, 1));
+        }
+        
+        /// <summary>
+        /// Executes closure.
+        /// </summary>
+        private void ExecuteClosureTask(BenchmarkState state)
+        {
+            Node.GetCompute().Call(new MyClosure("zzzz"));
+        }
+    }
+
+    /// <summary>
+    /// Compute func.
+    /// </summary>
+    internal class MyClosure : IComputeFunc<int>
+    {
+        /** */
+        private readonly string _s;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MyClosure"/> class.
+        /// </summary>
+        /// <param name="s">The s.</param>
+        public MyClosure(string s)
+        {
+            _s = s;
+        }
+
+        /** <inheritdoc /> */
+        public int Invoke()
+        {
+            return _s.Length;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetAsyncBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetAsyncBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetAsyncBenchmark.cs
new file mode 100644
index 0000000..d7e0c41
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetAsyncBenchmark.cs
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Benchmarks.Model;
+    using Apache.Ignite.Core.Cache;
+
+    /// <summary>
+    /// Async Get benchmark.
+    /// </summary>
+    internal class GetAsyncBenchmark : PlatformBenchmarkBase
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /** Native cache wrapper. */
+        private ICache<int, Employee> _cache;
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            base.OnStarted();
+
+            _cache = Node.GetCache<int, Employee>(CacheName);
+
+            for (int i = 0; i < Emps.Length; i++)
+                _cache.Put(i, Emps[i]);
+
+            _cache = _cache.WithAsync();
+        }
+
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("GetAsync", GetAsync, 1));
+        }
+        
+        /// <summary>
+        /// Cache getAsync.
+        /// </summary>
+        private void GetAsync(BenchmarkState state)
+        {
+            int idx = BenchmarkUtils.GetRandomInt(Dataset);
+
+            _cache.Get(idx);
+
+            _cache.GetFuture<Employee>().ToTask().Wait();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetBenchmark.cs
new file mode 100644
index 0000000..5d69669
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/GetBenchmark.cs
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Benchmarks.Model;
+    using Apache.Ignite.Core.Cache;
+
+    /// <summary>
+    /// Cache Get benchmark.
+    /// </summary>
+    internal class GetBenchmark : PlatformBenchmarkBase
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /** Native cache wrapper. */
+        private ICache<int, Employee> _cache;
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            base.OnStarted();
+
+            _cache = Node.GetCache<int, Employee>(CacheName);
+
+            for (int i = 0; i < Emps.Length; i++)
+                _cache.Put(i, Emps[i]);
+        }
+
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("Get", Get, 1));
+        }
+        
+        /// <summary>
+        /// Cache get.
+        /// </summary>
+        private void Get(BenchmarkState state)
+        {
+            var idx = BenchmarkUtils.GetRandomInt(Dataset);
+
+            _cache.Get(idx);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PlatformBenchmarkBase.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PlatformBenchmarkBase.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PlatformBenchmarkBase.cs
new file mode 100644
index 0000000..87fb2e9
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PlatformBenchmarkBase.cs
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Benchmarks.Model;
+    using Apache.Ignite.Core;
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Base class for all platform benchmarks.
+    /// </summary>
+    internal abstract class PlatformBenchmarkBase : BenchmarkBase
+    {
+        /** Default dataset. */
+        private const int DfltDataset = 100000;
+
+        /** Default payload. */
+        private const int DfltPayload = 128;
+
+        /** Native node. */
+        protected IIgnite Node;
+
+        /** Employees. */
+        protected Employee[] Emps;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        protected PlatformBenchmarkBase()
+        {
+            Dataset = DfltDataset;
+            Payload = DfltPayload;
+        }
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            Emps = new Employee[Dataset];
+
+            for (var i = 0; i < Emps.Length; i++)
+                Emps[i] = BenchmarkUtils.GetRandomEmployee(Payload);
+
+            var cfg = new IgniteConfiguration
+            {
+                PortableConfiguration = GetPortableConfiguration(),
+                JvmOptions = new List<string>
+                {
+                    "-Xms2g",
+                    "-Xmx2g",
+                    "-DIGNITE_QUIET=false",
+                    "-DIGNITE_NO_SHUTDOWN_HOOK=true"
+                },
+                JvmClasspath = Classpath ?? Core.Impl.Common.Classpath.CreateClasspath(),
+                JvmDllPath = DllPath,
+                SpringConfigUrl = ConfigPath
+            };
+
+            Node = Ignition.Start(cfg);
+        }
+
+        /// <summary>
+        /// Get portable configuration.
+        /// </summary>
+        /// <returns>Portable configuration.</returns>
+        private static PortableConfiguration GetPortableConfiguration()
+        {
+            return new PortableConfiguration
+            {
+                TypeConfigurations = new List<PortableTypeConfiguration>
+                {
+                    new PortableTypeConfiguration(typeof (Address)),
+                    new PortableTypeConfiguration(typeof (Company)),
+                    new PortableTypeConfiguration(typeof (Employee)),
+                    new PortableTypeConfiguration(typeof (MyClosure)),
+                    new PortableTypeConfiguration(typeof (MyJob))
+                },
+                DefaultMetadataEnabled = false
+            };
+        }
+
+        /// <summary>
+        /// Classpath.
+        /// </summary>
+        public string Classpath { get; set; }
+
+        /// <summary>
+        /// Path to JVM.DLL.
+        /// </summary>
+        public string DllPath { get; set; }
+
+        /// <summary>
+        /// Path to XML configuration.
+        /// </summary>
+        public string ConfigPath { get; set; }
+
+        /// <summary>
+        /// Data set size.
+        /// </summary>
+        public int Dataset { get; set; }
+
+        /// <summary>
+        /// Payload.
+        /// </summary>
+        public int Payload { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutAsyncBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutAsyncBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutAsyncBenchmark.cs
new file mode 100644
index 0000000..475a0c6
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutAsyncBenchmark.cs
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Cache;
+
+    /// <summary>
+    /// Async Put benchmark.
+    /// </summary>
+    internal class PutAsyncBenchmark : PlatformBenchmarkBase
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /** Native cache wrapper. */
+        private ICache<object, object> _cache;
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            base.OnStarted();
+
+            _cache = Node.GetCache<object, object>(CacheName).WithAsync();
+        }
+
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("PutAsync", PutAsync, 1));
+        }
+        
+        /// <summary>
+        /// Cache putAsync.
+        /// </summary>
+        private void PutAsync(BenchmarkState state)
+        {
+            int idx = BenchmarkUtils.GetRandomInt(Dataset);
+
+            _cache.Put(idx, Emps[idx]);
+
+            _cache.GetFuture<object>().Get();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutBenchmark.cs
new file mode 100644
index 0000000..d0c6f4b
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/PutBenchmark.cs
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Cache;
+
+    /// <summary>
+    /// Cache put benchmark.
+    /// </summary>
+    internal class PutBenchmark : PlatformBenchmarkBase
+    {
+        /** Cache name. */
+        private const string CacheName = "cache";
+
+        /** Native cache wrapper. */
+        private ICache<object, object> _cache;
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            base.OnStarted();
+
+            _cache = Node.GetCache<object, object>(CacheName);
+        }
+
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("Put", Put, 1));
+        }
+        
+        /// <summary>
+        /// Cache put.
+        /// </summary>
+        private void Put(BenchmarkState state)
+        {
+            int idx = BenchmarkUtils.GetRandomInt(Dataset);
+
+            _cache.Put(idx, Emps[idx]);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TaskBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TaskBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TaskBenchmark.cs
new file mode 100644
index 0000000..6a2585c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TaskBenchmark.cs
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Cluster;
+    using Apache.Ignite.Core.Compute;
+
+    /// <summary>
+    /// Compute task benchmark.
+    /// </summary>
+    internal class TaskBenchmark : PlatformBenchmarkBase
+    {
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("ExecuteEmptyTask", ExecuteEmptyTask, 1));
+        }
+
+        /// <summary>
+        /// Executes task.
+        /// </summary>
+        private void ExecuteEmptyTask(BenchmarkState state)
+        {
+            Node.GetCompute().Execute(new MyEmptyTask(), "zzzz");
+        }
+    }
+
+    /// <summary>
+    /// Compute task.
+    /// </summary>
+    internal class MyEmptyTask : IComputeTask<object, object, object>
+    {
+        /** <inheritDoc /> */
+        public IDictionary<IComputeJob<object>, IClusterNode> Map(IList<IClusterNode> subgrid, object arg)
+        {
+            return new Dictionary<IComputeJob<object>, IClusterNode>
+            {
+                {new MyJob((string) arg), subgrid[0]}
+            };
+        }
+
+        /** <inheritDoc /> */
+        public ComputeJobResultPolicy Result(IComputeJobResult<object> res, IList<IComputeJobResult<object>> rcvd)
+        {
+            return ComputeJobResultPolicy.Wait;
+        }
+
+        /** <inheritDoc /> */
+        public object Reduce(IList<IComputeJobResult<object>> results)
+        {
+            return results.Count == 0 ? null : results[0];
+        }
+    }
+
+    /// <summary>
+    /// Compute job.
+    /// </summary>
+    internal class MyJob : IComputeJob<object>
+    {
+        /** */
+        private readonly string _s;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MyJob"/> class.
+        /// </summary>
+        /// <param name="s">The s.</param>
+        public MyJob(string s)
+        {
+            _s = s;
+        }
+
+        /** <inheritDoc /> */
+        public object Execute()
+        {
+            return _s.Length;
+        }
+
+        /** <inheritDoc /> */
+        public void Cancel()
+        {
+            // No-op.
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TxBenchmark.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TxBenchmark.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TxBenchmark.cs
new file mode 100644
index 0000000..3666d45
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Interop/TxBenchmark.cs
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Interop
+{
+    using System.Collections.Generic;
+    using Apache.Ignite.Core.Cache;
+    using Apache.Ignite.Core.Transactions;
+
+    /// <summary>
+    /// Transactions benchmark.
+    /// </summary>
+    internal class TxBenchmark : PlatformBenchmarkBase
+    {
+        /** Cache name. */
+        private const string CacheName = "cache_tx";
+
+        /** Native cache wrapper. */
+        private ICache<object, object> _cache;
+
+        /** <inheritDoc /> */
+        protected override void OnStarted()
+        {
+            base.OnStarted();
+
+            _cache = Node.GetCache<object, object>(CacheName);
+        }
+
+        /** <inheritDoc /> */
+        protected override void GetDescriptors(ICollection<BenchmarkOperationDescriptor> descs)
+        {
+            descs.Add(BenchmarkOperationDescriptor.Create("PutTx", PutTx, 1));
+        }
+
+        /// <summary>
+        /// Cache put.
+        /// </summary>
+        private void PutTx(BenchmarkState state)
+        {
+            int idx = BenchmarkUtils.GetRandomInt(Dataset);
+
+            using (var tx = Node.GetTransactions().TxStart(TransactionConcurrency.Pessimistic,
+                TransactionIsolation.RepeatableRead))
+            {
+                _cache.Put(idx, Emps[idx]);
+
+                tx.Commit();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3852b0b6/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/Address.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/Address.cs b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/Address.cs
new file mode 100644
index 0000000..871814c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Model/Address.cs
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Benchmarks.Model
+{
+    using Apache.Ignite.Core.Portable;
+
+    /// <summary>
+    /// Address.
+    /// </summary>
+    internal class Address : IPortableMarshalAware
+    {
+        /// <summary>
+        /// City.
+        /// </summary>
+        public string City { get; set; }
+        
+        /// <summary>
+        /// Street.
+        /// </summary>
+        public string Street { get; set; }
+        
+        /// <summary>
+        /// Street number.
+        /// </summary>
+        public int StreetNumber { get; set; }
+
+        /// <summary>
+        /// Flat number.
+        /// </summary>
+        public int FlatNumber { get; set; }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="city">City.</param>
+        /// <param name="street">Street.</param>
+        /// <param name="streetNum">Street number.</param>
+        /// <param name="flatNum">Flat number.</param>
+        public Address(string city, string street, int streetNum, int flatNum)
+        {
+            City = city;
+            Street = street;
+            StreetNumber = streetNum;
+            FlatNumber = flatNum;
+        }
+
+        /** <inheritDoc /> */
+        public void WritePortable(IPortableWriter writer)
+        {
+            writer.WriteInt("streetNum", StreetNumber);
+            writer.WriteInt("flatNum", FlatNumber);
+            writer.WriteString("city", City);
+            writer.WriteString("street", Street);
+        }
+
+        /** <inheritDoc /> */
+        public void ReadPortable(IPortableReader reader)
+        {
+            StreetNumber = reader.ReadInt("streetNum");
+            FlatNumber = reader.ReadInt("flatNum");
+            City = reader.ReadString("city");
+            Street = reader.ReadString("street");
+        }
+    }
+}