Index: fuzzer/go/deduplicator/deduplicator.go |
diff --git a/fuzzer/go/deduplicator/deduplicator.go b/fuzzer/go/deduplicator/deduplicator.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..88ca84c6442ad7e50ecc178d3a30280f057e0fd9 |
--- /dev/null |
+++ b/fuzzer/go/deduplicator/deduplicator.go |
@@ -0,0 +1,62 @@ |
+package deduplicator |
+ |
+import ( |
+ "fmt" |
+ |
+ "go.skia.org/infra/fuzzer/go/frontend/data" |
+ "go.skia.org/infra/go/util" |
+) |
+ |
+const _MAX_STACKTRACE_LINES = 4 |
+ |
+type Deduplicator struct { |
+ seen map[string]bool |
+} |
+ |
+func New() *Deduplicator { |
+ return &Deduplicator{ |
+ seen: make(map[string]bool), |
+ } |
+} |
+ |
+func (d *Deduplicator) Clear() { |
+ d.seen = make(map[string]bool) |
+} |
+ |
+func (d *Deduplicator) IsUnique(report data.FuzzReport) bool { |
+ // Empty stacktraces should be manually deduplicated. |
+ if report.DebugStackTrace.IsEmpty() && report.ReleaseStackTrace.IsEmpty() { |
+ return true |
+ } |
+ // Other flags should also be looked at manually. |
+ if util.In("Other", report.DebugFlags) || util.In("Other", report.ReleaseFlags) { |
+ return true |
+ } |
+ if k := key(report); d.seen[k] { |
+ return false |
+ } else { |
+ d.seen[k] = true |
+ return true |
+ } |
+} |
+ |
+func key(r data.FuzzReport) string { |
+ ds := trim(r.DebugStackTrace) |
+ rs := trim(r.ReleaseStackTrace) |
+ return fmt.Sprintf("C:%s,F:%q,F:%q,S:%s,S:%s", r.FuzzCategory, r.DebugFlags, r.ReleaseFlags, ds.String(), rs.String()) |
+} |
+ |
+// trim returns a copy of the given stacktrace, with the line numbers removed and all but the |
+// first _MAX_STACKTRACE_LINES stacktraces removed. |
+func trim(st data.StackTrace) data.StackTrace { |
+ if frames := st.Frames; len(frames) > _MAX_STACKTRACE_LINES { |
+ st.Frames = st.Frames[0:_MAX_STACKTRACE_LINES] |
+ } |
+ // copy the frames, so we don't accidentally change the real report. |
+ st.Frames = append([]data.StackTraceFrame(nil), st.Frames...) |
+ // Remove line numbers from our deduping criteria. |
+ for i := range st.Frames { |
+ st.Frames[i].LineNumber = 0 |
+ } |
+ return st |
+} |