summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/Metrics.cpp95
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/wasm-binary.h13
-rw-r--r--src/wasm/wasm-binary.cpp1
-rw-r--r--test/passes/func-metrics.txt93
-rw-r--r--test/passes/func-metrics.wast56
-rw-r--r--test/passes/metrics.txt6
8 files changed, 239 insertions, 27 deletions
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index fe14135a4..822596cb3 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -19,6 +19,7 @@
#include <pass.h>
#include <support/colors.h>
#include <wasm.h>
+#include <wasm-binary.h>
namespace wasm {
@@ -26,6 +27,10 @@ using namespace std;
// Prints metrics between optimization passes.
struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<Metrics>>> {
+ bool byFunction;
+
+ Metrics(bool byFunction) : byFunction(byFunction) {}
+
static Metrics *lastMetricsPass;
map<const char *, int> counts;
@@ -35,28 +40,25 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
counts[name]++;
}
- void visitModule(Module* module) {
- ostream &o = cout;
- o << "Counts"
- << "\n";
- vector<const char*> keys;
- int total = 0;
- for (auto i : counts) {
- keys.push_back(i.first);
- total += i.second;
+ void doWalkModule(Module* module) {
+ // global things
+
+ for (auto& curr : module->functionTypes) {
+ visitFunctionType(curr.get());
}
- // add total
- keys.push_back("[total]");
- counts["[total]"] = total;
- // add vars
- size_t vars = 0;
- for (auto& func : module->functions) {
- vars += func->getNumVars();
+ for (auto& curr : module->imports) {
+ visitImport(curr.get());
+ }
+ for (auto& curr : module->exports) {
+ visitExport(curr.get());
}
- keys.push_back("[vars]");
- counts["[vars]"] = vars;
+ for (auto& curr : module->globals) {
+ walkGlobal(curr.get());
+ }
+ walkTable(&module->table);
+ walkMemory(&module->memory);
+
// add functions
- keys.push_back("[funcs]");
counts["[funcs]"] = module->functions.size();
// add memory and table
if (module->memory.exists) {
@@ -64,7 +66,6 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
for (auto& segment: module->memory.segments) {
size += segment.data.size();
}
- keys.push_back("[memory-data]");
counts["[memory-data]"] = size;
}
if (module->table.exists) {
@@ -72,13 +73,58 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
for (auto& segment: module->table.segments) {
size += segment.data.size();
}
- keys.push_back("[table-data]");
counts["[table-data]"] = size;
}
+
+ if (byFunction) {
+ // print global
+ printCounts("global");
+ // compute binary info, so we know function sizes
+ BufferWithRandomAccess buffer;
+ WasmBinaryWriter writer(module, buffer);
+ writer.write();
+ // print for each function
+ for (Index i = 0; i < module->functions.size(); i++) {
+ auto* func = module->functions[i].get();
+ counts.clear();
+ walkFunction(func);
+ counts["[vars]"] = func->getNumVars();
+ counts["[binary-bytes]"] = writer.tableOfContents.functionBodies[i].size;
+ printCounts(std::string("func: ") + func->name.str);
+ }
+ // can't comapre detailed info between passes yet
+ lastMetricsPass = nullptr;
+ } else {
+ // add function info
+ size_t vars = 0;
+ for (auto& func : module->functions) {
+ walkFunction(func.get());
+ vars += func->getNumVars();
+ }
+ counts["[vars]"] = vars;
+ // print
+ printCounts("total");
+ // compare to next time
+ lastMetricsPass = this;
+ }
+ }
+
+ void printCounts(std::string title) {
+ ostream &o = cout;
+ vector<const char*> keys;
+ // add total
+ int total = 0;
+ for (auto i : counts) {
+ keys.push_back(i.first);
+ total += i.second;
+ }
+ keys.push_back("[total]");
+ counts["[total]"] = total;
// sort
sort(keys.begin(), keys.end(), [](const char* a, const char* b) -> bool {
return strcmp(b, a) > 0;
});
+ o << title << "\n";
for (auto* key : keys) {
auto value = counts[key];
o << " " << left << setw(15) << key << ": " << setw(8)
@@ -101,12 +147,15 @@ struct Metrics : public WalkerPass<PostWalker<Metrics, UnifiedExpressionVisitor<
}
o << "\n";
}
- lastMetricsPass = this;
}
};
Pass *createMetricsPass() {
- return new Metrics();
+ return new Metrics(false);
+}
+
+Pass *createFunctionMetricsPass() {
+ return new Metrics(true);
}
Metrics *Metrics::lastMetricsPass;
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 2820b59e5..88734e85a 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -73,6 +73,7 @@ void PassRegistry::registerPasses() {
registerPass("duplicate-function-elimination", "removes duplicate functions", createDuplicateFunctionEliminationPass);
registerPass("extract-function", "leaves just one function (useful for debugging)", createExtractFunctionPass);
registerPass("flatten", "flattens out code, removing nesting", createFlattenPass);
+ registerPass("func-metrics", "reports function metrics", createFunctionMetricsPass);
registerPass("inlining", "inlines functions", createInliningPass);
registerPass("inlining-optimizing", "inlines functions and optimizes where we inlined", createInliningOptimizingPass);
registerPass("legalize-js-interface", "legalizes i64 types on the import/export boundary", createLegalizeJSInterfacePass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index 081f7e203..230cdfd86 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -32,6 +32,7 @@ Pass* createDuplicateFunctionEliminationPass();
Pass* createExtractFunctionPass();
Pass* createFlattenPass();
Pass* createFullPrinterPass();
+Pass* createFunctionMetricsPass();
Pass* createI64ToI32LoweringPass();
Pass* createInliningPass();
Pass* createInliningOptimizingPass();
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 12aecfeaa..813404895 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -666,10 +666,21 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
void prepare();
public:
- WasmBinaryWriter(Module* input, BufferWithRandomAccess& o, bool debug) : wasm(input), o(o), debug(debug) {
+ WasmBinaryWriter(Module* input, BufferWithRandomAccess& o, bool debug = false) : wasm(input), o(o), debug(debug) {
prepare();
}
+ // locations in the output binary for the various parts of the module
+ struct TableOfContents {
+ struct Entry {
+ Name name;
+ size_t offset; // where the entry starts
+ size_t size; // the size of the entry
+ Entry(Name name, size_t offset, size_t size) : name(name), offset(offset), size(size) {}
+ };
+ std::vector<Entry> functionBodies;
+ } tableOfContents;
+
void setNamesSection(bool set) { debugInfo = set; }
void setSourceMap(std::ostream* set, std::string url) {
sourceMap = set;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 1a7ab6267..514b489a9 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -287,6 +287,7 @@ void WasmBinaryWriter::writeFunctions() {
std::move(&o[start], &o[start] + size, &o[sizePos] + sizeFieldSize);
o.resize(o.size() - (MaxLEB32Bytes - sizeFieldSize));
}
+ tableOfContents.functionBodies.emplace_back(function->name, sizePos + sizeFieldSize, size);
}
currFunction = nullptr;
finishSection(start);
diff --git a/test/passes/func-metrics.txt b/test/passes/func-metrics.txt
new file mode 100644
index 000000000..c9b77eeaa
--- /dev/null
+++ b/test/passes/func-metrics.txt
@@ -0,0 +1,93 @@
+global
+ [funcs] : 3
+ [memory-data] : 9
+ [table-data] : 3
+ [total] : 18
+ const : 3
+func: empty
+ [binary-bytes] : 3
+ [total] : 4
+ [vars] : 0
+ nop : 1
+func: small
+ [binary-bytes] : 9
+ [total] : 14
+ [vars] : 0
+ block : 1
+ const : 1
+ drop : 1
+ nop : 1
+ return : 1
+func: ifs
+ [binary-bytes] : 51
+ [total] : 76
+ [vars] : 1
+ binary : 1
+ block : 1
+ const : 12
+ drop : 6
+ if : 4
+(module
+ (type $0 (func (param i32)))
+ (type $1 (func))
+ (global $glob i32 (i32.const 1337))
+ (table 256 256 anyfunc)
+ (elem (i32.const 0) $ifs $ifs $ifs)
+ (memory $0 256 256)
+ (data (i32.const 0) "\ff\ef\0f\1f 0@P\99")
+ (func $empty (; 0 ;) (type $1)
+ (nop)
+ )
+ (func $small (; 1 ;) (type $1)
+ (nop)
+ (drop
+ (i32.const 100421)
+ )
+ (return)
+ )
+ (func $ifs (; 2 ;) (type $0) (param $x i32)
+ (local $y f32)
+ (block $block0
+ (if
+ (i32.const 0)
+ (drop
+ (i32.const 1)
+ )
+ )
+ (if
+ (i32.const 0)
+ (drop
+ (i32.const 1)
+ )
+ (drop
+ (i32.const 2)
+ )
+ )
+ (if
+ (i32.const 4)
+ (drop
+ (i32.const 5)
+ )
+ (drop
+ (i32.const 6)
+ )
+ )
+ (drop
+ (i32.eq
+ (if (result i32)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+ )
+ (i32.const 177)
+ )
+ )
+ )
+ )
+)
+global
+ [funcs] : 0
+ [total] : 0
+(module
+ (memory $0 0)
+)
diff --git a/test/passes/func-metrics.wast b/test/passes/func-metrics.wast
new file mode 100644
index 000000000..9c2f35a81
--- /dev/null
+++ b/test/passes/func-metrics.wast
@@ -0,0 +1,56 @@
+(module
+ (memory 256 256)
+ (table 256 256 anyfunc)
+ (elem (i32.const 0) $ifs $ifs $ifs)
+ (data (i32.const 0) "\ff\ef\0f\1f\20\30\40\50\99")
+ (type $0 (func (param i32)))
+ (global $glob i32 (i32.const 1337))
+ (func $empty)
+ (func $small
+ (nop)
+ (drop (i32.const 100421))
+ (return)
+ )
+ (func $ifs (type $0) (param $x i32)
+ (local $y f32)
+ (block $block0
+ (if
+ (i32.const 0)
+ (drop
+ (i32.const 1)
+ )
+ )
+ (if
+ (i32.const 0)
+ (drop
+ (i32.const 1)
+ )
+ (drop
+ (i32.const 2)
+ )
+ )
+ (if
+ (i32.const 4)
+ (drop
+ (i32.const 5)
+ )
+ (drop
+ (i32.const 6)
+ )
+ )
+ (drop
+ (i32.eq
+ (if (result i32)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+ )
+ (i32.const 177)
+ )
+ )
+ )
+ )
+)
+;; module with no table or memory or anything for that matter
+(module
+)
diff --git a/test/passes/metrics.txt b/test/passes/metrics.txt
index 9041f36fe..f2670c550 100644
--- a/test/passes/metrics.txt
+++ b/test/passes/metrics.txt
@@ -1,8 +1,8 @@
-Counts
+total
[funcs] : 1
[memory-data] : 9
[table-data] : 3
- [total] : 27
+ [total] : 41
[vars] : 1
binary : 1
block : 1
@@ -56,7 +56,7 @@ Counts
)
)
)
-Counts
+total
[funcs] : 0
[total] : 0
[vars] : 0