wazevo: adds perfmap build tag to write perf-map (#1880)
Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
This commit is contained in:
@@ -2231,7 +2231,7 @@ L1 (SSA Block: blk0):
|
|||||||
fmt.Println(be.Format())
|
fmt.Println(be.Format())
|
||||||
}
|
}
|
||||||
|
|
||||||
be.Finalize()
|
be.Finalize(context.Background())
|
||||||
if verbose {
|
if verbose {
|
||||||
fmt.Println("============ finalization result ============")
|
fmt.Println("============ finalization result ============")
|
||||||
fmt.Println(be.Format())
|
fmt.Println(be.Format())
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ type Compiler interface {
|
|||||||
RegAlloc()
|
RegAlloc()
|
||||||
|
|
||||||
// Finalize performs the finalization of the compilation. This must be called after RegAlloc.
|
// Finalize performs the finalization of the compilation. This must be called after RegAlloc.
|
||||||
Finalize()
|
Finalize(ctx context.Context)
|
||||||
|
|
||||||
// Encode encodes the machine code to the buffer.
|
// Encode encodes the machine code to the buffer.
|
||||||
Encode()
|
Encode()
|
||||||
@@ -150,21 +150,21 @@ type SourceOffsetInfo struct {
|
|||||||
// Compile implements Compiler.Compile.
|
// Compile implements Compiler.Compile.
|
||||||
func (c *compiler) Compile(ctx context.Context) ([]byte, []RelocationInfo, error) {
|
func (c *compiler) Compile(ctx context.Context) ([]byte, []RelocationInfo, error) {
|
||||||
c.Lower()
|
c.Lower()
|
||||||
if wazevoapi.PrintSSAToBackendIRLowering {
|
if wazevoapi.PrintSSAToBackendIRLowering && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[after lowering for %s ]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
fmt.Printf("[[[after lowering for %s ]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
||||||
}
|
}
|
||||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||||
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After lowering to ISA specific IR", c.Format())
|
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After lowering to ISA specific IR", c.Format())
|
||||||
}
|
}
|
||||||
c.RegAlloc()
|
c.RegAlloc()
|
||||||
if wazevoapi.PrintRegisterAllocated {
|
if wazevoapi.PrintRegisterAllocated && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[after regalloc for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
fmt.Printf("[[[after regalloc for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
||||||
}
|
}
|
||||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||||
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After Register Allocation", c.Format())
|
wazevoapi.VerifyOrSetDeterministicCompilationContextValue(ctx, "After Register Allocation", c.Format())
|
||||||
}
|
}
|
||||||
c.Finalize()
|
c.Finalize(ctx)
|
||||||
if wazevoapi.PrintFinalizedMachineCode {
|
if wazevoapi.PrintFinalizedMachineCode && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[after finalize for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
fmt.Printf("[[[after finalize for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), c.Format())
|
||||||
}
|
}
|
||||||
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
if wazevoapi.DeterministicCompilationVerifierEnabled {
|
||||||
@@ -184,10 +184,10 @@ func (c *compiler) RegAlloc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finalize implements Compiler.Finalize.
|
// Finalize implements Compiler.Finalize.
|
||||||
func (c *compiler) Finalize() {
|
func (c *compiler) Finalize(ctx context.Context) {
|
||||||
c.mach.SetupPrologue()
|
c.mach.SetupPrologue()
|
||||||
c.mach.SetupEpilogue()
|
c.mach.SetupEpilogue()
|
||||||
c.mach.ResolveRelativeAddresses()
|
c.mach.ResolveRelativeAddresses(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode implements Compiler.Encode.
|
// Encode implements Compiler.Encode.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package arm64
|
package arm64
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -355,7 +356,7 @@ func (m *machine) resolveAddressingMode(arg0offset, ret0offset int64, i *instruc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ResolveRelativeAddresses implements backend.Machine.
|
// ResolveRelativeAddresses implements backend.Machine.
|
||||||
func (m *machine) ResolveRelativeAddresses() {
|
func (m *machine) ResolveRelativeAddresses(ctx context.Context) {
|
||||||
if len(m.unresolvedAddressModes) > 0 {
|
if len(m.unresolvedAddressModes) > 0 {
|
||||||
arg0offset, ret0offset := m.arg0OffsetFromSP(), m.ret0OffsetFromSP()
|
arg0offset, ret0offset := m.arg0OffsetFromSP(), m.ret0OffsetFromSP()
|
||||||
for _, i := range m.unresolvedAddressModes {
|
for _, i := range m.unresolvedAddressModes {
|
||||||
@@ -366,6 +367,18 @@ func (m *machine) ResolveRelativeAddresses() {
|
|||||||
// Reuse the slice to gather the unresolved conditional branches.
|
// Reuse the slice to gather the unresolved conditional branches.
|
||||||
cbrs := m.condBrRelocs[:0]
|
cbrs := m.condBrRelocs[:0]
|
||||||
|
|
||||||
|
var fn string
|
||||||
|
var fnIndex int
|
||||||
|
var labelToSSABlockID map[label]ssa.BasicBlockID
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
fn = wazevoapi.GetCurrentFunctionName(ctx)
|
||||||
|
labelToSSABlockID = make(map[label]ssa.BasicBlockID)
|
||||||
|
for i, l := range m.ssaBlockIDToLabels {
|
||||||
|
labelToSSABlockID[l] = ssa.BasicBlockID(i)
|
||||||
|
}
|
||||||
|
fnIndex = wazevoapi.GetCurrentFunctionIndex(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Next, in order to determine the offsets of relative jumps, we have to calculate the size of each label.
|
// Next, in order to determine the offsets of relative jumps, we have to calculate the size of each label.
|
||||||
var offset int64
|
var offset int64
|
||||||
for i, pos := range m.orderedBlockLabels {
|
for i, pos := range m.orderedBlockLabels {
|
||||||
@@ -397,6 +410,20 @@ func (m *machine) ResolveRelativeAddresses() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
if size > 0 {
|
||||||
|
l := pos.l
|
||||||
|
var labelStr string
|
||||||
|
if blkID, ok := labelToSSABlockID[l]; ok {
|
||||||
|
labelStr = fmt.Sprintf("%s::SSA_Block[%s]", l, blkID)
|
||||||
|
} else {
|
||||||
|
labelStr = l.String()
|
||||||
|
}
|
||||||
|
wazevoapi.PerfMap.AddModuleEntry(fnIndex, offset, uint64(size), fmt.Sprintf("%s:::::%s", fn, labelStr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos.binarySize = size
|
pos.binarySize = size
|
||||||
offset += size
|
offset += size
|
||||||
}
|
}
|
||||||
@@ -421,7 +448,8 @@ func (m *machine) ResolveRelativeAddresses() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if needRerun {
|
if needRerun {
|
||||||
m.ResolveRelativeAddresses()
|
m.ResolveRelativeAddresses(ctx)
|
||||||
|
wazevoapi.PerfMap.Clear()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ func (m *mockCompiler) Buf() []byte { return m.buf }
|
|||||||
func (m *mockCompiler) TypeOf(v regalloc.VReg) (ret ssa.Type) {
|
func (m *mockCompiler) TypeOf(v regalloc.VReg) (ret ssa.Type) {
|
||||||
return m.typeOf[v.ID()]
|
return m.typeOf[v.ID()]
|
||||||
}
|
}
|
||||||
func (m *mockCompiler) Finalize() {}
|
func (m *mockCompiler) Finalize(context.Context) {}
|
||||||
func (m *mockCompiler) RegAlloc() {}
|
func (m *mockCompiler) RegAlloc() {}
|
||||||
func (m *mockCompiler) Lower() {}
|
func (m *mockCompiler) Lower() {}
|
||||||
func (m *mockCompiler) Format() string { return "" }
|
func (m *mockCompiler) Format() string { return "" }
|
||||||
func (m *mockCompiler) Init() {}
|
func (m *mockCompiler) Init() {}
|
||||||
|
|
||||||
func newMockCompilationContext() *mockCompiler {
|
func newMockCompilationContext() *mockCompiler {
|
||||||
return &mockCompiler{
|
return &mockCompiler{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
|
||||||
@@ -89,7 +91,7 @@ type (
|
|||||||
|
|
||||||
// ResolveRelativeAddresses resolves the relative addresses after register allocations and prologue/epilogue setup.
|
// ResolveRelativeAddresses resolves the relative addresses after register allocations and prologue/epilogue setup.
|
||||||
// After this, the compiler is finally ready to emit machine code.
|
// After this, the compiler is finally ready to emit machine code.
|
||||||
ResolveRelativeAddresses()
|
ResolveRelativeAddresses(ctx context.Context)
|
||||||
|
|
||||||
// ResolveRelocations resolves the relocations after emitting machine code.
|
// ResolveRelocations resolves the relocations after emitting machine code.
|
||||||
ResolveRelocations(refToBinaryOffset map[ssa.FuncRef]int, binary []byte, relocations []RelocationInfo)
|
ResolveRelocations(refToBinaryOffset map[ssa.FuncRef]int, binary []byte, relocations []RelocationInfo)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc"
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/ssa"
|
||||||
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
|
"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
|
||||||
@@ -50,7 +52,7 @@ func (m mockMachine) SetupPrologue() {}
|
|||||||
func (m mockMachine) SetupEpilogue() {}
|
func (m mockMachine) SetupEpilogue() {}
|
||||||
|
|
||||||
// ResolveRelativeAddresses implements Machine.ResolveRelativeAddresses.
|
// ResolveRelativeAddresses implements Machine.ResolveRelativeAddresses.
|
||||||
func (m mockMachine) ResolveRelativeAddresses() {}
|
func (m mockMachine) ResolveRelativeAddresses(ctx context.Context) {}
|
||||||
|
|
||||||
// Function implements Machine.Function.
|
// Function implements Machine.Function.
|
||||||
func (m mockMachine) Function() (f regalloc.Function) { return }
|
func (m mockMachine) Function() (f regalloc.Function) { return }
|
||||||
|
|||||||
@@ -116,6 +116,11 @@ func NewEngine(ctx context.Context, _ api.CoreFeatures, fc filecache.Cache) wasm
|
|||||||
|
|
||||||
// CompileModule implements wasm.Engine.
|
// CompileModule implements wasm.Engine.
|
||||||
func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) (err error) {
|
func (e *engine) CompileModule(ctx context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) (err error) {
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
wazevoapi.PerfMap.Lock()
|
||||||
|
defer wazevoapi.PerfMap.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok, err := e.getCompiledModule(module, listeners, ensureTermination); ok { // cache hit!
|
if _, ok, err := e.getCompiledModule(module, listeners, ensureTermination); ok { // cache hit!
|
||||||
return nil
|
return nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -165,6 +170,11 @@ func (exec *executables) compileEntryPreambles(m *wasm.Module, machine backend.M
|
|||||||
buf := machine.CompileEntryPreamble(&sig)
|
buf := machine.CompileEntryPreamble(&sig)
|
||||||
executable := mmapExecutable(buf)
|
executable := mmapExecutable(buf)
|
||||||
exec.entryPreambles[i] = executable
|
exec.entryPreambles[i] = executable
|
||||||
|
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&executable[0])),
|
||||||
|
uint64(len(executable)), fmt.Sprintf("entry_preamble::type=%s", typ.String()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +227,7 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
|||||||
if len(def.ExportNames()) > 0 {
|
if len(def.ExportNames()) > 0 {
|
||||||
name = def.ExportNames()[0]
|
name = def.ExportNames()[0]
|
||||||
}
|
}
|
||||||
ctx = wazevoapi.SetCurrentFunctionName(ctx, fmt.Sprintf("[%d/%d] \"%s\"", i, len(module.CodeSection)-1, name))
|
ctx = wazevoapi.SetCurrentFunctionName(ctx, i, fmt.Sprintf("[%d/%d]%s", i, len(module.CodeSection)-1, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
needListener := len(listeners) > 0 && listeners[i] != nil
|
needListener := len(listeners) > 0 && listeners[i] != nil
|
||||||
@@ -271,6 +281,10 @@ func (e *engine) compileModule(ctx context.Context, module *wasm.Module, listene
|
|||||||
copy(executable[offset:], b)
|
copy(executable[offset:], b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&executable[0])), cm.functionOffsets)
|
||||||
|
}
|
||||||
|
|
||||||
if needSourceInfo {
|
if needSourceInfo {
|
||||||
for i := range cm.sourceMap.executableOffsets {
|
for i := range cm.sourceMap.executableOffsets {
|
||||||
cm.sourceMap.executableOffsets[i] += uintptr(unsafe.Pointer(&cm.executable[0]))
|
cm.sourceMap.executableOffsets[i] += uintptr(unsafe.Pointer(&cm.executable[0]))
|
||||||
@@ -310,7 +324,7 @@ func (e *engine) compileLocalWasmFunction(
|
|||||||
|
|
||||||
// Lower Wasm to SSA.
|
// Lower Wasm to SSA.
|
||||||
fe.LowerToSSA()
|
fe.LowerToSSA()
|
||||||
if wazevoapi.PrintSSA {
|
if wazevoapi.PrintSSA && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
fmt.Printf("[[[SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +335,7 @@ func (e *engine) compileLocalWasmFunction(
|
|||||||
// Run SSA-level optimization passes.
|
// Run SSA-level optimization passes.
|
||||||
ssaBuilder.RunPasses()
|
ssaBuilder.RunPasses()
|
||||||
|
|
||||||
if wazevoapi.PrintOptimizedSSA {
|
if wazevoapi.PrintOptimizedSSA && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[Optimized SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
fmt.Printf("[[[Optimized SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +346,7 @@ func (e *engine) compileLocalWasmFunction(
|
|||||||
// Finalize the layout of SSA blocks which might use the optimization results.
|
// Finalize the layout of SSA blocks which might use the optimization results.
|
||||||
ssaBuilder.LayoutBlocks()
|
ssaBuilder.LayoutBlocks()
|
||||||
|
|
||||||
if wazevoapi.PrintBlockLaidOutSSA {
|
if wazevoapi.PrintBlockLaidOutSSA && wazevoapi.PrintEnabledIndex(ctx) {
|
||||||
fmt.Printf("[[[Laidout SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
fmt.Printf("[[[Laidout SSA for %s]]]%s\n", wazevoapi.GetCurrentFunctionName(ctx), ssaBuilder.Format())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,6 +425,14 @@ func (e *engine) compileHostModule(ctx context.Context, module *wasm.Module, lis
|
|||||||
be.Encode()
|
be.Encode()
|
||||||
body := be.Buf()
|
body := be.Buf()
|
||||||
|
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
name := module.FunctionDefinition(wasm.Index(i)).DebugName()
|
||||||
|
wazevoapi.PerfMap.AddModuleEntry(i,
|
||||||
|
int64(totalSize),
|
||||||
|
uint64(len(body)),
|
||||||
|
fmt.Sprintf("trampoline:%s", name))
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: optimize as zero copy.
|
// TODO: optimize as zero copy.
|
||||||
copied := make([]byte, len(body))
|
copied := make([]byte, len(body))
|
||||||
copy(copied, body)
|
copy(copied, body)
|
||||||
@@ -430,6 +452,10 @@ func (e *engine) compileHostModule(ctx context.Context, module *wasm.Module, lis
|
|||||||
copy(executable[offset:], b)
|
copy(executable[offset:], b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
wazevoapi.PerfMap.Flush(uintptr(unsafe.Pointer(&executable[0])), cm.functionOffsets)
|
||||||
|
}
|
||||||
|
|
||||||
if runtime.GOARCH == "arm64" {
|
if runtime.GOARCH == "arm64" {
|
||||||
// On arm64, we cannot give all of rwx at the same time, so we change it to exec.
|
// On arm64, we cannot give all of rwx at the same time, so we change it to exec.
|
||||||
if err = platform.MprotectRX(executable); err != nil {
|
if err = platform.MprotectRX(executable); err != nil {
|
||||||
@@ -556,6 +582,10 @@ func (e *engine) compileSharedFunctions() {
|
|||||||
Results: []ssa.Type{ssa.TypeI32},
|
Results: []ssa.Type{ssa.TypeI32},
|
||||||
}, false)
|
}, false)
|
||||||
e.sharedFunctions.memoryGrowExecutable = mmapExecutable(src)
|
e.sharedFunctions.memoryGrowExecutable = mmapExecutable(src)
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
exe := e.sharedFunctions.memoryGrowExecutable
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "memory_grow_trampoline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.be.Init()
|
e.be.Init()
|
||||||
@@ -565,6 +595,10 @@ func (e *engine) compileSharedFunctions() {
|
|||||||
Results: []ssa.Type{ssa.TypeI32},
|
Results: []ssa.Type{ssa.TypeI32},
|
||||||
}, false)
|
}, false)
|
||||||
e.sharedFunctions.tableGrowExecutable = mmapExecutable(src)
|
e.sharedFunctions.tableGrowExecutable = mmapExecutable(src)
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
exe := e.sharedFunctions.tableGrowExecutable
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "table_grow_trampoline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.be.Init()
|
e.be.Init()
|
||||||
@@ -574,6 +608,10 @@ func (e *engine) compileSharedFunctions() {
|
|||||||
Results: []ssa.Type{ssa.TypeI32},
|
Results: []ssa.Type{ssa.TypeI32},
|
||||||
}, false)
|
}, false)
|
||||||
e.sharedFunctions.checkModuleExitCode = mmapExecutable(src)
|
e.sharedFunctions.checkModuleExitCode = mmapExecutable(src)
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
exe := e.sharedFunctions.checkModuleExitCode
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "check_module_exit_code_trampoline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.be.Init()
|
e.be.Init()
|
||||||
@@ -583,12 +621,20 @@ func (e *engine) compileSharedFunctions() {
|
|||||||
Results: []ssa.Type{ssa.TypeI64}, // returns the function reference.
|
Results: []ssa.Type{ssa.TypeI64}, // returns the function reference.
|
||||||
}, false)
|
}, false)
|
||||||
e.sharedFunctions.refFuncExecutable = mmapExecutable(src)
|
e.sharedFunctions.refFuncExecutable = mmapExecutable(src)
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
exe := e.sharedFunctions.refFuncExecutable
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "ref_func_trampoline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.be.Init()
|
e.be.Init()
|
||||||
{
|
{
|
||||||
src := e.machine.CompileStackGrowCallSequence()
|
src := e.machine.CompileStackGrowCallSequence()
|
||||||
e.sharedFunctions.stackGrowExecutable = mmapExecutable(src)
|
e.sharedFunctions.stackGrowExecutable = mmapExecutable(src)
|
||||||
|
if wazevoapi.PerfMapEnabled {
|
||||||
|
exe := e.sharedFunctions.stackGrowExecutable
|
||||||
|
wazevoapi.PerfMap.AddEntry(uintptr(unsafe.Pointer(&exe[0])), uint64(len(exe)), "stack_grow_trampoline")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.setFinalizer(e.sharedFunctions, sharedFunctionsFinalizer)
|
e.setFinalizer(e.sharedFunctions, sharedFunctionsFinalizer)
|
||||||
|
|||||||
@@ -40,6 +40,18 @@ const (
|
|||||||
PrintMachineCodeHexPerFunctionDisassemblable = false
|
PrintMachineCodeHexPerFunctionDisassemblable = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// printTarget is the function index to print the machine code. This is used for debugging to print the machine code
|
||||||
|
// of a specific function.
|
||||||
|
const printTarget = -1
|
||||||
|
|
||||||
|
// PrintEnabledIndex returns true if the current function index is the print target.
|
||||||
|
func PrintEnabledIndex(ctx context.Context) bool {
|
||||||
|
if printTarget == -1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return GetCurrentFunctionIndex(ctx) == printTarget
|
||||||
|
}
|
||||||
|
|
||||||
// ----- Validations -----
|
// ----- Validations -----
|
||||||
const (
|
const (
|
||||||
// SSAValidationEnabled enables the SSA validation. This is disabled by default since the operation is expensive.
|
// SSAValidationEnabled enables the SSA validation. This is disabled by default since the operation is expensive.
|
||||||
@@ -84,6 +96,7 @@ type (
|
|||||||
}
|
}
|
||||||
verifierStateContextKey struct{}
|
verifierStateContextKey struct{}
|
||||||
currentFunctionNameKey struct{}
|
currentFunctionNameKey struct{}
|
||||||
|
currentFunctionIndexKey struct{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDeterministicCompilationVerifierContext creates a new context with the deterministic compilation verifier used per wasm.Module.
|
// NewDeterministicCompilationVerifierContext creates a new context with the deterministic compilation verifier used per wasm.Module.
|
||||||
@@ -162,16 +175,26 @@ const NeedFunctionNameInContext = PrintSSA ||
|
|||||||
PrintRegisterAllocated ||
|
PrintRegisterAllocated ||
|
||||||
PrintFinalizedMachineCode ||
|
PrintFinalizedMachineCode ||
|
||||||
PrintMachineCodeHexPerFunction ||
|
PrintMachineCodeHexPerFunction ||
|
||||||
DeterministicCompilationVerifierEnabled
|
DeterministicCompilationVerifierEnabled ||
|
||||||
|
PerfMapEnabled
|
||||||
|
|
||||||
// SetCurrentFunctionName sets the current function name to the given `functionName`.
|
// SetCurrentFunctionName sets the current function name to the given `functionName`.
|
||||||
func SetCurrentFunctionName(ctx context.Context, functionName string) context.Context {
|
func SetCurrentFunctionName(ctx context.Context, index int, functionName string) context.Context {
|
||||||
return context.WithValue(ctx, currentFunctionNameKey{}, functionName)
|
ctx = context.WithValue(ctx, currentFunctionNameKey{}, functionName)
|
||||||
|
ctx = context.WithValue(ctx, currentFunctionIndexKey{}, index)
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentFunctionName returns the current function name.
|
// GetCurrentFunctionName returns the current function name.
|
||||||
func GetCurrentFunctionName(ctx context.Context) string {
|
func GetCurrentFunctionName(ctx context.Context) string {
|
||||||
return ctx.Value(currentFunctionNameKey{}).(string)
|
ret, _ := ctx.Value(currentFunctionNameKey{}).(string)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentFunctionIndex returns the current function index.
|
||||||
|
func GetCurrentFunctionIndex(ctx context.Context) int {
|
||||||
|
ret, _ := ctx.Value(currentFunctionIndexKey{}).(int)
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- High Register Pressure -----
|
// ----- High Register Pressure -----
|
||||||
|
|||||||
96
internal/engine/wazevo/wazevoapi/perfmap.go
Normal file
96
internal/engine/wazevo/wazevoapi/perfmap.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package wazevoapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var PerfMap *Perfmap
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if PerfMapEnabled {
|
||||||
|
pid := os.Getpid()
|
||||||
|
filename := "/tmp/perf-" + strconv.Itoa(pid) + ".map"
|
||||||
|
|
||||||
|
fh, err := os.OpenFile(filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
PerfMap = &Perfmap{fh: fh}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perfmap holds perfmap entries to be flushed into a perfmap file.
|
||||||
|
type Perfmap struct {
|
||||||
|
entries []entry
|
||||||
|
mux sync.Mutex
|
||||||
|
fh *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
type entry struct {
|
||||||
|
index int
|
||||||
|
offset int64
|
||||||
|
size uint64
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Perfmap) Lock() {
|
||||||
|
f.mux.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Perfmap) Unlock() {
|
||||||
|
f.mux.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddModuleEntry adds a perfmap entry into the perfmap file.
|
||||||
|
// index is the index of the function in the module, offset is the offset of the function in the module,
|
||||||
|
// size is the size of the function, and name is the name of the function.
|
||||||
|
//
|
||||||
|
// Note that the entries are not flushed into the perfmap file until Flush is called,
|
||||||
|
// and the entries are module-scoped; Perfmap must be locked until Flush is called.
|
||||||
|
func (f *Perfmap) AddModuleEntry(index int, offset int64, size uint64, name string) {
|
||||||
|
e := entry{index: index, offset: offset, size: size, name: name}
|
||||||
|
if f.entries == nil {
|
||||||
|
f.entries = []entry{e}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.entries = append(f.entries, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush writes the perfmap entries into the perfmap file where the entries are adjusted by the given `addr` and `functionOffsets`.
|
||||||
|
func (f *Perfmap) Flush(addr uintptr, functionOffsets []int) {
|
||||||
|
defer func() {
|
||||||
|
_ = f.fh.Sync()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, e := range f.entries {
|
||||||
|
if _, err := f.fh.WriteString(fmt.Sprintf("%x %s %s\n",
|
||||||
|
uintptr(e.offset)+addr+uintptr(functionOffsets[e.index]),
|
||||||
|
strconv.FormatUint(e.size, 16),
|
||||||
|
e.name,
|
||||||
|
)); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.entries = f.entries[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear clears the perfmap entries not yet flushed.
|
||||||
|
func (f *Perfmap) Clear() {
|
||||||
|
f.entries = f.entries[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEntry writes a perfmap entry directly into the perfmap file, not using the entries.
|
||||||
|
func (f *Perfmap) AddEntry(addr uintptr, size uint64, name string) {
|
||||||
|
_, err := f.fh.WriteString(fmt.Sprintf("%x %s %s\n",
|
||||||
|
addr,
|
||||||
|
strconv.FormatUint(size, 16),
|
||||||
|
name,
|
||||||
|
))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
5
internal/engine/wazevo/wazevoapi/perfmap_disabled.go
Normal file
5
internal/engine/wazevo/wazevoapi/perfmap_disabled.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !perfmap
|
||||||
|
|
||||||
|
package wazevoapi
|
||||||
|
|
||||||
|
const PerfMapEnabled = false
|
||||||
5
internal/engine/wazevo/wazevoapi/perfmap_enabled.go
Normal file
5
internal/engine/wazevo/wazevoapi/perfmap_enabled.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build perfmap
|
||||||
|
|
||||||
|
package wazevoapi
|
||||||
|
|
||||||
|
const PerfMapEnabled = true
|
||||||
Reference in New Issue
Block a user