perfetto 0.1.1 → 0.1.2

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
  SHA256:
3
- metadata.gz: 6642fce9318093a63a3d77565697ae113b3482aebd5408ec017eaedc6329c359
4
- data.tar.gz: d92d38f6e5c3a177bc160677bc1c6a7a5334cf899a68724a7ff686266aaef71f
3
+ metadata.gz: 6a32a441d8046750cb3a306de9a3081e07fecd7c1223d53f7151db609d23f43d
4
+ data.tar.gz: 8dc578f6032ef6fb709b5a60b2fddf38afea8aa8f877cc27964f0db37dc52948
5
5
  SHA512:
6
- metadata.gz: 12d78ef7a12958fe60be11128014f0327a6aae91543acefdf9c1d473438ad858d79830638699afa80684fedafda2b294f5b6ab486f6ffc9b6166b84c33f91cdf
7
- data.tar.gz: 471b51999fd8a7b93aa7dc5d2ed3722193f7d4beb02a74db265db437ab220ef99fb62a23ce437afb734c7385757feacf2b7a27a6112ea1fdec73450750a07e1f
6
+ metadata.gz: 29d28eb4c2153d6d798d0f9e17cd91e20dc68c6eb30af3d30210b39d96570a8494adedb0a2b01f9fddf68325bbdb365eb90b731d7c5560f9234a526455003b93
7
+ data.tar.gz: 585e6f74925e4c56cf1b524f1960d479ca9b5641dd7dff779225553512a51d7a4b970ba523de3554fa8f8debd5a975a8f71d817b59ecd10af34144d7548c0221
data/README.md CHANGED
@@ -3,3 +3,69 @@
3
3
  ## Visualization
4
4
 
5
5
  https://ui.perfetto.dev/
6
+
7
+ # Usage
8
+
9
+ ```ruby
10
+
11
+ require "perfetto"
12
+
13
+ Perfetto.setup enable_tracing: true
14
+
15
+ Perfetto.start_tracing
16
+
17
+ # Slice
18
+ # Stack frame is inferred from the begin event with the same category 'cpu_work'
19
+ Perfetto.trace_event_begin "cpu_work", "example_task"
20
+ sleep 0.1
21
+ Perfetto.trace_event_end "cpu_work"
22
+
23
+ # Slice with debug info
24
+ # Same as above, but "key"=>"value" is added to the event details
25
+ Perfetto.trace_event_begin_with_debug_info "cpu_work", "example_task2", "key", "value"
26
+ sleep 0.1
27
+ Perfetto.trace_event_end "cpu_work"
28
+
29
+ # Counter
30
+ 10.times do |n|
31
+ Perfetto.trace_counter "rendering", "frame_rate", n.even? ? 60 : 30
32
+ sleep 0.1
33
+ end
34
+ Perfetto.trace_counter "rendering", "frame_rate", 0
35
+
36
+ # Instant
37
+ Perfetto.trace_event_instant "cpu_work", "example_instant"
38
+
39
+ sleep 0.1
40
+
41
+ # Instant with debug info
42
+ Perfetto.trace_event_instant_with_debug_info "cpu_work", "example_instant2", "key", "value"
43
+
44
+ sleep 0.1
45
+
46
+ class Foo
47
+ def bar(a, b = 1, c: 2)
48
+ yield(a + b + c)
49
+ end
50
+
51
+ def baz(x)
52
+ puts x
53
+ sleep 0.1
54
+ end
55
+
56
+ # Intercept instance methods
57
+ include Perfetto::Interceptor
58
+ pftrace_all
59
+ end
60
+
61
+ f = Foo.new
62
+ f.bar(1, 2, c: 3) do |n|
63
+ n.times do |x|
64
+ f.baz x + n
65
+ end
66
+ end
67
+
68
+ Perfetto.stop_tracing "example.pftrace"
69
+ ```
70
+
71
+ ![example](./example/example.png)
Binary file
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Naming/MethodParameterName
4
+
5
+ require "perfetto"
6
+
7
+ Perfetto.setup enable_tracing: true
8
+
9
+ Perfetto.start_tracing
10
+
11
+ # Slice
12
+ # Stack frame is inferred from the begin event with the same category 'cpu_work'
13
+ Perfetto.trace_event_begin "cpu_work", "example_task"
14
+ sleep 0.1
15
+ Perfetto.trace_event_end "cpu_work"
16
+
17
+ # Slice with debug info
18
+ # Same as above, but "key"=>"value" is added to the event details
19
+ Perfetto.trace_event_begin_with_debug_info "cpu_work", "example_task2", "key", "value"
20
+ sleep 0.1
21
+ Perfetto.trace_event_end "cpu_work"
22
+
23
+ # Counter
24
+ 10.times do |n|
25
+ Perfetto.trace_counter "rendering", "frame_rate", n.even? ? 60 : 30
26
+ sleep 0.1
27
+ end
28
+ Perfetto.trace_counter "rendering", "frame_rate", 0
29
+
30
+ # Instant
31
+ Perfetto.trace_event_instant "cpu_work", "example_instant"
32
+
33
+ sleep 0.1
34
+
35
+ # Instant with debug info
36
+ Perfetto.trace_event_instant_with_debug_info "cpu_work", "example_instant2", "key", "value"
37
+
38
+ sleep 0.1
39
+
40
+ class Foo
41
+ def bar(a, b = 1, c: 2)
42
+ yield(a + b + c)
43
+ end
44
+
45
+ def baz(x)
46
+ puts x
47
+ sleep 0.1
48
+ end
49
+
50
+ # Intercept instance methods
51
+ include Perfetto::Interceptor
52
+ pftrace_all
53
+ end
54
+
55
+ f = Foo.new
56
+ f.bar(1, 2, c: 3) do |n|
57
+ n.times do |x|
58
+ f.baz x + n
59
+ end
60
+ end
61
+
62
+ Perfetto.stop_tracing "example.pftrace"
63
+
64
+ # rubocop:enable Naming/MethodParameterName
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perfetto
4
+ # Global configuration
5
+ class Configure
6
+ extend Configurable
7
+
8
+ set :enable_tracing, false
9
+ set :buffer_size_kb, 1024
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copy-pasted from https://github.com/midori-rb/midori.rb/blob/master/lib/midori/core_ext/configurable.rb
4
+ # rubocop:disable Style/OptionalBooleanParameter
5
+ # rubocop:disable Style/DocumentDynamicEvalDefinition
6
+ module Configurable
7
+ # Sets an option to the given value.
8
+ # @param [Symbol] option the name of config
9
+ # @param [Object] value value to the name
10
+ # @param [Boolean] read_only Generate option= method or not
11
+ # @return [nil] nil
12
+ def set(option, value = (not_set = true), read_only = false)
13
+ raise ArgumentError if not_set
14
+
15
+ setter = proc { |val| set option, val }
16
+ getter = proc { value }
17
+
18
+ define_singleton("#{option}=", setter) unless read_only
19
+ define_singleton(option, getter)
20
+ define_singleton("#{option}?", "!!#{option}") unless method_defined? "#{option}?"
21
+
22
+ self
23
+ end
24
+
25
+ private
26
+
27
+ # Dynamically defines a method on settings.
28
+ # @param [String] name method name
29
+ # @param [Proc] content method content
30
+ # @return [nil] nil
31
+ def define_singleton(name, content = Proc.new)
32
+ singleton_class.class_eval do
33
+ undef_method(name) if method_defined? name
34
+ if content.is_a?(String)
35
+ class_eval("def #{name}() #{content}; end", __FILE__,
36
+ __LINE__ - 1)
37
+ else
38
+ define_method(name, &content)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ # rubocop:enable Style/OptionalBooleanParameter
45
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perfetto
4
+ # To intercept method calls in other classes
5
+ module Interceptor
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ # Class methods for the interceptor
11
+ module ClassMethods
12
+ if Perfetto::Configure.enable_tracing
13
+ def pftrace(method_name)
14
+ original_method = instance_method(method_name)
15
+ alias_method "pftrace_#{method_name}", method_name
16
+ define_method(method_name) do |*args, **kwargs, &block|
17
+ Perfetto.trace_event_begin self.class.name, method_name.to_s
18
+ original_method.bind(self).call(*args, **kwargs, &block)
19
+ Perfetto.trace_event_end self.class.name
20
+ end
21
+ end
22
+
23
+ def pftrace_all
24
+ instance_methods(false).each do |method_name|
25
+ pftrace method_name
26
+ end
27
+ end
28
+ else # When tracing is disabled
29
+ def pftrace(_method_name); end
30
+ def pftrace_all; end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,11 +7,39 @@ module Perfetto
7
7
  alias stop_tracing_native stop_tracing
8
8
  end
9
9
 
10
- def self.start_tracing(buffer_size_kb = 1024)
11
- start_tracing_native buffer_size_kb
12
- end
10
+ if Perfetto::Configure.enable_tracing
11
+ # Default arguments implemented in this wrapper
12
+ def self.start_tracing
13
+ start_tracing_native Configure.buffer_size_kb
14
+ end
15
+
16
+ def self.stop_tracing(trace_file_name = "#{Time.now.strftime("%Y%m%d%H%M%S")}.pftrace")
17
+ stop_tracing_native trace_file_name
18
+ end
13
19
 
14
- def self.stop_tracing(trace_file_name = "perfetto.pftrace")
15
- stop_tracing_native trace_file_name
20
+ # Methods implemented in native extension
21
+ # We don't want to proxy these methods because they are called very frequently on hot paths
22
+ # def self.start_tracing; end
23
+ # def self.stop_tracing(_trace_file_name); end
24
+ # def self.trace_event_begin(_class_name, _method_name); end
25
+ # def self.trace_event_end(_class_name); end
26
+ # def self.trace_counter(_class_name, _counter_name, _counter_value); end
27
+ # def self.trace_counter_i64(_class_name, _counter_name, _counter_value); end
28
+ # def self.trace_counter_double(_class_name, _counter_name, _counter_value); end
29
+ # def self.trace_event_instant(_class_name, _method_name); end
30
+ # def self.trace_event_begin_with_debug_info(_class_name, _method_name, _debug_key, _debug_value); end
31
+ # def self.trace_event_instant_with_debug_info(_class_name, _method_name, _debug_key, _debug_value); end
32
+ else
33
+ # Stub methods
34
+ def self.start_tracing; end
35
+ def self.stop_tracing(_trace_file_name); end
36
+ def self.trace_event_begin(_class_name, _method_name); end
37
+ def self.trace_event_end(_class_name); end
38
+ def self.trace_counter(_class_name, _counter_name, _counter_value); end
39
+ def self.trace_counter_i64(_class_name, _counter_name, _counter_value); end
40
+ def self.trace_counter_double(_class_name, _counter_name, _counter_value); end
41
+ def self.trace_event_instant(_class_name, _method_name); end
42
+ def self.trace_event_begin_with_debug_info(_class_name, _method_name, _debug_key, _debug_value); end
43
+ def self.trace_event_instant_with_debug_info(_class_name, _method_name, _debug_key, _debug_value); end
16
44
  end
17
45
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Perfetto
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/perfetto.rb CHANGED
@@ -2,8 +2,23 @@
2
2
 
3
3
  require_relative "perfetto/version"
4
4
 
5
- # Native extension
6
- require_relative "perfetto/perfetto_native"
5
+ require_relative "perfetto/core_ext/configurable"
6
+ require_relative "perfetto/configure"
7
7
 
8
- # Ruby wrapper
9
- require_relative "perfetto/perfetto"
8
+ # To minimize the overhead of tracing at runtime
9
+ # we determine whether to enable instrumentations
10
+ # at the first call to 'setup' method instead of
11
+ # every call to bussiness logics being traced.
12
+ module Perfetto
13
+ def self.setup(enable_tracing: nil, buffer_size_kb: nil)
14
+ Configure.enable_tracing = enable_tracing unless enable_tracing.nil?
15
+ Configure.buffer_size_kb = buffer_size_kb unless buffer_size_kb.nil?
16
+
17
+ # Native extension
18
+ require_relative "perfetto/perfetto_native"
19
+ # Ruby wrapper
20
+ require_relative "perfetto/perfetto"
21
+ # Instrumentation Helper
22
+ require_relative "perfetto/interceptor"
23
+ end
24
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perfetto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kowalski Dark
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-01 00:00:00.000000000 Z
11
+ date: 2024-01-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Yet another event tracing library for Ruby.
14
14
  email:
@@ -21,6 +21,8 @@ files:
21
21
  - ".rubocop.yml"
22
22
  - README.md
23
23
  - Rakefile
24
+ - example/example.png
25
+ - example/example.rb
24
26
  - ext/perfetto/LICENSE
25
27
  - ext/perfetto/README.md
26
28
  - ext/perfetto/extconf.rb
@@ -30,6 +32,9 @@ files:
30
32
  - ext/perfetto/sdk.cc
31
33
  - ext/perfetto/sdk.h
32
34
  - lib/perfetto.rb
35
+ - lib/perfetto/configure.rb
36
+ - lib/perfetto/core_ext/configurable.rb
37
+ - lib/perfetto/interceptor.rb
33
38
  - lib/perfetto/perfetto.rb
34
39
  - lib/perfetto/version.rb
35
40
  - sig/perfetto.rbs