• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(() => {
6  let all_profiles = [];
7  let instanceMap = new WeakMap();
8  let instanceCounter = 0;
9
10  function instrument(imports, profile) {
11    let orig_imports = imports;
12    return new Proxy(imports, {
13      get: (obj, module_name) => {
14        let orig_module = orig_imports[module_name];
15        return new Proxy(orig_module, {
16          get: (obj, item_name) => {
17            let orig_func = orig_module[item_name];
18            let item = orig_func;
19            if (typeof orig_func == "function") {
20              var full_name = module_name + "." + item_name;
21              print("instrumented " + full_name);
22              profile[full_name] = {name: full_name, count: 0, total: 0};
23              item = function profiled_func(...args) {
24                var before = performance.now();
25                var result = orig_func(...args);
26                var delta = performance.now() - before;
27                var data = profile[full_name];
28                data.count++;
29                data.total += delta;
30                return result;
31              }
32            }
33            return item;
34          }
35        })
36      }
37    });
38  }
39
40  function dumpProfile(profile) {
41    let array = [];
42    for (let key in profile) {
43      if (key == "instanceNum") continue;
44      let data = profile[key];
45      if (data.count == 0) continue;
46      array.push(data);
47    }
48    print(`--- Import profile for instance ${profile.instanceNum} ---`);
49    if (array.length == 0) return;
50    array.sort((a, b) => b.total - a.total);
51    for (let data of array) {
52      print(`${padl(data.name, 30)}: ${padr(data.count, 10)} ${padp(data.total, 10)}ms`);
53    }
54  }
55
56  function padl(s, len) {
57    s = s.toString();
58    while (s.length < len) s = s + " ";
59    return s;
60  }
61  function padr(s, len) {
62    s = s.toString();
63    while (s.length < len) s = " " + s;
64    return s;
65  }
66  function padp(s, len) {
67    s = s.toString();
68    var i = s.indexOf(".");
69    if (i == -1) i = s.length;
70    while (i++ < len) s = " " + s;
71    return s;
72  }
73
74  // patch: WebAssembly.instantiate (async)
75  let orig_instantiate = WebAssembly.instantiate;
76  WebAssembly.instantiate = (m, imports, ...args) => {
77    let profile = {};
78    let promise = orig_instantiate(m, instrument(imports, profile), ...args);
79    promise.then((instance) => {
80      instanceMap.set(instance, profile);
81      all_profiles.push(profile);
82      profile.instanceNum = instanceCounter++;
83    });
84    return promise;
85  }
86
87  // patch: new WebAssembly.Instance (sync)
88  let orig_new_instance = WebAssembly.Instance;
89  WebAssembly.Instance = new Proxy(orig_new_instance, {
90    construct: (target, args) => {
91      let profile = {};
92      args[1] = instrument(args[1], profile);
93      let instance = new orig_new_instance(...args);
94      instanceMap.set(instance, profile);
95      all_profiles.push(profile);
96      profile.instanceNum = instanceCounter++;
97      return instance;
98    }
99  });
100
101  // expose: WebAssembly.dumpProfile(instance)
102  WebAssembly.dumpProfile = (instance) => {
103    let profile = instanceMap.get(instance);
104    if (profile === undefined) return;
105    dumpProfile(profile);
106  }
107  // expose: WebAssembly.clearProfile(instance)
108  WebAssembly.clearProfile = (instance) => {
109    let profile = instanceMap.get(instance);
110    if (profile === undefined) return;
111    for (let key in profile) {
112      if (key == "instanceNum") continue;
113      let data = p[key];
114      data.count = 0;
115      data.total = 0;
116    }
117  }
118  // expose: WebAssembly.dumpAllProfiles()
119  WebAssembly.dumpAllProfiles = () => {
120    for (let profile of all_profiles) dumpProfile(profile);
121  }
122  // expose: WebAssembly.getProfile(instance)
123  // returns: {
124  //    func_name1: {name: func_name1, count: <num>, total: <num>}
125  //    func_name2: {name: func_name1, count: <num>, total: <num>}
126  //    ...
127  // }
128  WebAssembly.getProfile = (instance) => {
129    return instanceMap.get(instance);
130  }
131})();
132