OLD | NEW |
1 package deduplicator | 1 package deduplicator |
2 | 2 |
3 import ( | 3 import ( |
4 "fmt" | 4 "fmt" |
| 5 "sync" |
5 | 6 |
6 » "go.skia.org/infra/fuzzer/go/frontend/data" | 7 » "go.skia.org/infra/fuzzer/go/data" |
7 "go.skia.org/infra/go/util" | 8 "go.skia.org/infra/go/util" |
8 ) | 9 ) |
9 | 10 |
10 const _MAX_STACKTRACE_LINES = 4 | 11 const _MAX_STACKTRACE_LINES = 4 |
11 | 12 |
12 type Deduplicator struct { | 13 type Deduplicator struct { |
13 » seen map[string]bool | 14 » seen map[string]bool |
| 15 » mutex sync.Mutex |
14 } | 16 } |
15 | 17 |
16 func New() *Deduplicator { | 18 func New() *Deduplicator { |
17 return &Deduplicator{ | 19 return &Deduplicator{ |
18 seen: make(map[string]bool), | 20 seen: make(map[string]bool), |
19 } | 21 } |
20 } | 22 } |
21 | 23 |
22 func (d *Deduplicator) Clear() { | 24 func (d *Deduplicator) Clear() { |
| 25 d.mutex.Lock() |
| 26 defer d.mutex.Unlock() |
23 d.seen = make(map[string]bool) | 27 d.seen = make(map[string]bool) |
24 } | 28 } |
25 | 29 |
26 func (d *Deduplicator) IsUnique(report data.FuzzReport) bool { | 30 func (d *Deduplicator) IsUnique(report data.FuzzReport) bool { |
27 // Empty stacktraces should be manually deduplicated. | 31 // Empty stacktraces should be manually deduplicated. |
28 if report.DebugStackTrace.IsEmpty() && report.ReleaseStackTrace.IsEmpty(
) { | 32 if report.DebugStackTrace.IsEmpty() && report.ReleaseStackTrace.IsEmpty(
) { |
29 return true | 33 return true |
30 } | 34 } |
31 // Other flags should also be looked at manually. | 35 // Other flags should also be looked at manually. |
32 if util.In("Other", report.DebugFlags) || util.In("Other", report.Releas
eFlags) { | 36 if util.In("Other", report.DebugFlags) || util.In("Other", report.Releas
eFlags) { |
33 return true | 37 return true |
34 } | 38 } |
| 39 d.mutex.Lock() |
| 40 defer d.mutex.Unlock() |
35 if k := key(report); d.seen[k] { | 41 if k := key(report); d.seen[k] { |
36 return false | 42 return false |
37 } else { | 43 } else { |
38 d.seen[k] = true | 44 d.seen[k] = true |
39 return true | 45 return true |
40 } | 46 } |
41 } | 47 } |
42 | 48 |
43 func key(r data.FuzzReport) string { | 49 func key(r data.FuzzReport) string { |
44 ds := trim(r.DebugStackTrace) | 50 ds := trim(r.DebugStackTrace) |
45 rs := trim(r.ReleaseStackTrace) | 51 rs := trim(r.ReleaseStackTrace) |
46 return fmt.Sprintf("C:%s,F:%q,F:%q,S:%s,S:%s", r.FuzzCategory, r.DebugFl
ags, r.ReleaseFlags, ds.String(), rs.String()) | 52 return fmt.Sprintf("C:%s,F:%q,F:%q,S:%s,S:%s", r.FuzzCategory, r.DebugFl
ags, r.ReleaseFlags, ds.String(), rs.String()) |
47 } | 53 } |
48 | 54 |
49 // trim returns a copy of the given stacktrace, with the line numbers removed an
d all but the | 55 // trim returns a copy of the given stacktrace, with the line numbers removed an
d all but the |
50 // first _MAX_STACKTRACE_LINES stacktraces removed. | 56 // first _MAX_STACKTRACE_LINES stacktraces removed. |
51 func trim(st data.StackTrace) data.StackTrace { | 57 func trim(st data.StackTrace) data.StackTrace { |
52 if frames := st.Frames; len(frames) > _MAX_STACKTRACE_LINES { | 58 if frames := st.Frames; len(frames) > _MAX_STACKTRACE_LINES { |
53 st.Frames = st.Frames[0:_MAX_STACKTRACE_LINES] | 59 st.Frames = st.Frames[0:_MAX_STACKTRACE_LINES] |
54 } | 60 } |
55 // copy the frames, so we don't accidentally change the real report. | 61 // copy the frames, so we don't accidentally change the real report. |
56 st.Frames = append([]data.StackTraceFrame(nil), st.Frames...) | 62 st.Frames = append([]data.StackTraceFrame(nil), st.Frames...) |
57 // Remove line numbers from our deduping criteria. | 63 // Remove line numbers from our deduping criteria. |
58 for i := range st.Frames { | 64 for i := range st.Frames { |
59 st.Frames[i].LineNumber = 0 | 65 st.Frames[i].LineNumber = 0 |
60 } | 66 } |
61 return st | 67 return st |
62 } | 68 } |
OLD | NEW |