Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: Icicle charts support #5383

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
776 changes: 391 additions & 385 deletions gen/proto/go/parca/query/v1alpha1/query.pb.go

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions gen/proto/swagger/parca/query/v1alpha1/query.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@
},
{
"name": "reportType",
"description": "report_type is the type of report to return\n\n - REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels",
"description": "report_type is the type of report to return\n\n - REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report",
"in": "query",
"required": false,
"type": "string",
Expand All @@ -333,7 +333,8 @@
"REPORT_TYPE_FLAMEGRAPH_ARROW",
"REPORT_TYPE_SOURCE",
"REPORT_TYPE_TABLE_ARROW",
"REPORT_TYPE_PROFILE_METADATA"
"REPORT_TYPE_PROFILE_METADATA",
"REPORT_TYPE_FLAMECHART"
],
"default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED"
},
Expand Down Expand Up @@ -613,10 +614,11 @@
"REPORT_TYPE_FLAMEGRAPH_ARROW",
"REPORT_TYPE_SOURCE",
"REPORT_TYPE_TABLE_ARROW",
"REPORT_TYPE_PROFILE_METADATA"
"REPORT_TYPE_PROFILE_METADATA",
"REPORT_TYPE_FLAMECHART"
],
"default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED",
"description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels",
"description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report",
"title": "ReportType is the type of report to return"
},
"metastorev1alpha1Function": {
Expand Down
5 changes: 3 additions & 2 deletions gen/proto/swagger/parca/share/v1alpha1/share.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
"REPORT_TYPE_FLAMEGRAPH_ARROW",
"REPORT_TYPE_SOURCE",
"REPORT_TYPE_TABLE_ARROW",
"REPORT_TYPE_PROFILE_METADATA"
"REPORT_TYPE_PROFILE_METADATA",
"REPORT_TYPE_FLAMECHART"
],
"default": "REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED",
"description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels",
"description": "- REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED: REPORT_TYPE_FLAMEGRAPH_UNSPECIFIED unspecified\n - REPORT_TYPE_PPROF: REPORT_TYPE_PPROF unspecified\n - REPORT_TYPE_TOP: REPORT_TYPE_TOP unspecified\n - REPORT_TYPE_CALLGRAPH: REPORT_TYPE_CALLGRAPH unspecified\n - REPORT_TYPE_FLAMEGRAPH_TABLE: REPORT_TYPE_FLAMEGRAPH_TABLE unspecified\n - REPORT_TYPE_FLAMEGRAPH_ARROW: REPORT_TYPE_FLAMEGRAPH_ARROW unspecified\n - REPORT_TYPE_SOURCE: REPORT_TYPE_SOURCE contains source code annotated with profiling information\n - REPORT_TYPE_TABLE_ARROW: REPORT_TYPE_TABLE_ARROW unspecified\n - REPORT_TYPE_PROFILE_METADATA: REPORT_TYPE_PROFILE_METADATA contains metadata about the profile i.e. binaries, labels\n - REPORT_TYPE_FLAMECHART: REPORT_TYPE_FLAMECHART contains flamechart representation of the report",
"title": "ReportType is the type of report to return"
},
"metastorev1alpha1Function": {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require (
github.com/ianlancetaylor/demangle v0.0.0-20240912202439-0a2b6291aafd
github.com/improbable-eng/grpc-web v0.15.0
github.com/klauspost/compress v1.17.11
github.com/m1gwings/treedrawer v0.3.3-beta
github.com/nanmu42/limitio v1.0.0
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,8 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U
github.com/linode/linodego v1.40.0 h1:7ESY0PwK94hoggoCtIroT1Xk6b1flrFBNZ6KwqbTqlI=
github.com/linode/linodego v1.40.0/go.mod h1:NsUw4l8QrLdIofRg1NYFBbW5ZERnmbZykVBszPZLORM=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/m1gwings/treedrawer v0.3.3-beta h1:VeeQ4I90+NL0G2Tga3H4EY4hbOyVP3ID4T93r21oLbQ=
github.com/m1gwings/treedrawer v0.3.3-beta/go.mod h1:Sebh5tCtjQWAG/B9xWct163vB9pCbBcA1ykaUErDUTY=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
Expand Down
25 changes: 21 additions & 4 deletions pkg/parcacol/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,20 @@ func (q *Querier) SymbolizeArrowRecord(
defer valuePerSecondColumn.Release()
}

indices = schema.FieldIndices(profile.ColumnTimestamp)
var timestampColumn *array.Int64
if len(indices) != 1 {
timestampColumn = arrowutils.MakeNullArray(q.pool, arrow.PrimitiveTypes.Int64, valueColumn.Len()).(*array.Int64)
defer timestampColumn.Release()
}

indices = schema.FieldIndices(profile.ColumnDuration)
var durationColumn *array.Int64
if len(indices) != 1 {
durationColumn = arrowutils.MakeNullArray(q.pool, arrow.PrimitiveTypes.Int64, valueColumn.Len()).(*array.Int64)
defer durationColumn.Release()
}

profileLabels := []arrow.Field{}
profileLabelColumns := []arrow.Array{}
for i, field := range schema.Fields() {
Expand All @@ -984,14 +998,17 @@ func (q *Querier) SymbolizeArrowRecord(
}
defer locationsRecord.Release()

columns := make([]arrow.Array, len(profileLabels)+3) // +3 for stacktrace locations, value and diff
columns := make([]arrow.Array, len(profileLabels)+5) // +5 for stacktrace locations, value, diff, timestamp and duration
copy(columns, profileLabelColumns)
columns[len(columns)-3] = locationsRecord.Column(0)
columns[len(columns)-2] = valueColumn
columns[len(columns)-5] = locationsRecord.Column(0)
columns[len(columns)-4] = valueColumn

diffColumn := CreateDiffColumn(q.pool, int(r.NumRows()))
defer diffColumn.Release()
columns[len(columns)-1] = diffColumn
columns[len(columns)-3] = diffColumn

columns[len(columns)-2] = timestampColumn
columns[len(columns)-1] = durationColumn

res[i] = array.NewRecord(profile.ArrowSchema(profileLabels), columns, r.NumRows())
}
Expand Down
16 changes: 12 additions & 4 deletions pkg/profile/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,26 @@ func LocationsArrowSchema() *arrow.Schema {
}

func ArrowSamplesField(profileLabelFields []arrow.Field) []arrow.Field {
numFields := len(profileLabelFields) + 3 // +3 for stacktraces, value and diff
numFields := len(profileLabelFields) + 5 // +5 for stacktraces, value, diff, timestamp and duration
fields := make([]arrow.Field, numFields)
copy(fields, profileLabelFields)
fields[numFields-3] = LocationsField
fields[numFields-2] = arrow.Field{
fields[numFields-5] = LocationsField
fields[numFields-4] = arrow.Field{
Name: "value",
Type: arrow.PrimitiveTypes.Int64,
}
fields[numFields-1] = arrow.Field{
fields[numFields-3] = arrow.Field{
Name: "diff",
Type: arrow.PrimitiveTypes.Int64,
}
fields[numFields-2] = arrow.Field{
Name: ColumnTimestamp,
Type: arrow.PrimitiveTypes.Int64,
}
fields[numFields-1] = arrow.Field{
Name: ColumnDuration,
Type: arrow.PrimitiveTypes.Int64,
}

return fields
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/profile/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type RecordReader struct {
Locations *array.List
Location *array.Struct
Address *array.Uint64
Timestamp *array.Int64
Duration *array.Int64
MappingStart *array.Uint64
MappingLimit *array.Uint64
MappingOffset *array.Uint64
Expand Down Expand Up @@ -120,6 +122,8 @@ func NewRecordReader(ar arrow.Record) *RecordReader {
lineFunctionStartLine := line.Field(4).(*array.Int64)
valueColumn := ar.Column(labelNum + 1).(*array.Int64)
diffColumn := ar.Column(labelNum + 2).(*array.Int64)
timestamp := ar.Column(labelNum + 3).(*array.Int64)
duration := ar.Column(labelNum + 4).(*array.Int64)

return &RecordReader{
Record: ar,
Expand Down Expand Up @@ -147,5 +151,7 @@ func NewRecordReader(ar arrow.Record) *RecordReader {
LineFunctionStartLine: lineFunctionStartLine,
Value: valueColumn,
Diff: diffColumn,
Timestamp: timestamp,
Duration: duration,
}
}
6 changes: 6 additions & 0 deletions pkg/profile/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type Writer struct {
FunctionStartLine *array.Int64Builder
Value *array.Int64Builder
Diff *array.Int64Builder
Timestamp *array.Int64Builder
Duration *array.Int64Builder
}

func (w *Writer) Release() {
Expand Down Expand Up @@ -87,6 +89,8 @@ func NewWriter(pool memory.Allocator, labelNames []string) Writer {

value := b.Field(labelNum + 1).(*array.Int64Builder)
diff := b.Field(labelNum + 2).(*array.Int64Builder)
timestamp := b.Field(labelNum + 3).(*array.Int64Builder)
duration := b.Field(labelNum + 4).(*array.Int64Builder)

return Writer{
RecordBuilder: b,
Expand All @@ -109,6 +113,8 @@ func NewWriter(pool memory.Allocator, labelNames []string) Writer {
FunctionStartLine: functionStartLine,
Value: value,
Diff: diff,
Timestamp: timestamp,
Duration: duration,
}
}

Expand Down
29 changes: 21 additions & 8 deletions pkg/query/columnquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,18 @@ func (q *ColumnQueryAPI) Query(ctx context.Context, req *pb.QueryRequest) (*pb.Q

groupBy := req.GetGroupBy().GetFields()
allowedGroupBy := map[string]struct{}{
profile.ColumnTimestamp: {},
profile.ColumnDuration: {},
FlamegraphFieldFunctionName: {},
FlamegraphFieldLocationAddress: {},
FlamegraphFieldMappingFile: {},
FlamegraphFieldFunctionFileName: {},
}

if req.GetReportType() == pb.QueryRequest_REPORT_TYPE_FLAMECHART {
groupBy = append(groupBy, profile.ColumnTimestamp, profile.ColumnDuration)
}

groupByLabels := make([]string, 0, len(groupBy))
for _, f := range groupBy {
if strings.HasPrefix(f, FlamegraphFieldLabels+".") {
Expand Down Expand Up @@ -592,7 +599,7 @@ func RenderReport(
Flamegraph: fg,
},
}, nil
case pb.QueryRequest_REPORT_TYPE_FLAMEGRAPH_ARROW:
case pb.QueryRequest_REPORT_TYPE_FLAMEGRAPH_ARROW, pb.QueryRequest_REPORT_TYPE_FLAMECHART:
fa, total, err := GenerateFlamegraphArrow(ctx, mem, tracer, p, groupBy, nodeTrimFraction)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to generate arrow flamegraph: %v", err.Error())
Expand Down Expand Up @@ -797,13 +804,13 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator,
compareCumulativeTotal := int64(0)
for _, r := range compare.Samples {
cols := r.Columns()
compareCumulativeTotal += math.Int64.Sum(cols[len(cols)-2].(*array.Int64))
compareCumulativeTotal += math.Int64.Sum(cols[len(cols)-4].(*array.Int64))
}

baseCumulativeTotal := int64(0)
for _, r := range base.Samples {
cols := r.Columns()
baseCumulativeTotal += math.Int64.Sum(cols[len(cols)-2].(*array.Int64))
baseCumulativeTotal += math.Int64.Sum(cols[len(cols)-4].(*array.Int64))
}

// Scale up base if compare is bigger
Expand All @@ -828,12 +835,12 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator,

if compareCumulativeRatio > 1.0 {
// If compareCumulativeRatio is bigger than 1.0 we have to scale all values
multi := multiplyInt64By(mem, cols[len(cols)-2].(*array.Int64), compareCumulativeRatio)
cols[len(cols)-1] = multi
multi := multiplyInt64By(mem, cols[len(cols)-4].(*array.Int64), compareCumulativeRatio)
cols[len(cols)-3] = multi
cleanupArrs = append(cleanupArrs, multi)
} else {
// otherwise we simply use the original values.
cols[len(cols)-1] = cols[len(cols)-2] // value as diff
cols[len(cols)-3] = cols[len(cols)-4] // value as diff
}

records = append(records, array.NewRecord(
Expand All @@ -849,16 +856,22 @@ func ComputeDiff(ctx context.Context, tracer trace.Tracer, mem memory.Allocator,

cols := make([]arrow.Array, len(columns))
copy(cols, columns)
diff := multiplyInt64By(mem, columns[len(columns)-2].(*array.Int64), -1*baseCumulativeRatio)
diff := multiplyInt64By(mem, columns[len(columns)-4].(*array.Int64), -1*baseCumulativeRatio)
defer diff.Release()
value := zeroInt64Array(mem, int(r.NumRows()))
defer value.Release()
timestamp := zeroInt64Array(mem, int(r.NumRows()))
defer timestamp.Release()
duration := zeroInt64Array(mem, int(r.NumRows()))
defer duration.Release()
records = append(records, array.NewRecord(
r.Schema(),
append(
cols[:len(cols)-2], // all other columns like locations
cols[:len(cols)-4], // all other columns like locations
value,
diff,
timestamp,
duration,
),
r.NumRows(),
))
Expand Down
12 changes: 12 additions & 0 deletions pkg/query/columnquery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,8 @@ func PprofToSymbolizedProfile(meta profile.Meta, prof *pprofprofile.Profile, ind

w.Value.Append(prof.Sample[i].Value[index])
w.Diff.Append(0)
w.Timestamp.Append(prof.TimeNanos)
w.Duration.Append(prof.DurationNanos)

for labelName, labelBuilder := range w.LabelBuildersMap {
if prof.Sample[i].Label == nil {
Expand Down Expand Up @@ -1359,6 +1361,8 @@ func TestFilterData(t *testing.T) {
w.FunctionStartLine.Append(1)
w.Value.Append(1)
w.Diff.Append(0)
w.Timestamp.Append(1)
w.Duration.Append(1)

frameFilter := map[string]struct{}{"test": {}}
originalRecord := w.RecordBuilder.NewRecord()
Expand Down Expand Up @@ -1405,6 +1409,8 @@ func TestFilterUnsymbolized(t *testing.T) {
w.Lines.Append(false)
w.Value.Append(1)
w.Diff.Append(0)
w.Timestamp.Append(1)
w.Duration.Append(1)

originalRecord := w.RecordBuilder.NewRecord()
recs, _, err := FilterProfileData(
Expand Down Expand Up @@ -1485,6 +1491,8 @@ func TestFilterDataWithPath(t *testing.T) {
w.FunctionStartLine.Append(0)
w.Value.Append(1)
w.Diff.Append(0)
w.Timestamp.Append(1)
w.Duration.Append(1)

frameFilter := map[string]struct{}{"libpython3.11.so.1.0": {}, "interpreter": {}}
originalRecord := w.RecordBuilder.NewRecord()
Expand Down Expand Up @@ -1567,6 +1575,8 @@ func TestFilterDataFrameFilter(t *testing.T) {
w.FunctionStartLine.Append(0)
w.Value.Append(1)
w.Diff.Append(0)
w.Timestamp.Append(1)
w.Duration.Append(1)

frameFilter := map[string]struct{}{"interpreter": {}}
originalRecord := w.RecordBuilder.NewRecord()
Expand Down Expand Up @@ -1649,6 +1659,8 @@ func BenchmarkFilterData(t *testing.B) {
w.FunctionStartLine.Append(1)
w.Value.Append(1)
w.Diff.Append(0)
w.Timestamp.Append(1)
w.Duration.Append(1)
}

originalRecord := w.RecordBuilder.NewRecord()
Expand Down
Loading
Loading