github.com/cilium/cilium@v1.16.2/bpf/tests/bpftest/gocovmerge.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  // Copyright (c) 2015, Wade Simmons
     5  // All rights reserved.
     6  
     7  // Redistribution and use in source and binary forms, with or without
     8  // modification, are permitted provided that the following conditions are met:
     9  
    10  // 1. Redistributions of source code must retain the above copyright notice, this
    11  //    list of conditions and the following disclaimer.
    12  // 2. Redistributions in binary form must reproduce the above copyright notice,
    13  //    this list of conditions and the following disclaimer in the documentation
    14  //    and/or other materials provided with the distribution.
    15  
    16  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    17  // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    18  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    19  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    20  // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    21  // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    22  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    23  // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    24  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    25  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    26  
    27  // https://github.com/wadey/gocovmerge
    28  
    29  package bpftests
    30  
    31  import (
    32  	"log"
    33  	"sort"
    34  
    35  	"golang.org/x/tools/cover"
    36  )
    37  
    38  func mergeProfiles(p *cover.Profile, merge *cover.Profile) {
    39  	if p.Mode != merge.Mode {
    40  		log.Fatalf("cannot merge profiles with different modes")
    41  	}
    42  	// Since the blocks are sorted, we can keep track of where the last block
    43  	// was inserted and only look at the blocks after that as targets for merge
    44  	startIndex := 0
    45  	for _, b := range merge.Blocks {
    46  		startIndex = mergeProfileBlock(p, b, startIndex)
    47  	}
    48  }
    49  
    50  func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) int {
    51  	sortFunc := func(i int) bool {
    52  		var pi cover.ProfileBlock
    53  		if i+startIndex < len(p.Blocks) {
    54  			pi = p.Blocks[i+startIndex]
    55  		} else {
    56  			pi = p.Blocks[len(p.Blocks)-1]
    57  		}
    58  		return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol)
    59  	}
    60  
    61  	i := 0
    62  	if !sortFunc(i) {
    63  		i = sort.Search(len(p.Blocks)-startIndex, sortFunc)
    64  	}
    65  	i += startIndex
    66  	if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol {
    67  		if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol {
    68  			log.Fatalf("OVERLAP MERGE: %v %v %v", p.FileName, p.Blocks[i], pb)
    69  		}
    70  		switch p.Mode {
    71  		case "set":
    72  			p.Blocks[i].Count |= pb.Count
    73  		case "count", "atomic":
    74  			p.Blocks[i].Count += pb.Count
    75  		default:
    76  			log.Fatalf("unsupported covermode: '%s'", p.Mode)
    77  		}
    78  	} else {
    79  		if i > 0 {
    80  			pa := p.Blocks[i-1]
    81  			if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) {
    82  				log.Fatalf("OVERLAP BEFORE: %v %v %v", p.FileName, pa, pb)
    83  			}
    84  		}
    85  		if i < len(p.Blocks)-1 {
    86  			pa := p.Blocks[i+1]
    87  			if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) {
    88  				log.Fatalf("OVERLAP AFTER: %v %v %v", p.FileName, pa, pb)
    89  			}
    90  		}
    91  		p.Blocks = append(p.Blocks, cover.ProfileBlock{})
    92  		copy(p.Blocks[i+1:], p.Blocks[i:])
    93  		p.Blocks[i] = pb
    94  	}
    95  	return i + 1
    96  }
    97  
    98  func addProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile {
    99  	i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName })
   100  	if i < len(profiles) && profiles[i].FileName == p.FileName {
   101  		mergeProfiles(profiles[i], p)
   102  	} else {
   103  		profiles = append(profiles, nil)
   104  		copy(profiles[i+1:], profiles[i:])
   105  		profiles[i] = p
   106  	}
   107  	return profiles
   108  }