Nessuna descrizione

filter.go 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package profile
  15. // Implements methods to filter samples from profiles.
  16. import "regexp"
  17. // FilterSamplesByName filters the samples in a profile and only keeps
  18. // samples where at least one frame matches focus but none match ignore.
  19. // Returns true is the corresponding regexp matched at least one sample.
  20. func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
  21. focusOrIgnore := make(map[uint64]bool)
  22. hidden := make(map[uint64]bool)
  23. for _, l := range p.Location {
  24. if ignore != nil && l.matchesName(ignore) {
  25. im = true
  26. focusOrIgnore[l.ID] = false
  27. } else if focus == nil || l.matchesName(focus) {
  28. fm = true
  29. focusOrIgnore[l.ID] = true
  30. }
  31. if hide != nil && l.matchesName(hide) {
  32. hm = true
  33. l.Line = l.unmatchedLines(hide)
  34. if len(l.Line) == 0 {
  35. hidden[l.ID] = true
  36. }
  37. }
  38. if show != nil {
  39. hnm = true
  40. l.Line = l.matchedLines(show)
  41. if len(l.Line) == 0 {
  42. hidden[l.ID] = true
  43. }
  44. }
  45. }
  46. s := make([]*Sample, 0, len(p.Sample))
  47. for _, sample := range p.Sample {
  48. if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
  49. if len(hidden) > 0 {
  50. var locs []*Location
  51. for _, loc := range sample.Location {
  52. if !hidden[loc.ID] {
  53. locs = append(locs, loc)
  54. }
  55. }
  56. if len(locs) == 0 {
  57. // Remove sample with no locations (by not adding it to s).
  58. continue
  59. }
  60. sample.Location = locs
  61. }
  62. s = append(s, sample)
  63. }
  64. }
  65. p.Sample = s
  66. return
  67. }
  68. // matchesName returns whether the location matches the regular
  69. // expression. It checks any available function names, file names, and
  70. // mapping object filename.
  71. func (loc *Location) matchesName(re *regexp.Regexp) bool {
  72. for _, ln := range loc.Line {
  73. if fn := ln.Function; fn != nil {
  74. if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
  75. return true
  76. }
  77. }
  78. }
  79. if m := loc.Mapping; m != nil && re.MatchString(m.File) {
  80. return true
  81. }
  82. return false
  83. }
  84. // unmatchedLines returns the lines in the location that do not match
  85. // the regular expression.
  86. func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
  87. if m := loc.Mapping; m != nil && re.MatchString(m.File) {
  88. return nil
  89. }
  90. var lines []Line
  91. for _, ln := range loc.Line {
  92. if fn := ln.Function; fn != nil {
  93. if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
  94. continue
  95. }
  96. }
  97. lines = append(lines, ln)
  98. }
  99. return lines
  100. }
  101. // matchedLines returns the lines in the location that match
  102. // the regular expression.
  103. func (loc *Location) matchedLines(re *regexp.Regexp) []Line {
  104. var lines []Line
  105. for _, ln := range loc.Line {
  106. if fn := ln.Function; fn != nil {
  107. if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) {
  108. continue
  109. }
  110. }
  111. lines = append(lines, ln)
  112. }
  113. return lines
  114. }
  115. // focusedAndNotIgnored looks up a slice of ids against a map of
  116. // focused/ignored locations. The map only contains locations that are
  117. // explicitly focused or ignored. Returns whether there is at least
  118. // one focused location but no ignored locations.
  119. func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
  120. var f bool
  121. for _, loc := range locs {
  122. if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
  123. if focus {
  124. // Found focused location. Must keep searching in case there
  125. // is an ignored one as well.
  126. f = true
  127. } else {
  128. // Found ignored location. Can return false right away.
  129. return false
  130. }
  131. }
  132. }
  133. return f
  134. }
  135. // TagMatch selects tags for filtering
  136. type TagMatch func(s *Sample) bool
  137. // FilterSamplesByTag removes all samples from the profile, except
  138. // those that match focus and do not match the ignore regular
  139. // expression.
  140. func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
  141. samples := make([]*Sample, 0, len(p.Sample))
  142. for _, s := range p.Sample {
  143. focused, ignored := true, false
  144. if focus != nil {
  145. focused = focus(s)
  146. }
  147. if ignore != nil {
  148. ignored = ignore(s)
  149. }
  150. fm = fm || focused
  151. im = im || ignored
  152. if focused && !ignored {
  153. samples = append(samples, s)
  154. }
  155. }
  156. p.Sample = samples
  157. return
  158. }