github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/internal/engine/wazevo/wazevoapi/perfmap.go (about) 1 package wazevoapi 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "sync" 8 ) 9 10 var PerfMap *Perfmap 11 12 func init() { 13 if PerfMapEnabled { 14 pid := os.Getpid() 15 filename := "/tmp/perf-" + strconv.Itoa(pid) + ".map" 16 17 fh, err := os.OpenFile(filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0o644) 18 if err != nil { 19 panic(err) 20 } 21 22 PerfMap = &Perfmap{fh: fh} 23 } 24 } 25 26 // Perfmap holds perfmap entries to be flushed into a perfmap file. 27 type Perfmap struct { 28 entries []entry 29 mux sync.Mutex 30 fh *os.File 31 } 32 33 type entry struct { 34 index int 35 offset int64 36 size uint64 37 name string 38 } 39 40 func (f *Perfmap) Lock() { 41 f.mux.Lock() 42 } 43 44 func (f *Perfmap) Unlock() { 45 f.mux.Unlock() 46 } 47 48 // AddModuleEntry adds a perfmap entry into the perfmap file. 49 // index is the index of the function in the module, offset is the offset of the function in the module, 50 // size is the size of the function, and name is the name of the function. 51 // 52 // Note that the entries are not flushed into the perfmap file until Flush is called, 53 // and the entries are module-scoped; Perfmap must be locked until Flush is called. 54 func (f *Perfmap) AddModuleEntry(index int, offset int64, size uint64, name string) { 55 e := entry{index: index, offset: offset, size: size, name: name} 56 if f.entries == nil { 57 f.entries = []entry{e} 58 return 59 } 60 f.entries = append(f.entries, e) 61 } 62 63 // Flush writes the perfmap entries into the perfmap file where the entries are adjusted by the given `addr` and `functionOffsets`. 64 func (f *Perfmap) Flush(addr uintptr, functionOffsets []int) { 65 defer func() { 66 _ = f.fh.Sync() 67 }() 68 69 for _, e := range f.entries { 70 if _, err := f.fh.WriteString(fmt.Sprintf("%x %s %s\n", 71 uintptr(e.offset)+addr+uintptr(functionOffsets[e.index]), 72 strconv.FormatUint(e.size, 16), 73 e.name, 74 )); err != nil { 75 panic(err) 76 } 77 } 78 f.entries = f.entries[:0] 79 } 80 81 // Clear clears the perfmap entries not yet flushed. 82 func (f *Perfmap) Clear() { 83 f.entries = f.entries[:0] 84 } 85 86 // AddEntry writes a perfmap entry directly into the perfmap file, not using the entries. 87 func (f *Perfmap) AddEntry(addr uintptr, size uint64, name string) { 88 _, err := f.fh.WriteString(fmt.Sprintf("%x %s %s\n", 89 addr, 90 strconv.FormatUint(size, 16), 91 name, 92 )) 93 if err != nil { 94 panic(err) 95 } 96 }