Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Memory Usage Improvements (to fix #65) #197

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6bed953
WIP: Reduce a benchmark from 4.6GB to 650MB 😅 by eliminating String#[…
kputnam Jun 15, 2019
8b5504b
Travis CI no longer supports 2.1.2-4
kputnam Jun 15, 2019
901a17b
Use Regexp#match? instead of =~ to avoid memory allocation
kputnam Jun 16, 2019
24ea222
Fix issue with empty strings in Substring#repro
kputnam Jun 16, 2019
8f5adc0
Remove #offset attribute from Position (only line, column, filename)
kputnam Jun 16, 2019
cac1bd0
Cleanup messes
kputnam Jun 16, 2019
70a253b
Eliminate 9.9MB of unused MatchData due to =~
kputnam Jun 17, 2019
05ef585
Eliminate 10.9MB by using a mutable buffer
kputnam Jun 17, 2019
ca4728e
Travis CI's 2.7.0 preview support seems broken
kputnam Jun 17, 2019
4452cd9
Rewrite tokenization code to minimize String allocations
kputnam Jun 22, 2019
f25c82b
Housekeeping
kputnam Jun 22, 2019
c128060
Tokenizer works, allocates one 3-byte String per segment
kputnam Jun 22, 2019
f80b6b7
Grind away the memory allocations, from 985MB allocated to 877MB in t…
kputnam Jun 23, 2019
dfc5566
Optimize StringPtr#==
kputnam Jun 23, 2019
9fca60e
Eliminate all calls to `StringPtr#reify`; benchmark runs slower at 14.9s
kputnam Jun 24, 2019
f5614d9
Restore one allocation to improve benchmark time to 6.2s
kputnam Jun 24, 2019
5dac65c
Leave segment_id as a String, not symbol. Benchmark at 6.8s
kputnam Jun 24, 2019
69a77df
Put it back, segment_id is a Symbol. No significant change in benchma…
kputnam Jun 24, 2019
de3ae6d
Housekeeping
kputnam Jun 24, 2019
f9a44aa
Hook the new tokenizer up to the existing parser
kputnam Jul 17, 2019
d06579e
Eliminate ~540MB of allocations from benchmark
kputnam Jul 19, 2019
2a61864
Rename native extension to reader/native_ext, strncmp to substr_eq?;
kputnam Jul 21, 2019
edd0f6e
Further performance improvements! Use reflection to specialize the
kputnam Jul 22, 2019
a908f9d
Fix C90 compilation warnings about declarations and assignments
kputnam Jul 22, 2019
6dea808
Fix build error
kputnam Jul 22, 2019
99bfef9
Commit summary forthcoming
kputnam Jul 30, 2019
5230a3b
Commit summary forthcoming
kputnam Sep 11, 2019
0aa0cf0
Write specs for memory allocations in StringPtr operations
kputnam Sep 12, 2019
6b82c4f
Eliminate implicit Array allocations from frequently-called constructors
kputnam Sep 13, 2019
2953357
More StringPtr specs
kputnam Sep 14, 2019
704589a
Housekeeping
kputnam Sep 17, 2019
7d0a032
Remove dependency on memory_profiler
kputnam Sep 17, 2019
3fe1d6b
Reduce benchmark allocations from 372MB to 213MB by rewriting input[n…
kputnam Sep 18, 2019
2a69df3
Write more specs for and tidy up Stupidedi::Reader::Tokenizer
kputnam Sep 22, 2019
925c777
Remove non-control characters from tokens before construction
kputnam Sep 24, 2019
9e91796
Fix syntax warnings and allocation specs
kputnam Sep 25, 2019
1ee5d59
Housekeeping
kputnam Sep 30, 2019
1ce9320
More housekeeping
kputnam Sep 30, 2019
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
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
Gemfile.lock
build/generated
.bundle
.ruby-version
lib/**/*.bundle
ext/**/Makefile
ext/**/*.o
ext/**/*.class
157 changes: 37 additions & 120 deletions .simplecov
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
require "base64"
require "simplecov-inline-html"
require "term/ansicolor"

# If you want to disable coverage, it's annoying to manually edit spec_helper.rb
# to comment-out `require "simplecov"`, then be certain not to commit that edit.
#
# Two other ways to accomplish this that don't require editing a tracked file:
# 1. Set/test a global ENV variable: `NOCOV=1 bundle exec rake spec`
# 2. Edit .rspec and add some flag. While RSpec doesn't have a way to let us
# add our own CLI options, we can sneak in via --tag '~coverage'.
#
# But #2 is tricky, because RSpec doesn't parse the options in .rspec until well
# after spec_helper.rb has executed. That means RSpec.configure {...} cannot
# check if '--tag ~coverage' was passed on the CLI or in .rspec file
#
# So, at best we can wait until after RSpec has run and peek at RSpec.world,
# which is the global configuration that's setup sometime after spec_helper.rb
# is executed. Then we can reconfigure the output of SimpleCov according to
# the RSpec filters.
#
# This handler must be registered *before* calling SimpleCov.start, because it
# registers its own at_exit handler that prints the results.
at_exit do
if RSpec.world.exclusion_filter.rules[:coverage] == true
SimpleCov.formatter = Class.new { def format(*args); end }
else
if defined?(SimpleCov::Formatter::CustomHtmlFormatter)
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::SummaryFormatter,
SimpleCov::Formatter::CustomHtmlFormatter])
else
SimpleCov.formatter = SimpleCov::Formatter::SummaryFormatter
end
end
end

SimpleCov.start do
coverage_dir "build/generated/coverage"

Expand All @@ -11,134 +43,19 @@ SimpleCov.start do
add_filter %r{/transaction_sets/[0-9]+/[A-Z0-9-]+\.rb}
add_filter %r{/stupidedi/editor}

add_group "Refinements", "lib/ruby"
add_group "Config", "lib/stupidedi/config"
add_group "Editor", "lib/stupidedi/editor"
add_group "Exceptions", "lib/stupidedi/exceptions"
add_group "Interchanges", "lib/stupidedi/interchanges"
add_group "Parser", "lib/stupidedi/parser"
add_group "Position", "lib/stupidedi/position"
add_group "Reader", "lib/stupidedi/reader"
add_group "Refinements", "lib/stupidedi/ruby"
add_group "Schema", "lib/stupidedi/schema"
add_group "Tokens", "lib/stupidedi/tokens"
add_group "TransactionSets", "lib/stupidedi/transaction_sets"
add_group "Values", "lib/stupidedi/values"
add_group "Versions", "lib/stupidedi/versions"
add_group "Writer", "lib/stupidedi/writer"
add_group "Zipper", "lib/stupidedi/zipper"
end

# Based on https://github.com/inossidabile/simplecov-summary/edit/master/lib/simplecov-summary.rb
class SimpleCov::Formatter::SummaryFormatter
def format(result)
puts "SimpleCov summary:"
name_width = (result.groups.keys + ["SUMMARY"]).map(&:length).max
count_width = result.groups.values.map(&:missed_lines).max.to_i.to_s.length

result.groups.sort.each do |name, files|
print_group(name, files, name_width, count_width)
end

print_group("SUMMARY", result.files, name_width, count_width)
end

def print_group(name, files, name_width, count_width)
pct = files.covered_percent
clr = case pct
when 90..100 then :green
when 80..90 then :yellow
else :red
end
puts Term::ANSIColor.send(clr,
(" % #{name_width}s: % 5s%% " +
"% #{count_width}s missed lines, " +
"% #{count_width + 2}s lines total") %
[name, pct.round(1), files.missed_lines.to_i, files.lines_of_code.to_i])
end
end

class SimpleCov::Formatter::CustomHtmlFormatter < SimpleCov::Formatter::InlineHTMLFormatter
def output_message(result)
end

# This image is missing from simplecov-inline-html
BORDER = <<-EOF.gsub(/\s/, '')
iVBORw0KGgoAAAANSUhEUgAAAAEAAABLCAIAAAA+tHrUAAAAUklEQVR4AcXH
sQ3AIAwFUfuDYADSMQkrMiVdqKGzLDnCRTaIUjzpjnvvodaKtRbM7KWqTkT4
PBF9Yu+NMQauUvx/Eu45Q0oJOWd3OsbomBmttQc0NiOlCz/4pgAAAABJRU5E
rkJggg==
EOF

# This image is missing from simplecov-inline-html
CONTROLS = <<-EOF.gsub(/\s/, '')
iVBORw0KGgoAAAANSUhEUgAAAOEAAABLCAMAAACx6hDAAAABj1BMVEVPT0/e
3t7b29vS0tK7urq5uLjq6uqZmZmSkpJaWlrU1NTj4+PFxcWvr6+goKBbW1u3
t7c9PT27u7vCwsKsrKxiYWGqqqq5ublbWlpeXV2Xl5fExMSbmpq6ubmNjY18
fHzy8vIrKystLS0sLCxNTU0uLi4wMDDNzc05OTns6+vl5eUvLy/q6ekqKipM
TExDQ0M4ODgyMjI2NjbZ2dk6OjrY2NjMzMxLS0vAwMBCQkLo5+dHR0cxMTFK
SkpBQUHv7u43NzdISEhFRUVRUVHx8fE7Ozs8PDwzMzNJSUnp6elGRkZQUFDr
6upeXl7t7e1gYGCoqKjv7+81NTWKiorn5uZERESCgoJdXV3p6OhOTk51dXVA
QEA+Pj6np6fu7e2+vr5cXFxSUlKJiYnOzs7s7OxTU1P29vbw8PB2dnZfX1/m
5eV4eHifn59qamqmpqbQ0NCOjo7Kysqzs7P4+PiDg4Otra3z8/M/Pz80NDSr
q6u/v7/Pz890dHRpaWmBgYH5+fn08/NoaGjPzs7///+ioqIRuwm9AAAGF0lE
QVR4AcTWd1PDNhQAcH8UDcszdvaOs0lCSNiQsCmjhe7d654fvE+y8QjGXAq+
vj+iu+enO/0iPdnSwdrx18f/YxzsfDDYkqrNtvp3Ynw1LrWbVWlrcCMdfLaz
XkSFh/rms1Vs6nFry+jBnEy0/DAWs414dPzxvwphynoRES6HBlpdWQOVh42Y
9RpetjEsou3QfwQPlnH/yO9XPD78wxs77yMcxMdLQh19vo9Wl7dE+zWUWQUa
UqECRA6sFE5DRCj/Gs2eC/XvMaUUX33jjejNQi7Zeilc56rwEh1bVozQsr7k
hCgQ4y4QObCLLSCGy39DlzFCSgihIBTjm4VcJyWFYEaEjT1jQSmOEWJMfzX2
Qt01AyClRFOHmaGqEZj1C8qEyxfGXuOZkDDGCAjF+Eah8J3Iss2jGg1bhCwD
EoiBENaaI4zQGCGF/KAS6i69XMCQZCUVqSUGk3ChPIuU9yvDzVSF3Gc7k14z
Pnq9iWPLnOgL79AuYaZpMiRi2zu2IgjP5y5QcHvC0aRQrYx2Rgo8o3Bggz9E
lNMLdJeekANtpzc9ytbbsVHPHk17VSD6wo7xAEBFUcz7+XxxfWpkxGH883ox
n9+LPCPHQXdB9+WIqbR4KCbJQUcGQq/8AXVWhaYnNN9BKDvN75Jm/Fjvu0QQ
igt/wIHugvmp+0nni6pZVKRFnpFQdwFRM1t5CJighYAgfCofGB810hGKLez9
kzzl03Z/YnvCJarxQ6fwFbtEXHOFWKS9vDiMhz5R3Wjlx+NxvrWhAjAs9Mtr
8CAQMk/I3kMoO9MvkqfcnmebjuwK9aKFCQMgrDcfFRIX7uYJtoJezKBHT/gJ
3KNhYai8rKckhC3M/pw8RS2d9R1Z8vcQKCCJ38M8j5g9VMQDZXUPRdbfw3RO
6Um1Wb99RZg7P5rYILx56kO/33gf1qJ9KODRPlRL/k2jqdE+9MoHxdT6UDqp
TtuvCCuFUZY3ohCKuxSIobt0FrlLW/CAfBu5SzWgu2EyLXqXivIU71J+0Tj9
s9eE+6N6z+ZTEt6HHSRC5LXdyPswRxikNx7hBzY9F34finKym9770BX+sKaQ
f9NoLOGbRg19pOjFLiYQmopUjUDgbnHlm+bf9u33tWkgjAP4VvUak251/v79
RCashUBhTGQV1zBtVLoX3dy0s0OmDETfGmhfCv3HzZPlSp7suKPFcL153zfZ
2BH2IT/unnAPDi9ZuKEQjrtcqF6XrgvXpevJlQuSq4mlwhc/yA8Xr0sTOQrx
qEU4W23Ry9cWzwq1xSd1baFHSOtDWcGH5VM4rQ/DeepDDULMh7lq/Bfz1vga
hPq/05Qr1BArtML/UGjfNIO3TDBbeMLZgk1nC4/OFkw8W0yWMZM/2bGjacav
xYIZP964OOMzJ65kM34l7iNRMhzTnABm+Xd21LRqWwEQCAFuIIECAZCYAgGQ
mBu+4n9dRGF7n1UBxEJYZWTljcCUGKRAJAb54VW23144If9fxUJwKvnqycOh
SPQr2U/eHhn+EYeXLHzkS3OrIDzza5BG8EX43FDLV8AcVoWMmquAIU3NPytZ
ePuKNHepsMP6cB6nmqTPgvRmXMVfHMCQp6vNiVNguyiEvt8pV3j1lzTXckJ8
4TtA4qZfolwgwaeLEimQCsHxfrQXRDjw3RgUQk45pEQKpEKIXf4H3cKmB6AQ
8uS/COMzSN+jRIjxmpf+Gh5e7ueQ6X0OFe/SPfPfpf9oPozp7UvnQ73C2dc0
g9nXNFqF5q9L1UJ9tYUGoaI+dP1Af304u1B/ja9DqOs7TflCDTFCaIVWaIVW
aIVWaIVWaIVWaIVDlfAgMlTI95eqhPc2oxYKvxkp7OEO2pvyUz8JcY+wsULc
5+3IT/20MeL7vE0ULj1/vzt8LDvzwzDaxr36xgqTreytk607Pz+f1u9fL6Re
P31wEkZD7LcwVJjepq9ftUZRY3P87mLGB2EjGh4ll9Bg4RISj3ZGa93uVjHd
brQ22uFAI4WK1i7s69rFxq7j3htzhfL2vKQ37yU25+ElNFJIWiwxgv7KY95g
aaaQG3vyHlkEmitEI0bV52yikOe7KnygYcK/0sK5wtrjpuMAAAAASUVORK5C
YII=
EOF

def file(path)
if path.end_with?("application.css")
css = super(path)
css.gsub!("url(colorbox/border.png)", "url(data:image/png;base64,#{BORDER})")
css.gsub!("url(colorbox/controls.png)", "url(data:image/png;base64,#{CONTROLS})")

# Fit more stuff without scroll bars, don't linewrap filenames
css << <<-EOF
body { padding:0 !important; }
.src_link { white-space:nowrap; }
.file_list { font-size: .8rem; }
.ui-icon { width:0px !important; height:0px !important; }
th { font-size:.7rem; overflow:hidden; white-space:normal !important; }
EOF
css
else
super(path)
end
end
end

SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::SummaryFormatter,
SimpleCov::Formatter::CustomHtmlFormatter
])
end unless ENV.include?("NOCOV")
71 changes: 45 additions & 26 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,57 @@
language: ruby
cache: bundler

before_install:
# https://docs.travis-ci.com/user/languages/ruby/#bundler-20
- if [[ $(ruby -v) < "ruby 2.3" ]];
then
gem install bundler -v "< 2";
else
gem update --system;
gem install bundler;
bundle install;
bundle update --bundler;
fi

env:
- NOCOV=1

os:
- osx
- linux
# windows

rvm:
# 2.0.0
- 2.1.0
- 2.1.1
- 2.1.2
- 2.1.3
- 2.1.4
- 2.1.5
- 2.1.6
- 2.1.7
- 2.1.8
- 2.2.0
- 2.2.1
- 2.2.2
- 2.2.3
- 2.2.4
- 2.3.0
- 2.3.1
- 2.3.2
- 2.3.3
- 2.4.1
- 2.4.3
- 2.5.0
- 2.5.1
- 2.5.3
- 2.6.3
- 2.7.0-preview1
# 2.0.0
# 2.1.0
# 2.1.1
# 2.1.2
# 2.1.3
# 2.1.4
# 2.1.5
# 2.1.6
# 2.1.7
- 2.1.8
# 2.2.0
# 2.2.1
# 2.2.2
# 2.2.3
- 2.2.4
# 2.3.0
# 2.3.1
# 2.3.2
- 2.3.3
# 2.4.1
- 2.4.3
# 2.5.0
# 2.5.1
- 2.5.3
- 2.6.3

# NOTE: Travis CI is limited to 200 entries in the build matrix
# matrix:
# exclude:
# - os: linux
# rvm: 2.1.8
# - os: windows
# rvm: 2.6.3
14 changes: 10 additions & 4 deletions .yardopts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
--load ./build/doc/lib/meta-plugin/lib/yard-meta.rb
--asset doc/images:images
--files doc/**/*.md
--exclude 'element_defs\.rb'
--exclude 'segment_defs\.rb'
--exclude 'segment_defs\/'

--exclude '/editor'
--exclude '/guides.rb'
--exclude '/contrib.rb'
--exclude '/versions/functional_groups.rb'

--exclude '/versions/[0-9]'
--exclude '/interchanges/[0-9]'
--exclude '/transaction_sets/[0-9]'

lib/**/*.rb
spec/examples/**/*_spec.rb
spec/**/*_spec.rb
39 changes: 14 additions & 25 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
source "http://rubygems.org"

gem "cantor", "~> 1.2.1"
gemspec(path: "build/gemspec", name: "stupidedi")
gemspec(path: "build/gemspec", name: "stupidedi-core")
gemspec(path: "build/gemspec", name: "stupidedi-defs")
gemspec(path: "build/gemspec", name: "stupidedi-exts")

group :development do
gem "rake"
gem "term-ansicolor"
gem "yard", "= 0.9.16"
gem "rdiscount", "~> 2.2"

gem "rspec", "3.8.0"
gem "rspec-collection_matchers"

gem "yard","~> 0.9.12"
# gem "redcarpet","~> 3.4.0", :platforms => [:mri]

# https://github.com/colszowka/simplecov#ruby-version-compatibility
gem "simplecov", :platforms => [:ruby_24, :ruby_25]
gem "simplecov-inline-html", :platforms => [:ruby_24, :ruby_25]

# gem "stackprof"
# gem "fasterer"
# gem "benchmark-ips"
# gem "memory_profiler"
# gem "allocation_stats"
# gem "heapy"

# We're using a patched version installed in yard/ until the
# maintainer improves the plugin. The patch has been submitted
# to the author.
#
# gem "yard-rspec", "~> 0.1"
gem "irb"# "~> 1.0"
gem "rake", "~> 12.3"
gem "rspec", "~> 3.8"
# gem "rspec-collection_matchers"# " "
# gem "stackprof", "~> 0.2"
# gem "benchmark-ips"# ""
gem "simplecov"# ""
gem "simplecov-inline-html" if RUBY_VERSION >= "2.4"
end
50 changes: 0 additions & 50 deletions Gemfile.lock

This file was deleted.

File renamed without changes.
Loading