panko_serializer 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.clang-format +102 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +22 -0
- data/.travis.yml +8 -0
- data/Gemfile +36 -0
- data/LICENSE.txt +21 -0
- data/README.md +8 -0
- data/Rakefile +62 -0
- data/benchmarks/BENCHMARKS.md +48 -0
- data/benchmarks/allocs.rb +23 -0
- data/benchmarks/app.rb +13 -0
- data/benchmarks/benchmarking_support.rb +43 -0
- data/benchmarks/bm_active_model_serializers.rb +45 -0
- data/benchmarks/bm_controller.rb +81 -0
- data/benchmarks/bm_panko_json.rb +60 -0
- data/benchmarks/bm_panko_object.rb +69 -0
- data/benchmarks/profile.rb +88 -0
- data/benchmarks/sanity.rb +67 -0
- data/benchmarks/setup.rb +62 -0
- data/benchmarks/type_casts/bm_active_record.rb +57 -0
- data/benchmarks/type_casts/bm_panko.rb +67 -0
- data/benchmarks/type_casts/bm_pg.rb +35 -0
- data/benchmarks/type_casts/support.rb +16 -0
- data/ext/panko_serializer/attributes_iterator.c +62 -0
- data/ext/panko_serializer/attributes_iterator.h +17 -0
- data/ext/panko_serializer/extconf.rb +8 -0
- data/ext/panko_serializer/panko_serializer.c +189 -0
- data/ext/panko_serializer/panko_serializer.h +17 -0
- data/ext/panko_serializer/serialization_descriptor.c +166 -0
- data/ext/panko_serializer/serialization_descriptor.h +30 -0
- data/ext/panko_serializer/time_conversion.c +94 -0
- data/ext/panko_serializer/time_conversion.h +6 -0
- data/ext/panko_serializer/type_cast.c +271 -0
- data/ext/panko_serializer/type_cast.h +74 -0
- data/lib/panko/array_serializer.rb +40 -0
- data/lib/panko/cache.rb +35 -0
- data/lib/panko/serialization_descriptor.rb +119 -0
- data/lib/panko/serializer.rb +57 -0
- data/lib/panko/version.rb +4 -0
- data/lib/panko.rb +8 -0
- data/panko_serializer.gemspec +31 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 30e3e534552c9c7592b512b679460e53de9eae33
|
4
|
+
data.tar.gz: a0a70502582161816691ba9aaa327ed17695bf8c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 26d0cf119bad48ec684ce49fc8c6413d3a35e976ca135c96d37d7d6e738f19f00f23225195873289bfa5aff3f6059c27bb8bf54fd3f881d75c3e57b4b3da6847
|
7
|
+
data.tar.gz: d55cb3c5e156c2f4d64ac67ac9429328d3476944876cdfe4a41ef0b149bd78a636b229061d9648d5a0a9eb3eca79ea68000ab0a6f7ca9d0b472be9163b546903
|
data/.clang-format
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
---
|
2
|
+
Language: Cpp
|
3
|
+
# BasedOnStyle: Chromium
|
4
|
+
AccessModifierOffset: -1
|
5
|
+
AlignAfterOpenBracket: Align
|
6
|
+
AlignConsecutiveAssignments: false
|
7
|
+
AlignConsecutiveDeclarations: false
|
8
|
+
AlignEscapedNewlines: Left
|
9
|
+
AlignOperands: true
|
10
|
+
AlignTrailingComments: true
|
11
|
+
AllowAllParametersOfDeclarationOnNextLine: false
|
12
|
+
AllowShortBlocksOnASingleLine: false
|
13
|
+
AllowShortCaseLabelsOnASingleLine: false
|
14
|
+
AllowShortFunctionsOnASingleLine: Inline
|
15
|
+
AllowShortIfStatementsOnASingleLine: false
|
16
|
+
AllowShortLoopsOnASingleLine: false
|
17
|
+
AlwaysBreakAfterDefinitionReturnType: None
|
18
|
+
AlwaysBreakAfterReturnType: None
|
19
|
+
AlwaysBreakBeforeMultilineStrings: true
|
20
|
+
AlwaysBreakTemplateDeclarations: true
|
21
|
+
BinPackArguments: true
|
22
|
+
BinPackParameters: false
|
23
|
+
BraceWrapping:
|
24
|
+
AfterClass: false
|
25
|
+
AfterControlStatement: false
|
26
|
+
AfterEnum: false
|
27
|
+
AfterFunction: false
|
28
|
+
AfterNamespace: false
|
29
|
+
AfterObjCDeclaration: false
|
30
|
+
AfterStruct: false
|
31
|
+
AfterUnion: false
|
32
|
+
BeforeCatch: false
|
33
|
+
BeforeElse: false
|
34
|
+
IndentBraces: false
|
35
|
+
SplitEmptyFunctionBody: true
|
36
|
+
BreakBeforeBinaryOperators: None
|
37
|
+
BreakBeforeBraces: Attach
|
38
|
+
BreakBeforeInheritanceComma: false
|
39
|
+
BreakBeforeTernaryOperators: true
|
40
|
+
BreakConstructorInitializersBeforeComma: false
|
41
|
+
BreakConstructorInitializers: BeforeColon
|
42
|
+
BreakAfterJavaFieldAnnotations: false
|
43
|
+
BreakStringLiterals: true
|
44
|
+
ColumnLimit: 80
|
45
|
+
CommentPragmas: '^ IWYU pragma:'
|
46
|
+
CompactNamespaces: false
|
47
|
+
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
48
|
+
ConstructorInitializerIndentWidth: 4
|
49
|
+
ContinuationIndentWidth: 4
|
50
|
+
Cpp11BracedListStyle: true
|
51
|
+
DerivePointerAlignment: false
|
52
|
+
DisableFormat: false
|
53
|
+
ExperimentalAutoDetectBinPacking: false
|
54
|
+
FixNamespaceComments: true
|
55
|
+
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
56
|
+
IncludeCategories:
|
57
|
+
- Regex: '^<.*\.h>'
|
58
|
+
Priority: 1
|
59
|
+
- Regex: '^<.*'
|
60
|
+
Priority: 2
|
61
|
+
- Regex: '.*'
|
62
|
+
Priority: 3
|
63
|
+
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
64
|
+
IndentCaseLabels: true
|
65
|
+
IndentWidth: 2
|
66
|
+
IndentWrappedFunctionNames: false
|
67
|
+
JavaScriptQuotes: Leave
|
68
|
+
JavaScriptWrapImports: true
|
69
|
+
KeepEmptyLinesAtTheStartOfBlocks: false
|
70
|
+
MacroBlockBegin: ''
|
71
|
+
MacroBlockEnd: ''
|
72
|
+
MaxEmptyLinesToKeep: 1
|
73
|
+
NamespaceIndentation: None
|
74
|
+
ObjCBlockIndentWidth: 2
|
75
|
+
ObjCSpaceAfterProperty: false
|
76
|
+
ObjCSpaceBeforeProtocolList: false
|
77
|
+
PenaltyBreakAssignment: 2
|
78
|
+
PenaltyBreakBeforeFirstCallParameter: 1
|
79
|
+
PenaltyBreakComment: 300
|
80
|
+
PenaltyBreakFirstLessLess: 120
|
81
|
+
PenaltyBreakString: 1000
|
82
|
+
PenaltyExcessCharacter: 1000000
|
83
|
+
PenaltyReturnTypeOnItsOwnLine: 200
|
84
|
+
PointerAlignment: Left
|
85
|
+
ReflowComments: true
|
86
|
+
SortIncludes: true
|
87
|
+
SpaceAfterCStyleCast: false
|
88
|
+
SpaceAfterTemplateKeyword: true
|
89
|
+
SpaceBeforeAssignmentOperators: true
|
90
|
+
SpaceBeforeParens: ControlStatements
|
91
|
+
SpaceInEmptyParentheses: false
|
92
|
+
SpacesBeforeTrailingComments: 2
|
93
|
+
SpacesInAngles: false
|
94
|
+
SpacesInContainerLiterals: true
|
95
|
+
SpacesInCStyleCastParentheses: false
|
96
|
+
SpacesInParentheses: false
|
97
|
+
SpacesInSquareBrackets: false
|
98
|
+
Standard: Auto
|
99
|
+
TabWidth: 8
|
100
|
+
UseTab: Never
|
101
|
+
...
|
102
|
+
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisabledByDefault: true
|
3
|
+
TargetRubyVersion: 2.4.1
|
4
|
+
DisplayCopNames: true
|
5
|
+
StyleGuideCopsOnly: false
|
6
|
+
|
7
|
+
Metrics/LineLength:
|
8
|
+
Max: 120
|
9
|
+
|
10
|
+
Style/StringLiterals:
|
11
|
+
EnforcedStyle: double_quotes
|
12
|
+
|
13
|
+
Style/FrozenStringLiteralComment:
|
14
|
+
Enabled: true
|
15
|
+
EnforcedStyle: always
|
16
|
+
|
17
|
+
Layout/TrailingBlankLines:
|
18
|
+
Enabled: true
|
19
|
+
|
20
|
+
Layout/TrailingWhitespace:
|
21
|
+
Enabled: true
|
22
|
+
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
source "https://rubygems.org"
|
3
|
+
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
version = "4.2"
|
7
|
+
gem_version = "~> #{version}.9"
|
8
|
+
|
9
|
+
gem "rails", gem_version
|
10
|
+
gem "railties", gem_version
|
11
|
+
gem "activesupport", gem_version
|
12
|
+
gem "activemodel", gem_version
|
13
|
+
gem "actionpack", gem_version
|
14
|
+
gem "activerecord", gem_version, group: :test
|
15
|
+
|
16
|
+
group :benchmarks do
|
17
|
+
gem "sqlite3"
|
18
|
+
gem "pg"
|
19
|
+
|
20
|
+
gem "memory_profiler"
|
21
|
+
gem "ruby-prof"
|
22
|
+
gem "ruby-prof-flamegraph"
|
23
|
+
|
24
|
+
gem "benchmark-ips"
|
25
|
+
gem "active_model_serializers", "0.9.7"
|
26
|
+
|
27
|
+
gem "terminal-table"
|
28
|
+
end
|
29
|
+
|
30
|
+
group :test do
|
31
|
+
gem "faker"
|
32
|
+
end
|
33
|
+
|
34
|
+
group :development do
|
35
|
+
gem "byebug"
|
36
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Yosi Attias
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
require "json"
|
5
|
+
require "terminal-table"
|
6
|
+
require "rake/extensiontask"
|
7
|
+
|
8
|
+
gem = Gem::Specification.load( File.dirname(__FILE__) + "/panko_serializer.gemspec" )
|
9
|
+
|
10
|
+
|
11
|
+
Rake::ExtensionTask.new("panko_serializer", gem) do |ext|
|
12
|
+
ext.lib_dir = "lib/panko"
|
13
|
+
end
|
14
|
+
|
15
|
+
Gem::PackageTask.new(gem) do |pkg|
|
16
|
+
pkg.need_zip = pkg.need_tar = false
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::RakeTask.new(:spec)
|
20
|
+
Rake::Task[:spec].prerequisites << :compile
|
21
|
+
|
22
|
+
task default: :spec
|
23
|
+
|
24
|
+
|
25
|
+
def run_benchmarks(files, items_count: 14_000)
|
26
|
+
headings = ["Benchmark", "ip/s", "allocs/retained"]
|
27
|
+
files.each do |benchmark_file|
|
28
|
+
output = `ITEMS_COUNT=#{items_count} RAILS_ENV=production ruby #{benchmark_file}`
|
29
|
+
|
30
|
+
rows = output.each_line.map do |line|
|
31
|
+
result = JSON.parse(line)
|
32
|
+
result.values
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "\n\n"
|
36
|
+
title = File.basename(benchmark_file, ".rb")
|
37
|
+
table = Terminal::Table.new title: title, headings: headings, rows: rows
|
38
|
+
puts table
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Run all benchmarks"
|
43
|
+
task :benchmarks do
|
44
|
+
run_benchmarks Dir[File.join(__dir__, "benchmarks", "**", "bm_*")]
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Type Casts - Benchmarks"
|
48
|
+
task :bm_type_casts do
|
49
|
+
run_benchmarks Dir[File.join(__dir__, "benchmarks", "type_casts", "bm_*")]
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Sanity Benchmarks"
|
53
|
+
task :sanity do
|
54
|
+
puts Time.now.strftime("%d/%m %H:%M:%S")
|
55
|
+
puts "=========================="
|
56
|
+
|
57
|
+
run_benchmarks [
|
58
|
+
File.join(__dir__, "benchmarks", "sanity.rb")
|
59
|
+
], items_count: 2300
|
60
|
+
|
61
|
+
puts "\n\n"
|
62
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
## Initial state
|
2
|
+
```
|
3
|
+
Native_Posts_2300 57 ip/s 13802 allocs/op
|
4
|
+
Native_Posts_50 2956 ip/s 302 allocs/op
|
5
|
+
|
6
|
+
AMS_Simple_Posts_2300 21 ip/s 94309 allocs/op
|
7
|
+
AMS_Simple_Posts_50 1008 ip/s 2059 allocs/op
|
8
|
+
AMS_HasOne_Posts_2300 9 ip/s 147209 allocs/op
|
9
|
+
AMS_HasOne_Posts_50 451 ip/s 3209 allocs/op
|
10
|
+
|
11
|
+
Panko_HasOne_Posts_2300 164 ip/s 2372 allocs/op
|
12
|
+
Panko_HasOne_Posts_50 6118 ip/s 122 allocs/op
|
13
|
+
Panko_Reused_HasOne_Posts_2300 178 ip/s 2303 allocs/op
|
14
|
+
Panko_Reused_HasOne_Posts_50 8203 ip/s 53 allocs/op
|
15
|
+
|
16
|
+
Panko_Simple_Posts_2300 150 ip/s 2372 allocs/op
|
17
|
+
Panko_Simple_Posts_50 5639 ip/s 122 allocs/op
|
18
|
+
Panko_Reused_Simple_Posts_2300 180 ip/s 2303 allocs/op
|
19
|
+
Panko_Reused_Simple_Posts_50 8388 ip/s 53 allocs/op
|
20
|
+
```
|
21
|
+
|
22
|
+
## Refactorings, method call support, combining
|
23
|
+
|
24
|
+
### class eval
|
25
|
+
```
|
26
|
+
Panko_HasOne_Posts_2300 64 ip/s 9477 allocs/op
|
27
|
+
Panko_HasOne_Posts_50 2397 ip/s 477 allocs/op
|
28
|
+
Panko_Reused_HasOne_Posts_2300 70 ip/s 9423 allocs/op
|
29
|
+
Panko_Reused_HasOne_Posts_50 2596 ip/s 423 allocs/op
|
30
|
+
|
31
|
+
Panko_Simple_Posts_2300 191 ip/s 2472 allocs/op
|
32
|
+
Panko_Simple_Posts_50 5128 ip/s 222 allocs/op
|
33
|
+
Panko_Reused_Simple_Posts_2300 180 ip/s 2418 allocs/op
|
34
|
+
Panko_Reused_Simple_Posts_50 5534 ip/s 168 allocs/op
|
35
|
+
```
|
36
|
+
|
37
|
+
### instance eval
|
38
|
+
```
|
39
|
+
Panko_HasOne_Posts_2300 60 ip/s 9473 allocs/op
|
40
|
+
Panko_HasOne_Posts_50 2399 ip/s 473 allocs/op
|
41
|
+
Panko_Reused_HasOne_Posts_2300 66 ip/s 9419 allocs/op
|
42
|
+
Panko_Reused_HasOne_Posts_50 2582 ip/s 419 allocs/op
|
43
|
+
|
44
|
+
Panko_Simple_Posts_2300 195 ip/s 2470 allocs/op
|
45
|
+
Panko_Simple_Posts_50 4838 ip/s 220 allocs/op
|
46
|
+
Panko_Reused_Simple_Posts_2300 196 ip/s 2416 allocs/op
|
47
|
+
Panko_Reused_Simple_Posts_50 6241 ip/s 166 allocs/op
|
48
|
+
```
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require_relative "./benchmarking_support"
|
4
|
+
require_relative "./app"
|
5
|
+
require_relative "./setup"
|
6
|
+
|
7
|
+
require "memory_profiler"
|
8
|
+
|
9
|
+
class PostFastSerializer < Panko::Serializer
|
10
|
+
attributes :id, :body, :title, :author_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def count_allocs(&block)
|
14
|
+
memory_report = MemoryProfiler.report(&block)
|
15
|
+
puts memory_report.pretty_print
|
16
|
+
end
|
17
|
+
|
18
|
+
posts = Post.all.to_a
|
19
|
+
merged_options = {}.merge(each_serializer: PostFastSerializer)
|
20
|
+
posts_array_serializer = Panko::ArraySerializer.new([], merged_options)
|
21
|
+
|
22
|
+
# prints out 18402
|
23
|
+
count_allocs { posts_array_serializer.serialize_to_json posts }
|
data/benchmarks/app.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
|
5
|
+
require "rails"
|
6
|
+
require "active_model"
|
7
|
+
require "active_support"
|
8
|
+
require "active_support/json"
|
9
|
+
require "action_controller"
|
10
|
+
require "action_controller/railtie"
|
11
|
+
|
12
|
+
require "active_model_serializers"
|
13
|
+
require "panko"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "benchmark/ips"
|
3
|
+
require "json"
|
4
|
+
require "memory_profiler"
|
5
|
+
|
6
|
+
module Benchmark
|
7
|
+
module ActiveModelSerializers
|
8
|
+
def data
|
9
|
+
posts = Post.all.includes(:author).to_a
|
10
|
+
posts_50 = posts.first(50).to_a
|
11
|
+
{ all: posts, small: posts_50 }
|
12
|
+
end
|
13
|
+
|
14
|
+
def ams(label = nil, time: 10, disable_gc: true, warmup: 3, &block)
|
15
|
+
fail ArgumentError.new, "block should be passed" unless block_given?
|
16
|
+
|
17
|
+
GC.start
|
18
|
+
|
19
|
+
if disable_gc
|
20
|
+
GC.disable
|
21
|
+
else
|
22
|
+
GC.enable
|
23
|
+
end
|
24
|
+
|
25
|
+
memory_report = MemoryProfiler.report(&block)
|
26
|
+
|
27
|
+
report = Benchmark.ips(time, warmup, true) do |x|
|
28
|
+
x.report(label) { yield }
|
29
|
+
end
|
30
|
+
|
31
|
+
results = {
|
32
|
+
label: label,
|
33
|
+
ips: ActiveSupport::NumberHelper.number_to_delimited(report.entries.first.ips.round(2)),
|
34
|
+
allocs: "#{memory_report.total_allocated}/#{memory_report.total_retained}"
|
35
|
+
}.to_json
|
36
|
+
|
37
|
+
puts results
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
extend Benchmark::ActiveModelSerializers
|
43
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./benchmarking_support"
|
3
|
+
require_relative "./app"
|
4
|
+
require_relative "./setup"
|
5
|
+
|
6
|
+
class AmsAuthorFastSerializer < ActiveModel::Serializer
|
7
|
+
attributes :id, :name
|
8
|
+
end
|
9
|
+
|
10
|
+
class AmsPostFastSerializer < ActiveModel::Serializer
|
11
|
+
attributes :id, :body, :title, :author_id
|
12
|
+
end
|
13
|
+
|
14
|
+
class AmsPostWithHasOneFastSerializer < ActiveModel::Serializer
|
15
|
+
attributes :id, :body, :title, :author_id
|
16
|
+
|
17
|
+
has_one :author, serializer: AmsAuthorFastSerializer
|
18
|
+
end
|
19
|
+
|
20
|
+
def benchmark_ams(prefix, serializer, options = {})
|
21
|
+
merged_options = options.merge(each_serializer: serializer)
|
22
|
+
|
23
|
+
data = Benchmark.data
|
24
|
+
posts = data[:all]
|
25
|
+
posts_50 = data[:small]
|
26
|
+
|
27
|
+
|
28
|
+
Benchmark.ams("AMS_#{prefix}_Posts_#{posts.count}") do
|
29
|
+
ActiveModel::ArraySerializer.new(posts, merged_options).serializable_object
|
30
|
+
end
|
31
|
+
|
32
|
+
data = Benchmark.data
|
33
|
+
posts = data[:all]
|
34
|
+
posts_50 = data[:small]
|
35
|
+
|
36
|
+
Benchmark.ams("AMS_#{prefix}_Posts_50") do
|
37
|
+
ActiveModel::ArraySerializer.new(posts_50, merged_options).serializable_object
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
benchmark_ams "HasOne", AmsPostWithHasOneFastSerializer
|
43
|
+
benchmark_ams "Simple", AmsPostFastSerializer
|
44
|
+
benchmark_ams "Except", AmsPostWithHasOneFastSerializer, except: [:title]
|
45
|
+
benchmark_ams "Include", AmsPostWithHasOneFastSerializer, include: [:id, :body, :author_id, :author]
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./benchmarking_support"
|
3
|
+
require_relative "./app"
|
4
|
+
require_relative "./setup"
|
5
|
+
|
6
|
+
class NullLogger < Logger
|
7
|
+
def initialize(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(*args, &block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class BenchmarkApp < Rails::Application
|
15
|
+
routes.append do
|
16
|
+
get "/simple" => "main#simple"
|
17
|
+
get "/text" => "main#text"
|
18
|
+
|
19
|
+
get "/serialize_to_string" => "main#serialize_to_string"
|
20
|
+
end
|
21
|
+
|
22
|
+
config.secret_token = "s"*30
|
23
|
+
config.secret_key_base = "foo"
|
24
|
+
config.consider_all_requests_local = false
|
25
|
+
|
26
|
+
# simulate production
|
27
|
+
config.cache_classes = true
|
28
|
+
config.eager_load = true
|
29
|
+
config.action_controller.perform_caching = true
|
30
|
+
|
31
|
+
# otherwise deadlock occured
|
32
|
+
config.middleware.delete "Rack::Lock"
|
33
|
+
|
34
|
+
# to disable log files
|
35
|
+
config.logger = NullLogger.new
|
36
|
+
config.active_support.deprecation = :log
|
37
|
+
end
|
38
|
+
|
39
|
+
BenchmarkApp.initialize!
|
40
|
+
|
41
|
+
class AuthorFastSerializer < Panko::Serializer
|
42
|
+
attributes :id, :name
|
43
|
+
end
|
44
|
+
|
45
|
+
class PostWithHasOneFastSerializer < Panko::Serializer
|
46
|
+
attributes :id, :body, :title, :author_id
|
47
|
+
|
48
|
+
has_one :author, serializer: AuthorFastSerializer
|
49
|
+
end
|
50
|
+
|
51
|
+
class MainController < ActionController::Base
|
52
|
+
def text
|
53
|
+
render text: '{"ok":true}'.freeze, content_type: "application/json".freeze
|
54
|
+
end
|
55
|
+
|
56
|
+
def simple
|
57
|
+
render json: { ok: true }
|
58
|
+
end
|
59
|
+
|
60
|
+
def serialize_to_string
|
61
|
+
data = Benchmark.data[:all]
|
62
|
+
render text: Panko::ArraySerializer.new(data, each_serializer: PostWithHasOneFastSerializer).to_json, content_type: "application/json".freeze
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RouteNotFoundError < StandardError;end
|
67
|
+
|
68
|
+
|
69
|
+
def request(method, path)
|
70
|
+
response = Rack::MockRequest.new(BenchmarkApp).send(method, path)
|
71
|
+
if response.status.in?([404, 500])
|
72
|
+
raise RouteNotFoundError.new, 'not found #{method.to_s.upcase} #{path}'
|
73
|
+
end
|
74
|
+
response
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
Benchmark.ams("text") { request(:get, "/text") }
|
79
|
+
Benchmark.ams("simple") { request(:get, "/simple") }
|
80
|
+
|
81
|
+
Benchmark.ams("serialize_to_string") { request(:get, "/serialize_to_string") }
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./benchmarking_support"
|
3
|
+
require_relative "./app"
|
4
|
+
require_relative "./setup"
|
5
|
+
|
6
|
+
class AuthorFastSerializer < Panko::Serializer
|
7
|
+
attributes :id, :name
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class PostFastSerializer < Panko::Serializer
|
12
|
+
attributes :id, :body, :title, :author_id
|
13
|
+
end
|
14
|
+
|
15
|
+
class PostFastWithMethodCallSerializer < Panko::Serializer
|
16
|
+
attributes :id, :body, :title, :author_id, :method_call
|
17
|
+
|
18
|
+
def method_call
|
19
|
+
object.id * 2
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class PostWithHasOneFastSerializer < Panko::Serializer
|
24
|
+
attributes :id, :body, :title, :author_id
|
25
|
+
|
26
|
+
has_one :author, serializer: AuthorFastSerializer
|
27
|
+
end
|
28
|
+
|
29
|
+
class AuthorWithHasManyFastSerializer < Panko::Serializer
|
30
|
+
attributes :id, :name
|
31
|
+
|
32
|
+
has_many :posts, serializer: PostFastSerializer
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def benchmark(prefix, serializer, options = {})
|
37
|
+
data = Benchmark.data
|
38
|
+
posts = data[:all]
|
39
|
+
posts_50 = data[:small]
|
40
|
+
|
41
|
+
merged_options = options.merge(each_serializer: serializer)
|
42
|
+
|
43
|
+
Benchmark.ams("Panko_#{prefix}_Posts_#{posts.count}") do
|
44
|
+
Panko::ArraySerializer.new(posts, merged_options).to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
data = Benchmark.data
|
48
|
+
posts = data[:all]
|
49
|
+
posts_50 = data[:small]
|
50
|
+
|
51
|
+
Benchmark.ams("Panko_#{prefix}_Posts_50") do
|
52
|
+
Panko::ArraySerializer.new(posts_50, merged_options).to_json
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
benchmark "HasOne", PostWithHasOneFastSerializer
|
57
|
+
benchmark "Simple", PostFastSerializer
|
58
|
+
benchmark "SimpleWithMethodCall", PostFastWithMethodCallSerializer
|
59
|
+
benchmark "Except", PostWithHasOneFastSerializer, except: [:title]
|
60
|
+
benchmark "Include", PostWithHasOneFastSerializer, include: [:id, :body, :author_id, :author]
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./benchmarking_support"
|
3
|
+
require_relative "./app"
|
4
|
+
require_relative "./setup"
|
5
|
+
|
6
|
+
class AuthorFastSerializer < Panko::Serializer
|
7
|
+
attributes :id, :name
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class PostFastSerializer < Panko::Serializer
|
12
|
+
attributes :id, :body, :title, :author_id
|
13
|
+
end
|
14
|
+
|
15
|
+
class PostWithHasOneFastSerializer < Panko::Serializer
|
16
|
+
attributes :id, :body, :title, :author_id
|
17
|
+
|
18
|
+
has_one :author, serializer: AuthorFastSerializer
|
19
|
+
end
|
20
|
+
|
21
|
+
class AuthorWithHasManyFastSerializer < Panko::Serializer
|
22
|
+
attributes :id, :name
|
23
|
+
|
24
|
+
has_many :posts, serializer: PostFastSerializer
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def benchmark(prefix, serializer, options = {})
|
29
|
+
data = Benchmark.data
|
30
|
+
posts = data[:all]
|
31
|
+
posts_50 = data[:small]
|
32
|
+
|
33
|
+
merged_options = options.merge(each_serializer: serializer)
|
34
|
+
|
35
|
+
Benchmark.ams("Panko_#{prefix}_Posts_#{posts.count}") do
|
36
|
+
Panko::ArraySerializer.new(posts, merged_options).to_a
|
37
|
+
end
|
38
|
+
|
39
|
+
data = Benchmark.data
|
40
|
+
posts = data[:all]
|
41
|
+
posts_50 = data[:small]
|
42
|
+
|
43
|
+
Benchmark.ams("Panko_#{prefix}_Posts_50") do
|
44
|
+
Panko::ArraySerializer.new(posts_50, merged_options).to_a
|
45
|
+
end
|
46
|
+
|
47
|
+
posts_array_serializer = Panko::ArraySerializer.new([], merged_options)
|
48
|
+
|
49
|
+
data = Benchmark.data
|
50
|
+
posts = data[:all]
|
51
|
+
posts_50 = data[:small]
|
52
|
+
|
53
|
+
Benchmark.ams("Panko_Reused_#{prefix}_Posts_#{posts.count}") do
|
54
|
+
posts_array_serializer.serialize posts
|
55
|
+
end
|
56
|
+
|
57
|
+
data = Benchmark.data
|
58
|
+
posts = data[:all]
|
59
|
+
posts_50 = data[:small]
|
60
|
+
|
61
|
+
Benchmark.ams("Panko_Reused_#{prefix}_Posts_50") do
|
62
|
+
posts_array_serializer.serialize posts_50
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
benchmark "HasOne", PostWithHasOneFastSerializer
|
67
|
+
benchmark "Simple", PostFastSerializer
|
68
|
+
benchmark "Except", PostWithHasOneFastSerializer, except: [:title]
|
69
|
+
benchmark "Include", PostWithHasOneFastSerializer, include: [:id, :body, :author_id, :author]
|