Brak opisu

filter.go 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. l.Line = l.matchedLines(show)
  40. if len(l.Line) == 0 {
  41. hidden[l.ID] = true
  42. } else {
  43. hnm = true
  44. }
  45. }
  46. }
  47. s := make([]*Sample, 0, len(p.Sample))
  48. for _, sample := range p.Sample {
  49. if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
  50. if len(hidden) > 0 {
  51. var locs []*Location
  52. for _, loc := range sample.Location {
  53. if !hidden[loc.ID] {
  54. locs = append(locs, loc)
  55. }
  56. }
  57. if len(locs) == 0 {
  58. // Remove sample with no locations (by not adding it to s).
  59. continue
  60. }
  61. sample.Location = locs
  62. }
  63. s = append(s, sample)
  64. }
  65. }
  66. p.Sample = s
  67. return
  68. }
  69. // FilterTagsByName filters the tags in a profile and only keeps
  70. // tags that match show and not hide.
  71. func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) {
  72. matchRemove := func(name string) bool {
  73. matchShow := show == nil || show.MatchString(name)
  74. matchHide := hide != nil && hide.MatchString(name)
  75. if matchShow {
  76. sm = true
  77. }
  78. if matchHide {
  79. hm = true
  80. }
  81. return !matchShow || matchHide
  82. }
  83. for _, s := range p.Sample {
  84. for lab := range s.Label {
  85. if matchRemove(lab) {
  86. delete(s.Label, lab)
  87. }
  88. }
  89. for lab := range s.NumLabel {
  90. if matchRemove(lab) {
  91. delete(s.NumLabel, lab)
  92. }
  93. }
  94. }
  95. return
  96. }
  97. // matchesName returns whether the location matches the regular
  98. // expression. It checks any available function names, file names, and
  99. // mapping object filename.
  100. func (loc *Location) matchesName(re *regexp.Regexp) bool {
  101. for _, ln := range loc.Line {
  102. if fn := ln.Function; fn != nil {
  103. if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
  104. return true
  105. }
  106. }
  107. }
  108. if m := loc.Mapping; m != nil && re.MatchString(m.File) {
  109. return true
  110. }
  111. return false
  112. }
  113. // unmatchedLines returns the lines in the location that do not match
  114. // the regular expression.
  115. func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
  116. if m := loc.Mapping; m != nil && re.MatchString(m.File) {
  117. return nil
  118. }
  119. var lines []Line
  120. for _, ln := range loc.Line {
  121. if fn := ln.Function; fn != nil {
  122. if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
  123. continue
  124. }
  125. }
  126. lines = append(lines, ln)
  127. }
  128. return lines
  129. }
  130. // matchedLines returns the lines in the location that match
  131. // the regular expression.
  132. func (loc *Location) matchedLines(re *regexp.Regexp) []Line {
  133. if m := loc.Mapping; m != nil && re.MatchString(m.File) {
  134. return loc.Line
  135. }
  136. var lines []Line
  137. for _, ln := range loc.Line {
  138. if fn := ln.Function; fn != nil {
  139. if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) {
  140. continue
  141. }
  142. }
  143. lines = append(lines, ln)
  144. }
  145. return lines
  146. }
  147. // focusedAndNotIgnored looks up a slice of ids against a map of
  148. // focused/ignored locations. The map only contains locations that are
  149. // explicitly focused or ignored. Returns whether there is at least
  150. // one focused location but no ignored locations.
  151. func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
  152. var f bool
  153. for _, loc := range locs {
  154. if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
  155. if focus {
  156. // Found focused location. Must keep searching in case there
  157. // is an ignored one as well.
  158. f = true
  159. } else {
  160. // Found ignored location. Can return false right away.
  161. return false
  162. }
  163. }
  164. }
  165. return f
  166. }
  167. // TagMatch selects tags for filtering
  168. type TagMatch func(s *Sample) bool
  169. // FilterSamplesByTag removes all samples from the profile, except
  170. // those that match focus and do not match the ignore regular
  171. // expression.
  172. func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
  173. samples := make([]*Sample, 0, len(p.Sample))
  174. for _, s := range p.Sample {
  175. focused, ignored := true, false
  176. if focus != nil {
  177. focused = focus(s)
  178. }
  179. if ignore != nil {
  180. ignored = ignore(s)
  181. }
  182. fm = fm || focused
  183. im = im || ignored
  184. if focused && !ignored {
  185. samples = append(samples, s)
  186. }
  187. }
  188. p.Sample = samples
  189. return
  190. }