How to use NewExecutionSegmentSequenceWrapper method of lib Package

Best K6 code snippet using lib.NewExecutionSegmentSequenceWrapper

execution_segment.go

Source:execution_segment.go Github

copy

Full Screen

...440 // The striped offsets, i.e. the repeating indexes that "belong" to each441 // execution segment in the sequence.442 offsets [][]int64443}444// NewExecutionSegmentSequenceWrapper expects a filled-out execution segment445// sequence. It pre-calculates the initial caches of and returns a new446// ExecutionSegmentSequenceWrapper, but doesn't calculate the striped offsets.447func NewExecutionSegmentSequenceWrapper(ess ExecutionSegmentSequence) *ExecutionSegmentSequenceWrapper {448 if !ess.IsFull() {449 panic(fmt.Sprintf("Cannot wrap around a non-full execution segment sequence '%s'", ess))450 }451 sequenceLength := len(ess)452 offsets := make([][]int64, sequenceLength)453 lcd := ess.LCD()454 // This will contain the normalized numerator values (i.e. what they would have455 // been if all denominators were equal to the LCD), sorted in descending456 // order (i.e. biggest segments are first), with references to their actual457 // indexes in the execution segment sequence (i.e. `seq` above).458 sortedNormalizedIndexes := make([]struct {459 normNumerator int64460 originalIndex int461 }, sequenceLength)462 for i := range ess {463 normalizedNumerator := ess[i].length.Num().Int64() * (lcd / ess[i].length.Denom().Int64())464 sortedNormalizedIndexes[i].normNumerator = normalizedNumerator465 sortedNormalizedIndexes[i].originalIndex = i466 offsets[i] = make([]int64, 0, normalizedNumerator+1)467 }468 sort.SliceStable(sortedNormalizedIndexes, func(i, j int) bool {469 return sortedNormalizedIndexes[i].normNumerator > sortedNormalizedIndexes[j].normNumerator470 })471 // This is the striping algorithm. Imagine you have a number of rational472 // numbers which all add up to 1 (or less), and call them segments. If you473 // want each to get proportional amount of anything, you need to give them474 // their numerator count of elements for each denominator amount from the475 // original elements. So, for 1/3, you give 1 element for each 3 elements.476 // For 3/5 - 3 elements for each 5. If you have, for example, a sequence477 // with elements with length 3/5 and 1/3, in order to know how to distribute478 // it accurately, you need to get the LCD(lowest common denominitor). In479 // this case, between 3 and 5, the LCD is 15. Then to transform the numbers480 // to have the same, LCD equal, denominator. So 3/5 becomes 9/15 and 1/3481 // becomes 5/15. So now for each 15 elements 9 need to go to the 3/5, and 5482 // need to go to 1/3. This is what we did above in sortedNormalizedIndexes.483 //484 // We use the algorithm below to split elements between ExecutionSegments by485 // using their length as the rational number. As we would like to get486 // non-sequential elements, we try to get the maximum distance between them.487 // That is the number of elements divided by the number of elements for any488 // given segment, which concidently is the length of the segment reversed.489 // The algorithm below does the following:490 // 1. Goes through the elements from 0 to the lcd-1491 // 2. For each of element, it goes through the segments and looks if the492 // amount of already taken elements by the given segment, multiplied by493 // that segment's length inverted, is equal to or less to the current494 // element index. If it is, give that element to that segment. If not,495 // continue with the next element.496 // The code below specifically avoids using big.Rat, for performance497 // reasons, which complicates the code somewhat. As additional note, the498 // sorting of the segments from biggest to smallest helps with the fact that499 // the biggest elements will need to take the most elements, and for them it500 // will be the hardest to not get sequential elements.501 prev := make([]int64, sequenceLength)502 chosenCounts := make([]int64, sequenceLength)503 saveIndex := func(iteration int64, index int, numerator int64) {504 offsets[index] = append(offsets[index], iteration-prev[index])505 prev[index] = iteration506 if int64(len(offsets[index])) == numerator {507 offsets[index] = append(offsets[index], offsets[index][0]+lcd-iteration)508 }509 }510 for i := int64(0); i < lcd; i++ {511 for sortedIndex, chosenCount := range chosenCounts {512 num := chosenCount * lcd513 denom := sortedNormalizedIndexes[sortedIndex].normNumerator514 if i > num/denom || (i == num/denom && num%denom == 0) {515 chosenCounts[sortedIndex]++516 saveIndex(i, sortedNormalizedIndexes[sortedIndex].originalIndex, denom)517 break518 }519 }520 }521 return &ExecutionSegmentSequenceWrapper{ExecutionSegmentSequence: ess, lcd: lcd, offsets: offsets}522}523// LCD returns the (cached) least common denominator of the sequence - no need524// to calculate it again, since we did it in the constructor.525func (essw *ExecutionSegmentSequenceWrapper) LCD() int64 {526 return essw.lcd527}528// ScaleInt64 scales the provided value for the given segment.529func (essw *ExecutionSegmentSequenceWrapper) ScaleInt64(segmentIndex int, value int64) int64 {530 start := essw.offsets[segmentIndex][0]531 offsets := essw.offsets[segmentIndex][1:]532 result := (value / essw.lcd) * int64(len(offsets))533 for gi, i := 0, start; i < value%essw.lcd; gi, i = gi+1, i+offsets[gi] {534 result++535 }536 return result537}538// GetStripedOffsets returns the stripped offsets for the given segment539// the returned values are as follows in order:540// - start: the first value that is for the segment541// - offsets: a list of offsets from the previous value for the segment. This are only the offsets542// to from the start to the next start if we chunk the elements we are going to strip543// into lcd sized chunks544// - lcd: the LCD of the lengths of all segments in the sequence. This is also the number of545// elements after which the algorithm starts to loop and give the same values546func (essw *ExecutionSegmentSequenceWrapper) GetStripedOffsets(segmentIndex int) (int64, []int64, int64) {547 offsets := essw.offsets[segmentIndex]548 return offsets[0], offsets[1:], essw.lcd549}550// GetTuple returns an ExecutionTuple for the specified segment index.551func (essw *ExecutionSegmentSequenceWrapper) GetTuple(segmentIndex int) *ExecutionTuple {552 return &ExecutionTuple{553 Sequence: essw,554 Segment: essw.ExecutionSegmentSequence[segmentIndex],555 SegmentIndex: segmentIndex,556 }557}558// GetNewExecutionSegmentSequenceFromValue uses the value provided, splits it559// between all the segments, using the striping offsets in the sequence,560// generating a new segment sequence. It then returns a new561// ExecutionSegmentSequenceWrapper, with the new sequence and segments, such562// that each new segment in the new sequence has length `Scale(value)/value`563// while keeping the order.564//565// Additionally, the position of a given segment index can be tracked (since566// empty segments are removed), so that you can reconstruct an ExecutionTuple,567// if required. If the segment with the trackedIndex is not part of the new568// sequence, or if a new sequence cannot be generated (for example, for 0569// values), an error will be returned.570func (essw *ExecutionSegmentSequenceWrapper) GetNewExecutionSegmentSequenceFromValue(value int64, trackedIndex int) (571 newSequence *ExecutionSegmentSequenceWrapper, newIndex int, err error,572) {573 if value < 1 {574 return nil, -1, fmt.Errorf("cannot generate new sequence for value %d", value)575 }576 if value%essw.lcd == 0 { // the value is perfectly divisible so we will get the same tuple577 return essw, trackedIndex, nil578 }579 newIndex = -1580 newESS := make(ExecutionSegmentSequence, 0, len(essw.ExecutionSegmentSequence)) // this can be smaller581 prev := int64(0)582 for i := range essw.ExecutionSegmentSequence {583 newValue := essw.ScaleInt64(i, value)584 if newValue == 0 {585 continue586 }587 currentES := newExecutionSegment(big.NewRat(prev, value), big.NewRat(prev+newValue, value))588 prev += newValue589 if i == trackedIndex {590 newIndex = len(newESS)591 }592 newESS = append(newESS, currentES)593 }594 if newIndex == -1 {595 return nil, -1, fmt.Errorf(596 "segment %d (%s) isn't present in the new sequence",597 trackedIndex, essw.ExecutionSegmentSequence[trackedIndex],598 )599 }600 return NewExecutionSegmentSequenceWrapper(newESS), newIndex, nil601}602// ExecutionTuple is the combination of an ExecutionSegmentSequence(Wrapper) and603// a specific ExecutionSegment from it. It gives easy access to the efficient604// scaling and striping algorithms for that specific segment, since the results605// are cached in the sequence wrapper. It is also the basis for the606// SegmentedIndex type below, which is the actual implementation of a segmented607// (striped) iterator, usable both for segmenting actual iterations and for608// partitioning data between multiple instances.609//610// For example, let's try to segment a load test in 3 unequal parts: 50%, 25%611// and 25% (so the ExecutionSegmentSequence will contain these segments: 0:1/2,612// 1/2:3/4, 3/4:1). The building blocks that k6 needs for distributed execution613// are segmented (non-overlapping) iterators and proportionally dividing integer614// numbers as fairly as possible between multiple segments in a stable manner.615//616// The segmented iterators (i.e. SegmentedIndex values below) will be like this:617//618// Normal iterator: 0 1 2 3 4 5 6 7 8 9 10 11 ...619// Instance 1 (0:1/2) iterator: 0 2 4 6 8 10 ...620// Instance 2 (1/2:3/4) iterator: 1 5 9 ...621// Instance 2 (3/4:1) iterator: 3 7 11 ...622//623// See how every instance has its own uniqe non-overlapping iterator, but when624// we combine all of them, we cover every possible value in the original one.625//626// We also can use this property to scale integer numbers proportionally, as627// fairly as possible, between the instances, like this:628//629// Global int value to scale: 1 2 3 4 5 6 7 8 9 10 11 12 ...630// Calling ScaleInt64():631// - Instance 1 (0:1/2) value: 1 1 2 2 3 3 4 4 5 5 6 6 ...632// - Instance 2 (1/2:3/4) value: 0 1 1 1 1 2 2 2 2 3 3 3 ...633// - Instance 2 (3/4:1) value: 0 0 0 1 1 1 1 2 2 2 2 3 ...634//635// Notice how the sum of the per-instance values is always equal to the global636// value - this is what ExecutionTuple.ScaleInt64() does. Also compare both637// tables (their positions match), see how we only increment the value for a638// particular instance when we would have cycled the iterator on that step.639//640// This also makes the scaling stable, in contrast to ExecutionSegment.Scale().641// Scaled values will only ever increase, since we just increment them in a642// specific order between instances. There will never be a situation where643// `ScaleInt64(i)` is less than `ScaleInt64(i+n)` for any positive n!644//645// The algorithm that calculates the offsets and everything that's necessary to646// have these segmented iterators is in NewExecutionSegmentSequenceWrapper().647// The ExecutionTuple simply exposes them efficiently for a single segment of648// the sequence, so it's the thing that most users will probably need.649type ExecutionTuple struct { // TODO rename? make fields private and have getter methods?650 Sequence *ExecutionSegmentSequenceWrapper651 Segment *ExecutionSegment652 SegmentIndex int653}654func (et *ExecutionTuple) String() string {655 return fmt.Sprintf("%s in %s", et.Segment, et.Sequence)656}657// NewExecutionTuple returns a new ExecutionTuple for the provided segment and658// sequence.659//660// TODO: don't return a pointer?661func NewExecutionTuple(segment *ExecutionSegment, sequence *ExecutionSegmentSequence) (*ExecutionTuple, error) {662 filledSeq := GetFilledExecutionSegmentSequence(sequence, segment)663 wrapper := NewExecutionSegmentSequenceWrapper(filledSeq)664 index, err := wrapper.FindSegmentPosition(segment)665 if err != nil {666 return nil, err667 }668 return &ExecutionTuple{Sequence: wrapper, Segment: segment, SegmentIndex: index}, nil669}670// ScaleInt64 scales the provided value for our execution segment.671func (et *ExecutionTuple) ScaleInt64(value int64) int64 {672 if len(et.Sequence.ExecutionSegmentSequence) == 1 {673 return value // if we don't have any segmentation, just return the original value674 }675 return et.Sequence.ScaleInt64(et.SegmentIndex, value)676}677// GetStripedOffsets returns the striped offsets for our execution segment....

Full Screen

Full Screen

NewExecutionSegmentSequenceWrapper

Using AI Code Generation

copy

Full Screen

1func main() {2}3func main() {4}5func main() {6}7func main() {8}9func main() {10}11func main() {12}13func main() {14}15func main() {16}17func main() {18}19func main() {20}21func main() {22}23func main() {24}25func main() {

Full Screen

Full Screen

NewExecutionSegmentSequenceWrapper

Using AI Code Generation

copy

Full Screen

1func main() {2 seq, err := lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")3 if err != nil {4 log.Fatal(err)5 }6 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")7 if err != nil {8 log.Fatal(err)9 }10 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")11 if err != nil {12 log.Fatal(err)13 }14 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")15 if err != nil {16 log.Fatal(err)17 }18 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")19 if err != nil {20 log.Fatal(err)21 }22 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")23 if err != nil {24 log.Fatal(err)25 }26 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")27 if err != nil {28 log.Fatal(err)29 }30 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")31 if err != nil {32 log.Fatal(err)33 }34 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")35 if err != nil {36 log.Fatal(err)37 }38 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")39 if err != nil {40 log.Fatal(err)41 }42 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")43 if err != nil {44 log.Fatal(err)45 }46 seq, err = lib.NewExecutionSegmentSequenceWrapper("1/2,2/3")

Full Screen

Full Screen

NewExecutionSegmentSequenceWrapper

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 series := []lib.Series{4 {Name: "test1", Tags: map[string]string{"tag1": "val1"}},5 {Name: "test2", Tags: map[string]string{"tag1": "val2"}},6 {Name: "test3", Tags: map[string]string{"tag1": "val3"}},7 }8 essw := lib.NewExecutionSegmentSequenceWrapper(series, 3)9 for i, s := range essw.Series {10 fmt.Printf("series %d: %s11 }12}13import (14func main() {15 series := []lib.Series{16 {Name: "test1", Tags: map[string]string{"tag1": "val1"}},17 {Name: "test2", Tags: map[string]string{"tag1": "val2"}},18 {Name: "test3", Tags: map[string]string{"tag1": "val3"}},19 }20 essw := lib.NewExecutionSegmentSequenceWrapper(series, 2)21 for i, s := range essw.Series {22 fmt.Printf("series %d: %s23 }24}25import (26func main() {27 series := []lib.Series{28 {Name: "test1", Tags: map[string]string{"tag1": "val1"}},29 {Name: "test2", Tags: map[string]string{"tag1": "val2"}},30 {Name: "test3", Tags: map[string]string{"tag1": "val3

Full Screen

Full Screen

NewExecutionSegmentSequenceWrapper

Using AI Code Generation

copy

Full Screen

1func main() {2 sequence := NewExecutionSegmentSequenceWrapper()3 sequence.AddSegmentWrapper(0.0, 0.3)4 sequence.AddSegmentWrapper(0.3, 0.6)5 sequence.AddSegmentWrapper(0.6, 1.0)6 runner := NewRunnerWrapper()7 runner.RunWrapper(sequence)8}9func main() {10 runner := NewRunnerWrapper()11 runner.RunWrapper(nil)12}13func main() {14 runner := NewRunnerWrapper()15 runner.RunWrapper(nil)16}17func main() {18 runner := NewRunnerWrapper()19 runner.RunWrapper(nil)20}21func main() {22 runner := NewRunnerWrapper()23 runner.RunWrapper(nil)24}25func main() {26 runner := NewRunnerWrapper()27 runner.RunWrapper(nil)28}29func main() {30 runner := NewRunnerWrapper()31 runner.RunWrapper(nil)32}33func main() {34 runner := NewRunnerWrapper()35 runner.RunWrapper(nil)36}37func main() {38 runner := NewRunnerWrapper()39 runner.RunWrapper(nil)40}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run K6 automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used method in

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful