Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: third_party/WebKit/Source/build/scripts/make_instrumenting_probes.py

Issue 2798453002: [instrumentation]: Move probe subscriptions to JSON5 config file from PIDL. (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/probe/CoreProbes.json5 » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2017 The Chromium Authors. All rights reserved. 1 # Copyright 2017 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import ast 5 import ast
6 import optparse 6 import optparse
7 import os.path 7 import os.path
8 import re 8 import re
9 import sys 9 import sys
10 10
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 model = [] 96 model = []
97 while len(source): 97 while len(source):
98 match, source = match_and_consume(r"interface\s(\w*)\s?\{([^\{]*)\}", so urce) 98 match, source = match_and_consume(r"interface\s(\w*)\s?\{([^\{]*)\}", so urce)
99 if not match: 99 if not match:
100 sys.stderr.write("Cannot parse %s\n" % source[:100]) 100 sys.stderr.write("Cannot parse %s\n" % source[:100])
101 sys.exit(1) 101 sys.exit(1)
102 model.append(File(match.group(1), match.group(2))) 102 model.append(File(match.group(1), match.group(2)))
103 return model 103 return model
104 104
105 105
106 def include_probes_header():
107 return "#include \"%s\"" % config["settings"]["probes_header"]
108
109
106 class File(object): 110 class File(object):
107 def __init__(self, name, source): 111 def __init__(self, name, source):
108 self.name = name 112 self.name = name
109 self.header_name = self.name + "Inl" 113 self.header_name = self.name + "Inl"
110 self.includes = [include_inspector_header(base_name)] 114 self.includes = [include_probes_header()]
111 self.forward_declarations = [] 115 self.forward_declarations = []
112 self.declarations = [] 116 self.declarations = []
113 for line in map(str.strip, source.split("\n")): 117 for line in map(str.strip, source.split("\n")):
114 line = re.sub(r"\s{2,}", " ", line).strip() # Collapse whitespace 118 line = re.sub(r"\s{2,}", " ", line).strip() # Collapse whitespace
115 if len(line) == 0: 119 if len(line) == 0:
116 continue 120 continue
117 elif line.startswith("#include"): 121 elif line.startswith("#include"):
118 self.includes.append(line) 122 self.includes.append(line)
119 elif line.startswith("class ") or line.startswith("struct "): 123 elif line.startswith("class ") or line.startswith("struct "):
120 self.forward_declarations.append(line) 124 self.forward_declarations.append(line)
121 else: 125 else:
122 self.declarations.append(Method(line)) 126 self.declarations.append(Method(line))
123 self.includes.sort() 127 self.includes.sort()
124 self.forward_declarations.sort() 128 self.forward_declarations.sort()
125 129
126 130
127 def include_header(name):
128 return "#include \"%s.h\"" % name
129
130
131 def include_inspector_header(name):
132 if name == "PerformanceMonitor":
133 return include_header("core/frame/" + name)
134 if name == "PlatformProbes":
135 return include_header("platform/probe/" + name)
136 if name == "CoreProbes":
137 return include_header("core/probe/" + name)
138 return include_header("core/inspector/" + name)
139
140
141 class Method(object): 131 class Method(object):
142 def __init__(self, source): 132 def __init__(self, source):
143 match = re.match(r"(\[[\w|,|=|\s]*\])?\s?(\w*\*?) (\w*)\((.*)\)\s?;", so urce) 133 match = re.match(r"(?:(\w+\*?)\s+)?(\w+)\s*\((.*)\)\s*;", source)
144 if not match: 134 if not match:
145 sys.stderr.write("Cannot parse %s\n" % source) 135 sys.stderr.write("Cannot parse %s\n" % source)
146 sys.exit(1) 136 sys.exit(1)
147 137
148 self.options = [] 138 self.return_type = match.group(1) or ""
149 if match.group(1): 139 self.name = match.group(2)
150 options_str = re.sub(r"\s", "", match.group(1)[1:-1])
151 if len(options_str) != 0:
152 self.options = options_str.split(",")
153
154 self.return_type = match.group(2)
155 self.name = match.group(3)
156 self.is_scoped = self.return_type == "" 140 self.is_scoped = self.return_type == ""
157 141
158 # Splitting parameters by a comma, assuming that attribute lists contain no more than one attribute. 142 # Splitting parameters by a comma, assuming that attribute lists contain no more than one attribute.
159 self.params = map(Parameter, map(str.strip, match.group(4).split(","))) 143 self.params = map(Parameter, map(str.strip, match.group(3).split(",")))
160 144
161 self.returns_value = self.return_type != "" and self.return_type != "voi d" 145 self.returns_value = self.return_type != "" and self.return_type != "voi d"
162 if self.return_type == "bool": 146 if self.return_type == "bool":
163 self.default_return_value = "false" 147 self.default_return_value = "false"
164 elif self.returns_value: 148 elif self.returns_value:
165 sys.stderr.write("Can only return bool: %s\n" % self.name) 149 sys.stderr.write("Can only return bool: %s\n" % self.name)
166 sys.exit(1) 150 sys.exit(1)
167 151
168 self.agents = [option for option in self.options if "=" not in option]
169
170 if self.returns_value and len(self.agents) > 1:
171 sys.stderr.write("Can only return value from a single agent: %s\n" % self.name)
172 sys.exit(1)
173
174 152
175 class Parameter(object): 153 class Parameter(object):
176 def __init__(self, source): 154 def __init__(self, source):
177 self.options = [] 155 self.options = []
178 match, source = match_and_consume(r"\[(\w*)\]", source) 156 match, source = match_and_consume(r"\[(\w*)\]", source)
179 if match: 157 if match:
180 self.options.append(match.group(1)) 158 self.options.append(match.group(1))
181 159
182 parts = map(str.strip, source.split("=")) 160 parts = map(str.strip, source.split("="))
183 self.default_value = parts[1] if len(parts) != 1 else None 161 self.default_value = parts[1] if len(parts) != 1 else None
(...skipping 30 matching lines...) Expand all
214 default_config = { 192 default_config = {
215 "settings": {}, 193 "settings": {},
216 "observers": {} 194 "observers": {}
217 } 195 }
218 if not file_name: 196 if not file_name:
219 return default_config 197 return default_config
220 with open(file_name) as config_file: 198 with open(file_name) as config_file:
221 return _json5_loads(config_file.read()) or default_config 199 return _json5_loads(config_file.read()) or default_config
222 200
223 201
202 def build_observers():
203 all_pidl_probes = set()
204 for f in files:
205 probes = set([probe.name for probe in f.declarations])
206 if all_pidl_probes & probes:
207 raise Exception("Multiple probe declarations: %s" % all_pidl_probes & probes)
208 all_pidl_probes |= probes
209
210 all_observers = set()
211 observers_by_probe = {}
212 unused_probes = set(all_pidl_probes)
213 for observer_name in config["observers"]:
214 all_observers.add(observer_name)
215 observer = config["observers"][observer_name]
216 for probe in observer["probes"]:
217 unused_probes.discard(probe)
218 if probe not in all_pidl_probes:
219 raise Exception('Probe %s is not declared in PIDL file' % probe)
220 if probe not in observers_by_probe:
221 observers_by_probe[probe] = set()
222 observers_by_probe[probe].add(observer_name)
223 if unused_probes:
224 raise Exception("Unused probes: %s" % unused_probes)
225
226 for f in files:
227 for probe in f.declarations:
228 probe.agents = observers_by_probe[probe.name]
229 if probe.returns_value and len(probe.agents) > 1:
230 raise Exception("Can only return value from a single observer: % s\n" % probe.name)
231 return all_observers
232
233
224 cmdline_parser = optparse.OptionParser() 234 cmdline_parser = optparse.OptionParser()
225 cmdline_parser.add_option("--output_dir") 235 cmdline_parser.add_option("--output_dir")
226 cmdline_parser.add_option("--config") 236 cmdline_parser.add_option("--config")
227 237
228 try: 238 try:
229 arg_options, arg_values = cmdline_parser.parse_args() 239 arg_options, arg_values = cmdline_parser.parse_args()
230 if len(arg_values) != 1: 240 if len(arg_values) != 1:
231 raise Exception("Exactly one plain argument expected (found %s)" % len(a rg_values)) 241 raise Exception("Exactly one plain argument expected (found %s)" % len(a rg_values))
232 input_path = arg_values[0] 242 input_path = arg_values[0]
233 output_dirpath = arg_options.output_dir 243 output_dirpath = arg_options.output_dir
234 if not output_dirpath: 244 if not output_dirpath:
235 raise Exception("Output directory must be specified") 245 raise Exception("Output directory must be specified")
236 config_file_name = arg_options.config 246 config_file_name = arg_options.config
237 except Exception: 247 except Exception:
238 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html 248 # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
239 exc = sys.exc_info()[1] 249 exc = sys.exc_info()[1]
240 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc) 250 sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
241 sys.stderr.write("Usage: <script> [options] <probes.pidl>\n") 251 sys.stderr.write("Usage: <script> [options] <probes.pidl>\n")
242 sys.stderr.write("Options:\n") 252 sys.stderr.write("Options:\n")
243 sys.stderr.write("\t--config <config_file.json5>\n") 253 sys.stderr.write("\t--config <config_file.json5>\n")
244 sys.stderr.write("\t--output_dir <output_dir>\n") 254 sys.stderr.write("\t--output_dir <output_dir>\n")
245 exit(1) 255 exit(1)
246 256
247 config = load_config(config_file_name) 257 config = load_config(config_file_name)
248 jinja_env = initialize_jinja_env(output_dirpath) 258 jinja_env = initialize_jinja_env(output_dirpath)
249 all_agents = set()
250 base_name = os.path.splitext(os.path.basename(input_path))[0] 259 base_name = os.path.splitext(os.path.basename(input_path))[0]
251 260
252 fin = open(input_path, "r") 261 fin = open(input_path, "r")
253 files = load_model_from_idl(fin.read()) 262 files = load_model_from_idl(fin.read())
254 fin.close() 263 fin.close()
255 264
256 for f in files:
257 for declaration in f.declarations:
258 for agent in declaration.agents:
259 all_agents.add(agent)
260
261 template_context = { 265 template_context = {
262 "files": files, 266 "files": files,
263 "agents": all_agents, 267 "agents": build_observers(),
264 "config": config, 268 "config": config,
265 "name": base_name, 269 "name": base_name,
266 "input_file": os.path.basename(input_path) 270 "input_file": os.path.basename(input_path)
267 } 271 }
268 cpp_template = jinja_env.get_template("/InstrumentingProbesImpl.cpp.tmpl") 272 cpp_template = jinja_env.get_template("/InstrumentingProbesImpl.cpp.tmpl")
269 cpp_file = open(output_dirpath + "/" + base_name + "Impl.cpp", "w") 273 cpp_file = open(output_dirpath + "/" + base_name + "Impl.cpp", "w")
270 cpp_file.write(cpp_template.render(template_context)) 274 cpp_file.write(cpp_template.render(template_context))
271 cpp_file.close() 275 cpp_file.close()
272 276
273 sink_h_template = jinja_env.get_template("/ProbeSink.h.tmpl") 277 sink_h_template = jinja_env.get_template("/ProbeSink.h.tmpl")
274 sink_h_file = open(output_dirpath + "/" + to_singular(base_name) + "Sink.h", "w" ) 278 sink_h_file = open(output_dirpath + "/" + to_singular(base_name) + "Sink.h", "w" )
275 sink_h_file.write(sink_h_template.render(template_context)) 279 sink_h_file.write(sink_h_template.render(template_context))
276 sink_h_file.close() 280 sink_h_file.close()
277 281
278 for f in files: 282 for f in files:
279 template_context["file"] = f 283 template_context["file"] = f
280 h_template = jinja_env.get_template("/InstrumentingProbesInl.h.tmpl") 284 h_template = jinja_env.get_template("/InstrumentingProbesInl.h.tmpl")
281 h_file = open(output_dirpath + "/" + f.header_name + ".h", "w") 285 h_file = open(output_dirpath + "/" + f.header_name + ".h", "w")
282 h_file.write(h_template.render(template_context)) 286 h_file.write(h_template.render(template_context))
283 h_file.close() 287 h_file.close()
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/probe/CoreProbes.json5 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698