• Version 1.15.2
Show / Hide Table of Contents

GC Free Sample

Source code


using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using OnixS.Fix;
using OnixS.Fix.Fix42;

namespace GCFree
{
    using static Console;

    internal static class GCFree
    {
        private static readonly AutoResetEvent ready = new AutoResetEvent(false);

#if DEBUG
        private const int WarmupNumberOfMessages = 100000;
        private const int NumberOfMessages = 100000;
#else
        private const int WarmupNumberOfMessages = 500000;
        private const int NumberOfMessages = 1000000;
#endif
        /// <summary>
        ///     The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            WriteLine(GetProductName());

            try {
                var settings = new EngineSettings()
                {
                    LicenseStore = GetLicenseStoreFolder(),
                };
                settings.ListenPorts.Add(10450);

                Engine.Init(settings);

                const string Sender = "Acceptor";
                const string Target = "Initiator";

                const ProtocolVersion Version = ProtocolVersion.Fix42;

                using var acceptor = new Session(Sender, Target, Version, false)
                {
                    ReuseEventArguments = true,
                    ReuseInboundMessage = true
                };

                acceptor.InboundApplicationMessage += (object sender, InboundMessageEventArgs e) =>
                {
                    ((Session)sender).Send(e.Message);
                };

                acceptor.LogonAsAcceptor();

                using var initiator = new Session(Target, Sender, Version, false)
                {
                    ReuseEventArguments = true,
                    ReuseInboundMessage = true
                };

                var receivedReply = new AutoResetEvent(false);

                long initiatorReceiverAllocatedStart = 0, initiatorSenderAllocatedStart = 0,
                    initiatorReceiverAllocatedEnd = 0, initiatorSenderAllocatedEnd = 0;

                initiator.InboundApplicationMessage += (object sender, InboundMessageEventArgs e) =>
                {
                    if (initiatorReceiverAllocatedStart == 0)
                        initiatorReceiverAllocatedStart = GC.GetAllocatedBytesForCurrentThread();
                    initiatorReceiverAllocatedEnd = GC.GetAllocatedBytesForCurrentThread();
                    receivedReply.Set();
                };
                initiator.OutboundApplicationMessage += (object sender, MessageEventArgs e) =>
                {
                    if (initiatorSenderAllocatedStart == 0)
                        initiatorSenderAllocatedStart = GC.GetAllocatedBytesForCurrentThread();
                    initiatorSenderAllocatedEnd = GC.GetAllocatedBytesForCurrentThread();
                };

                initiator.LogonAsInitiator(IPAddress.Loopback, settings.ListenPorts[0]);

                const int NumberOfOrders = 1000;

                var order = CreateOrder(Version);
                order.Validate();

                // Warmup
                initiator.Send(order);
                receivedReply.WaitOne();

                long startBytes = GC.GetAllocatedBytesForCurrentThread();

                for (int i = 0; i < NumberOfOrders; ++i)
                {
                    initiator.Send(order);
                    receivedReply.WaitOne();
                }

                long allocatedBytes = GC.GetAllocatedBytesForCurrentThread() - startBytes;

                long initiatorSenderAllocatedBytes = initiatorSenderAllocatedEnd - initiatorSenderAllocatedStart;
                long initiatorReceiverAllocatedBytes = initiatorReceiverAllocatedEnd - initiatorReceiverAllocatedStart;
                Console.WriteLine($"Main: {allocatedBytes} bytes were allocated per {NumberOfOrders} normal orders");
                Console.WriteLine($"Sender: {initiatorSenderAllocatedBytes} bytes were allocated per {NumberOfOrders} normal orders");
                Console.WriteLine($"Receiver: {initiatorReceiverAllocatedBytes} bytes were allocated per {NumberOfOrders} normal orders");

                initiatorSenderAllocatedStart = initiatorSenderAllocatedEnd = initiatorReceiverAllocatedStart = initiatorReceiverAllocatedEnd = 0;


                var serializedOrder = new SerializedMessage(order);

                // Warmup
                initiator.Send(serializedOrder);
                receivedReply.WaitOne();

                startBytes = GC.GetAllocatedBytesForCurrentThread();

                for (int i = 0; i < NumberOfOrders; ++i)
                {
                    initiator.Send(serializedOrder);
                    receivedReply.WaitOne();
                }

                allocatedBytes = GC.GetAllocatedBytesForCurrentThread() - startBytes;
                initiatorSenderAllocatedBytes = initiatorSenderAllocatedEnd - initiatorSenderAllocatedStart;
                initiatorReceiverAllocatedBytes = initiatorReceiverAllocatedEnd - initiatorReceiverAllocatedStart;

                Console.WriteLine($"{allocatedBytes} bytes were allocated per {NumberOfOrders} serialized orders");
                Console.WriteLine($"Sender: {initiatorSenderAllocatedBytes} bytes were allocated per {NumberOfOrders} serialized orders");
                Console.WriteLine($"Receiver: {initiatorReceiverAllocatedBytes} bytes were allocated per {NumberOfOrders} serialized orders");

                initiator.Logout();
                acceptor.Logout();

                Engine.Shutdown();
            }
            catch (Exception ex) {
                WriteLine("Exception: " + ex);
            }
        }

        private static Message CreateOrder(ProtocolVersion version)
        {
            var order = new Message(MsgType.Order_Single, version, 130);

            order.Set(Tag.HandlInst, "1")
            .Set(Tag.ClOrdID, "ClOrdID")
            .Set(Tag.Symbol, "IBM")
            .Set(Tag.Side, "1")
            .Set(Tag.OrderQty, 1000)
            .Set(Tag.OrdType, "1")
            .Set(Tag.TransactTime, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss", CultureInfo.InvariantCulture));

            return order;
        }

        private static string GetLicenseStoreFolder()
        {
            string path = Path.Join(AppContext.BaseDirectory, "../../../../../license");

            if (Directory.Exists(path))
                return path;

            // We assume to run after `dotnet publish` using the default path.
            return Path.Join(AppContext.BaseDirectory, "../../../../../../license");
        }

        private static string GetProductName()
        {
            var assemblyName = typeof(Engine).Assembly.GetName();
            return $"GC Free Sample\n\n{assemblyName.Name} version {assemblyName.Version}\n";
        }
    }
}

In this article
Back to top Copyright © Onix Solutions.
Generated by DocFX