You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2022/11/21 01:41:14 UTC

[lucenenet] 10/13: BenchmarkDotNet: Centralized build configuration logic so we can add a new version in just one place. Also, include a LocalBuild in the benchmarks so we can compare to the current source code.

This is an automated email from the ASF dual-hosted git repository.

nightowl888 pushed a commit to branch benchmarkdotnet
in repository https://gitbox.apache.org/repos/asf/lucenenet.git

commit 1aca8539dd4297f8bb737fbf726492135475d799
Author: Shad Storhaug <sh...@shadstorhaug.com>
AuthorDate: Wed Apr 21 14:53:34 2021 +0700

    BenchmarkDotNet: Centralized build configuration logic so we can add a new version in just one place. Also, include a LocalBuild in the benchmarks so we can compare to the current source code.
---
 .../BuildConfigurations.cs                         |  62 ++++++++
 .../FacetsAssociationsBenchmarks.cs                |  25 ++--
 .../FacetsDistanceBenchmarks.cs                    |  26 ++--
 .../FacetsExpressionAggregationBenchmarks.cs       |  26 ++--
 .../FacetsMultiCategoryListsBenchmarks.cs          |  25 ++--
 .../FacetsRangeBenchmarks.cs                       |  25 ++--
 .../FacetsSimpleBenchmarks.cs                      |  25 ++--
 .../FacetsSimpleSortedSetBenchmarks.cs             |  25 ++--
 .../HomePageScriptBenchmarks.cs                    |  24 +--
 .../IndexFilesBenchmarks.cs                        |  27 ++--
 .../Lucene.Net.Tests.BenchmarkDotNet.csproj        |  25 +++-
 .../SearchFilesBenchmarks.cs                       |  28 ++--
 .../Util/ContentGenerator.cs                       |   6 +-
 .../Util/PathUtil.cs                               |   2 +-
 .../Util/RandomNumbers.cs                          | 161 +++++++++++++++++++++
 .../Util/RandomPicks.cs                            |  67 +++++++++
 16 files changed, 465 insertions(+), 114 deletions(-)

diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/BuildConfigurations.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/BuildConfigurations.cs
new file mode 100644
index 000000000..6d70a2537
--- /dev/null
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/BuildConfigurations.cs
@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+
+namespace Lucene.Net.Tests.BenchmarkDotNet
+{
+    /*
+     * 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.
+     */
+
+    public static class BuildConfigurations
+    {
+        public static IList<BuildConfiguration> Configs = new List<BuildConfiguration>
+        {
+            //new BuildConfiguration { PackageVersion = "4.8.0-beta00005" },
+            //new BuildConfiguration { PackageVersion = "4.8.0-beta00006" },
+            //new BuildConfiguration { PackageVersion = "4.8.0-beta00007" },
+            //new BuildConfiguration { PackageVersion = "4.8.0-beta00008" },
+            //new BuildConfiguration { PackageVersion = "4.8.0-beta00009" },
+            new BuildConfiguration { PackageVersion = "4.8.0-beta00010" },
+            new BuildConfiguration { PackageVersion = "4.8.0-beta00011" },
+            new BuildConfiguration { PackageVersion = "4.8.0-beta00012" },
+            new BuildConfiguration { PackageVersion = "4.8.0-beta00013" },
+            new BuildConfiguration { PackageVersion = "4.8.0-beta00014" },
+            new BuildConfiguration { CustomConfigurationName = "LocalBuild", Id = "LocalBuild" },
+        };
+    }
+
+    public class BuildConfiguration
+    {
+        private string id;
+
+        /// <summary>
+        /// NuGet package version. May be on a NuGet feed or a local directory configured as a feed.
+        /// </summary>
+        public string PackageVersion { get; set; }
+
+        public string CustomConfigurationName { get; set; }
+
+        public string Id
+        {
+            get
+            {
+                if (id is null)
+                    return PackageVersion;
+                return id;
+            }
+            set => id = value;
+        }
+    }
+}
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsAssociationsBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsAssociationsBenchmarks.cs
index 973146b38..0de3df198 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsAssociationsBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsAssociationsBenchmarks.cs
@@ -32,16 +32,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsDistanceBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsDistanceBenchmarks.cs
index e9cdeb521..6fbf6f069 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsDistanceBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsDistanceBenchmarks.cs
@@ -32,16 +32,22 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Expressions", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsExpressionAggregationBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsExpressionAggregationBenchmarks.cs
index 63b6c27ba..eaed15772 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsExpressionAggregationBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsExpressionAggregationBenchmarks.cs
@@ -32,16 +32,22 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Expressions", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Expressions", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsMultiCategoryListsBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsMultiCategoryListsBenchmarks.cs
index 5b02e2d81..3f7e8a78d 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsMultiCategoryListsBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsMultiCategoryListsBenchmarks.cs
@@ -32,16 +32,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsRangeBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsRangeBenchmarks.cs
index b57077a33..8e5be3a99 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsRangeBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsRangeBenchmarks.cs
@@ -32,16 +32,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleBenchmarks.cs
index 4a55f2bd4..981a65a2c 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleBenchmarks.cs
@@ -32,16 +32,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleSortedSetBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleSortedSetBenchmarks.cs
index a685afaab..591b09131 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleSortedSetBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/FacetsSimpleSortedSetBenchmarks.cs
@@ -32,16 +32,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.Facet", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.Facet", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/HomePageScriptBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/HomePageScriptBenchmarks.cs
index 9581edf65..ba11f56b9 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/HomePageScriptBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/HomePageScriptBenchmarks.cs
@@ -39,16 +39,20 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/IndexFilesBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/IndexFilesBenchmarks.cs
index 674f2c938..8656a1b45 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/IndexFilesBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/IndexFilesBenchmarks.cs
@@ -5,9 +5,8 @@ using Lucene.Net.Analysis;
 using Lucene.Net.Analysis.Standard;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
-using Lucene.Net.Randomized.Generators;
 using Lucene.Net.Store;
-using Lucene.Net.Tests.BenchmarkDotNet.Util;
+using Lucene.Net.BenchmarkDotNet.Util;
 using Lucene.Net.Util;
 using System;
 using System.IO;
@@ -42,16 +41,20 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/Lucene.Net.Tests.BenchmarkDotNet.csproj b/src/Lucene.Net.Tests.BenchmarkDotNet/Lucene.Net.Tests.BenchmarkDotNet.csproj
index eafd35045..02e675434 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/Lucene.Net.Tests.BenchmarkDotNet.csproj
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/Lucene.Net.Tests.BenchmarkDotNet.csproj
@@ -2,8 +2,11 @@
 
   <PropertyGroup>
     <OutputType>Exe</OutputType>
-    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <TargetFramework>net5.0</TargetFramework>
     <StartupObject>Lucene.Net.Tests.BenchmarkDotNet.Program</StartupObject>
+    
+    <!-- Don't sign the assembly so we don't get warnings about early versions of Lucene.NET that weren't signed -->
+    <SignAssembly>false</SignAssembly>
   </PropertyGroup>
 
   <ItemGroup>
@@ -11,18 +14,28 @@
     <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.12.1" />
   </ItemGroup>
 
-  <ItemGroup>
-    <PackageReference Include="J2N" Version="1.0.0-beta-0001" />
+  <PropertyGroup Condition=" '$(Configuration)' == 'LocalBuild' ">
+    <Optimize>true</Optimize>
+  </PropertyGroup>
+
+  <ItemGroup Condition=" '$(Configuration)' == 'LocalBuild' ">
+    <ProjectReference Include="..\Lucene.Net.Analysis.Common\Lucene.Net.Analysis.Common.csproj" />
+    <ProjectReference Include="..\Lucene.Net.Expressions\Lucene.Net.Expressions.csproj" />
+    <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj" />
+    <ProjectReference Include="..\Lucene.Net.QueryParser\Lucene.Net.QueryParser.csproj" />
+    <PackageReference Include="J2N" Version="$(J2NPackageVersion)" />
+  </ItemGroup>
+
+  <ItemGroup Condition=" '$(Configuration)' != 'LocalBuild' ">
+    <!-- These are minimal versions required to make the project compile - each higher version upgrades these based on NuGet dependencies -->
     <PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00005" />
     <PackageReference Include="Lucene.Net.Expressions" Version="4.8.0-beta00005" />
     <PackageReference Include="Lucene.Net.Facet" Version="4.8.0-beta00005" />
     <PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00005" />
+    <PackageReference Include="J2N" Version="1.0.0-beta-0001" />
   </ItemGroup>
   
   <ItemGroup>
-    <Compile Include="..\Lucene.Net.TestFramework\Support\Randomized\Generators\RandomPicks.cs" LinkBase="Util" />
-    <Compile Include="..\Lucene.Net.TestFramework\Support\Randomized\Generators\RandomInts.cs" LinkBase="Util" />
-    <Compile Include="..\Lucene.Net\Support\ExceptionToNetNumericConventionAttribute.cs" LinkBase="Util" />
     <Compile Include="..\Lucene.Net.Demo\Facet\AssociationsFacetsExample.cs" LinkBase="Util" />
     <Compile Include="..\Lucene.Net.Demo\Facet\DistanceFacetsExample.cs" LinkBase="Util" />
     <Compile Include="..\Lucene.Net.Demo\Facet\ExpressionAggregationFacetsExample.cs" LinkBase="Util" />
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/SearchFilesBenchmarks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/SearchFilesBenchmarks.cs
index 669434afd..9e5361e0c 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/SearchFilesBenchmarks.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/SearchFilesBenchmarks.cs
@@ -5,10 +5,9 @@ using Lucene.Net.Analysis;
 using Lucene.Net.Analysis.Standard;
 using Lucene.Net.Index;
 using Lucene.Net.QueryParsers.Classic;
-using Lucene.Net.Randomized.Generators;
 using Lucene.Net.Search;
 using Lucene.Net.Store;
-using Lucene.Net.Tests.BenchmarkDotNet.Util;
+using Lucene.Net.BenchmarkDotNet.Util;
 using Lucene.Net.Util;
 using System;
 using System.IO;
@@ -42,16 +41,21 @@ namespace Lucene.Net.Tests.BenchmarkDotNet
             {
                 var baseJob = Job.MediumRun;
 
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00014").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00014").WithId("4.8.0-beta00014"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00013").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00013").WithId("4.8.0-beta00013"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00012").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00012").WithId("4.8.0-beta00012"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00011").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00011").WithId("4.8.0-beta00011"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00010").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00010").WithId("4.8.0-beta00010"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00009").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00009").WithId("4.8.0-beta00009"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00008").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00008").WithId("4.8.0-beta00008"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00007").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00007").WithId("4.8.0-beta00007"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00006").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00006").WithId("4.8.0-beta00006"));
-                AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", "4.8.0-beta00005").WithNuGet("Lucene.Net.QueryParser", "4.8.0-beta00005").WithId("4.8.0-beta00005"));
+                for (int i = 0; i < BuildConfigurations.Configs.Count; i++)
+                {
+                    var config = BuildConfigurations.Configs[i];
+                    if (string.IsNullOrEmpty(config.CustomConfigurationName))
+                    {
+                        AddJob(baseJob.WithNuGet("Lucene.Net.Analysis.Common", config.PackageVersion)
+                                      .WithNuGet("Lucene.Net.QueryParser", config.PackageVersion)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                    else
+                    {
+                        AddJob(baseJob.WithCustomBuildConfiguration(config.CustomConfigurationName)
+                                      .WithId($"{i:000}-{config.Id}"));
+                    }
+                }
             }
         }
 
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/ContentGenerator.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/ContentGenerator.cs
index 15612e922..e81c03cc8 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/ContentGenerator.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/ContentGenerator.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
-namespace Lucene.Net.Randomized.Generators
+namespace Lucene.Net.BenchmarkDotNet.Util
 {
     /*
      * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -93,7 +93,7 @@ namespace Lucene.Net.Randomized.Generators
         /// </summary>
         public static string RandomSimpleString(Random r, int minLength, int maxLength)
         {
-            int end = RandomInts.RandomInt32Between(r, minLength, maxLength);
+            int end = RandomNumbers.RandomInt32Between(r, minLength, maxLength);
             if (end == 0)
             {
                 // allow 0 length
@@ -102,7 +102,7 @@ namespace Lucene.Net.Randomized.Generators
             char[] buffer = new char[end];
             for (int i = 0; i < end; i++)
             {
-                buffer[i] = (char)RandomInts.RandomInt32Between(r, 'a', 'z');
+                buffer[i] = (char)RandomNumbers.RandomInt32Between(r, 'a', 'z');
             }
             return new string(buffer, 0, end);
         }
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/PathUtil.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/PathUtil.cs
index aaf9c8633..014e13c4a 100644
--- a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/PathUtil.cs
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/PathUtil.cs
@@ -1,7 +1,7 @@
 using System;
 using System.IO;
 
-namespace Lucene.Net.Tests.BenchmarkDotNet.Util
+namespace Lucene.Net.BenchmarkDotNet.Util
 {
     /*
      * Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomNumbers.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomNumbers.cs
new file mode 100644
index 000000000..149adbcb9
--- /dev/null
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomNumbers.cs
@@ -0,0 +1,161 @@
+using J2N.Numerics;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+
+namespace Lucene.Net.BenchmarkDotNet.Util
+{
+    /*
+     * 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.
+     */
+
+    /// <summary>
+    /// Utility classes for selecting random numbers from within a range or the 
+    /// numeric domain for a given type.
+    /// </summary>
+    /// <seealso cref="BiasedNumbers"/>
+    public static class RandomNumbers
+    {
+        /// <summary>
+        /// Returns a random <see cref="int"/> from <paramref name="minValue"/> (inclusive) to <paramref name="maxValue"/> (inclusive).
+        /// </summary>
+        /// <param name="random">A <see cref="Random"/> instance.</param>
+        /// <param name="minValue">The inclusive start of the range.</param>
+        /// <param name="maxValue">The inclusive end of the range.</param>
+        /// <returns>A random <see cref="int"/> from <paramref name="minValue"/> (inclusive) to <paramref name="maxValue"/> (inclusive).</returns>
+        /// <exception cref="ArgumentException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> is <c>null</c>.</exception>
+        public static int RandomInt32Between(Random random, int minValue, int maxValue)
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+            if (minValue > maxValue)
+                throw new ArgumentException($"{nameof(minValue)} must be less than or equal to {nameof(maxValue)}. {nameof(minValue)}: {minValue}, {nameof(maxValue)}: {maxValue}");
+            var range = maxValue - minValue;
+            if (range < int.MaxValue)
+                return minValue + random.Next(1 + range);
+
+            return minValue + (int)Math.Round(random.NextDouble() * range);
+        }
+
+        /// <summary>
+        /// Returns a random <see cref="long"/> from <paramref name="minValue"/> to <paramref name="maxValue"/> (inclusive).
+        /// </summary>
+        /// <param name="random">A <see cref="Random"/> instance.</param>
+        /// <param name="minValue">The inclusive start of the range.</param>
+        /// <param name="maxValue">The inclusive end of the range.</param>
+        /// <returns>A random <see cref="long"/> from <paramref name="minValue"/> to <paramref name="maxValue"/> (inclusive).</returns>
+        /// <exception cref="ArgumentException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> is <c>null</c>.</exception>
+        public static long RandomInt64Between(Random random, long minValue, long maxValue)
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+            if (minValue > maxValue)
+                throw new ArgumentException($"{nameof(minValue)} must be less than or equal to {nameof(maxValue)}. {nameof(minValue)}: {minValue}, {nameof(maxValue)}: {maxValue}");
+
+            BigInteger range = (BigInteger)maxValue + (BigInteger)1 - (BigInteger)minValue;
+            if (range.CompareTo((BigInteger)int.MaxValue) <= 0)
+            {
+                return minValue + random.Next((int)range);
+            }
+            else
+            {
+                // probably not evenly distributed when range is large, but OK for tests
+                //BigInteger augend = BigInteger.Multiply(range,  new BigInteger(r.NextDouble()));
+                //long result = start + (long)augend;
+
+                // NOTE: Using BigInteger/Decimal doesn't work because r.NextDouble() is always
+                // rounded down to 0, which makes the result always the same as start. This alternative solution was
+                // snagged from https://stackoverflow.com/a/13095144. All we really care about here is that we get
+                // a pretty good random distribution of values between start and end.
+
+                //Working with ulong so that modulo works correctly with values > long.MaxValue
+                ulong uRange = (ulong)unchecked(maxValue - minValue);
+
+                //Prevent a modolo bias; see https://stackoverflow.com/a/10984975/238419
+                //for more information.
+                //In the worst case, the expected number of calls is 2 (though usually it's
+                //much closer to 1) so this loop doesn't really hurt performance at all.
+                ulong ulongRand;
+                do
+                {
+                    byte[] buf = new byte[8];
+                    random.NextBytes(buf);
+                    ulongRand = (ulong)BitConverter.ToInt64(buf, 0);
+                } while (ulongRand > ulong.MaxValue - ((ulong.MaxValue % uRange) + 1) % uRange);
+
+                long result = (long)(ulongRand % uRange) + minValue + random.Next(0, 1); // Randomly decide whether to increment by 1 to make the second parameter "inclusive"
+
+                Debug.Assert(result >= minValue);
+                Debug.Assert(result <= maxValue);
+                return result;
+            }
+        }
+
+        /// <summary>
+        /// Similar to <see cref="Random.Next(int)"/>, but returns a <see cref="long"/> between
+        /// 0 (inclusive) and <paramref name="maxValue"/> (exclusive).
+        /// </summary>
+        /// <param name="random">A <see cref="Random"/> instance.</param>
+        /// <param name="maxValue">The bound on the random number to be returned. Must be positive.</param>
+        /// <returns>A random <see cref="long"/> between 0 and <paramref name="maxValue"/> - 1.</returns>
+        /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxValue"/> is less than 1.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> is <c>null</c>.</exception>
+        public static long NextInt64(Random random, long maxValue)
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+            if (maxValue <= 0)
+                throw new ArgumentOutOfRangeException(nameof(maxValue), maxValue, $"{nameof(maxValue)} must be greater than or equal to 0");
+
+            long value = random.NextInt64();
+            long range = maxValue - 1;
+            if ((maxValue & range) == 0L)
+            {
+                value &= range;
+            }
+            else
+            {
+                for (long u = value.TripleShift(1); u + range - (value = u % maxValue) < 0L;)
+                {
+                    u = random.NextInt64().TripleShift(1);
+                }
+            }
+            return value;
+        }
+    }
+
+    internal static class RandomExtensions
+    {
+        /// <summary>
+        /// Generates a random <see cref="long"/>.
+        /// </summary>
+        /// <param name="random">This <see cref="Random"/>.</param>
+        /// <returns>A random <see cref="long"/>.</returns>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> is <c>null</c>.</exception>
+        // http://stackoverflow.com/a/6651656
+        public static long NextInt64(this Random random) // .NET specific to cover missing member from Java
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+
+            byte[] buffer = new byte[8];
+            random.NextBytes(buffer);
+            return BitConverter.ToInt64(buffer, 0);
+        }
+    }
+}
diff --git a/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomPicks.cs b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomPicks.cs
new file mode 100644
index 000000000..e968f842d
--- /dev/null
+++ b/src/Lucene.Net.Tests.BenchmarkDotNet/Util/RandomPicks.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.BenchmarkDotNet.Util
+{
+    /*
+     * 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.
+     */
+
+    /// <summary>
+    /// Random selections of objects.
+    /// </summary>
+    public class RandomPicks
+    {
+        /// <summary>
+        /// Pick a random element from the <paramref name="list"/> (which may be an array).
+        /// </summary>
+        /// <exception cref="ArgumentException"><paramref name="list"/> contains no items.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> or <paramref name="list"/> is <c>null</c>.</exception>
+        public static T RandomFrom<T>(Random random, IList<T> list)
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+            if (list is null)
+                throw new ArgumentNullException(nameof(list));
+
+            if (list.Count == 0)
+            {
+                throw new ArgumentException("Can't pick a random object from an empty list.");
+            }
+            return list[random.Next(0, list.Count)];
+        }
+
+        /// <summary>
+        /// Pick a random element from the <paramref name="collection"/>.
+        /// </summary>
+        /// <exception cref="ArgumentException"><paramref name="collection"/> contains no items.</exception>
+        /// <exception cref="ArgumentNullException"><paramref name="random"/> or <paramref name="collection"/> is <c>null</c>.</exception>
+        public static T RandomFrom<T>(Random random, ICollection<T> collection)
+        {
+            if (random is null)
+                throw new ArgumentNullException(nameof(random));
+            if (collection is null)
+                throw new ArgumentNullException(nameof(collection));
+
+            if (collection.Count == 0)
+            {
+                throw new ArgumentException("Can't pick a random object from an empty collection.");
+            }
+            return collection.ElementAt(random.Next(0, collection.Count));
+        }
+    }
+}