blob: 9bceeee98e65811f3b87708f613f64222f0b4a51 [file] [log] [blame] [edit]
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