Ei kuvausta

filter.go 5.2KB

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