Skip to content

Commit dfed573

Browse files
committed
port wakeuptime
1 parent c85a415 commit dfed573

File tree

8 files changed

+1046
-8
lines changed

8 files changed

+1046
-8
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
/tools/biopattern/biopattern
2121
/tools/biosnoop/biosnoop
2222
/tools/biostacks/biostacks
23+
/tools/biotop/biotop
2324
/tools/bitesize/bitesize
2425
/tools/cachestat/cachestat
26+
/tools/capable/capable
2527
/tools/cpudist/cpudist
2628
/tools/cpufreq/cpufreq
2729
/tools/drsnoop/drsnoop
@@ -34,6 +36,7 @@
3436
/tools/funclatency/funclatency
3537
/tools/gethostlatency/gethostlatency
3638
/tools/hardirqs/hardirqs
39+
/tools/javagc/javagc
3740
/tools/klockstat/klockstat
3841
/tools/ksnoop/ksnoop
3942
/tools/llcstat/llcstat
@@ -57,6 +60,9 @@
5760
/tools/tcpconnlat/tcpconnlat
5861
/tools/tcplife/tcplife
5962
/tools/tcprtt/tcprtt
63+
/tools/tcpstates/tcpstates
6064
/tools/tcpsynbl/tcpsynbl
65+
/tools/tcptop/tcptop
6166
/tools/tcptracer/tcptracer
6267
/tools/vfsstat/vfsstat
68+
/tools/wakeuptime/wakeuptime

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@
5858
* [ ] tcptop
5959
* [x] [tcptracer](./tools/tcptracer)
6060
* [ ] vfsstat
61-
* [ ] wakeuptime
61+
* [x] [wakeuptime](./tools/wakeuptime)

common/tracehelpers.go

Lines changed: 304 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package common
33
import (
44
"bufio"
55
"bytes"
6+
"debug/elf"
7+
"errors"
68
"fmt"
79
"os"
810
"sort"
@@ -196,7 +198,7 @@ type Ksym struct {
196198
}
197199

198200
type Ksyms struct {
199-
Syms []Ksym
201+
syms []Ksym
200202
// Strs string
201203
}
202204

@@ -220,31 +222,30 @@ func LoadKsyms() (*Ksyms, error) {
220222
return nil, err
221223
}
222224
name := fields[2]
223-
ksyms.Syms = append(ksyms.Syms, Ksym{
225+
ksyms.syms = append(ksyms.syms, Ksym{
224226
Name: name,
225227
Addr: addr,
226228
})
227229
}
228230

229-
syms := ksyms.Syms
231+
syms := ksyms.syms
230232
sort.Slice(syms, func(i, j int) bool {
231233
if syms[i].Addr == syms[j].Addr {
232234
return syms[i].Name >= syms[j].Name
233235
}
234236
return syms[i].Addr >= syms[j].Addr
235237
})
236238

237-
ksyms.Syms = syms
239+
ksyms.syms = syms
238240
return ksyms, nil
239241
}
240242

241243
func (k *Ksyms) MapAddr(addr uint64) *Ksym {
242-
syms := k.Syms
244+
syms := k.syms
243245
i := sort.Search(len(syms), func(i int) bool {
244246
return syms[i].Addr <= addr
245247
})
246248

247-
// fmt.Printf("%d ? %d\n", addr, i)
248249
if i < len(syms) {
249250
v := syms[i]
250251
return &v
@@ -253,11 +254,307 @@ func (k *Ksyms) MapAddr(addr uint64) *Ksym {
253254
}
254255

255256
func (k *Ksyms) GetSymbol(name string) *Ksym {
256-
for _, v := range k.Syms {
257+
for _, v := range k.syms {
257258
v := v
258259
if v.Name == name {
259260
return &v
260261
}
261262
}
262263
return nil
263264
}
265+
266+
type LoadRange struct {
267+
start uint64
268+
end uint64
269+
fileOff uint64
270+
}
271+
272+
const (
273+
EXEC = iota
274+
DYN
275+
PERF_MAP
276+
VDSO
277+
UNKNOWN
278+
)
279+
280+
type Sym struct {
281+
Name string
282+
start uint
283+
size uint
284+
}
285+
286+
type Syms struct {
287+
dsos []Dso
288+
}
289+
290+
func (s *Syms) MapAddr(addr uint64) *Sym {
291+
d, _ := s.findDso(addr)
292+
if d == nil {
293+
return nil
294+
}
295+
return nil
296+
}
297+
298+
func (s *Syms) findDso(addr uint64) (*Dso, uint64) {
299+
var offset uint64
300+
for _, d := range s.dsos {
301+
for _, r := range d.ranges {
302+
if addr <= r.start || addr >= r.end {
303+
continue
304+
}
305+
if d._type == DYN || d._type == VDSO {
306+
/* Offset within the mmap */
307+
offset = addr - r.start + r.fileOff
308+
/* Offset within the ELF for dyn symbol lookup */
309+
offset += d.shAddr - d.shOffset
310+
} else {
311+
offset = addr
312+
}
313+
return &d, offset
314+
}
315+
}
316+
317+
return nil, 0
318+
}
319+
320+
func (s *Syms) find_sym() {
321+
322+
}
323+
324+
type Dso struct {
325+
name string
326+
ranges []LoadRange
327+
// range_sz int
328+
/* Dyn's first text section virtual addr at execution */
329+
shAddr uint64
330+
/* Dyn's first text section file offset */
331+
shOffset uint64
332+
_type int
333+
syms []Sym
334+
335+
/*
336+
* libbpf's struct btf is actually a pretty efficient
337+
* "set of strings" data structure, so we create an
338+
* empty one and use it to store symbol names.
339+
*/
340+
// struct btf *btf;
341+
}
342+
343+
func (d *Dso) findSym(offset uint64) *Sym {
344+
syms := d.syms
345+
i := sort.Search(len(syms), func(i int) bool {
346+
// return syms[i].Addr <= addr
347+
return true
348+
})
349+
350+
if i < len(syms) {
351+
v := syms[i]
352+
return &v
353+
}
354+
return nil
355+
}
356+
357+
func (d *Dso) loadSymTable() error {
358+
switch d._type {
359+
case PERF_MAP:
360+
return d.loadSymTableFromPerfMap()
361+
case EXEC, DYN:
362+
return d.loadSymTableFromElf(0)
363+
case VDSO:
364+
return d.loadSymTableFromVdsoImage()
365+
default:
366+
return errors.New("unsupported type")
367+
}
368+
}
369+
370+
func (d *Dso) loadSymTableFromPerfMap() error {
371+
return errors.New("unsupported type")
372+
}
373+
374+
func (d *Dso) loadSymTableFromElf(fd int) error {
375+
return nil
376+
}
377+
378+
func (d *Dso) loadSymTableFromVdsoImage() error {
379+
return nil
380+
}
381+
382+
type SymsCache struct {
383+
data []SymsCacheData
384+
// Nr int
385+
}
386+
387+
type SymsCacheData struct {
388+
syms Syms
389+
tgid int
390+
}
391+
392+
func NewSymsCache() *SymsCache {
393+
return &SymsCache{}
394+
}
395+
396+
func (s *SymsCache) GetSyms(tgid int) (*Syms, error) {
397+
for _, d := range s.data {
398+
if d.tgid == tgid {
399+
return &d.syms, nil
400+
}
401+
}
402+
403+
syms, err := symsLoadPid(tgid)
404+
if err != nil {
405+
return nil, err
406+
}
407+
s.data = append(s.data, SymsCacheData{
408+
syms: *syms,
409+
tgid: tgid,
410+
})
411+
return syms, nil
412+
}
413+
414+
func (s *Syms) addDso(m addrMap, name string) error {
415+
var d *Dso
416+
for _, item := range s.dsos {
417+
if item.name == name {
418+
d = &item
419+
}
420+
}
421+
if d == nil {
422+
d = &Dso{
423+
name: name,
424+
}
425+
}
426+
d.ranges = append(d.ranges, LoadRange{
427+
start: m.startAddr,
428+
end: m.endAddr,
429+
fileOff: m.fileOff,
430+
})
431+
432+
elfType, err := getElfType(name)
433+
if err != nil {
434+
return err
435+
}
436+
if elfType == elf.ET_EXEC {
437+
d._type = EXEC
438+
} else if elfType == elf.ET_DYN {
439+
d._type = DYN
440+
var err error
441+
d.shAddr, d.shOffset, err = getElfTextScnInfo(name)
442+
if err != nil {
443+
return err
444+
}
445+
} else if isPerfMap(name) {
446+
d._type = PERF_MAP
447+
} else if isVdso(name) {
448+
d._type = VDSO
449+
} else {
450+
d._type = UNKNOWN
451+
}
452+
453+
return nil
454+
}
455+
456+
func getElfTextScnInfo(path string) (uint64, uint64, error) {
457+
f, err := elf.Open(path)
458+
if err != nil {
459+
return 0, 0, err
460+
}
461+
defer f.Close()
462+
for _, s := range f.Sections {
463+
if s.Name == ".text" {
464+
return s.Addr, s.Offset, nil
465+
}
466+
}
467+
return 0, 0, errors.New("not found")
468+
}
469+
470+
func getElfType(path string) (elf.Type, error) {
471+
if isVdso(path) {
472+
return 0, nil
473+
}
474+
f, err := elf.Open(path)
475+
if err != nil {
476+
return 0, err
477+
}
478+
f.Close()
479+
return f.Type, nil
480+
}
481+
482+
func symsLoadPid(tgid int) (*Syms, error) {
483+
name := fmt.Sprintf("/proc/%d/maps", tgid)
484+
return symsLoadFile(name)
485+
}
486+
487+
type addrMap struct {
488+
startAddr uint64
489+
endAddr uint64
490+
fileOff uint64
491+
devMajor uint64
492+
devMinor uint64
493+
inode uint64
494+
}
495+
496+
func symsLoadFile(name string) (*Syms, error) {
497+
fdata, err := os.ReadFile(name)
498+
if err != nil {
499+
return nil, err
500+
}
501+
var syms *Syms
502+
s := bufio.NewScanner(bytes.NewReader(fdata))
503+
for s.Scan() {
504+
line := strings.TrimSpace(s.Text())
505+
if line == "" {
506+
continue
507+
}
508+
var addrMap addrMap
509+
var perm string
510+
var name string
511+
n, err := fmt.Fscanf(strings.NewReader(line),
512+
"%x-%x %4s %x %x:%x %u%s",
513+
&addrMap.startAddr, &addrMap.endAddr, &perm, &addrMap.fileOff,
514+
&addrMap.devMajor, &addrMap.devMinor, &addrMap.inode, &name)
515+
if err != nil {
516+
return nil, err
517+
}
518+
if n == 0 {
519+
continue
520+
}
521+
if len(perm) < 3 || perm[2] != 'x' {
522+
continue
523+
}
524+
if !isFileBacked(name) {
525+
continue
526+
}
527+
if isVdso(name) {
528+
break
529+
}
530+
if err := syms.addDso(addrMap, name); err != nil {
531+
return nil, err
532+
}
533+
}
534+
535+
return syms, nil
536+
}
537+
538+
func isFileBacked(mapname string) bool {
539+
if mapname == "" {
540+
return false
541+
}
542+
if strings.HasPrefix(mapname, "//anon") ||
543+
strings.HasPrefix(mapname, "/dev/zero") ||
544+
strings.HasPrefix(mapname, "/anon_hugepage") ||
545+
strings.HasPrefix(mapname, "[stack") ||
546+
strings.HasPrefix(mapname, "/SYSV") ||
547+
strings.HasPrefix(mapname, "[heap]") ||
548+
strings.HasPrefix(mapname, "[vsyscall]") {
549+
return false
550+
}
551+
return true
552+
}
553+
554+
func isVdso(path string) bool {
555+
return path == "[vdso]"
556+
}
557+
558+
func isPerfMap(path string) bool {
559+
return false
560+
}

0 commit comments

Comments
 (0)