snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
This commit is contained in:
179
benchmark/stats/curve.go
Normal file
179
benchmark/stats/curve.go
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package stats
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/csv"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
rand "math/rand/v2"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// payloadCurveRange represents a line within a payload curve CSV file.
|
||||
type payloadCurveRange struct {
|
||||
from, to int32
|
||||
weight float64
|
||||
}
|
||||
|
||||
// newPayloadCurveRange receives a line from a payload curve CSV file and
|
||||
// returns a *payloadCurveRange if the values are acceptable.
|
||||
func newPayloadCurveRange(line []string) (*payloadCurveRange, error) {
|
||||
if len(line) != 3 {
|
||||
return nil, fmt.Errorf("invalid number of entries in line %v (expected 3)", line)
|
||||
}
|
||||
|
||||
var from, to int64
|
||||
var weight float64
|
||||
var err error
|
||||
if from, err = strconv.ParseInt(line[0], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if from <= 0 {
|
||||
return nil, fmt.Errorf("line %v: field (%d) must be in (0, %d]", line, from, math.MaxInt32)
|
||||
}
|
||||
if to, err = strconv.ParseInt(line[1], 10, 32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if to <= 0 {
|
||||
return nil, fmt.Errorf("line %v: field %d must be in (0, %d]", line, to, math.MaxInt32)
|
||||
}
|
||||
if from > to {
|
||||
return nil, fmt.Errorf("line %v: from (%d) > to (%d)", line, from, to)
|
||||
}
|
||||
if weight, err = strconv.ParseFloat(line[2], 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &payloadCurveRange{from: int32(from), to: int32(to), weight: weight}, nil
|
||||
}
|
||||
|
||||
// chooseRandom picks a payload size (in bytes) for a particular range. This is
|
||||
// done with a uniform distribution.
|
||||
func (pcr *payloadCurveRange) chooseRandom() int {
|
||||
if pcr.from == pcr.to { // fast path
|
||||
return int(pcr.from)
|
||||
}
|
||||
|
||||
return int(rand.Int32N(pcr.to-pcr.from+1) + pcr.from)
|
||||
}
|
||||
|
||||
// sha256file is a helper function that returns a hex string matching the
|
||||
// SHA-256 sum of the input file.
|
||||
func sha256file(file string) (string, error) {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sum := sha256.Sum256(data)
|
||||
return hex.EncodeToString(sum[:]), nil
|
||||
}
|
||||
|
||||
// PayloadCurve is an internal representation of a weighted random distribution
|
||||
// CSV file. Once a *PayloadCurve is created with NewPayloadCurve, the
|
||||
// ChooseRandom function should be called to generate random payload sizes.
|
||||
type PayloadCurve struct {
|
||||
pcrs []*payloadCurveRange
|
||||
// Sha256 must be a public field so that the gob encoder can write it to
|
||||
// disk. This will be needed at decode-time by the Hash function.
|
||||
Sha256 string
|
||||
}
|
||||
|
||||
// NewPayloadCurve parses a .csv file and returns a *PayloadCurve if no errors
|
||||
// were encountered in parsing and initialization.
|
||||
func NewPayloadCurve(file string) (*PayloadCurve, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := csv.NewReader(f)
|
||||
lines, err := r.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &PayloadCurve{}
|
||||
var total float64
|
||||
for _, line := range lines {
|
||||
pcr, err := newPayloadCurveRange(line)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret.pcrs = append(ret.pcrs, pcr)
|
||||
total += pcr.weight
|
||||
}
|
||||
|
||||
ret.Sha256, err = sha256file(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pcr := range ret.pcrs {
|
||||
pcr.weight /= total
|
||||
}
|
||||
|
||||
sort.Slice(ret.pcrs, func(i, j int) bool {
|
||||
if ret.pcrs[i].from == ret.pcrs[j].from {
|
||||
return ret.pcrs[i].to < ret.pcrs[j].to
|
||||
}
|
||||
return ret.pcrs[i].from < ret.pcrs[j].from
|
||||
})
|
||||
|
||||
var lastTo int32
|
||||
for _, pcr := range ret.pcrs {
|
||||
if lastTo >= pcr.from {
|
||||
return nil, fmt.Errorf("[%d, %d] overlaps with a different line", pcr.from, pcr.to)
|
||||
}
|
||||
lastTo = pcr.to
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ChooseRandom picks a random payload size (in bytes) that follows the
|
||||
// underlying weighted random distribution.
|
||||
func (pc *PayloadCurve) ChooseRandom() int {
|
||||
target := rand.Float64()
|
||||
var seen float64
|
||||
for _, pcr := range pc.pcrs {
|
||||
seen += pcr.weight
|
||||
if seen >= target {
|
||||
return pcr.chooseRandom()
|
||||
}
|
||||
}
|
||||
|
||||
// This should never happen, but if it does, return a sane default.
|
||||
return 1
|
||||
}
|
||||
|
||||
// Hash returns a string uniquely identifying a payload curve file for feature
|
||||
// matching purposes.
|
||||
func (pc *PayloadCurve) Hash() string {
|
||||
return pc.Sha256
|
||||
}
|
||||
|
||||
// ShortHash returns a shortened version of Hash for display purposes.
|
||||
func (pc *PayloadCurve) ShortHash() string {
|
||||
return pc.Sha256[:8]
|
||||
}
|
||||
Reference in New Issue
Block a user