Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
88eccfa
RUBY-3209 Generate api docs (#2768)
comandeo-mongo Aug 7, 2023
ae75857
RUBY-3308 Fixing serverless test failures (#2770)
jamis Aug 14, 2023
b36d358
RUBY-3314 Implement variable iterations for benchmarks (#2771)
jamis Aug 17, 2023
6e88e3e
RUBY-3313 Record benchmark percentiles (#2772)
jamis Aug 21, 2023
5598035
RUBY-3315 BSON benchmark scoring (#2773)
jamis Aug 22, 2023
c303ab6
RUBY-3242 Add spec tests for runCommand (#2776)
comandeo-mongo Aug 25, 2023
42f7838
RUBY-2748 Retry reads/writes on another mongos (#2717)
comandeo-mongo Aug 25, 2023
f447d09
RUBY-3316 Quality of life updates for BSON benchmarks (#2774)
jamis Aug 28, 2023
765976a
RUBY-3268 search index management helpers (#2777)
jamis Sep 7, 2023
d3b3d6b
RUBY-3324 bump drivers-evergreen-tools to get updated atlas setup/tea…
jamis Sep 13, 2023
70c23a9
RUBY-3328 add `execution` expansion to environment for atlas cluster …
jamis Sep 18, 2023
17e4ec4
RUBY-3372 Fix failing explain tests (#2782)
comandeo-mongo Sep 18, 2023
70e5f38
RUBY-3279 Bump min server version for FLE test (#2779)
comandeo-mongo Sep 18, 2023
b1f9faf
RUBY-3267 make specs pass when X.509 authentication is active (#2781)
jamis Sep 19, 2023
49f0046
RUBY-2706 Test find related options (#2789)
comandeo-mongo Oct 5, 2023
4b007a6
RUBY-3331: Inline server lifecycle callout (#2790)
alexbevi Oct 6, 2023
b6549ac
RUBY-3296 Write to log when non-genuine host is detected (#2791)
jamis Oct 11, 2023
cb21f01
RUBY-3149 Test on AWS Lambda (#2800)
comandeo-mongo Oct 20, 2023
014a50f
Fix serverless tests (#2802)
comandeo-mongo Oct 31, 2023
16a2095
RUBY-3333 Update AWS auth tests (#2803)
comandeo-mongo Nov 2, 2023
79dba06
RUBY-3347 add additional serverless project to tests (#2810)
jamis Nov 21, 2023
ba527e1
Fix broken link in Mongo::Monitoring::Event::Secure (#2775)
alexbevi Nov 28, 2023
829cd5a
RUBY-3341 Document error handling in transactions (#2809)
comandeo-mongo Dec 5, 2023
0b29297
RUBY-3365 remove spec (#2820)
jamis Jan 9, 2024
20d16a7
RUBY-3362 sync specs to fix failing tests on server version 7.3 (#2819)
jamis Jan 9, 2024
95e1752
RUBY-3361 resync specs (#2818)
jamis Jan 9, 2024
756f67e
RUBY-3298 Add container info to handshake metadata (#2821)
jamis Jan 12, 2024
488fce0
RUBY-1813 Discard ServerSessions involved in network errors (#2825)
jamis Jan 15, 2024
0d99359
RUBY-3329 Connection String: make delimiting slash between hosts and …
jamis Jan 15, 2024
b7acff4
RUBY-2254 sort by id when comparing collection contents (#2823)
jamis Jan 15, 2024
aaa2a56
RUBY-1791 Raise if transactions not supported (#2822)
comandeo-mongo Jan 15, 2024
72cf221
RUBY-3358 Handle nil session is write_worker (#2826)
comandeo-mongo Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
RUBY-3313 Record benchmark percentiles (#2772)
* RUBY-3314 Implement variable iterations for benchmarks

* report percentiles along with the median

* rename Benchmarking::Micro to Benchmarking::BSON

* refactoring to appease rubocop
  • Loading branch information
jamis authored and comandeo-mongo committed Jan 24, 2024
commit 6e88e3e97cad74a9cf9e38305461daa6ec02913b
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ Style/Documentation:
Exclude:
- 'spec/**/*'

Style/FormatStringToken:
Enabled: false

Style/ModuleFunction:
EnforcedStyle: extend_self

Expand Down
40 changes: 24 additions & 16 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,24 +135,32 @@ require_relative "profile/benchmarking"

# Some require data files, available from the drivers team. See the comments above each task for details."
namespace :benchmark do
desc "Run the driver benchmark tests."

namespace :micro do
desc "Run the common driver micro benchmarking tests"
desc "Run the bson benchmarking tests"
task :bson do
puts "BSON BENCHMARK"
Mongo::Benchmarking.report({
bson: Mongo::Benchmarking::BSON.run_all({
flat: %i[ encode decode ],
deep: %i[ encode decode ],
full: %i[ encode decode ],
})
})
end

namespace :bson do
namespace :flat do
desc "Benchmarking for flat bson documents."

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called flat_bson.json.
task :encode do
puts "MICRO BENCHMARK:: FLAT:: ENCODE"
Mongo::Benchmarking::Micro.run(:flat, :encode)
puts "BSON BENCHMARK :: FLAT :: ENCODE"
Mongo::Benchmarking.report({ bson: { flat: { encode: Mongo::Benchmarking::BSON.run(:flat, :encode) } } })
end

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called flat_bson.json.
task :decode do
puts "MICRO BENCHMARK:: FLAT:: DECODE"
Mongo::Benchmarking::Micro.run(:flat, :decode)
puts "BSON BENCHMARK :: FLAT :: DECODE"
Mongo::Benchmarking.report({ bson: { flat: { decode: Mongo::Benchmarking::BSON.run(:flat, :decode) } } })
end
end

Expand All @@ -161,14 +169,14 @@ namespace :benchmark do

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called deep_bson.json.
task :encode do
puts "MICRO BENCHMARK:: DEEP:: ENCODE"
Mongo::Benchmarking::Micro.run(:deep, :encode)
puts "BSON BENCHMARK :: DEEP :: ENCODE"
Mongo::Benchmarking.report({ bson: { deep: { encode: Mongo::Benchmarking::BSON.run(:deep, :encode) } } })
end

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called deep_bson.json.
task :decode do
puts "MICRO BENCHMARK:: DEEP:: DECODE"
Mongo::Benchmarking::Micro.run(:deep, :decode)
puts "BSON BENCHMARK :: DEEP :: DECODE"
Mongo::Benchmarking.report({ bson: { deep: { decode: Mongo::Benchmarking::BSON.run(:deep, :decode) } } })
end
end

Expand All @@ -177,14 +185,14 @@ namespace :benchmark do

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called full_bson.json.
task :encode do
puts "MICRO BENCHMARK:: FULL:: ENCODE"
Mongo::Benchmarking::Micro.run(:full, :encode)
puts "BSON BENCHMARK :: FULL :: ENCODE"
Mongo::Benchmarking.report({ bson: { full: { encode: Mongo::Benchmarking::BSON.run(:full, :encode) } } })
end

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called full_bson.json.
task :decode do
puts "MICRO BENCHMARK:: FULL:: DECODE"
Mongo::Benchmarking::Micro.run(:full, :decode)
puts "BSON BENCHMARK :: FULL :: DECODE"
Mongo::Benchmarking.report({ bson: { full: { decode: Mongo::Benchmarking::BSON.run(:full, :decode) } } })
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion profile/benchmarking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

require 'benchmark'
require_relative 'benchmarking/helper'
require_relative 'benchmarking/micro'
require_relative 'benchmarking/bson'
require_relative 'benchmarking/single_doc'
require_relative 'benchmarking/multi_doc'
require_relative 'benchmarking/parallel'
Expand Down
78 changes: 43 additions & 35 deletions profile/benchmarking/micro.rb → profile/benchmarking/bson.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,74 +18,82 @@ module Mongo
module Benchmarking
# These tests focus on BSON encoding and decoding; they are client-side only and
# do not involve any transmission of data to or from the server.
#
# @since 2.2.3
module Micro
module BSON
extend self

# Run a micro benchmark test.
# Runs all of the benchmarks specified by the given mapping.
#
# @example Run a collection of benchmarks.
# Benchmarking::BSON.run_all(
# flat: %i[ encode decode ],
# deep: %i[ encode decode ],
# full: %i[ encode decode ]
# )
#
# @return [ Hash ] a hash of the results for each benchmark
def run_all(map)
{}.tap do |results|
map.each do |type, actions|
results[type] = {}

actions.each do |action|
results[type][action] = run(type, action)
end
end
end
end

# Run a BSON benchmark test.
#
# @example Run a test.
# Benchmarking::Micro.run(:flat)
# Benchmarking::BSON.run(:flat)
#
# @param [ Symbol ] type The type of test to run.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The test results.
# @param [ :encode | :decode ] action The action to perform.
#
# @since 2.2.3
def run(type, action, repetitions = Benchmarking::TEST_REPETITIONS)
file_name = type.to_s << '_bson.json'
GC.disable
file_path = [ Benchmarking::DATA_PATH, file_name ].join('/')
puts "#{action} : #{send(action, file_path, repetitions)}"
GC.enable
# @return [ Array<Number> ] The test results for each iteration
def run(type, action)
file_path = File.join(Benchmarking::DATA_PATH, "#{type}_bson.json")
Benchmarking.without_gc { send(action, file_path) }
end

# Run an encoding micro benchmark test.
# Run an encoding BSON benchmark test.
#
# @example Run an encoding test.
# Benchmarking::Micro.encode(file_name)
# Benchmarking::BSON.encode(file_name)
#
# @param [ String ] file_name The name of the file with data for the test.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The median of the results.
#
# @since 2.2.3
def encode(file_name, repetitions)
# @return [ Array<Numeric> ] The list of the results for each iteration
def encode(file_name)
data = Benchmarking.load_file(file_name)
document = BSON::Document.new(data.first)
document = ::BSON::Document.new(data.first)

results = Benchmarking.benchmark(max_iterations: repetitions) do
Benchmarking.benchmark do
10_000.times { document.to_bson }
end
Benchmarking.median(results)
end

# Run a decoding micro benchmark test.
# Run a decoding BSON benchmark test.
#
# @example Run an decoding test.
# Benchmarking::Micro.decode(file_name)
# Benchmarking::BSON.decode(file_name)
#
# @param [ String ] file_name The name of the file with data for the test.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The median of the results.
#
# @since 2.2.3
def decode(file_name, repetitions)
# @return [ Array<Numeric> ] The list of the results for each iteration
def decode(file_name)
data = Benchmarking.load_file(file_name)
buffer = BSON::Document.new(data.first).to_bson
buffer = ::BSON::Document.new(data.first).to_bson

results = Benchmarking.benchmark(max_iterations: repetitions) do
Benchmarking.benchmark do
10_000.times do
BSON::Document.from_bson(buffer)
::BSON::Document.from_bson(buffer)
buffer.rewind!
end
end

Benchmarking.median(results)
end
end
end
Expand Down
72 changes: 68 additions & 4 deletions profile/benchmarking/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def load_file(file_name)
# @since 2.2.3
def parse_json(document)
JSON.parse(document).tap do |doc|
doc['_id'] = BSON::ObjectId.from_string(doc['_id']['$oid']) if doc['_id'] && doc['_id']['$oid']
doc['_id'] = ::BSON::ObjectId.from_string(doc['_id']['$oid']) if doc['_id'] && doc['_id']['$oid']
end
end

Expand Down Expand Up @@ -81,19 +81,83 @@ def benchmark(max_iterations: Benchmarking::TEST_REPETITIONS, min_time: 60, max_
end
end

# Formats and displays a report of the given results.
#
# @param [ Hash ] results the results of a benchmarking run.
# @param [ Integer ] indent how much the report should be indented.
# @param [ Array<Numeric> ] percentiles the percentile values to report
def report(results, indent: 0, percentiles: [ 10, 25, 50, 75, 90, 95, 98, 99 ])
results.each do |key, value|
puts format('%*s%s:', indent, '', key)
if value.is_a?(Hash)
report(value, indent: indent + 2, percentiles: percentiles)
else
report_result(value, indent, percentiles)
end
end
end

# A utility class for returning the list item at a given percentile
# value.
class Percentiles
# @return [ Array<Number> ] the sorted list of numbers to consider
attr_reader :list

# Create a new Percentiles object that encapsulates the given list of
# numbers.
#
# @param [ Array<Number> ] list the list of numbers to considier
def initialize(list)
@list = list.sort
end

# Finds and returns the element in the list that represents the given
# percentile value.
#
# @param [ Number ] percentile a number in the range [1,100]
#
# @return [ Number ] the element of the list for the given percentile.
def [](percentile)
i = (list.size * percentile / 100.0).ceil - 1
list[i]
end
end

# Get the median of values in a list.
#
# @example Get the median.
# Benchmarking.median(values)
#
# @param [ Array ] The values to get the median of.
# @param [ Array ] values The values to get the median of.
#
# @return [ Numeric ] The median of the list.
#
# @since 2.2.3
def median(values)
i = (values.size / 2) - 1
values.sort[i]
end

# Runs a given block with GC disabled.
def without_gc
GC.disable
yield
ensure
GC.enable
end

private

# Formats and displays the results of a single benchmark run.
#
# @param [ Array<Numeric> ] results the results to report
# @param [ Integer ] indent how much the report should be indented
# @param [ Array<Numeric> ] percentiles the percentiles to report
def report_result(results, indent, percentiles)
ps = Percentiles.new(results)
puts format('%*smedian: %g', indent + 2, '', ps[50])
puts format('%*spercentiles:', indent + 2, '')
percentiles.each do |pct|
puts format('%*s%g: %g', indent + 4, '', pct, ps[pct])
end
end
end
end