go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/changepoints/bayesian/counts.go (about) 1 // Copyright 2023 The LUCI Authors. 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 15 package bayesian 16 17 import "go.chromium.org/luci/analysis/internal/changepoints/inputbuffer" 18 19 // Stores counts of test run outcomes. 20 type counts struct { 21 // The total number of test runs. A run corresponds to a 22 // single ResultDB invocation and the test results directly 23 // included in it (e.g. swarming task). 24 // Each run can have have one or more test results, each of 25 // which we will call a 'try'. 26 Runs int 27 28 // The number of test runs which contained at least one 29 // unexpected test result. 30 // 31 // The ratio HasUnexpected / Runs is the ratio that 32 // explains the test's tendency to produce runs with 33 // unexpected result(s). 34 HasUnexpected int 35 36 // The number of times a test run contained at least one 37 // unexpected result AND had additional test results (i.e. had 38 // an unexpected result AND two or more test results in total). 39 Retried int 40 41 // The number of times a test run contained only 42 // unexpected test results AND had at least two unexpected 43 // results (i.e. was unexpected after all retries). 44 // 45 // The ratio UnexpectedAfterRetry / Retried measures the 46 // consistency / stickiness of the test's unexpected results, 47 // that is, the tendency for it to continue producing unexpected 48 // results if there is one unexpected result. The inverse of 49 // consistency is often called 'flakiness'. 50 UnexpectedAfterRetry int 51 } 52 53 func (h counts) addVerdict(cp inputbuffer.PositionVerdict) counts { 54 if cp.IsSimpleExpectedPass { 55 h.Runs += 1 56 return h 57 } 58 for _, run := range cp.Details.Runs { 59 if run.IsDuplicate { 60 continue 61 } 62 h.Runs += 1 63 if run.Unexpected.Count() == 0 { 64 continue 65 } 66 h.HasUnexpected += 1 67 if run.Expected.Count()+run.Unexpected.Count() < 2 { 68 continue 69 } 70 h.Retried += 1 71 if run.Expected.Count() > 0 { 72 continue 73 } 74 h.UnexpectedAfterRetry += 1 75 } 76 return h 77 } 78 79 func (h counts) add(other counts) counts { 80 h.Runs += other.Runs 81 h.HasUnexpected += other.HasUnexpected 82 h.Retried += other.Retried 83 h.UnexpectedAfterRetry += other.UnexpectedAfterRetry 84 return h 85 } 86 87 func (h counts) subtract(other counts) counts { 88 h.Runs -= other.Runs 89 h.HasUnexpected -= other.HasUnexpected 90 h.Retried -= other.Retried 91 h.UnexpectedAfterRetry -= other.UnexpectedAfterRetry 92 93 if h.Runs < 0 || h.HasUnexpected < 0 || h.Retried < 0 || h.UnexpectedAfterRetry < 0 { 94 // This indicates a logic error somewhere. 95 panic("subtraction resulted in value smaller than zero") 96 } 97 return h 98 }