File: Lsp\LspCompletionSerializationBenchmarks.cs
Web Access
Project: src\src\Tools\IdeBenchmarks\IdeBenchmarks.csproj (IdeBenchmarks)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.UnitTests.Completion;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Test.Utilities;
using Newtonsoft.Json;
using Roslyn.Test.Utilities;
using Xunit;
using LSP = Roslyn.LanguageServer.Protocol;
 
namespace IdeBenchmarks.Lsp
{
    [MemoryDiagnoser]
    public class LspCompletionSerializationBenchmarks : AbstractLanguageServerProtocolTests
    {
        protected override TestComposition Composition => FeaturesLspComposition;
        private readonly UseExportProviderAttribute _useExportProviderAttribute = new();
 
        private LSP.CompletionList? _list;
 
        public LspCompletionSerializationBenchmarks() : base(null)
        {
        }
 
        [GlobalSetup]
        public void GlobalSetup()
        {
        }
 
        [IterationSetup]
        public void IterationSetup()
        {
            _useExportProviderAttribute.Before(null);
            LoadSolutionAsync().Wait();
        }
 
        [IterationCleanup]
        public void CleanupAsync()
        {
            _useExportProviderAttribute.Before(null);
        }
 
        private async Task LoadSolutionAsync()
        {
            var markup =
@"using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Buffers.Text;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Media;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
class A
{
    void M()
    {
        {|caret:|}
    }
}";
            await using var testServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace: false, new LSP.VSInternalClientCapabilities
            {
                TextDocument = new LSP.TextDocumentClientCapabilities
                {
                    Completion = new LSP.CompletionSetting
                    {
                        CompletionListSetting = new LSP.CompletionListSetting
                        {
                            ItemDefaults = ["editRange", "commitCharacters", "data"],
                        }
                    }
                }
            }).ConfigureAwait(false);
 
            var globalOptions = testServer.TestWorkspace.GetService<IGlobalOptionService>();
            globalOptions.SetGlobalOption(LspOptionsStorage.MaxCompletionListSize, -1);
 
            var caret = testServer.GetLocations("caret").Single();
            var completionParams = new LSP.CompletionParams()
            {
                TextDocument = CreateTextDocumentIdentifier(caret.Uri),
                Position = caret.Range.Start,
                Context = new LSP.CompletionContext()
                {
                    TriggerKind = LSP.CompletionTriggerKind.Invoked,
                }
            };
 
            var document = testServer.GetCurrentSolution().Projects.First().Documents.First();
            var results = await testServer.ExecuteRequestAsync<LSP.CompletionParams, LSP.CompletionList>(LSP.Methods.TextDocumentCompletionName, completionParams, CancellationToken.None);
 
            var list = (await CompletionTests.RunGetCompletionsAsync(testServer, completionParams));
            if (list.Items.Length == 0)
                throw new System.Exception();
 
            using var _ = ArrayBuilder<LSP.CompletionItem>.GetInstance(out var builder);
            while (builder.Count < 10000)
            {
                foreach (var item in list.Items)
                {
                    builder.Add(item);
                    if (item.CommitCharacters is not null || item.Data is not null)
                        throw new InvalidDataException();
 
                    if (builder.Count == 10000)
                        break;
                }
            }
 
            list.Items = builder.ToArray();
            _list = list;
        }
 
        [Benchmark]
        public async Task Serialization()
        {
            var serializer = new JsonSerializer();
            serializer.Formatting = Formatting.None;
            serializer.NullValueHandling = NullValueHandling.Ignore;
            serializer.DefaultValueHandling = DefaultValueHandling.Ignore;
 
            using var stream = new MemoryStream();
            var sw = new StreamWriter(stream);
            var jsonWriter = new JsonTextWriter(sw);
            {
                serializer.Serialize(jsonWriter, _list);
                await jsonWriter.FlushAsync();
            }
 
            stream.Seek(0, SeekOrigin.Begin);
 
            using (var sr = new StreamReader(stream))
            using (var jsonReader = new JsonTextReader(sr))
            {
                var list = serializer.Deserialize<LSP.CompletionList>(jsonReader);
                if (list!.Items.Length != _list!.Items.Length)
                    throw new System.Exception();
            }
        }
 
        [Fact]
        public async Task Test()
        {
            await LoadSolutionAsync();
            await Serialization();
        }
    }
}