Skip to content

Commit

Permalink
Merge pull request #3850 from parca-dev/filter-perf
Browse files Browse the repository at this point in the history
pkg/query: Improve filter performance
  • Loading branch information
brancz authored Sep 21, 2023
2 parents 57e1275 + fa67ec6 commit 302a192
Showing 1 changed file with 23 additions and 10 deletions.
33 changes: 23 additions & 10 deletions pkg/query/columnquery.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,13 @@ func FilterProfileData(

// We want to filter by function name case-insensitive, so we need to lowercase the query.
// We lower case the query here, so we don't have to do it for every sample.
filterQuery = strings.ToLower(filterQuery)
filterQueryBytes := []byte(strings.ToLower(filterQuery))
res := make([]arrow.Record, 0, len(records))
allValues := int64(0)
allFiltered := int64(0)

for _, r := range records {
filteredRecord, valueSum, filteredSum, err := filterRecord(ctx, tracer, pool, r, filterQuery)
filteredRecord, valueSum, filteredSum, err := filterRecord(ctx, tracer, pool, r, filterQueryBytes)
if err != nil {
return nil, 0, fmt.Errorf("filter record: %w", err)
}
Expand All @@ -303,7 +303,7 @@ func filterRecord(
tracer trace.Tracer,
pool memory.Allocator,
rec arrow.Record,
filterQuery string,
filterQueryBytes []byte,
) (arrow.Record, int64, int64, error) {
r := profile.NewRecordReader(rec)

Expand All @@ -316,16 +316,29 @@ func filterRecord(
w := profile.NewWriter(pool, labelNames)
defer w.RecordBuilder.Release()

indexMatches := map[uint32]struct{}{}
for i := 0; i < r.LineFunctionNameDict.Len(); i++ {
if bytes.Contains(bytes.ToLower(r.LineFunctionNameDict.Value(i)), filterQueryBytes) {
indexMatches[uint32(i)] = struct{}{}
}
}

if len(indexMatches) == 0 {
return w.RecordBuilder.NewRecord(), math.Int64.Sum(r.Value), 0, nil
}

for i := 0; i < int(rec.NumRows()); i++ {
lOffsetStart, lOffsetEnd := r.Locations.ValueOffsets(i)
keepRow := false
for j := int(lOffsetStart); j < int(lOffsetEnd); j++ {
llOffsetStart, llOffsetEnd := r.Lines.ValueOffsets(j)

for k := int(llOffsetStart); k < int(llOffsetEnd); k++ {
if r.LineFunctionNameIndices.IsValid(k) && bytes.Contains(bytes.ToLower(r.LineFunctionNameDict.Value(int(r.LineFunctionNameIndices.Value(k)))), []byte(filterQuery)) {
keepRow = true
break
if lOffsetStart < lOffsetEnd {
firstStart, _ := r.Lines.ValueOffsets(int(lOffsetStart))
_, lastEnd := r.Lines.ValueOffsets(int(lOffsetEnd - 1))
for k := int(firstStart); k < int(lastEnd); k++ {
if r.LineFunctionNameIndices.IsValid(k) {
if _, ok := indexMatches[r.LineFunctionNameIndices.Value(k)]; ok {
keepRow = true
break
}
}
}
}
Expand Down

0 comments on commit 302a192

Please sign in to comment.