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