commit 43c1518cfff680781b943075ceeb6ca61a3536dd Author: Preston Sego Date: Thu Aug 3 08:39:02 2017 -0400 compare ams with jsonapi-rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..42303d4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +*.gem +*.rbc +.bundle +.config +.yardoc +Gemfile.lock +Gemfile.local +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +Vagrantfile +.vagrant +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +*.swp +.ruby-version +.ruby-gemset +vendor/bundle +tags + +# silly macs +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..3ea519c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,100 @@ +## Have an issue? + +Before opening an issue, try the following: + +##### Consult the documentation + +See if your issue can be resolved by information in the [documentation](README.md). + +##### Check for an existing issue + +Take a look at the issues to see if a similar one has already been created. If +one exists, please add any additional information that might expedite +resolution. + +#### Open an issue + +If the documentation wasn't able to help resolve the issue and no issue already +exists, please open a new issue with the following in mind: + +- Please make sure only to include one issue per report. If you encounter + multiple, unrelated issues, please report them as such. +- Be detailed. Provide backtraces and example code when possible. Provide + information about your environment. e.g., Ruby version, rails version, etc. +- Own your issue. Actively participate in the discussion and help drive the + issue to closure. +- If you resolve your own issue, please share the details on the issue and close + it out. Others might have the same issue and sharing solutions is helpful. + +## Contributing + +Contributing can be done in many ways and is not exclusive to code. If you have +thoughts on a particular issue or feature, we encourage you to open new issues +for discussion or add your comments to existing ones. + +#### Pull requests + +We also gladly welcome pull requests. When preparing to work on pull request, +please adhere to these standards: + +- Base work on the relevant branch: + [0.10-stable](https://github.com/rails-api/active_model_serializers/tree/0-10-stable) + or + [0.9-stable](https://github.com/rails-api/active_model_serializers/tree/0-9-stable) + or + [0.8-stable](https://github.com/rails-api/active_model_serializers/tree/0-8-stable) +- Squash your commits and regularly rebase off master. +- Provide a description of the changes contained in the pull request. +- Note any specific areas that should be reviewed. +- Include tests. +- The test suite must pass on [supported Ruby versions](.travis.yml) +- Include updates to the [documentation](docs) + where applicable. +- Update the + [CHANGELOG](CHANGELOG.md) + to the appropriate sections with a brief description of the changes. +- Do not change the VERSION file. + +#### Running tests + +Run all tests + +`$ rake test` + +Run a single test suite + +`$ rake test TEST=path/to/test.rb` + +Run a single test + +`$ rake test TEST=path/to/test.rb TESTOPTS="--name=test_something"` + +Run tests against different Rails versions by setting the RAILS_VERSION variable +and bundling gems. (save this script somewhere executable and run from top of AMS repository) + +```bash +#!/usr/bin/env bash + +rcommand='puts YAML.load_file("./.travis.yml")["env"]["matrix"].join(" ").gsub("RAILS_VERSION=", "")' +versions=$(ruby -ryaml -e "$rcommand") + +for version in ${versions[@]}; do + export RAILS_VERSION="$version" + rm -f Gemfile.lock + bundle check || bundle --local || bundle + bundle exec rake test + if [ "$?" -eq 0 ]; then + # green in ANSI + echo -e "\033[32m **** Tests passed against Rails ${RAILS_VERSION} **** \033[0m" + else + # red in ANSI + echo -e "\033[31m **** Tests failed against Rails ${RAILS_VERSION} **** \033[0m" + read -p '[Enter] any key to continue, [q] to quit...' prompt + if [ "$prompt" = 'q' ]; then + unset RAILS_VERSION + exit 1 + fi +fi + unset RAILS_VERSION +done +``` diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 00000000..36841988 --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2014 Steve Klabnik + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..fa198daa --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# AMS Benchmarking + +## Benchmarks + +### Comparison with other Serialization Libraries + +``` +cd benchmarks/serialization_libraries +bundle install +bundle exec ruby benchmark +``` + + +## Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/benchmarks/serialization_libraries/Gemfile b/benchmarks/serialization_libraries/Gemfile new file mode 100644 index 00000000..1d84897e --- /dev/null +++ b/benchmarks/serialization_libraries/Gemfile @@ -0,0 +1,19 @@ +source 'https://rubygems.org' + +gem 'oj' +gem 'oj_mimic_json' + +gem 'rails', '> 5' +gem 'sqlite3' + +gem 'benchmark-ips', require: 'benchmark/ips' +gem "benchmark-memory" + +gem 'awesome_print' +gem 'pry-byebug' +gem 'kalibera' + + +# The Serialization libs benchmarked: +gem 'active_model_serializers' +gem 'jsonapi-rb' diff --git a/benchmarks/serialization_libraries/benchmark.rb b/benchmarks/serialization_libraries/benchmark.rb new file mode 100644 index 00000000..7d6830e8 --- /dev/null +++ b/benchmarks/serialization_libraries/benchmark.rb @@ -0,0 +1,36 @@ +require 'rails/all' +Bundler.require(*Rails.groups) + +ActiveRecord::Base.logger = nil +ActiveModelSerializers.logger = nil + +require './support/rails' +require './support/bench_helper' + +# AMS +require './support/serializers/user_serializer.rb' +require './support/serializers/post_serializer' +require './support/serializers/comment_serializer' +# jsonapi-rb +require 'jsonapi/serializable' +require './support/serializers/serializable_comment' +require './support/serializers/serializable_post' +require './support/serializers/serializable_user' + +GC.disable + +%i[ips memory].each do |bench| + BenchHelper.clear_data + BenchHelper.seed_data + + Benchmark.send(bench) do |x| + x.config(time: 10, warmup: 5, stats: :bootstrap, confidence: 95) if x.respond_to?(:config) + + x.report('ams ') { BenchHelper.test_render(:ams) } + x.report('jsonapi-rb ') { BenchHelper.test_render(:jsonapi_rb) } + x.report('ams eager') { BenchHelper.test_manual_eagerload(:ams) } + x.report('jsonapi-rb eager') { BenchHelper.test_manual_eagerload(:jsonapi_rb) } + + x.compare! + end +end diff --git a/benchmarks/serialization_libraries/support/bench.sqlite3 b/benchmarks/serialization_libraries/support/bench.sqlite3 new file mode 100644 index 00000000..a886ae03 Binary files /dev/null and b/benchmarks/serialization_libraries/support/bench.sqlite3 differ diff --git a/benchmarks/serialization_libraries/support/bench_helper.rb b/benchmarks/serialization_libraries/support/bench_helper.rb new file mode 100644 index 00000000..4a3f0b12 --- /dev/null +++ b/benchmarks/serialization_libraries/support/bench_helper.rb @@ -0,0 +1,64 @@ +module BenchHelper + module_function + + def clear_data + Comment.delete_all + Post.delete_all + User.delete_all + end + + def seed_data + data_config = { + comments_per_post: 2, + posts: 20 + } + + u = User.create(first_name: 'Diana', last_name: 'Prince', birthday: 3000.years.ago) + + data_config[:posts].times do + p = Post.create(user_id: u.id, title: 'Some Post', body: 'awesome content') + data_config[:comments_per_post].times do + Comment.create(author: 'me', comment: 'nice blog', post_id: p.id) + end + end + end + + def test_render(render_gem) + render_data( + User.first, + render_gem + ) + end + + def test_manual_eagerload(render_gem) + render_data( + # User.auto_include(false).includes(posts: [:comments]).first, + User.includes(posts: [:comments]).first, + render_gem + ) + end + + def render_data(data, render_gem) + return render_with_ams(data) if render_gem == :ams + + render_with_jsonapi_rb(data) + end + + def render_with_ams(data) + ActiveModelSerializers::SerializableResource.new( + data, + include: 'posts.comments', + # fields: params[:fields], + adapter: :json_api + ).as_json + end + + def render_with_jsonapi_rb(data) + JSONAPI::Serializable::SuccessRenderer.new.render( + data, + include: 'posts.comments', + # fields: params[:fields] || [], + class: SerializableUser + ) + end +end diff --git a/benchmarks/serialization_libraries/support/rails.rb b/benchmarks/serialization_libraries/support/rails.rb new file mode 100644 index 00000000..94ef7cda --- /dev/null +++ b/benchmarks/serialization_libraries/support/rails.rb @@ -0,0 +1,49 @@ +require 'sqlite3' +db_file = File.join(File.dirname(__FILE__), 'bench.sqlite3') +db = SQLite3::Database.new(db_file) +ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: db_file) + +ActiveRecord::Schema.define(version: 20_170_620_020_730) do + create_table 'comments', force: :cascade do |t| + t.integer 'post_id' + t.string 'author' + t.string 'comment' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['post_id'], name: 'index_comments_on_post_id' + end + + create_table 'posts', force: :cascade do |t| + t.integer 'user_id' + t.string 'title' + t.string 'body' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['user_id'], name: 'index_posts_on_user_id' + end + + create_table 'users', force: :cascade do |t| + t.string 'first_name' + t.string 'last_name' + t.datetime 'birthday' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end +end + +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end + +class Comment < ApplicationRecord + belongs_to :post +end + +class Post < ApplicationRecord + has_many :comments + belongs_to :user +end + +class User < ApplicationRecord + has_many :posts +end diff --git a/benchmarks/serialization_libraries/support/serializers/comment_serializer.rb b/benchmarks/serialization_libraries/support/serializers/comment_serializer.rb new file mode 100644 index 00000000..18591200 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/comment_serializer.rb @@ -0,0 +1,6 @@ +class CommentSerializer < ActiveModel::Serializer + attributes :id, + :author, :comment + + belongs_to :post#, serializer: PostSerializer +end diff --git a/benchmarks/serialization_libraries/support/serializers/post_serializer.rb b/benchmarks/serialization_libraries/support/serializers/post_serializer.rb new file mode 100644 index 00000000..7b6c6169 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/post_serializer.rb @@ -0,0 +1,8 @@ +class PostSerializer < ActiveModel::Serializer + attributes :id, + :title, :body, + :created_at, :updated_at + + belongs_to :user#, serializer: UserSerializer + has_many :comments#, each_serializer: CommentSerializer +end diff --git a/benchmarks/serialization_libraries/support/serializers/serializable_comment.rb b/benchmarks/serialization_libraries/support/serializers/serializable_comment.rb new file mode 100644 index 00000000..a6e72fc5 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/serializable_comment.rb @@ -0,0 +1,7 @@ +class SerializableComment < JSONAPI::Serializable::Resource + type 'comments' + + attributes :author, :comment + + belongs_to :post, class: 'SerializablePost' +end diff --git a/benchmarks/serialization_libraries/support/serializers/serializable_post.rb b/benchmarks/serialization_libraries/support/serializers/serializable_post.rb new file mode 100644 index 00000000..a63fe0d7 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/serializable_post.rb @@ -0,0 +1,9 @@ +class SerializablePost < JSONAPI::Serializable::Resource + type 'posts' + + attributes :title, :body, + :created_at, :updated_at + + belongs_to :user, class: 'SerializableUser' + has_many :comments, class: 'SerializableComment' +end diff --git a/benchmarks/serialization_libraries/support/serializers/serializable_user.rb b/benchmarks/serialization_libraries/support/serializers/serializable_user.rb new file mode 100644 index 00000000..7e2afb09 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/serializable_user.rb @@ -0,0 +1,9 @@ +class SerializableUser < JSONAPI::Serializable::Resource + type 'users' + + + attributes :first_name, :last_name, :birthday, + :created_at, :updated_at + + has_many :posts, class: 'SerializablePost' +end diff --git a/benchmarks/serialization_libraries/support/serializers/user_serializer.rb b/benchmarks/serialization_libraries/support/serializers/user_serializer.rb new file mode 100644 index 00000000..84135708 --- /dev/null +++ b/benchmarks/serialization_libraries/support/serializers/user_serializer.rb @@ -0,0 +1,7 @@ +class UserSerializer < ActiveModel::Serializer + attributes :id, + :first_name, :last_name, :birthday, + :created_at, :updated_at + + has_many :posts#, each_serializer: PostSerializer +end