aboutsummaryrefslogtreecommitdiff
path: root/src/experimental/noncallgraphprofiling.diff
blob: 9bceeee98e65811f3b87708f613f64222f0b4a51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
diff --git a/src/jsifier.js b/src/jsifier.js
index da8c4db..2d606be 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -432,12 +432,16 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
       func.JS = '\nfunction ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n';
 
       if (PROFILE) {
-        func.JS += '  if (PROFILING) { '
-                +      'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
-                +      'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
-                +      'PROFILING_NODE.calls++; '
-                +      'var __profilingStartTime__ = Date.now() '
-                +    '}\n';
+        if (PROFILE_CALLGRAPH) {
+          func.JS += '  if (PROFILING) { '
+                  +      'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; '
+                  +      'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };'
+                  +      'PROFILING_NODE.calls++; '
+                  +      'var __profilingStartTime__ = Date.now() '
+                  +    '}\n';
+        } else {
+          func.JS += '  PROFILING_DATA[' + Profiling.getIndex(func.ident) + '] -= Date.now();';
+        }
       }
 
       func.JS += '  ' + RuntimeGenerator.stackEnter(func.initialStack) + ';\n';
@@ -733,10 +737,14 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
   makeFuncLineActor('return', function(item) {
     var ret = RuntimeGenerator.stackExit(item.funcData.initialStack) + ';\n';
     if (PROFILE) {
-      ret += 'if (PROFILING) { '
-          +    'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
-          +    'PROFILING_NODE = __parentProfilingNode__ '
-          +  '}\n';
+      if (PROFILE_CALLGRAPH) {
+        ret += 'if (PROFILING) { '
+            +    'PROFILING_NODE.time += Date.now() - __profilingStartTime__; '
+            +    'PROFILING_NODE = __parentProfilingNode__ '
+            +  '}\n';
+      } else {
+        ret += 'PROFILING_DATA[' + Profiling.getIndex(item.funcData.ident) + '] += Date.now();'
+      }
     }
     if (LABEL_DEBUG) {
       ret += "print(INDENT + 'Exiting: " + item.funcData.ident + "');\n"
@@ -945,6 +953,9 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
     print(shellParts[0]);
       var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
       var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()), CONSTANTS));
+      if (PROFILE && !PROFILE_CALLGRAPH) {
+        pre = pre.replace('{{PROFILING_DATA}}', Profiling.generateIndexing());
+      }
       print(pre);
       print('Runtime.QUANTUM_SIZE = ' + QUANTUM_SIZE);
       if (RUNTIME_TYPE_INFO) {
diff --git a/src/modules.js b/src/modules.js
index 20f42f9..624c5ae 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -226,13 +226,15 @@ var Functions = {
 
   indexedFunctions: [0, 0], // Start at a non-0 (even, see below) value
 
+  skip: true,
+
   // Mark a function as needing indexing, and returns the index
   getIndex: function(ident) {
     var key = this.indexedFunctions.indexOf(ident);
     if (key < 0) {
       key = this.indexedFunctions.length;
       this.indexedFunctions[key] = ident;
-      this.indexedFunctions[key+1] = 0; // Need to have keys be even numbers, see |polymorph| test
+      if (this.skip) this.indexedFunctions[key+1] = 0; // Need to have keys be even numbers, see |polymorph| test
     }
     return key.toString();
   },
@@ -281,3 +283,19 @@ var LibraryManager = {
   }
 };
 
+var Profiling = { // We use the same principle of function hashing as in Functions
+  currFunctions: [],
+  implementedFunctions: null,
+  indexedFunctions: [],
+  getIndex: Functions.getIndex,
+
+  generateIndexing: function() {
+    var ret = 'var PROFILING_DATA = new Array(' + this.indexedFunctions.length + ');\n'
+            + 'for (var i = 0; i < ' + this.indexedFunctions.length + '; i++) {\n'
+            + '  PROFILING_DATA[i] = 0;\n'
+            + '}\n'
+            + 'var PROFILING_NAMES = ' + JSON.stringify(this.indexedFunctions) + ';\n';
+    return ret;
+  }
+};
+
diff --git a/src/preamble.js b/src/preamble.js
index 1c1ec91..1bda448 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -276,22 +276,26 @@ var START_TIME = Date.now();
 
 #if PROFILE
 var PROFILING = 0;
+
+#if PROFILE_CALLGRAPH
 var PROFILING_ROOT = { time: 0, children: {}, calls: 0 };
 var PROFILING_NODE;
-
 function startProfiling() {
   PROFILING_NODE = PROFILING_ROOT;
   PROFILING = 1;
 }
 Module['startProfiling'] = startProfiling;
-
 function stopProfiling() {
   PROFILING = 0;
   assert(PROFILING_NODE === PROFILING_ROOT, 'Must have popped all the profiling call stack');
 }
 Module['stopProfiling'] = stopProfiling;
+#else
+{{PROFILING_DATA}}
+#endif
 
 function printProfiling() {
+#if PROFILE_CALLGRAPH
   function dumpData(name_, node, indent) {
     print(indent + ('________' + node.time).substr(-8) + ': ' + name_ + ' (' + node.calls + ')');
     var children = [];
@@ -303,9 +307,20 @@ function printProfiling() {
     children.forEach(function(child) { dumpData(child.name_, child, indent + '  ') });
   }
   dumpData('root', PROFILING_ROOT, ' ');
+#else
+  var items = [];
+  for (var i = 0; i < PROFILING_NAMES.length; i++) {
+    items.push({ name_: PROFILING_NAMES[i], time: PROFILING_DATA[i] });
+  }
+  items.sort(function(x, y) { return y.time - x.time });
+  items.forEach(function(item) {
+    print(('________' + item.time).substr(-8) + ': ' + item.name_);
+  });
+#endif
 }
 Module['printProfiling'] = printProfiling;
 
+#if PROFILE_CALLGRAPH
 function printXULProfiling() {
   function dumpData(name_, node, indent) {
     var children = [];
@@ -357,6 +372,7 @@ function printXULProfiling() {
 }
 Module['printXULProfiling'] = printXULProfiling;
 #endif
+#endif
 
 //========================================
 // Runtime essentials
diff --git a/src/settings.js b/src/settings.js
index ef8b399..749468b 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -114,7 +114,8 @@ AUTO_OPTIMIZE = 0; // When run with the CHECK_* options, will not fail on errors
                    // checking enabled and which do not, that is, this is a way to automate the
                    // generation of line data for CORRECT_*_LINES options
 
-PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example.
+PROFILE = 1; // Enables runtime profiling. As lightweight as possible.
+PROFILE_CALLGRAPH = 0; // Much heavier profiling, of entire callgraphs.
 
 EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported, so they are guaranteed to
                                 // be accessible outside of the generated code.
diff --git a/tests/runner.py b/tests/runner.py
index f7ae9b0..3caedad 100644
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -3525,16 +3525,16 @@ if 'benchmark' not in str(sys.argv):
       def post(filename):
         src = open(filename, 'a')
         src.write('''
-          startProfiling();
+          //startProfiling();
           run();
-          stopProfiling();
+          //stopProfiling();
           printProfiling();
           print('*ok*');
         ''')
         src.close()
 
       # Using build_ll_hook forces a recompile, which leads to DFE being done even without opts
-      self.do_test(src, ': __Z6inner1i (5000)\n*ok*', post_build=post)
+      self.do_test(src, ': __Z6inner2i\n*ok*', post_build=post)
 
     ### Integration tests