-
Notifications
You must be signed in to change notification settings - Fork 763
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/vscgo: convert pprof to json
Adds `vscgo dump-pprof` and `vscgo serve-pprof` to support a custom profile renderer. Ideally `dump-pprof` would be sufficient. Unfortunately, `serve-pprof` is necessary (AFAIK) to work around profiles that are too large to fit within a NodeJS Buffer (when converted to JSON). Fixes #3573. Change-Id: I0767ff02912852e0cd4bec5745c79ff50f2d3b38 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/621516 Reviewed-by: Hongxiang Jiang <[email protected]> kokoro-CI: kokoro <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]> Commit-Queue: Ethan Reesor <[email protected]>
- Loading branch information
1 parent
4457dbf
commit 866878e
Showing
6 changed files
with
207 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,6 @@ | ||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= | ||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= | ||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= | ||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= | ||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= | ||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||
golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7 h1:nU8/tAV/21mkPrCjACUeSibjhynTovgRMXc32+Y1Aec= | ||
golang.org/x/telemetry v0.0.0-20240712210958-268b4a8ec2d7/go.mod h1:amNmu/SBSm2GAF3X+9U2C0epLocdh+r5Z+7oMYO5cLM= | ||
golang.org/x/telemetry v0.0.0-20241004145657-5eebfecbdf1f h1:ZYeTr2+AUYPLt6ZdXsnUUHem8NJbgmZaHisnB21BOz0= | ||
golang.org/x/telemetry v0.0.0-20241004145657-5eebfecbdf1f/go.mod h1:uskmY3Y2C5OU/HAtQlc9Jq98qE2bf7H3kCPFgkab838= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// Copyright 2024 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package vscgo | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"net" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/google/pprof/profile" | ||
) | ||
|
||
func runPprofDump(args []string) error { | ||
if len(args) != 1 { | ||
return fmt.Errorf("usage: dump-pprof <profile>") | ||
} | ||
|
||
p, err := readPprof(args[0]) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return json.NewEncoder(os.Stdout).Encode((*Profile)(p)) | ||
} | ||
|
||
func runPprofServe(args []string) error { | ||
if len(args) != 2 { | ||
return fmt.Errorf("usage: serve-pprof <addr> <profile>") | ||
} | ||
|
||
l, err := net.Listen("tcp", args[0]) | ||
if err != nil { | ||
return err | ||
} | ||
defer l.Close() | ||
|
||
p, err := readPprof(args[1]) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = json.NewEncoder(os.Stdout).Encode(map[string]any{ | ||
"Listen": l.Addr(), | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Set("Access-Control-Allow-Origin", "*") | ||
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") | ||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type") | ||
|
||
if r.Method == "OPTIONS" { | ||
w.WriteHeader(http.StatusOK) | ||
return | ||
} | ||
|
||
w.Header().Set("Content-Type", "application/json") | ||
err := json.NewEncoder(w).Encode((*Profile)(p)) | ||
if err != nil { | ||
log.Println("Error: ", err) | ||
} | ||
})) | ||
} | ||
|
||
func readPprof(arg string) (*Profile, error) { | ||
f, err := os.Open(arg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
p, err := profile.Parse(f) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return (*Profile)(p), nil | ||
} | ||
|
||
type Profile profile.Profile | ||
|
||
func (p *Profile) MarshalJSON() ([]byte, error) { | ||
q := struct { | ||
SampleType []*profile.ValueType | ||
DefaultSampleType string | ||
Sample []*Sample | ||
Mapping []*profile.Mapping | ||
Location []*Location | ||
Function []*profile.Function | ||
Comments []string | ||
DropFrames string | ||
KeepFrames string | ||
TimeNanos int64 | ||
DurationNanos int64 | ||
PeriodType *profile.ValueType | ||
Period int64 | ||
}{ | ||
SampleType: p.SampleType, | ||
DefaultSampleType: p.DefaultSampleType, | ||
Sample: make([]*Sample, len(p.Sample)), | ||
Mapping: p.Mapping, | ||
Location: make([]*Location, len(p.Location)), | ||
Function: p.Function, | ||
Comments: p.Comments, | ||
DropFrames: p.DropFrames, | ||
KeepFrames: p.KeepFrames, | ||
TimeNanos: p.TimeNanos, | ||
DurationNanos: p.DurationNanos, | ||
PeriodType: p.PeriodType, | ||
Period: p.Period, | ||
} | ||
for i, s := range p.Sample { | ||
q.Sample[i] = (*Sample)(s) | ||
} | ||
for i, l := range p.Location { | ||
q.Location[i] = (*Location)(l) | ||
} | ||
return json.Marshal(q) | ||
} | ||
|
||
type Sample profile.Sample | ||
|
||
func (p *Sample) MarshalJSON() ([]byte, error) { | ||
q := struct { | ||
Location []uint64 | ||
Value []int64 | ||
Label map[string][]string | ||
NumLabel map[string][]int64 | ||
NumUnit map[string][]string | ||
}{ | ||
Location: make([]uint64, len(p.Location)), | ||
Value: p.Value, | ||
Label: p.Label, | ||
NumLabel: p.NumLabel, | ||
NumUnit: p.NumUnit, | ||
} | ||
for i, l := range p.Location { | ||
q.Location[i] = l.ID | ||
} | ||
return json.Marshal(q) | ||
} | ||
|
||
type Location profile.Location | ||
|
||
func (p *Location) MarshalJSON() ([]byte, error) { | ||
q := struct { | ||
ID uint64 | ||
Mapping uint64 | ||
Address uint64 | ||
Line []Line | ||
IsFolded bool | ||
}{ | ||
ID: p.ID, | ||
Mapping: p.Mapping.ID, | ||
Address: p.Address, | ||
Line: make([]Line, len(p.Line)), | ||
IsFolded: p.IsFolded, | ||
} | ||
for i, l := range p.Line { | ||
q.Line[i] = Line(l) | ||
} | ||
return json.Marshal(q) | ||
} | ||
|
||
type Line profile.Line | ||
|
||
func (p *Line) MarshalJSON() ([]byte, error) { | ||
q := struct { | ||
Function uint64 | ||
Line int64 | ||
Column int64 | ||
}{ | ||
Function: p.Function.ID, | ||
Line: p.Line, | ||
Column: p.Column, | ||
} | ||
return json.Marshal(q) | ||
} |