• Version 1.16.0
Show / Hide Table of Contents

Parsing Benchmark Sample Project

This sample demonstrates how to measure the performance of the message parsing.

© Onix Solutions

Source code


using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using OnixS.Fix;

namespace Benchmark.Parsing
{
    using static Console;

    /// <summary>
    /// Measures the parsing performance.
    /// </summary>
    static class Parsing
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static int Main()
        {
            WriteLine(GetProductName());

            try {
                Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
            }
            catch (Exception ex) {
                WriteLine("\nWarning: unable to set real-time priority to this process - " + ex.Message);
                WriteLine(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
                            ? "To enable process priority control run this benchmark under administrator"
                            : "To enable process priority control run this benchmark using 'sudo dotnet Parsing.dll'\n");
            }

            try {
                var settings = new EngineSettings()
                {
                    LicenseStore = GetLicenseStoreFolder(),
                    DisableNetworkLevel = true,
                    ValidateRepeatingGroupEntryCount = false,
                    ValidateCheckSum = false
                };
                settings.Versions.Clear();

                const ProtocolVersion FixProtocolVersion = ProtocolVersion.Fix40;
                settings.Versions.Add(FixProtocolVersion);

                Engine.Init(settings);

                var dictionary = Engine.Instance.MessageInfoDictionaryManager[FixProtocolVersion];

                const string TestCasesSectionName = "TestCases";

                if (! (ConfigurationManager.GetSection(TestCasesSectionName) is NameValueCollection testCases))
                {
                    throw new EngineException($"The configuration file '{ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath}'" +
                        $" with '{TestCasesSectionName}' section was not found.");
                }

                foreach (string testCase in testCases) {
                    WriteLine($"Test case: {testCase}");
                    Benchmark(testCases[testCase], dictionary);
                }
            }
            catch (Exception ex) {
                WriteLine("EXCEPTION: " + ex);
                return 1;
            }
            finally {
                if (Engine.IsInitialized)
                    Engine.Shutdown();
            }

            return 0;
        }

        private static void Benchmark(string fileName, IMessageInfoDictionary dictionary)
        {
            ReadOnlySpan<byte> rawMsg = GetRawMessage(fileName);

            const int WarmUpCycles = 1000;

            for (int i = 0; i < WarmUpCycles; ++i) {
                Message msg = Message.Parse(rawMsg, dictionary);
            }

            long start = TimestampHelper.Ticks;

            const int TestCycles = 1000000;

            for (int i = 0; i < TestCycles; ++i) {
                Message msg = Message.Parse(rawMsg, dictionary);
            }

            double elapsedSeconds = TimestampHelper.ElapsedSeconds(start);

            double msgPerSec = TestCycles / elapsedSeconds;
            double kbPerSec = rawMsg.Length * TestCycles / elapsedSeconds / 1024;

            WriteLine($"Performance: {string.Format("{0:n0}", msgPerSec)} msg/sec, {string.Format("{0:n0}", kbPerSec)} kB/sec.");
            WriteLine();
        }

        private static ReadOnlySpan<byte> GetRawMessage(string fileName)
        {
            Span<byte> rawMsg = File.ReadAllBytes(fileName);

            const byte FieldDelimiter = 1;
            int msgLength = rawMsg.LastIndexOf(FieldDelimiter);

            return rawMsg.Slice(0, msgLength);
        }

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

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

            // expecting it run after dotnet publish using default paths
            return Path.Join(AppContext.BaseDirectory, "../../../../../../../license");
        }

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

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