gtag('config', 'G-0PFHD683JR');
Price Prediction

Testing.b.looop: Some of the predictable criteria for you

Go to developers who wrote standards using testing The package has faced some different pitfalls. GO 1.24 introduces new way to write easy -to -use criteria, but at the same time more powerful: testing.B.Loop.

Traditionally, the Going criteria are written using an episode 0 to b.N:

func Benchmark(b *testing.B) {
  for range b.N {
    ... code to measure ...
  }
}

Use b.Loop Instead is a trivial change:

func Benchmark(b *testing.B) {
  for b.Loop() {
    ... code to measure ...
  }
}

testing.B.Loop It has many benefits:

  • It prevents unwanted software improvements within the standard ring.
  • It automatically excludes the setting and cleaning code from standard timing.
  • The code cannot mistake the total number of repetitions or repetition.

These were all easy mistakes b.NStyle standards that silently lead to fake standard results. As an additional reward, b.Loop-Style standards until they are completed in less time!

Let’s explore the advantages testing.B.Loop And how to use it effectively.

Old episode problems

Before moving to 1.24, while the main structure of the standard was simple, the most advanced criteria require more care:

func Benchmark(b *testing.B) {
  ... setup ...
  b.ResetTimer() // if setup may be expensive
  for range b.N {
    ... code to measure ...
    ... use sinks or accumulation to prevent dead-code elimination ...
  }
  b.StopTimer() // if cleanup or reporting may be expensive
  ... cleanup ...
  ... report ...
}

If the preparation or cleaning is not trivial, the developer must surround the standard episode with ResetTimer wow StopTimer Calls. It is easy to forget this, and even if the developer remembers that it may be necessary, it may be difficult to judge whether the preparation or cleaning is “expensive enough” to request them.

Without this, and testing The package can only time the entire measurement function. If you delete the measurement function, the preparation and cleaning code will be included in the total time measurement, which is silently tending to the final standard result.

There is another more accurate dilemma that requires a deeper understanding: (Source of example)

func isCond(b byte) bool {
  if b%3 == 1 && b%7 == 2 && b%17 == 11 && b%31 == 9 {
    return true
  }
  return false
}

func BenchmarkIsCondWrong(b *testing.B) {
  for range b.N {
    isCond(201)
  }
}

In this example, the user may notice isCond Nanosyoni sub -implementation. CPU is fast, but not so quickly! This anomaly apparently stems from the fact that isCond It is guaranteed, and since its result is never used, the translator cancels it as a dead symbol. As a result, this standard does not measure isCond Absolutely it measures the time it takes not to do anything.

In this case, the nanoscopic sub -result is a clear red sign, but in the most complex standards, the disposal of partial dead code can lead to results that appear reasonable but still do not measure what is intended.

how testing.B.Loop Help

Unlike a b.N-Arrange, standard, testing.B.Loop Capable to track when it is called for the first time in a standard when the final repetition ends. the b.ResetTimer At the beginning of the episode and b.StopTimer At the end it is merged into testing.B.LoopEliminate the need for the standard temporary management manually to prepare the setting code and cleaning code.

Moreover, the GO code now discovers the episodes where the situation is just an invitation to testing.B.Loop It is forbidden to eliminate the dead code inside the ring. In Go 1.24, this is performed by intolerance of the body of such an episode, but we are planning Improved This is in the future.

Another nice feature of testing.B.Loop It is one colonial approach. with b.N-Approach, the standard test package must require several times with different values b.NRefer to the measured time to a threshold.

in contrast, b.Loop The standard loop can simply be run until it reaches time, and only needs to call the standard once. internally, b.Loop It continues to use an intensification process to extinguish the general expenses of the measurement, but this is hidden from the caller and can be more efficient.

Certain restrictions from b.NThe model ring is still applied to b.Loop-Tyle episode. The user’s responsibility remains in the temporary management within the standard episode, when necessary: ​​(Example of the source)

func BenchmarkSortInts(b *testing.B) {
  ints := make([]int, N)
  for b.Loop() {
    b.StopTimer()
    fillRandomInts(ints)
    b.StartTimer()
    slices.Sort(ints)
  }
}

In this example, to evaluate the sorting performance in its place slices.SortRetailing a random capacity for each repetition. The user must manually manage the time in such cases.

Moreover, there is still something that has to be one episode in the standard of the standard function (a b.N-The Style episode can not coexist with a b.Loop-Episode), and every repetition of the episode should do the same.

When to use

the testing.B.Loop The method is now the preferred way to write standards:

func Benchmark(b *testing.B) {
  ... setup ...
  for b.Loop() {
    // optional timer control for in-loop setup/cleanup
    ... code to measure ...
  }
  ... cleanup ...
}

testing.B.Loop It provides faster, more accurate and easier measurement.

Thanks and appreciation

Thank you very much for everyone in society who made notes on the issue of the proposal and reported the mistakes as this feature was issued! I am also grateful to Elie Peespersky on his useful summaries. Finally, thank you very much to Austin Clemens, Sherry Moy and Michael Prat, for their review, studied design options and document improvement. Thank you all for your contributions!


Credits: Junang Shao

Will Patterson photography on Unsplash

This article is available on Go Blog Under CC with a verb license 4.0.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button