metababel 0.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 579d0e3d53d8a2cc77b458621e278d01e98cc5a9b736f9615671c35d5a7ec881
4
+ data.tar.gz: dede291f1c00394ed257784551fc3c2cffbcd1c9d5404fdb305f272d10c4bb41
5
+ SHA512:
6
+ metadata.gz: 8da116eba6fc46b84324f10ace6a46aad4b8144d8ec4eadbbfe80c380abf4cd2cd7deaafcc70e3ac86ce3e6ce4971e354029ff93b7885f87e19cb455a6d22a37
7
+ data.tar.gz: 585f64b8cb02ab0255d131a94f4ecda9fa24dcd7ecaecc7d1ffa9825004671dd550054fbdd638ac3a0fe597fbf1881f1b78cc6ab4cea2c00e75a9b009f6b55ea
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ <img width="384" alt="METABABEL" src="https://user-images.githubusercontent.com/6524907/217338770-ab69a6c8-f0fa-4e00-9b8f-bf5d2192d0bd.png">
2
+
3
+ # What symbols to provide?
4
+
5
+ ## Filter & Sink
6
+
7
+ Link with a object file who export the symbol `btx_register_usr_callbacks(void *)`.
8
+
9
+ The implementation of `btx_register_usr_callbacks` should conssist of calls to `btx_register_callbacks_#{stream_class_name}_#{event_class_name}(btx_handle, &callbacks)`.
10
+
11
+ ## Source:
12
+
13
+ Link with a object file who export the symbol `btx_push_usr_messages(struct xprof_common_data *common_data)`.
14
+
15
+ # Function Provided
16
+
17
+ ## Source & Filter
18
+
19
+ In the callbacks, and in the `btx_push_usr_messages`, you have access to `btx_push_message_{stream_class_name}_#{event_class_name}(struct xprof_common_data *common_data, ...)`.
20
+
21
+
22
+ # Source Description
23
+
24
+ ## State Machine
25
+
26
+ ```mermaid
27
+ stateDiagram-v2
28
+ [*] --> BTX_SOURCE_STATE_INITIALIZING
29
+ BTX_SOURCE_STATE_INITIALIZING --> BTX_SOURCE_STATE_PROCESSING
30
+ BTX_SOURCE_STATE_PROCESSING --> BTX_SOURCE_STATE_FINALIZING
31
+ BTX_SOURCE_STATE_FINALIZING --> BTX_FILTER_STATE_FINISHED
32
+ BTX_FILTER_STATE_FINISHED --> [*]
33
+ ```
34
+
35
+ # Filter Description
36
+
37
+ ## State Machine
38
+
39
+ ```mermaid
40
+ stateDiagram-v2
41
+ [*] --> BTX_SOURCE_STATE_INITIALIZING
42
+ BTX_SOURCE_STATE_INITIALIZING --> BTX_FILTER_PROCESSING
43
+ state BTX_FILTER_PROCESSING {
44
+ [*] --> BTX_FILTER_PROCESSING_STATE_READING
45
+ [*] --> BTX_FILTER_PROCESSING_STATE_SENDING
46
+ BTX_FILTER_PROCESSING_STATE_SENDING --> BTX_FILTER_PROCESSING_STATE_READING
47
+ BTX_FILTER_PROCESSING_STATE_READING --> BTX_FILTER_PROCESSING_STATE_SENDING
48
+ BTX_FILTER_PROCESSING_STATE_READING --> BTX_FILTER_PROCESSING_STATE_FINISHED
49
+ BTX_FILTER_PROCESSING_STATE_FINISHED --> [*]
50
+ }
51
+ BTX_FILTER_PROCESSING --> BTX_FILTER_STATE_FINALIZING
52
+ BTX_FILTER_STATE_FINALIZING --> BTX_FILTER_STATE_FINISHED
53
+ BTX_FILTER_STATE_FINISHED --> [*]
54
+ ```
55
+
56
+ # Sink Description
57
+
58
+ At finalization we will call the `btx_user_finalization(struct xprof_common_data *common_data)`
59
+
60
+
data/bin/metababel ADDED
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'optparse'
5
+ require 'erb'
6
+ require 'metababel'
7
+ require 'fileutils'
8
+
9
+ def validate_model(yaml)
10
+ raise "Invalid Model #{yaml}" unless yaml[:stream_classes].all? do |d|
11
+ d.key?(:event_common_context_field_class) || d[:event_classes].all? do |d2|
12
+ d2.key?(:payload_field_class)
13
+ end
14
+ end
15
+ end
16
+
17
+ class Hash
18
+ # Copy pasted from rails (https://apidock.com/rails/Hash/deep_merge%21)
19
+ def deep_merge!(other_hash, &block)
20
+ merge!(other_hash) do |key, this_val, other_val|
21
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
22
+ this_val.deep_merge(other_val, &block)
23
+ elsif block_given?
24
+ block.call(key, this_val, other_val)
25
+ else
26
+ other_val
27
+ end
28
+ end
29
+ end
30
+
31
+ def deep_merge(other_hash, &block)
32
+ dup.deep_merge!(other_hash, &block)
33
+ end
34
+ end
35
+
36
+ EventInfo = Struct.new(:name, :args, :body, :index_stream_class, :index_event_class) do
37
+ def name_sanitized
38
+ name.gsub(/[^0-9A-Za-z-]/, '_')
39
+ end
40
+ end
41
+
42
+ def erb_render_and_save(vars,
43
+ basename, out_folder, out_name: nil, prefix: 'btx_')
44
+ template = File.read(File.join(__dir__, "../template/#{basename}.erb"))
45
+ # We need to trim line who contain only with space, because we indent our erb block <% %>
46
+ # The trim_mode remove line only when it's start with the erb block
47
+ # The regex remove the lines who are not indented
48
+ # Maybe related to `https://github.com/ruby/erb/issues/24`
49
+ str = ERB.new(template, trim_mode: '<>').result_with_hash(vars).gsub(/^ +$\n/, '')
50
+ File.open(File.join(out_folder, "#{prefix}#{out_name || basename}"), 'w') do |f|
51
+ f.write(str)
52
+ end
53
+ end
54
+
55
+ class Babeltrace2Gen::BTTraceClass
56
+ def map_event_classes_with_index
57
+ @stream_classes.map.with_index do |s, index_stream_class|
58
+ s.event_classes.map.with_index do |e, index_event_class|
59
+ yield(e, index_stream_class, index_event_class)
60
+ end
61
+ end.flatten
62
+ end
63
+ end
64
+
65
+ class GeneratedArg < Struct.new(:type, :name)
66
+ end
67
+
68
+ # We preprent an empty new line from the body as a hack, to correct the indentation
69
+ # Indeeed the <%= body %> will be indented, but we don't don't want it,
70
+ # in the body string is already indented
71
+ # But we clean the white space empty line afterward \o/
72
+ def wrote_event_dispatchers(folder, t)
73
+ event_name = 'event'
74
+ event_dispatchers = t.map_event_classes_with_index do |e, index_stream_class, index_event_class|
75
+ arg_variables = []
76
+ body = Babeltrace2Gen.context(indent: 1) do
77
+ e.get_getter(event: event_name, arg_variables: arg_variables)
78
+ end
79
+ EventInfo.new(e.name, arg_variables, "\n" + body, index_stream_class, index_event_class)
80
+ end
81
+
82
+ d = { event_dispatchers: event_dispatchers,
83
+ event_name: event_name }
84
+
85
+ erb_render_and_save(d, 'upstream.h', folder)
86
+ erb_render_and_save(d, 'upstream.c', folder)
87
+ end
88
+
89
+ def wrote_creates(folder, t)
90
+ event_name = 'event'
91
+ downstream_events = t.map_event_classes_with_index do |e, index_stream_class, index_event_class|
92
+ arg_variables = []
93
+ body = Babeltrace2Gen.context(indent: 1) do
94
+ e.get_setter(event: event_name, arg_variables: arg_variables)
95
+ end
96
+ EventInfo.new(e.name, arg_variables, "\n" + body, index_stream_class, index_event_class)
97
+ end
98
+
99
+ body_declarator_classes = "\n" + Babeltrace2Gen.context(indent: 1) do
100
+ t.get_declarator(variable: 'trace_class')
101
+ end
102
+
103
+ d = { body_declarator_classes: body_declarator_classes,
104
+ downstream_events: downstream_events,
105
+ stream_classes: t.stream_classes,
106
+ event_name: event_name }
107
+
108
+ erb_render_and_save(d, 'downstream.h', folder)
109
+ erb_render_and_save(d, 'downstream.c', folder)
110
+ end
111
+
112
+ def wrote_component(options, d, folder)
113
+
114
+ component_dispatchers = [EventInfo.new('initialize_usr_data',
115
+ [GeneratedArg.new('void **', 'usr_data_p')]),
116
+ EventInfo.new('finalize_usr_data',
117
+ [GeneratedArg.new('void *', 'usr_data')]),
118
+ EventInfo.new('read_params',
119
+ [GeneratedArg.new('void *', 'usr_data'),
120
+ GeneratedArg.new('btx_params_t *', 'usr_params')])
121
+ ]
122
+
123
+ if options[:component_type] == "SOURCE"
124
+ component_dispatchers << EventInfo.new('push_usr_messages',
125
+ [GeneratedArg.new('void *', 'usr_data'),
126
+ GeneratedArg.new('btx_source_status_t*', 'status') ])
127
+ end
128
+
129
+ d2 = { component_dispatchers: component_dispatchers,
130
+ event_name: 'dummy_event' }
131
+
132
+ erb_render_and_save(d2.update(d).update(:options => options), 'component.h', folder)
133
+ erb_render_and_save(d2.update(d).update(:options => options), 'component.c', folder)
134
+ end
135
+
136
+ options = { plugin_name: 'metababel',
137
+ component_name: 'btx' }
138
+
139
+ # Display help if no arguments.
140
+ ARGV << '-h' if ARGV.empty?
141
+
142
+ OptionParser.new do |opts|
143
+ opts.banner = 'Usage: example.rb [options]'
144
+
145
+ opts.on('-h', '--help', 'Prints this help') do
146
+ puts opts
147
+ exit
148
+ end
149
+
150
+ opts.on('-v', '--version', 'Prints this help') do
151
+ puts "Ruby: #{RUBY_VERSION}"
152
+ puts "Metababel: #{Metababel::VERSION}"
153
+ exit
154
+ end
155
+
156
+ opts.on('-t', '--component TYPE', '[Mandatory] Node within a trace processing graph.') do |p|
157
+ options[:component_type] = p
158
+ end
159
+
160
+ opts.on('-u', '--upstreams PATH', Array, '[Mandatory] Path to the bt2 yaml file.') do |p|
161
+ options[:upstreams] = p
162
+ end
163
+
164
+ opts.on('-d', '--downstream PATH', '[Optional] Path to the bt2 yaml file.') do |p|
165
+ options[:downstream] = p
166
+ end
167
+
168
+ opts.on('-p', '--plugin-name PATH', '[Optional] Name of the bt2 plugin created.') do |p|
169
+ options[:plugin_name] = p
170
+ end
171
+
172
+ opts.on('-c', '--component-name PATH', '[Optional] Name of the bt2 componant created.') do |p|
173
+ options[:component_name] = p
174
+ end
175
+
176
+ opts.on('--params PATH', '[Optional] Name of YAML params definition.') do |p|
177
+ options[:params] = p
178
+ end
179
+
180
+ opts.on('-o', '--output FOLDER', '[Optional] Output folder path.') do |p|
181
+ options[:folder] = p
182
+ end
183
+
184
+ opts.on('-i', '--usr-data-header NAME', '[Optional] User datatypes definitions.') do |p|
185
+ options[:usr_data_header] = p
186
+ end
187
+ end.parse!
188
+
189
+ raise OptionParser::MissingArgument if options[:component_type].nil?
190
+
191
+ # Babeltrace can be extended by plugins, which provide one or more component classes.
192
+ base_folder = options[:folder] || "#{options[:component_type]}.#{options[:plugin_name]}.#{options[:component_name]}"
193
+ folder = "#{base_folder}/metababel"
194
+ FileUtils.mkdir_p(folder)
195
+
196
+ d = {:options => options}
197
+
198
+ d[:params_declaration] = ''
199
+ d[:params_definition] = ''
200
+ if options.key?(:params)
201
+ y = YAML.load_file(options[:params])
202
+ c = Babeltrace2Gen::BTValueCLass.from_h(y)
203
+ body = Babeltrace2Gen.context(indent: 1) do
204
+ c.get('usr_params', 'params')
205
+ end
206
+ d[:params_declaration] = c.get_struct_definition('params')
207
+ d[:params_definition] = body
208
+ end
209
+
210
+ erb_render_and_save(d, "#{options[:component_type].downcase}.c", base_folder, out_name: "#{options[:plugin_name]}.c")
211
+ erb_render_and_save({options: options}, 'metababel.h', folder, prefix: '')
212
+
213
+ wrote_component(options, d, folder)
214
+ if %w[SOURCE FILTER].include?(options[:component_type])
215
+ raise 'Missing downstream model' unless options[:downstream]
216
+
217
+ y = YAML.load_file(options[:downstream])
218
+ validate_model(y)
219
+ t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
220
+ wrote_creates(folder, t)
221
+ end
222
+
223
+ if %w[FILTER SINK].include?(options[:component_type])
224
+ raise 'Missing upstream models' unless options[:upstreams]
225
+
226
+ y = options[:upstreams].reduce({}) do |y, upstream|
227
+ # Need to specialize for merging arrays
228
+ y.deep_merge(YAML.load_file(upstream)) { |_key, old, new| old + new }
229
+ end
230
+ validate_model(y)
231
+ t = Babeltrace2Gen::BTTraceClass.from_h(nil, y)
232
+ wrote_event_dispatchers(folder, t)
233
+ end
@@ -0,0 +1,38 @@
1
+ module Babeltrace2Gen
2
+ module BTPrinter
3
+ @@output = ''
4
+ @@indent = 0
5
+ INDENT_INCREMENT = ' '.freeze
6
+
7
+ def pr(str)
8
+ @@output << INDENT_INCREMENT * @@indent << str << "\n"
9
+ end
10
+ module_function :pr
11
+
12
+ def scope
13
+ pr '{'
14
+ @@indent += 1
15
+ yield
16
+ @@indent -= 1
17
+ pr '}'
18
+ end
19
+
20
+ def self.context(output: '', indent: 0)
21
+ @@output = output
22
+ @@indent = indent
23
+ yield
24
+ @@output
25
+ end
26
+
27
+ # Maybe not the best place
28
+ def name_sanitized
29
+ raise unless @name
30
+
31
+ @name.gsub(/[^0-9A-Za-z\-]/, '_')
32
+ end
33
+ end
34
+
35
+ def self.context(**args, &block)
36
+ BTPrinter.context(**args, &block)
37
+ end
38
+ end