allocation_stats 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58815fef555e954a433a92b7cef4eddd6858569a
4
- data.tar.gz: 6607ada6920ec63153e39418023e77d216eca304
3
+ metadata.gz: 1bab6c1d1c04a30dff3888fe15caf0c70dd4b270
4
+ data.tar.gz: 42e214b270edde7ff0829000f68b79c315837523
5
5
  SHA512:
6
- metadata.gz: 6d4da2e5ad7dc0257b91124fbd506e58dece431047d9e73aee0f20d251c1a462477b1cba0a44c483122be048b2d8b5826d67e83acdf2802174f22e576e622591
7
- data.tar.gz: 52e28c0ba9065822aef3bc575c00c39e1096603b26b610b6df5b912e70e5edd5e17db72bc88c4591f7df9e226201052b2fd42d775ead90ad30ca8c08286384ce
6
+ metadata.gz: 6cd17f62c21a31baec49f1d4e888d3bd05526a544ce77ace63dae4237c61a5d0f0f53195119a6c1ad0b3ac9ed9ae09e1b2519e7acbdbdb51e7406ed633f81feb
7
+ data.tar.gz: d52980763fdb7a9445b2ac2de36a8dc927aa0da69df5596841d275534acfddc9a85d7bf48f1e29a0a0e25ca8924f795292346b5017c6e31ba2b0de828fbd6faf
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
+ coverage
1
2
  doc
2
3
  .yardoc
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,9 @@
1
+ v0.1.3
2
+
3
+ * Fixed: BasicObjects can be tracked; fixes #1
4
+ * Added: much more documentation: up to 83%
5
+ * Fixed: Working with new frozen String keys
6
+
1
7
  v0.1.2
2
8
 
3
9
  * Added: `homepage` in the gemspec
data/Gemfile CHANGED
@@ -9,6 +9,7 @@ end
9
9
 
10
10
  group :test do
11
11
  gem "rspec"
12
+ gem "simplecov", require: false
12
13
  gem "pry"
13
14
 
14
15
  gem "yajl-ruby", "= 1.1.0"
data/Gemfile.lock CHANGED
@@ -3,7 +3,9 @@ GEM
3
3
  specs:
4
4
  coderay (1.0.9)
5
5
  diff-lcs (1.2.4)
6
+ docile (1.1.1)
6
7
  method_source (0.8.2)
8
+ multi_json (1.8.2)
7
9
  pry (0.9.12.2)
8
10
  coderay (~> 1.0.5)
9
11
  method_source (~> 0.8)
@@ -16,6 +18,11 @@ GEM
16
18
  rspec-expectations (2.13.0)
17
19
  diff-lcs (>= 1.1.3, < 2.0)
18
20
  rspec-mocks (2.13.1)
21
+ simplecov (0.8.2)
22
+ docile (~> 1.1.0)
23
+ multi_json
24
+ simplecov-html (~> 0.8.0)
25
+ simplecov-html (0.8.0)
19
26
  slop (3.4.6)
20
27
  yajl-ruby (1.1.0)
21
28
  yard (0.8.7)
@@ -26,5 +33,6 @@ PLATFORMS
26
33
  DEPENDENCIES
27
34
  pry
28
35
  rspec
36
+ simplecov
29
37
  yajl-ruby (= 1.1.0)
30
38
  yard
data/TODO CHANGED
@@ -1,3 +1,2 @@
1
- * release first gem version
2
1
  * more in the README
3
2
  * binary
@@ -3,18 +3,20 @@
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "allocation_stats"
6
- spec.version = "0.1.2"
6
+ spec.version = "0.1.3"
7
7
  spec.authors = ["Sam Rawlins"]
8
8
  spec.email = ["sam.rawlins@gmail.com"]
9
9
  spec.homepage = "https://github.com/srawlins/allocation_stats"
10
10
  spec.license = "Apache v2"
11
11
  spec.summary = "Tooling for tracing object allocations in Ruby 2.1"
12
- spec.description = "Tooling for tracing object allocations in Ruby 2.1"
12
+ spec.description = "Tooling for tracing object allocations in Ruby 2.1; " +
13
+ "aggregate information about object allocations; group, " +
14
+ "sort, and filter allocation information."
13
15
 
14
16
  spec.files = `git ls-files`.split("\n")
15
17
  spec.require_paths = ["lib"]
16
18
 
17
- spec.add_development_dependency "rspec"
19
+ spec.add_development_dependency "rspec", "< 3"
18
20
 
19
21
  # ">= 2.1.0" seems logical, but rubygems thought that "2.1.0.dev.0" did not fit that bill.
20
22
  # "> 2.0.0" was my next guess, but apparently "2.0.0.247" _does_ fit that bill.
@@ -2,6 +2,7 @@
2
2
  # Licensed under the Apache License, Version 2.0, found in the LICENSE file.
3
3
 
4
4
  require "objspace"
5
+ require_relative "allocation_stats/core_ext/basic_object"
5
6
  require_relative "allocation_stats/allocation"
6
7
  require_relative "allocation_stats/allocations_proxy"
7
8
 
@@ -38,6 +39,9 @@ class AllocationStats
38
39
 
39
40
  def initialize(burn: 0)
40
41
  @burn = burn
42
+ # Copying ridiculous workaround from:
43
+ # https://github.com/ruby/ruby/commit/7170baa878ac0223f26fcf8c8bf25492415e6eaa
44
+ Class.name
41
45
  end
42
46
 
43
47
  def self.trace(&block)
@@ -62,8 +66,8 @@ class AllocationStats
62
66
  @existing_object_ids = {}
63
67
 
64
68
  ObjectSpace.each_object.to_a.each do |object|
65
- @existing_object_ids[object.object_id / 1000] ||= []
66
- @existing_object_ids[object.object_id / 1000] << object.object_id
69
+ @existing_object_ids[object.__id__ / 1000] ||= []
70
+ @existing_object_ids[object.__id__ / 1000] << object.__id__
67
71
  end
68
72
 
69
73
  ObjectSpace.trace_object_allocations {
@@ -77,6 +81,9 @@ class AllocationStats
77
81
  return self
78
82
  end
79
83
 
84
+ # Begin tracing object allocations. Tracing must be stopped with
85
+ # AllocationStats#stop. Garbage collection is disabled while tracing is
86
+ # enabled.
80
87
  def start
81
88
  GC.start
82
89
  GC.disable
@@ -84,8 +91,8 @@ class AllocationStats
84
91
  @existing_object_ids = {}
85
92
 
86
93
  ObjectSpace.each_object.to_a.each do |object|
87
- @existing_object_ids[object.object_id / 1000] ||= []
88
- @existing_object_ids[object.object_id / 1000] << object.object_id
94
+ @existing_object_ids[object.__id__ / 1000] ||= []
95
+ @existing_object_ids[object.__id__ / 1000] << object.__id__
89
96
  end
90
97
 
91
98
  ObjectSpace.trace_object_allocations_start
@@ -98,13 +105,14 @@ class AllocationStats
98
105
  ObjectSpace.each_object.to_a.each do |object|
99
106
  next if ObjectSpace.allocation_sourcefile(object).nil?
100
107
  next if ObjectSpace.allocation_sourcefile(object) == __FILE__
101
- next if @existing_object_ids[object.object_id / 1000] &&
102
- @existing_object_ids[object.object_id / 1000].include?(object.object_id)
108
+ next if @existing_object_ids[object.__id__ / 1000] &&
109
+ @existing_object_ids[object.__id__ / 1000].include?(object.__id__)
103
110
 
104
111
  @new_allocations << Allocation.new(object)
105
112
  end
106
113
  end
107
114
 
115
+ # Stop tracing object allocations that was started with AllocationStats#start.
108
116
  def stop
109
117
  collect_new_allocations
110
118
  ObjectSpace.trace_object_allocations_stop
@@ -4,6 +4,7 @@
4
4
  require "json"
5
5
 
6
6
  class AllocationStats
7
+ # Information about an individual allocation is captured in this class.
7
8
  class Allocation
8
9
  # a convenience constants
9
10
  PWD = Dir.pwd
@@ -77,6 +78,16 @@ class AllocationStats
77
78
  alias_path ? sourcefile_alias : @sourcefile
78
79
  end
79
80
 
81
+ # Returns class name, plus, for Arrays, extended information. When all of
82
+ # the elements of the Array are instances of a total of three or fewer
83
+ # classes, then those classes are listed in brackets. For example:
84
+ #
85
+ # @example Array with only Fixnum and Bignum elements
86
+ # allocation.class_plus #=> "Array<Fixnum,Bignum>"
87
+ # @example Array with elements of class A, B, C, and D
88
+ # allocation.class_plus #=> "Array"
89
+ # @example String (not an Array)
90
+ # allocation.class_plus #=> "String"
80
91
  def class_plus
81
92
  case @object
82
93
  when Array
@@ -139,6 +139,15 @@ class AllocationStats
139
139
  self
140
140
  end
141
141
 
142
+ # Group allocations by one or more attributes, that is, a list of symbols.
143
+ # Commonly, you might want to group allocations by:
144
+ #
145
+ # * :sourcefile, :sourceline, :class
146
+ # * :sourcefile, :method_id, :class
147
+ # * :classpath, :method_id, :class
148
+ #
149
+ # In this case, `:class` is the class of the allocated object (as opposed
150
+ # to `:classpath`, the classpath where the allocation occured).
142
151
  def group_by(*args)
143
152
  @group_keys = args
144
153
 
@@ -175,9 +184,9 @@ class AllocationStats
175
184
  lambda { |allocation| allocation.sourcefile(@alias_paths) }
176
185
  elsif Allocation::HELPERS.include?(faux) ||
177
186
  Allocation::ATTRIBUTES.include?(faux)
178
- lambda { |allocation| allocation.send(faux) }
187
+ lambda { |allocation| allocation.__send__(faux) }
179
188
  else
180
- lambda { |allocation| allocation.object.send(faux) }
189
+ lambda { |allocation| allocation.object.__send__(faux) }
181
190
  end
182
191
  end
183
192
  end
@@ -237,6 +246,9 @@ class AllocationStats
237
246
  to_a.to_json
238
247
  end
239
248
 
249
+ # Return tabular information about the un-grouped list of Allocations.
250
+ #
251
+ # @private
240
252
  def to_text_from_plain(resolved, columns: DEFAULT_COLUMNS)
241
253
  getters = attribute_getters(columns)
242
254
 
@@ -263,6 +275,9 @@ class AllocationStats
263
275
  end
264
276
  private :to_text_from_plain
265
277
 
278
+ # Return tabular information about the grouped Allocations.
279
+ #
280
+ # @private
266
281
  def to_text_from_groups(resolved)
267
282
  columns = @group_keys + ["count"]
268
283
 
@@ -0,0 +1,11 @@
1
+ # monkey patch to BasicObject, allowing it to respnd to :class
2
+ #
3
+ # @private
4
+ class BasicObject
5
+ # monkey patch to BasicObject, allowing it to respnd to :class
6
+ #
7
+ # @private
8
+ def class
9
+ (class << self; self end).superclass
10
+ end
11
+ end
@@ -53,6 +53,22 @@ describe AllocationStats::AllocationsProxy do
53
53
  results.keys.should include([__FILE__, Array])
54
54
  end
55
55
 
56
+ it "should track new BasicObjects" do
57
+ class BO < BasicObject; end
58
+
59
+ stats = AllocationStats.trace do
60
+ bo = BO.new
61
+ end
62
+
63
+ results = stats.allocations.group_by(:sourcefile).all
64
+ expect(results.class).to be(Hash)
65
+ expect(results.keys.size).to eq(1)
66
+ expect(results.keys.first).to eq([__FILE__])
67
+ expect(results[[__FILE__]].class).to eq(Array)
68
+ expect(results[[__FILE__]].size).to eq(1)
69
+ expect(results[[__FILE__]].first.object.class).to be(BO)
70
+ end
71
+
56
72
  it "should track new objects by path and class_name (Array with 1x type)" do
57
73
  stats = AllocationStats.trace do
58
74
  square_groups = []
@@ -312,7 +328,7 @@ describe AllocationStats::AllocationsProxy do
312
328
  first = {
313
329
  "file" => "<PWD>/spec/spec_helper.rb",
314
330
  "file (raw)" => "/usr/local/google/home/srawlins/code/allocation_stats/spec/spec_helper.rb",
315
- "line" => 20,
331
+ "line" => 23,
316
332
  "class_path" => "MyClass",
317
333
  "method_id" => :my_method.to_s,
318
334
  "memsize" => 192,
@@ -33,14 +33,14 @@ describe AllocationStats do
33
33
  stats.new_allocations.size.should == 1
34
34
  end
35
35
 
36
- it "should only track new objects; String keys in Hashes count twice :(" do
36
+ it "should only track new objects; String keys in Hashes are frozen" do
37
37
  existing_array = [1,2,3,4,5]
38
38
 
39
39
  stats = AllocationStats.trace do
40
40
  new_hash = {"foo" => "bar", "baz" => "quux"}
41
41
  end
42
42
 
43
- stats.new_allocations.size.should == 7
43
+ stats.new_allocations.size.should == 3
44
44
  end
45
45
 
46
46
  it "should only track new objects, using instance method" do
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # Copyright 2013 Google Inc. All Rights Reserved.
2
2
  # Licensed under the Apache License, Version 2.0, found in the LICENSE file.
3
3
 
4
+ require "simplecov"
5
+ SimpleCov.start
6
+
4
7
  require_relative "../lib/allocation_stats"
5
8
  require "yaml"
6
9
  require "yajl"
metadata CHANGED
@@ -1,30 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: allocation_stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Rawlins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-04 00:00:00.000000000 Z
11
+ date: 2013-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "<"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
27
- description: Tooling for tracing object allocations in Ruby 2.1
26
+ version: '3'
27
+ description: Tooling for tracing object allocations in Ruby 2.1; aggregate information
28
+ about object allocations; group, sort, and filter allocation information.
28
29
  email:
29
30
  - sam.rawlins@gmail.com
30
31
  executables: []
@@ -51,6 +52,7 @@ files:
51
52
  - lib/allocation_stats.rb
52
53
  - lib/allocation_stats/allocation.rb
53
54
  - lib/allocation_stats/allocations_proxy.rb
55
+ - lib/allocation_stats/core_ext/basic_object.rb
54
56
  - spec/allocation_stats/allocations_proxy_spec.rb
55
57
  - spec/allocation_stats_spec.rb
56
58
  - spec/spec_helper.rb
@@ -74,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
76
  version: '0'
75
77
  requirements: []
76
78
  rubyforge_project:
77
- rubygems_version: 2.2.0.preview.1
79
+ rubygems_version: 2.2.0.rc.1
78
80
  signing_key:
79
81
  specification_version: 4
80
82
  summary: Tooling for tracing object allocations in Ruby 2.1