github.com/intel/goresctrl@v0.5.0/pkg/rdt/bitmask.go (about) 1 /* 2 Copyright 2019 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package rdt 18 19 import ( 20 "fmt" 21 "math/bits" 22 "strconv" 23 "strings" 24 ) 25 26 // bitmask represents a generic 64 bit wide bitmask 27 type bitmask uint64 28 29 // MarshalJSON implements the Marshaler interface of "encoding/json" 30 func (b bitmask) MarshalJSON() ([]byte, error) { 31 return []byte(fmt.Sprintf("\"%#x\"", b)), nil 32 } 33 34 // listStr prints the bitmask in human-readable format, similar to e.g. the 35 // cpuset format of the Linux kernel 36 func (b bitmask) listStr() string { 37 str := "" 38 sep := "" 39 40 shift := int(0) 41 lsbOne := b.lsbOne() 42 43 // Process "ranges of ones" 44 for lsbOne != -1 { 45 b >>= uint(lsbOne) 46 47 // Get range lenght from the position of the first zero 48 numOnes := b.lsbZero() 49 50 if numOnes == 1 { 51 str += sep + strconv.Itoa(lsbOne+shift) 52 } else { 53 str += sep + strconv.Itoa(lsbOne+shift) + "-" + strconv.Itoa(lsbOne+numOnes-1+shift) 54 } 55 56 // Shift away the bits that have been processed 57 b >>= uint(numOnes) 58 shift += lsbOne + numOnes 59 60 // Get next bit that is set (if any) 61 lsbOne = b.lsbOne() 62 63 sep = "," 64 } 65 66 return str 67 } 68 69 // listStrToBitmask parses a string containing a human-readable list of bit 70 // numbers into a bitmask 71 func listStrToBitmask(str string) (bitmask, error) { 72 b := bitmask(0) 73 74 // Empty bitmask 75 if len(str) == 0 { 76 return b, nil 77 } 78 79 ranges := strings.Split(str, ",") 80 for _, ran := range ranges { 81 split := strings.SplitN(ran, "-", 2) 82 83 bitNum, err := strconv.ParseUint(split[0], 10, 6) 84 if err != nil { 85 return b, fmt.Errorf("invalid bitmask %q: %v", str, err) 86 } 87 88 if len(split) == 1 { 89 b |= 1 << bitNum 90 } else { 91 endNum, err := strconv.ParseUint(split[1], 10, 6) 92 if err != nil { 93 return b, fmt.Errorf("invalid bitmask %q: %v", str, err) 94 } 95 if endNum <= bitNum { 96 return b, fmt.Errorf("invalid range %q in bitmask %q", ran, str) 97 } 98 b |= (1<<(endNum-bitNum+1) - 1) << bitNum 99 } 100 } 101 return b, nil 102 } 103 104 func (b bitmask) lsbOne() int { 105 if b == 0 { 106 return -1 107 } 108 return bits.TrailingZeros64(uint64(b)) 109 } 110 111 func (b bitmask) msbOne() int { 112 // Returns -1 for b == 0 113 return 63 - bits.LeadingZeros64(uint64(b)) 114 } 115 116 func (b bitmask) lsbZero() int { 117 return bits.TrailingZeros64(^uint64(b)) 118 }