Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: improve inlining cost model #17566

Open
josharian opened this issue Oct 24, 2016 · 82 comments
Open

cmd/compile: improve inlining cost model #17566

josharian opened this issue Oct 24, 2016 · 82 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance ToolSpeed
Milestone

Comments

@josharian
Copy link
Contributor

josharian commented Oct 24, 2016

The current inlining cost model is simplistic. Every gc.Node in a function has a cost of one. However, the actual impact of each node varies. Some nodes (OKEY) are placeholders never generate any code. Some nodes (OAPPEND) generate lots of code.

In addition to leading to bad inlining decisions, this design means that any refactoring that changes the AST structure can have unexpected and significant impact on compiled code. See CL 31674 for an example.

Inlining occurs near the beginning of compilation, which makes good predictions hard. For example, new or make or & might allocate (large runtime call, much code generated) or not (near zero code generated). As another example, code guarded by if false still gets counted. As another example, we don't know whether bounds checks (which generate lots of code) will be eliminated or not.

One approach is to hand-write a better cost model: append is very expensive, things that might end up in a runtime call are moderately expensive, pure structure and variable/const declarations are cheap or free.

Another approach is to compile lots of code and generate a simple machine-built model (e.g. linear regression) from it.

I have tried both of these approaches, and believe both of them to be improvements, but did not mail either of them, for two reasons:

  • Inlining significantly impacts binary size, runtime performance, and compilation speed. Minor changes to the cost model or to the budget can have big impacts on all three. I hoped to find a model and budget that was clearly pareto optimal, but I did not. In order to make forward progress, we need to make a decision about what metric(s) we want to optimize for, and which code to measure those metric on. This is to my mind the single biggest blocker for improving inlining.
  • Changing inlining decisions impacts the runtime as well as other code and minor inlining changes to the runtime can have outsized performance impacts. I see several possible ways to address this. (1) We could add a //go:inline annotation for use in the runtime only, to allow runtime authors to force the compiler to inline performance-critical functions. If a non-inlinable function was marked //go:inline, compilation would fail. (2) We could add a //go:mustinline annotation for use in the runtime only (see CL 22785), to allow runtime authors to protect currently-inlined functions against becoming non-inlined. (3) We could tune runtime inlining (cost model, budget, etc.) independently.

Three other related ideas:

  • We might want to take into account the number and size of parameters and return values of a function when deciding whether to inline it, since those determine the cost in binary size of setting up the function call.
  • We might want to have separate budgets for expressions and control flow, since branches end up being more expensive on most metrics.
  • We could treat intra-package inlining different than inter-package inlining. When inlining across packages, we don't actually need to decide early on whether to allow inlining, since the actual inlining will occur in an entirely different compiler invocation. We could thus wait until function compilation is complete, and we know exactly how large the fully optimized code is, and then make our decision about whether other packages should inline that function. Downsides to this otherwise appealing idea are: (1) unexpected performance impact of moving a function from one package to another, (2) it introduces a significant dependency between full compilation and writing export data, which e.g. would prevent cmd/go: build dependent packages as soon as export data is ready #15734.

cc @dr2chase @randall77 @ianlancetaylor @mdempsky

@ianlancetaylor
Copy link
Contributor

I'm going to toss in a few more ideas to consider.

An unexported function that is only called once is often cheaper to inline.

Functions that include tests of parameter values can be cheaper to inline for specific calls that pass constant arguments for those parameters. That is, the cost of inlining is not solely determined by the function itself, it is also determined by the nature of the call.

Functions that only make function calls in error cases, which is fairly common, can be cheaper to handle as a mix of inlining and outlining: you inline the main control flow but leave the error handling in a separate function. This may be particularly worth considering when inlining across packages, as the export data only needs to include the main control flow. (Error cases are detectable as the control flow blocks that return a non-nil value for a single result parameter of type error.)

One of the most important optimizations for large programs is feedback directed optimization aka profiled guided optimization. One of the most important lessons to learn from feedback/profiling is which functions are worth inlining, both on a per-call basis and on a "most calls pass X as argument N" basis. Therefore, while we have no FDO/PGO framework at present, any work on inlining should consider how to incorporate information gleaned from such a framework when it exists.

Pareto optimal is a nice goal but I suspect it is somewhat unrealistic. It's almost always possible to find a horrible decision made by any specific algorithm, but the algorithm can still be better on realistic benchmarks.

@rasky
Copy link
Member

rasky commented Oct 24, 2016

Functions that include tests of parameter values can be cheaper to inline for specific calls that pass constant arguments for those parameters. That is, the cost of inlining is not solely determined by the function itself, it is also determined by the nature of the call.

A common case where this would apply is when calling marshallers/unmarshallers that use reflect to inspect interface{} parameters. Many of them tend to have a "fast-path" in case reflect.Type is some basic type or has some basic property. Inlining that fast-path would make it even faster. Eg: see binary.Read and think how much of its code could be pulled when the value bound to the interface{} argument is known at compile-time.

@thanm
Copy link
Contributor

thanm commented Oct 24, 2016

Along the lines of what iant@ said, it's common for C++ compilers take into account whether a callsite appears in a loop (and thus might be "hotter"). This can help for toolchains that don't support FDO/PGO or for applications in which FDO/PGO are not being used.

@minux
Copy link
Member

minux commented Oct 25, 2016 via email

@dr2chase
Copy link
Contributor

Couldn't we obtain a minor improvement in the cost model by measuring the size of generated assembly language? It would require preserving a copy of the tree till after compilation, and doing compilation bottom-up (same way as inlining is scheduled) but that would give you a more accurate measure. There's a moderate chance of being able to determine goodness of constant parameters at the SSA-level, too.

Note that this would require rearranging all of these transformations (inlining, escape analysis, closure conversion, compilation) to run them function/recursive-function-nest at-a-time, so that the results from compiling bottom-most functions all the way to assembly language would be available to inform inlining at the next level up.

@josharian
Copy link
Contributor Author

doing compilation bottom-up

I have also considered this. There'd be a lot of high risk work rearranging the rest of the compiler to work this way. It could also hurt our chances to get a big boost out of concurrent compilation; you want to start on the biggest, slowest functions ASAP, but those are the most likely to depend on many other functions.

@dr2chase
Copy link
Contributor

It doesn't look that high risk to me; it's just another iteration order. SSA also gives us a slightly more tractable place to compute things like "constant parameter values that shrink code size", even if it is only so crude as looking for blocks directly conditional on comparisons with parameter values.

@josharian
Copy link
Contributor Author

I think we could test the inlining benefits of the bottom-up compilation pretty easily. One way is to do it just for inter-package compilation (as suggested above); another is to hack cmd/compile to dump the function asm size somewhere and then hack cmd/go to compile all packages twice, using the dumped sizes for the second round.

@CAFxX
Copy link
Contributor

CAFxX commented Nov 22, 2016

An unexported function that is only called once is often cheaper to inline.

Out of curiosity, why "often"? I can't think off the top of my head a case in which the contrary is true.

Also, just to understand, in -buildmode=exe basically every single function beside the entry function is going to be considered unexported?

@ianlancetaylor
Copy link
Contributor

An unexported function that is only called once is often cheaper to inline.

Out of curiosity, why "often"? I can't think off the top of my head a case in which the contrary is true.

It is not true when the code looks like

func internal() {
    // Large complex function with loops.
}

func External() {
    if veryRareCase {
        internal()
    }
}

Because in the normal case where you don't need to call internal you don't have set up a stack frame.

Also, just to understand, in -buildmode=exe basically every single function beside the entry function is going to be considered unexported?

In package main, yes.

@CAFxX
Copy link
Contributor

CAFxX commented Nov 22, 2016

Because in the normal case where you don't need to call internal you don't have set up a stack frame.

Oh I see, makes sense. Would be nice (also in other cases) if setting up the stack frame could be sunk in the if, but likely it wouldn't be worth the extra effort.

Also, just to understand, in -buildmode=exe basically every single function beside the entry function is going to be considered unexported?

In package main, yes.

The tyranny of unit-at-a-time :D

@RalphCorderoy
Copy link

Functions that start with a run of if param1 == nil { return nil } where the tests and return values are simple parameters or constants would avoid the call overhead if just this part was inlined. The size of setting up the call/return could be weighed against the size of the simple tests.

@mvdan
Copy link
Member

mvdan commented Jan 18, 2017

@RalphCorderoy I've been thinking about the same kind of function body "chunking" for early returns. Especially interesting for quick paths, where the slow path is too big to inline.

Unless the compiler chunks, it's up to the developer to split the function in two I presume.

@RalphCorderoy
Copy link

Hi @mvdan, Split the function in two with the intention the compiler then inlines the non-leaf first one?
Another possibility on stripping some of the simple quick paths is the remaining slow non-inlined function no longer needs some of the parameters.

@mvdan
Copy link
Member

mvdan commented Jan 19, 2017

Yes, for example, here tryFastPath is likely small enough to be inlined (if forward thunk funcs were inlineable, see #8421):

func tryFastPath() {
    if someCond {
        // fast path
        return ...
    }
    return slowPath()
}

@josharian
Copy link
Contributor Author

Too late for 1.9.

@gopherbot
Copy link
Contributor

Change https://golang.org/cl/57410 mentions this issue: runtime: add TestIntendedInlining

gopherbot pushed a commit that referenced this issue Aug 22, 2017
The intent is to allow more aggressive refactoring
in the runtime without silent performance changes.

The test would be useful for many functions.
I've seeded it with the runtime functions tophash and add;
it will grow organically (or wither!) from here.

Updates #21536 and #17566

Change-Id: Ib26d9cfd395e7a8844150224da0856add7bedc42
Reviewed-on: https://go-review.googlesource.com/57410
Reviewed-by: Martin Möhrmann <moehrmann@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
@TocarIP
Copy link
Contributor

TocarIP commented Sep 25, 2017

Another example of current inlining heuristic punishing more readable code

if !foo {
  return
}
if !bar {
  return
}
if !baz {
  return
}
//do stuff

is more "expensive" than

if foo && bar && baz {
// do stuff
}
return

This is based on real code from regexp package (see https://go-review.googlesource.com/c/go/+/65491
for details)

@ghasemloo
Copy link

@josharian
Copy link
Contributor Author

josharian commented May 30, 2020

Here’s a compromise idea that I imagine will please no one. :)

Allow call site annotations like /*go1.16:inline*/. (Maybe also function-site annotations?) /* annotations are necessary because there may be multiple calls on one line. For versions other than go 1.16, this is a no-op. And the annotation is a no-op unless you pass the compiler flag -l=manual. That compiler flag disables inlining except exactly where annotated. (Or maybe the existence of a single relevant annotation disables all inlining except exactly that requested.) If a requested inlining at a call site is impossible, compilation fails.

This grants complete control to the user who really needs it. It is enough of a pain to discourage casual use. It is scoped to exactly one Go version to avoid accidental rot. It provides raw data about optimal inlining decisions to compiler authors.

@randall77
Copy link
Contributor

Not sure I see the argument here. Im not arguing for function annotation, I explicitly argued for a callsite annotation.

I'm not specifically talking about your suggestion. Just the general idea of inline annotations, both callsite and declaration site.

Why wouldn't be callsite annotations be enough for library functions?

func (t *T) Foo() int {
    return t.x + t.y
}

With callsite annotations every place t.Foo is used needs an annotation. As opposed to just once at the definition. Which will lead to library authors adding "This function will perform better if you add a @inline annotation at each call site" to their docs.

Hence why I specifically argue about an annotation on the callsite and not on the function. I agree library authors sometime feel the pressure you're mentioning, but as I clearly stated manual inlining is happening today for that very reason, and therefore I find it hard to consider this as a very compelling argument against the callsite annotation.

This will happen with both callsite or declaration annotations, just at a slightly different level.

func Foo() {
   internalFoo()
}

If the library containing Foo isn't a hot path in my application, I'd rather not have Foo inlined into its call sites, or have internalFoo inlined into Foo. So an inline annotation at the declaration of Foo and/or one at the callsite of internalFoo are both at least unnecessary and likely code-size harmful (assuming that the bodies were big enough to not be covered by the inlining heuristic we have today).

@mvdan
Copy link
Member

mvdan commented May 30, 2020

Quick observation: right now, the manual inlining generally only happens within a module or even a single package, not crossing module boundaries. Perhaps some form of directive could have a similar restriction, to prevent public APIs from being littered with dubious performance directives. Or perhaps we could even restrict it to unexported functions.

@zeebo
Copy link
Contributor

zeebo commented May 30, 2020

I was seconds away from posting a similar suggestion about only allowing inlining annotations on unexported functions.

That would cover every case I've ever ran into and avoid all of the terrible manual inlining I have done for substantial gains over the literal years.


edit: The main pain with not having control comes from exploratory programming. It is a ton of work to manually inline, find out it's not a great idea, and then undo. Then do that a ton over many refactorings that could change the assumptions. I would personally be happy manually inlining still if it wasn't so painful to discover when it was a good idea for a specific case. So even if the annotations were ignored unless compiled with a special flag, I'd still be happy.

@CAFxX
Copy link
Contributor

CAFxX commented May 31, 2020

I'm not specifically talking about your suggestion. Just the general idea of inline annotations, both callsite and declaration site.

I was just pointing out that the arguments you made don't really apply to callsite annotations as much as they apply to function annotations, though. Conflating the two don't seem to help discussion.

With callsite annotations every place t.Foo is used needs an annotation.

Each place where the caller cares enough to and the inliner doesn't do it automatically, yes. That is pretty much exactly what we want to avoid the copy-paste scenario. Why would that be an argument against callsite annotations? We all agree it would be ideal if the inliner was better so that we didn't have to; the assumption is that it likely won't become so much better that there will be no need for manual control.

As opposed to just once at the definition. Which will lead to library authors adding "This function will perform better if you add a @inline annotation at each call site" to their docs.

That is pretty much what is already happening today, with the difference right now the inlining has to be done manually. Callsite annotations wouldn't make this worse, on the contrary, not only it would avoid having to duplicate code, it would potetntially even avoid having to expose additional APIs (like the one linked above).

This will happen with both callsite or declaration annotations, just at a slightly different level.

My point was that it is already happening today, with the difference that right now people have to manually inline code. That point still applies.

Furthermore, I think we agree it would happen less in the case of callsite annotations.

func Foo() {
   internalFoo()
}

If the library containing Foo isn't a hot path in my application, I'd rather not have Foo inlined into its call sites, or have internalFoo inlined into Foo. So an inline annotation at the declaration of Foo and/or one at the callsite of internalFoo are both at least unnecessary and likely code-size harmful (assuming that the bodies were big enough to not be covered by the inlining heuristic we have today).

This is definitely one valid argument. I kinda already offered a solution for that though ("even though it's pretty much orthogonal to the proposal itself, when the inliner gets better and starts to actually make decisions based on callsites instead of functions, it may actually transitively propagate it as a hint that the specific callpath is expected to be frequently executed").

Regardless, I wouldn't discount a practical solution just because it doesn't cover 100% of the possible use-cases (as by that standard Go itself likely wouldn't exist)

Quick observation: right now, the manual inlining generally only happens within a module or even a single package, not crossing module boundaries. Perhaps some form of directive could have a similar restriction, to prevent public APIs from being littered with dubious performance directives. Or perhaps we could even restrict it to unexported functions.

One note though: I still think there's value in allowing callsite annotations to request cross-module inlining (I gave one example just above, and can probably dig a few others up). Restricing function annotations to unexported symbols OTOH sounds like a pretty reasonable compromise.

And the annotation is a no-op unless you pass the compiler flag -l=manual.

Or maybe, only callsite annotations in the root module (the module that contains the main package) are enabled by default?

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 5, 2020
@mvdan
Copy link
Member

mvdan commented Jun 20, 2020

One note though: I still think there's value in allowing callsite annotations to request cross-module inlining (I gave one example just above, and can probably dig a few others up).

I think the danger there is that people could add notes to their function definition godoc like "for maximum performance, annotate calls with...". We can strongly warn against that kind of thing, but it will happen anyway. That's why I think starting with unexported funcs would give a large part of the benefit at little risk, so it could be the first step for an annotation.

@renthraysk
Copy link

renthraysk commented Jul 12, 2020

Just hit an annoyance with the inliner in past few days, reading and writing individual bits.

Writer.WriteBit() function is inlineable. By making 2 concessions/hacks, x argument an uint64, and reusing x for carry result.

However, ReadBit() which is using a similar strategy, is "function too complex: cost 88 exceeds budget 80"

@elichai
Copy link

elichai commented Aug 11, 2020

I'm having a bunch of problems with bad inlining when implementing hash functions.
I had to manually inline functions, move things from function to another to please the inliner and more, at the end I increased the perf by 200%(which is huge for hashes) just by manually inlining and similar things.

I also can't use the useful:

func memset(s []byte, c byte) {
	for i := range s {
		s[i] = c
	}
}

Because the fact that it doesn't inline range loops, then if I call memset(s, 0) it will call to memset and then loop instead of just calling to runtime.memclrNoHeapPointers which it could've done if it knew that c=0

@martisch
Copy link
Contributor

martisch commented Aug 12, 2020

Because the fact that it doesn't inline range loops, then if I call memset(s, 0) it will call to memset and then loop instead of just calling to runtime.memclrNoHeapPointers which it could've done if it new that c=0

I dont think the existing range clear optimizations will trigger even if the inlining is changed.
Thats something that will not only need inlining but the range clear optimization detection to move into the ssa pass that can represent that c is a constant in the loop.

Better to write that directly for now:

func memclear(s []byte) {
	for i := range s {
		s[i] = 0
	}
}

If inlining is improved it can take care of the call overhead here.

@yuzefovich
Copy link

My colleague wrote a tool that folks following this thread might find useful (it allows for adding comments that are "assertions" on the compiled code for checking whether a function (or a call-site) is inlined). We at cockroachdb began introducing these "assertions" into the codebase and are verifying them during the linter test runs.

@FiloSottile
Copy link
Contributor

I just came out of a fight with the inliner and figured I would report back. I was trying to outline an allocation for a function with multiple return values, and the inliner had a lot of non-obvious opinions.

Here's the version that finally worked, with cost 72.

func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
	var e [4]field.Element
	X, Y, Z, T = v.extendedCoordinates(&e)
	return
}

Both the more idiomatic ways to write this function have costs higher than 84.

Avoiding the named returns costs 84.

func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
	var e [4]field.Element
	return v.extendedCoordinates(&e)
}

Making separate allocations costs 90.

func (v *Point) ExtendedCoordinates() (X, Y, Z, T *field.Element) {
	var X1, Y1, Z1, T1 field.Element
	X, Y, Z, T = v.extendedCoordinates(&X1, &Y1, &Z1, &T1)
	return
}

nimelehin added a commit to nimelehin/go that referenced this issue Sep 6, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise which calls are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode. The forContext contains a liveCounter which shows
for how many nodes this FOR is ancestor.

Current constants are the following:
A "big" FOR is a FOR which contains >=inlineBigForNodes(50) nodes or
has more than inlineBigForCallNodes(5) inlinable call nodes. In such
FORs no boost is applied. Other FORs are considired to be small and
boost callsites with an extra budget equals to inlineExtraForBudget(20).

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.15s ± 1%     ~     (p=0.589 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.70s ± 0%   -0.08%  (p=0.002 n=6+6)
FmtFprintfEmpty-8          31.9ns ± 0%    31.9ns ± 3%     ~     (p=0.907 n=6+6)
FmtFprintfString-8         57.0ns ± 0%    57.6ns ± 0%   +1.19%  (p=0.004 n=5+6)
FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%   -1.57%  (p=0.002 n=6+6)
FmtFprintfIntInt-8          103ns ± 0%     103ns ± 0%     ~     (p=0.079 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.37%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     173ns ± 0%   +2.55%  (p=0.004 n=5+6)
FmtManyArgs-8               450ns ± 1%     450ns ± 0%     ~     (p=1.000 n=6+6)
GobDecode-8                4.38ms ± 1%    4.35ms ± 1%     ~     (p=0.132 n=6+6)
GobEncode-8                3.07ms ± 0%    3.06ms ± 0%   -0.38%  (p=0.009 n=6+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.095 n=5+5)
Gunzip-8                   28.2ms ± 0%    28.4ms ± 0%   +0.57%  (p=0.004 n=6+6)
HTTPClientServer-8         45.1µs ± 1%    45.3µs ± 1%     ~     (p=0.082 n=5+6)
JSONEncode-8               7.98ms ± 1%    7.94ms ± 0%   -0.47%  (p=0.015 n=6+6)
JSONDecode-8               35.4ms ± 1%    35.1ms ± 0%   -1.04%  (p=0.002 n=6+6)
Mandelbrot200-8            4.50ms ± 0%    4.50ms ± 0%     ~     (p=0.699 n=6+6)
GoParse-8                  2.98ms ± 0%    2.99ms ± 1%     ~     (p=0.095 n=5+5)
RegexpMatchEasy0_32-8      55.5ns ± 1%    52.8ns ± 2%   -4.94%  (p=0.002 n=6+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%   -9.18%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.4ns ± 2%   -3.34%  (p=0.002 n=6+6)
RegexpMatchEasy1_1K-8       272ns ± 2%     268ns ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchMedium_32-8      907ns ± 5%     897ns ± 7%     ~     (p=0.660 n=6+6)
RegexpMatchMedium_1K-8     26.5µs ± 0%    26.6µs ± 0%   +0.41%  (p=0.008 n=5+5)
RegexpMatchHard_32-8       1.28µs ± 0%    1.29µs ± 1%     ~     (p=0.167 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.6µs ± 0%     ~     (p=0.126 n=6+5)
Revcomp-8                   398ms ± 0%     395ms ± 0%   -0.64%  (p=0.010 n=6+4)
Template-8                 48.4ms ± 0%    47.8ms ± 0%   -1.30%  (p=0.008 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.108 n=6+6)
TimeFormat-8                294ns ± 0%     259ns ± 0%  -11.86%  (p=0.000 n=5+6)
[Geo mean]                 40.4µs         40.0µs        -1.11%

name                     old speed      new speed      delta
GobDecode-8               175MB/s ± 1%   176MB/s ± 1%     ~     (p=0.132 n=6+6)
GobEncode-8               250MB/s ± 0%   251MB/s ± 0%   +0.38%  (p=0.009 n=6+6)
Gzip-8                   99.3MB/s ± 0%  99.4MB/s ± 0%     ~     (p=0.095 n=5+5)
Gunzip-8                  687MB/s ± 0%   683MB/s ± 0%   -0.57%  (p=0.004 n=6+6)
JSONEncode-8              243MB/s ± 1%   244MB/s ± 0%   +0.47%  (p=0.015 n=6+6)
JSONDecode-8             54.8MB/s ± 1%  55.3MB/s ± 0%   +1.04%  (p=0.002 n=6+6)
GoParse-8                19.4MB/s ± 0%  19.4MB/s ± 1%     ~     (p=0.103 n=5+5)
RegexpMatchEasy0_32-8     576MB/s ± 1%   606MB/s ± 2%   +5.21%  (p=0.002 n=6+6)
RegexpMatchEasy0_1K-8    5.75GB/s ± 0%  6.33GB/s ± 1%  +10.10%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   661MB/s ± 2%   +3.47%  (p=0.002 n=6+6)
RegexpMatchEasy1_1K-8    3.76GB/s ± 2%  3.82GB/s ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchMedium_32-8   35.4MB/s ± 5%  35.7MB/s ± 7%     ~     (p=0.615 n=6+6)
RegexpMatchMedium_1K-8   38.6MB/s ± 0%  38.4MB/s ± 0%   -0.40%  (p=0.008 n=5+5)
RegexpMatchHard_32-8     25.0MB/s ± 0%  24.8MB/s ± 1%     ~     (p=0.167 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%     ~     (p=0.238 n=5+5)
Revcomp-8                 639MB/s ± 0%   643MB/s ± 0%   +0.65%  (p=0.010 n=6+4)
Template-8               40.1MB/s ± 0%  40.6MB/s ± 0%   +1.32%  (p=0.008 n=5+5)
[Geo mean]                176MB/s        178MB/s        +1.38%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 6, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode. The forContext contains a liveCounter which shows
for how many nodes this FOR is ancestor.

Current constants are the following:
A "big" FOR is a FOR which contains >=inlineBigForNodes(50) nodes or
has more than inlineBigForCallNodes(5) inlinable call nodes. In such
FORs no boost is applied. Other FORs are considired to be small and
boost callsites with an extra budget equals to inlineExtraForBudget(20).

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.15s ± 1%     ~     (p=0.589 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.70s ± 0%   -0.08%  (p=0.002 n=6+6)
FmtFprintfEmpty-8          31.9ns ± 0%    31.9ns ± 3%     ~     (p=0.907 n=6+6)
FmtFprintfString-8         57.0ns ± 0%    57.6ns ± 0%   +1.19%  (p=0.004 n=5+6)
FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%   -1.57%  (p=0.002 n=6+6)
FmtFprintfIntInt-8          103ns ± 0%     103ns ± 0%     ~     (p=0.079 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.37%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     173ns ± 0%   +2.55%  (p=0.004 n=5+6)
FmtManyArgs-8               450ns ± 1%     450ns ± 0%     ~     (p=1.000 n=6+6)
GobDecode-8                4.38ms ± 1%    4.35ms ± 1%     ~     (p=0.132 n=6+6)
GobEncode-8                3.07ms ± 0%    3.06ms ± 0%   -0.38%  (p=0.009 n=6+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.095 n=5+5)
Gunzip-8                   28.2ms ± 0%    28.4ms ± 0%   +0.57%  (p=0.004 n=6+6)
HTTPClientServer-8         45.1µs ± 1%    45.3µs ± 1%     ~     (p=0.082 n=5+6)
JSONEncode-8               7.98ms ± 1%    7.94ms ± 0%   -0.47%  (p=0.015 n=6+6)
JSONDecode-8               35.4ms ± 1%    35.1ms ± 0%   -1.04%  (p=0.002 n=6+6)
Mandelbrot200-8            4.50ms ± 0%    4.50ms ± 0%     ~     (p=0.699 n=6+6)
GoParse-8                  2.98ms ± 0%    2.99ms ± 1%     ~     (p=0.095 n=5+5)
RegexpMatchEasy0_32-8      55.5ns ± 1%    52.8ns ± 2%   -4.94%  (p=0.002 n=6+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%   -9.18%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.4ns ± 2%   -3.34%  (p=0.002 n=6+6)
RegexpMatchEasy1_1K-8       272ns ± 2%     268ns ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchMedium_32-8      907ns ± 5%     897ns ± 7%     ~     (p=0.660 n=6+6)
RegexpMatchMedium_1K-8     26.5µs ± 0%    26.6µs ± 0%   +0.41%  (p=0.008 n=5+5)
RegexpMatchHard_32-8       1.28µs ± 0%    1.29µs ± 1%     ~     (p=0.167 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.6µs ± 0%     ~     (p=0.126 n=6+5)
Revcomp-8                   398ms ± 0%     395ms ± 0%   -0.64%  (p=0.010 n=6+4)
Template-8                 48.4ms ± 0%    47.8ms ± 0%   -1.30%  (p=0.008 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.108 n=6+6)
TimeFormat-8                294ns ± 0%     259ns ± 0%  -11.86%  (p=0.000 n=5+6)
[Geo mean]                 40.4µs         40.0µs        -1.11%

name                     old speed      new speed      delta
GobDecode-8               175MB/s ± 1%   176MB/s ± 1%     ~     (p=0.132 n=6+6)
GobEncode-8               250MB/s ± 0%   251MB/s ± 0%   +0.38%  (p=0.009 n=6+6)
Gzip-8                   99.3MB/s ± 0%  99.4MB/s ± 0%     ~     (p=0.095 n=5+5)
Gunzip-8                  687MB/s ± 0%   683MB/s ± 0%   -0.57%  (p=0.004 n=6+6)
JSONEncode-8              243MB/s ± 1%   244MB/s ± 0%   +0.47%  (p=0.015 n=6+6)
JSONDecode-8             54.8MB/s ± 1%  55.3MB/s ± 0%   +1.04%  (p=0.002 n=6+6)
GoParse-8                19.4MB/s ± 0%  19.4MB/s ± 1%     ~     (p=0.103 n=5+5)
RegexpMatchEasy0_32-8     576MB/s ± 1%   606MB/s ± 2%   +5.21%  (p=0.002 n=6+6)
RegexpMatchEasy0_1K-8    5.75GB/s ± 0%  6.33GB/s ± 1%  +10.10%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   661MB/s ± 2%   +3.47%  (p=0.002 n=6+6)
RegexpMatchEasy1_1K-8    3.76GB/s ± 2%  3.82GB/s ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchMedium_32-8   35.4MB/s ± 5%  35.7MB/s ± 7%     ~     (p=0.615 n=6+6)
RegexpMatchMedium_1K-8   38.6MB/s ± 0%  38.4MB/s ± 0%   -0.40%  (p=0.008 n=5+5)
RegexpMatchHard_32-8     25.0MB/s ± 0%  24.8MB/s ± 1%     ~     (p=0.167 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%     ~     (p=0.238 n=5+5)
Revcomp-8                 639MB/s ± 0%   643MB/s ± 0%   +0.65%  (p=0.010 n=6+4)
Template-8               40.1MB/s ± 0%  40.6MB/s ± 0%   +1.32%  (p=0.008 n=5+5)
[Geo mean]                176MB/s        178MB/s        +1.38%
@gopherbot
Copy link
Contributor

Change https://golang.org/cl/347732 mentions this issue: cmd/compile: boost inlining into FORs

nimelehin added a commit to nimelehin/go that referenced this issue Sep 9, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode. The forContext contains a liveCounter which shows
for how many nodes this FOR is ancestor.

Current constants are the following:
A "big" FOR is a FOR which contains >=inlineBigForNodes(37) nodes or
has more than inlineBigForCallNodes(3) inlinable call nodes. In such
FORs no boost is applied. Other FORs are considired to be small and
boost callsites with an extra budget equals to inlineExtraForBudget(13).

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
 BinaryTree17-8              2.15s ± 1%     2.16s ± 1%    ~     (p=0.132 n=6+6)
 Fannkuch11-8                2.70s ± 0%     2.70s ± 0%  +0.12%  (p=0.004 n=6+5)
 FmtFprintfEmpty-8          31.9ns ± 0%    31.3ns ± 0%  -2.05%  (p=0.008 n=5+5)
 FmtFprintfString-8         57.0ns ± 0%    57.7ns ± 1%  +1.30%  (p=0.002 n=6+6)
 FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%  -1.63%  (p=0.008 n=5+5)
 FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%  -1.01%  (p=0.000 n=5+6)
 FmtFprintfPrefixedInt-8     119ns ± 0%     119ns ± 0%  +0.31%  (p=0.026 n=5+6)
 FmtFprintfFloat-8           169ns ± 0%     169ns ± 0%  +0.14%  (p=0.008 n=5+5)
 FmtManyArgs-8               445ns ± 0%     452ns ± 0%  +1.39%  (p=0.004 n=6+5)
 GobDecode-8                4.37ms ± 1%    4.42ms ± 1%  +1.03%  (p=0.002 n=6+6)
 GobEncode-8                3.07ms ± 0%    3.03ms ± 0%  -1.07%  (p=0.004 n=5+6)
 Gzip-8                      195ms ± 0%     195ms ± 0%    ~     (p=0.063 n=5+4)
 Gunzip-8                   28.2ms ± 0%    28.8ms ± 0%  +2.13%  (p=0.004 n=5+6)
 HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%  +0.94%  (p=0.030 n=6+5)
 JSONEncode-8               8.01ms ± 0%    8.00ms ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8               35.3ms ± 1%    35.2ms ± 0%    ~     (p=0.841 n=5+5)
 Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 0%    ~     (p=0.093 n=6+6)
 GoParse-8                  3.03ms ± 1%    2.97ms ± 1%  -1.97%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 1%  -3.89%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%  -8.72%  (p=0.004 n=5+6)
 RegexpMatchEasy1_32-8      50.1ns ± 0%    47.4ns ± 1%  -5.32%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8       271ns ± 1%     261ns ± 0%  -3.67%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8      949ns ± 0%     904ns ± 5%  -4.81%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8     27.1µs ± 7%    27.3µs ± 6%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8       1.28µs ± 2%    1.27µs ± 1%    ~     (p=0.180 n=6+6)
 RegexpMatchHard_1K-8       38.5µs ± 0%    38.5µs ± 0%    ~     (p=0.329 n=6+5)
 Revcomp-8                   397ms ± 0%     396ms ± 0%  -0.33%  (p=0.026 n=6+6)
 Template-8                 48.1ms ± 1%    48.2ms ± 1%    ~     (p=0.222 n=5+5)
 TimeParse-8                 213ns ± 0%     214ns ± 0%    ~     (p=0.076 n=4+6)
 TimeFormat-8                295ns ± 1%     292ns ± 0%  -1.13%  (p=0.000 n=6+5)
 [Geo mean]                 40.5µs         40.1µs       -0.96%

 name                     old speed      new speed      delta
 GobDecode-8               176MB/s ± 1%   174MB/s ± 1%  -1.02%  (p=0.002 n=6+6)
 GobEncode-8               250MB/s ± 0%   253MB/s ± 0%  +1.08%  (p=0.004 n=5+6)
 Gzip-8                    100MB/s ± 0%   100MB/s ± 0%  +0.23%  (p=0.048 n=5+4)
 Gunzip-8                  687MB/s ± 0%   673MB/s ± 0%  -2.08%  (p=0.004 n=5+6)
 JSONEncode-8              242MB/s ± 0%   243MB/s ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8             54.9MB/s ± 1%  55.1MB/s ± 0%    ~     (p=0.873 n=5+5)
 GoParse-8                19.1MB/s ± 1%  19.5MB/s ± 1%  +2.01%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 1%  +4.06%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  6.30GB/s ± 1%  +9.90%  (p=0.002 n=6+6)
 RegexpMatchEasy1_32-8     639MB/s ± 0%   675MB/s ± 1%  +5.63%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.92GB/s ± 0%  +3.81%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8   33.7MB/s ± 0%  35.5MB/s ± 5%  +5.30%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8   37.9MB/s ± 6%  37.6MB/s ± 5%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8     24.9MB/s ± 2%  25.2MB/s ± 1%    ~     (p=0.167 n=6+6)
 RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%    ~     (p=0.355 n=6+5)
 Revcomp-8                 640MB/s ± 0%   642MB/s ± 0%  +0.33%  (p=0.026 n=6+6)
 Template-8               40.4MB/s ± 1%  40.2MB/s ± 1%    ~     (p=0.222 n=5+5)
 [Geo mean]                175MB/s        178MB/s       +1.69%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 9, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode. The forContext contains a liveCounter which shows
for how many nodes this FOR is ancestor.

Current constants are the following:
A "big" FOR is a FOR which contains >=inlineBigForNodes(37) nodes or
has more than inlineBigForCallNodes(3) inlinable call nodes. In such
FORs no boost is applied. Other FORs are considired to be small and
boost callsites with an extra budget equals to inlineExtraForBudget(13).

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
 BinaryTree17-8              2.15s ± 1%     2.16s ± 1%    ~     (p=0.132 n=6+6)
 Fannkuch11-8                2.70s ± 0%     2.70s ± 0%  +0.12%  (p=0.004 n=6+5)
 FmtFprintfEmpty-8          31.9ns ± 0%    31.3ns ± 0%  -2.05%  (p=0.008 n=5+5)
 FmtFprintfString-8         57.0ns ± 0%    57.7ns ± 1%  +1.30%  (p=0.002 n=6+6)
 FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%  -1.63%  (p=0.008 n=5+5)
 FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%  -1.01%  (p=0.000 n=5+6)
 FmtFprintfPrefixedInt-8     119ns ± 0%     119ns ± 0%  +0.31%  (p=0.026 n=5+6)
 FmtFprintfFloat-8           169ns ± 0%     169ns ± 0%  +0.14%  (p=0.008 n=5+5)
 FmtManyArgs-8               445ns ± 0%     452ns ± 0%  +1.39%  (p=0.004 n=6+5)
 GobDecode-8                4.37ms ± 1%    4.42ms ± 1%  +1.03%  (p=0.002 n=6+6)
 GobEncode-8                3.07ms ± 0%    3.03ms ± 0%  -1.07%  (p=0.004 n=5+6)
 Gzip-8                      195ms ± 0%     195ms ± 0%    ~     (p=0.063 n=5+4)
 Gunzip-8                   28.2ms ± 0%    28.8ms ± 0%  +2.13%  (p=0.004 n=5+6)
 HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%  +0.94%  (p=0.030 n=6+5)
 JSONEncode-8               8.01ms ± 0%    8.00ms ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8               35.3ms ± 1%    35.2ms ± 0%    ~     (p=0.841 n=5+5)
 Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 0%    ~     (p=0.093 n=6+6)
 GoParse-8                  3.03ms ± 1%    2.97ms ± 1%  -1.97%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 1%  -3.89%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%  -8.72%  (p=0.004 n=5+6)
 RegexpMatchEasy1_32-8      50.1ns ± 0%    47.4ns ± 1%  -5.32%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8       271ns ± 1%     261ns ± 0%  -3.67%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8      949ns ± 0%     904ns ± 5%  -4.81%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8     27.1µs ± 7%    27.3µs ± 6%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8       1.28µs ± 2%    1.27µs ± 1%    ~     (p=0.180 n=6+6)
 RegexpMatchHard_1K-8       38.5µs ± 0%    38.5µs ± 0%    ~     (p=0.329 n=6+5)
 Revcomp-8                   397ms ± 0%     396ms ± 0%  -0.33%  (p=0.026 n=6+6)
 Template-8                 48.1ms ± 1%    48.2ms ± 1%    ~     (p=0.222 n=5+5)
 TimeParse-8                 213ns ± 0%     214ns ± 0%    ~     (p=0.076 n=4+6)
 TimeFormat-8                295ns ± 1%     292ns ± 0%  -1.13%  (p=0.000 n=6+5)
 [Geo mean]                 40.5µs         40.1µs       -0.96%

 name                     old speed      new speed      delta
 GobDecode-8               176MB/s ± 1%   174MB/s ± 1%  -1.02%  (p=0.002 n=6+6)
 GobEncode-8               250MB/s ± 0%   253MB/s ± 0%  +1.08%  (p=0.004 n=5+6)
 Gzip-8                    100MB/s ± 0%   100MB/s ± 0%  +0.23%  (p=0.048 n=5+4)
 Gunzip-8                  687MB/s ± 0%   673MB/s ± 0%  -2.08%  (p=0.004 n=5+6)
 JSONEncode-8              242MB/s ± 0%   243MB/s ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8             54.9MB/s ± 1%  55.1MB/s ± 0%    ~     (p=0.873 n=5+5)
 GoParse-8                19.1MB/s ± 1%  19.5MB/s ± 1%  +2.01%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 1%  +4.06%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  6.30GB/s ± 1%  +9.90%  (p=0.002 n=6+6)
 RegexpMatchEasy1_32-8     639MB/s ± 0%   675MB/s ± 1%  +5.63%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.92GB/s ± 0%  +3.81%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8   33.7MB/s ± 0%  35.5MB/s ± 5%  +5.30%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8   37.9MB/s ± 6%  37.6MB/s ± 5%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8     24.9MB/s ± 2%  25.2MB/s ± 1%    ~     (p=0.167 n=6+6)
 RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%    ~     (p=0.355 n=6+5)
 Revcomp-8                 640MB/s ± 0%   642MB/s ± 0%  +0.33%  (p=0.026 n=6+6)
 Template-8               40.4MB/s ± 1%  40.2MB/s ± 1%    ~     (p=0.222 n=5+5)
 [Geo mean]                175MB/s        178MB/s       +1.69%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 9, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode. The forContext contains a liveCounter which shows
for how many nodes this FOR is ancestor.

Current constants are the following:
A "big" FOR is a FOR which contains >=inlineBigForNodes(37) nodes or
has more than inlineBigForCallNodes(3) inlinable call nodes. In such
FORs no boost is applied. Other FORs are considired to be small and
boost callsites with an extra budget equals to inlineExtraForBudget(13).

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
 BinaryTree17-8              2.15s ± 1%     2.16s ± 1%    ~     (p=0.132 n=6+6)
 Fannkuch11-8                2.70s ± 0%     2.70s ± 0%  +0.12%  (p=0.004 n=6+5)
 FmtFprintfEmpty-8          31.9ns ± 0%    31.3ns ± 0%  -2.05%  (p=0.008 n=5+5)
 FmtFprintfString-8         57.0ns ± 0%    57.7ns ± 1%  +1.30%  (p=0.002 n=6+6)
 FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%  -1.63%  (p=0.008 n=5+5)
 FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%  -1.01%  (p=0.000 n=5+6)
 FmtFprintfPrefixedInt-8     119ns ± 0%     119ns ± 0%  +0.31%  (p=0.026 n=5+6)
 FmtFprintfFloat-8           169ns ± 0%     169ns ± 0%  +0.14%  (p=0.008 n=5+5)
 FmtManyArgs-8               445ns ± 0%     452ns ± 0%  +1.39%  (p=0.004 n=6+5)
 GobDecode-8                4.37ms ± 1%    4.42ms ± 1%  +1.03%  (p=0.002 n=6+6)
 GobEncode-8                3.07ms ± 0%    3.03ms ± 0%  -1.07%  (p=0.004 n=5+6)
 Gzip-8                      195ms ± 0%     195ms ± 0%    ~     (p=0.063 n=5+4)
 Gunzip-8                   28.2ms ± 0%    28.8ms ± 0%  +2.13%  (p=0.004 n=5+6)
 HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%  +0.94%  (p=0.030 n=6+5)
 JSONEncode-8               8.01ms ± 0%    8.00ms ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8               35.3ms ± 1%    35.2ms ± 0%    ~     (p=0.841 n=5+5)
 Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 0%    ~     (p=0.093 n=6+6)
 GoParse-8                  3.03ms ± 1%    2.97ms ± 1%  -1.97%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 1%  -3.89%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%  -8.72%  (p=0.004 n=5+6)
 RegexpMatchEasy1_32-8      50.1ns ± 0%    47.4ns ± 1%  -5.32%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8       271ns ± 1%     261ns ± 0%  -3.67%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8      949ns ± 0%     904ns ± 5%  -4.81%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8     27.1µs ± 7%    27.3µs ± 6%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8       1.28µs ± 2%    1.27µs ± 1%    ~     (p=0.180 n=6+6)
 RegexpMatchHard_1K-8       38.5µs ± 0%    38.5µs ± 0%    ~     (p=0.329 n=6+5)
 Revcomp-8                   397ms ± 0%     396ms ± 0%  -0.33%  (p=0.026 n=6+6)
 Template-8                 48.1ms ± 1%    48.2ms ± 1%    ~     (p=0.222 n=5+5)
 TimeParse-8                 213ns ± 0%     214ns ± 0%    ~     (p=0.076 n=4+6)
 TimeFormat-8                295ns ± 1%     292ns ± 0%  -1.13%  (p=0.000 n=6+5)
 [Geo mean]                 40.5µs         40.1µs       -0.96%

 name                     old speed      new speed      delta
 GobDecode-8               176MB/s ± 1%   174MB/s ± 1%  -1.02%  (p=0.002 n=6+6)
 GobEncode-8               250MB/s ± 0%   253MB/s ± 0%  +1.08%  (p=0.004 n=5+6)
 Gzip-8                    100MB/s ± 0%   100MB/s ± 0%  +0.23%  (p=0.048 n=5+4)
 Gunzip-8                  687MB/s ± 0%   673MB/s ± 0%  -2.08%  (p=0.004 n=5+6)
 JSONEncode-8              242MB/s ± 0%   243MB/s ± 1%    ~     (p=0.429 n=5+6)
 JSONDecode-8             54.9MB/s ± 1%  55.1MB/s ± 0%    ~     (p=0.873 n=5+5)
 GoParse-8                19.1MB/s ± 1%  19.5MB/s ± 1%  +2.01%  (p=0.004 n=6+5)
 RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 1%  +4.06%  (p=0.008 n=5+5)
 RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  6.30GB/s ± 1%  +9.90%  (p=0.002 n=6+6)
 RegexpMatchEasy1_32-8     639MB/s ± 0%   675MB/s ± 1%  +5.63%  (p=0.008 n=5+5)
 RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.92GB/s ± 0%  +3.81%  (p=0.002 n=6+6)
 RegexpMatchMedium_32-8   33.7MB/s ± 0%  35.5MB/s ± 5%  +5.30%  (p=0.004 n=5+6)
 RegexpMatchMedium_1K-8   37.9MB/s ± 6%  37.6MB/s ± 5%    ~     (p=0.818 n=6+6)
 RegexpMatchHard_32-8     24.9MB/s ± 2%  25.2MB/s ± 1%    ~     (p=0.167 n=6+6)
 RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%    ~     (p=0.355 n=6+5)
 Revcomp-8                 640MB/s ± 0%   642MB/s ± 0%  +0.33%  (p=0.026 n=6+6)
 Template-8               40.4MB/s ± 1%  40.2MB/s ± 1%    ~     (p=0.222 n=5+5)
 [Geo mean]                175MB/s        178MB/s       +1.69%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 10, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(47). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%   +0.86%  (p=0.041 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.72s ± 0%   +0.71%  (p=0.002 n=6+6)
FmtFprintfEmpty-8          31.9ns ± 0%    31.6ns ± 0%   -1.06%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    58.3ns ± 0%   +2.26%  (p=0.004 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%   -1.65%  (p=0.000 n=5+4)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -0.91%  (p=0.000 n=5+6)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.60%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     171ns ± 0%   +1.50%  (p=0.004 n=5+6)
FmtManyArgs-8               445ns ± 0%     445ns ± 0%     ~     (p=0.506 n=6+5)
GobDecode-8                4.37ms ± 1%    4.41ms ± 0%   +0.79%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.05ms ± 0%   -0.42%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     194ms ± 0%   -0.40%  (p=0.009 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.9ms ± 0%   +2.22%  (p=0.004 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 0%   +0.97%  (p=0.030 n=6+5)
JSONEncode-8               8.01ms ± 0%    7.95ms ± 0%   -0.78%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.0ms ± 0%   -1.04%  (p=0.004 n=5+6)
Mandelbrot200-8            4.50ms ± 0%    4.50ms ± 0%     ~     (p=0.662 n=6+5)
GoParse-8                  3.03ms ± 1%    2.96ms ± 0%   -2.41%  (p=0.004 n=6+5)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.8ns ± 0%   -2.83%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%   -8.76%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    49.6ns ± 0%   -0.92%  (p=0.004 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     268ns ± 0%   -1.15%  (p=0.002 n=6+6)
RegexpMatchMedium_32-8      949ns ± 0%     862ns ± 0%   -9.20%  (p=0.008 n=5+5)
RegexpMatchMedium_1K-8     27.1µs ± 7%    27.4µs ± 7%     ~     (p=0.589 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.27µs ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.5µs ± 0%     ~     (p=0.132 n=6+6)
Revcomp-8                   397ms ± 0%     397ms ± 0%     ~     (p=1.000 n=6+6)
Template-8                 48.1ms ± 1%    47.8ms ± 0%   -0.48%  (p=0.016 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.467 n=4+6)
TimeFormat-8                295ns ± 1%     294ns ± 0%     ~     (p=0.554 n=6+5)
[Geo mean]                 40.5µs         40.2µs        -0.81%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.79%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   251MB/s ± 0%   +0.42%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%   +0.40%  (p=0.009 n=5+6)
Gunzip-8                  687MB/s ± 0%   672MB/s ± 0%   -2.17%  (p=0.004 n=5+6)
JSONEncode-8              242MB/s ± 0%   244MB/s ± 0%   +0.78%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.5MB/s ± 0%   +1.05%  (p=0.004 n=5+6)
GoParse-8                19.1MB/s ± 1%  19.6MB/s ± 0%   +2.48%  (p=0.004 n=6+5)
RegexpMatchEasy0_32-8     578MB/s ± 0%   594MB/s ± 0%   +2.89%  (p=0.008 n=5+5)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  6.31GB/s ± 1%   +9.95%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   645MB/s ± 0%   +0.93%  (p=0.004 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.82GB/s ± 0%   +1.15%  (p=0.002 n=6+6)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  37.1MB/s ± 0%  +10.15%  (p=0.008 n=5+5)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  37.5MB/s ± 7%     ~     (p=0.697 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  25.1MB/s ± 1%     ~     (p=0.058 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%     ~     (p=0.195 n=6+6)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=1.000 n=6+6)
Template-8               40.4MB/s ± 1%  40.6MB/s ± 0%   +0.47%  (p=0.016 n=5+5)
[Geo mean]                175MB/s        178MB/s        +1.56%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 10, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(47). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10441232 -> 10465920, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%   +0.86%  (p=0.041 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.72s ± 0%   +0.71%  (p=0.002 n=6+6)
FmtFprintfEmpty-8          31.9ns ± 0%    31.6ns ± 0%   -1.06%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    58.3ns ± 0%   +2.26%  (p=0.004 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    64.1ns ± 0%   -1.65%  (p=0.000 n=5+4)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -0.91%  (p=0.000 n=5+6)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.60%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     171ns ± 0%   +1.50%  (p=0.004 n=5+6)
FmtManyArgs-8               445ns ± 0%     445ns ± 0%     ~     (p=0.506 n=6+5)
GobDecode-8                4.37ms ± 1%    4.41ms ± 0%   +0.79%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.05ms ± 0%   -0.42%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     194ms ± 0%   -0.40%  (p=0.009 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.9ms ± 0%   +2.22%  (p=0.004 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 0%   +0.97%  (p=0.030 n=6+5)
JSONEncode-8               8.01ms ± 0%    7.95ms ± 0%   -0.78%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.0ms ± 0%   -1.04%  (p=0.004 n=5+6)
Mandelbrot200-8            4.50ms ± 0%    4.50ms ± 0%     ~     (p=0.662 n=6+5)
GoParse-8                  3.03ms ± 1%    2.96ms ± 0%   -2.41%  (p=0.004 n=6+5)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.8ns ± 0%   -2.83%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     162ns ± 1%   -8.76%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    49.6ns ± 0%   -0.92%  (p=0.004 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     268ns ± 0%   -1.15%  (p=0.002 n=6+6)
RegexpMatchMedium_32-8      949ns ± 0%     862ns ± 0%   -9.20%  (p=0.008 n=5+5)
RegexpMatchMedium_1K-8     27.1µs ± 7%    27.4µs ± 7%     ~     (p=0.589 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.27µs ± 1%     ~     (p=0.065 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.5µs ± 0%     ~     (p=0.132 n=6+6)
Revcomp-8                   397ms ± 0%     397ms ± 0%     ~     (p=1.000 n=6+6)
Template-8                 48.1ms ± 1%    47.8ms ± 0%   -0.48%  (p=0.016 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.467 n=4+6)
TimeFormat-8                295ns ± 1%     294ns ± 0%     ~     (p=0.554 n=6+5)
[Geo mean]                 40.5µs         40.2µs        -0.81%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.79%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   251MB/s ± 0%   +0.42%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%   +0.40%  (p=0.009 n=5+6)
Gunzip-8                  687MB/s ± 0%   672MB/s ± 0%   -2.17%  (p=0.004 n=5+6)
JSONEncode-8              242MB/s ± 0%   244MB/s ± 0%   +0.78%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.5MB/s ± 0%   +1.05%  (p=0.004 n=5+6)
GoParse-8                19.1MB/s ± 1%  19.6MB/s ± 0%   +2.48%  (p=0.004 n=6+5)
RegexpMatchEasy0_32-8     578MB/s ± 0%   594MB/s ± 0%   +2.89%  (p=0.008 n=5+5)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  6.31GB/s ± 1%   +9.95%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   645MB/s ± 0%   +0.93%  (p=0.004 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.82GB/s ± 0%   +1.15%  (p=0.002 n=6+6)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  37.1MB/s ± 0%  +10.15%  (p=0.008 n=5+5)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  37.5MB/s ± 7%     ~     (p=0.697 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  25.1MB/s ± 1%     ~     (p=0.058 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.6MB/s ± 0%     ~     (p=0.195 n=6+6)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=1.000 n=6+6)
Template-8               40.4MB/s ± 1%  40.6MB/s ± 0%   +0.47%  (p=0.016 n=5+5)
[Geo mean]                175MB/s        178MB/s        +1.56%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 23, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(105). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10454800 -> 10475120, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%     ~     (p=0.065 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.69s ± 0%   -0.25%  (p=0.010 n=6+4)
FmtFprintfEmpty-8          31.9ns ± 0%    31.4ns ± 0%   -1.61%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    57.1ns ± 0%   +0.26%  (p=0.013 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    63.9ns ± 0%   -1.95%  (p=0.008 n=5+5)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -1.01%  (p=0.000 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.50%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     174ns ± 0%   +2.75%  (p=0.008 n=5+5)
FmtManyArgs-8               445ns ± 0%     447ns ± 0%   +0.46%  (p=0.002 n=6+6)
GobDecode-8                4.37ms ± 1%    4.40ms ± 0%   +0.62%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.04ms ± 0%   -0.78%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.429 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.2ms ± 0%     ~     (p=0.662 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%     ~     (p=0.093 n=6+6)
JSONEncode-8               8.01ms ± 0%    8.03ms ± 0%   +0.31%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.1ms ± 0%   -0.72%  (p=0.008 n=5+5)
Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 1%     ~     (p=0.937 n=6+6)
GoParse-8                  3.03ms ± 1%    3.00ms ± 1%     ~     (p=0.180 n=6+6)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 3%   -3.92%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     175ns ± 1%   -1.57%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.3ns ± 5%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     262ns ± 1%   -3.26%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8      949ns ± 0%     886ns ± 7%     ~     (p=0.329 n=5+6)
RegexpMatchMedium_1K-8     27.1µs ± 7%    28.1µs ± 6%     ~     (p=0.394 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.29µs ± 0%     ~     (p=0.056 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.4µs ± 0%   -0.25%  (p=0.009 n=6+5)
Revcomp-8                   397ms ± 0%     396ms ± 0%     ~     (p=0.429 n=6+5)
Template-8                 48.1ms ± 1%    48.1ms ± 0%     ~     (p=0.222 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.210 n=4+6)
TimeFormat-8                295ns ± 1%     259ns ± 0%  -12.22%  (p=0.002 n=6+6)
[Geo mean]                 40.5µs         40.1µs        -1.00%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.61%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   252MB/s ± 0%   +0.79%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%     ~     (p=0.351 n=5+6)
Gunzip-8                  687MB/s ± 0%   687MB/s ± 0%     ~     (p=0.662 n=5+6)
JSONEncode-8              242MB/s ± 0%   242MB/s ± 0%   -0.31%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.3MB/s ± 0%   +0.71%  (p=0.008 n=5+5)
GoParse-8                19.1MB/s ± 1%  19.3MB/s ± 1%     ~     (p=0.143 n=6+6)
RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 3%   +4.10%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  5.85GB/s ± 1%   +1.90%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   663MB/s ± 4%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.91GB/s ± 1%   +3.38%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  36.2MB/s ± 7%     ~     (p=0.268 n=5+6)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  36.5MB/s ± 6%     ~     (p=0.411 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  24.8MB/s ± 0%     ~     (p=0.063 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.7MB/s ± 0%   +0.25%  (p=0.009 n=6+5)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=0.429 n=6+5)
Template-8               40.4MB/s ± 1%  40.3MB/s ± 0%     ~     (p=0.222 n=5+5)
[Geo mean]                175MB/s        177MB/s        +1.05%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 23, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(105). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10454800 -> 10475120, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%     ~     (p=0.065 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.69s ± 0%   -0.25%  (p=0.010 n=6+4)
FmtFprintfEmpty-8          31.9ns ± 0%    31.4ns ± 0%   -1.61%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    57.1ns ± 0%   +0.26%  (p=0.013 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    63.9ns ± 0%   -1.95%  (p=0.008 n=5+5)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -1.01%  (p=0.000 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.50%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     174ns ± 0%   +2.75%  (p=0.008 n=5+5)
FmtManyArgs-8               445ns ± 0%     447ns ± 0%   +0.46%  (p=0.002 n=6+6)
GobDecode-8                4.37ms ± 1%    4.40ms ± 0%   +0.62%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.04ms ± 0%   -0.78%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.429 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.2ms ± 0%     ~     (p=0.662 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%     ~     (p=0.093 n=6+6)
JSONEncode-8               8.01ms ± 0%    8.03ms ± 0%   +0.31%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.1ms ± 0%   -0.72%  (p=0.008 n=5+5)
Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 1%     ~     (p=0.937 n=6+6)
GoParse-8                  3.03ms ± 1%    3.00ms ± 1%     ~     (p=0.180 n=6+6)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 3%   -3.92%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     175ns ± 1%   -1.57%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.3ns ± 5%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     262ns ± 1%   -3.26%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8      949ns ± 0%     886ns ± 7%     ~     (p=0.329 n=5+6)
RegexpMatchMedium_1K-8     27.1µs ± 7%    28.1µs ± 6%     ~     (p=0.394 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.29µs ± 0%     ~     (p=0.056 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.4µs ± 0%   -0.25%  (p=0.009 n=6+5)
Revcomp-8                   397ms ± 0%     396ms ± 0%     ~     (p=0.429 n=6+5)
Template-8                 48.1ms ± 1%    48.1ms ± 0%     ~     (p=0.222 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.210 n=4+6)
TimeFormat-8                295ns ± 1%     259ns ± 0%  -12.22%  (p=0.002 n=6+6)
[Geo mean]                 40.5µs         40.1µs        -1.00%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.61%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   252MB/s ± 0%   +0.79%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%     ~     (p=0.351 n=5+6)
Gunzip-8                  687MB/s ± 0%   687MB/s ± 0%     ~     (p=0.662 n=5+6)
JSONEncode-8              242MB/s ± 0%   242MB/s ± 0%   -0.31%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.3MB/s ± 0%   +0.71%  (p=0.008 n=5+5)
GoParse-8                19.1MB/s ± 1%  19.3MB/s ± 1%     ~     (p=0.143 n=6+6)
RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 3%   +4.10%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  5.85GB/s ± 1%   +1.90%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   663MB/s ± 4%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.91GB/s ± 1%   +3.38%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  36.2MB/s ± 7%     ~     (p=0.268 n=5+6)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  36.5MB/s ± 6%     ~     (p=0.411 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  24.8MB/s ± 0%     ~     (p=0.063 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.7MB/s ± 0%   +0.25%  (p=0.009 n=6+5)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=0.429 n=6+5)
Template-8               40.4MB/s ± 1%  40.3MB/s ± 0%     ~     (p=0.222 n=5+5)
[Geo mean]                175MB/s        177MB/s        +1.05%
nimelehin added a commit to nimelehin/go that referenced this issue Sep 23, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(105). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10454800 -> 10475120, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%     ~     (p=0.065 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.69s ± 0%   -0.25%  (p=0.010 n=6+4)
FmtFprintfEmpty-8          31.9ns ± 0%    31.4ns ± 0%   -1.61%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    57.1ns ± 0%   +0.26%  (p=0.013 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    63.9ns ± 0%   -1.95%  (p=0.008 n=5+5)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -1.01%  (p=0.000 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.50%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     174ns ± 0%   +2.75%  (p=0.008 n=5+5)
FmtManyArgs-8               445ns ± 0%     447ns ± 0%   +0.46%  (p=0.002 n=6+6)
GobDecode-8                4.37ms ± 1%    4.40ms ± 0%   +0.62%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.04ms ± 0%   -0.78%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.429 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.2ms ± 0%     ~     (p=0.662 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%     ~     (p=0.093 n=6+6)
JSONEncode-8               8.01ms ± 0%    8.03ms ± 0%   +0.31%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.1ms ± 0%   -0.72%  (p=0.008 n=5+5)
Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 1%     ~     (p=0.937 n=6+6)
GoParse-8                  3.03ms ± 1%    3.00ms ± 1%     ~     (p=0.180 n=6+6)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 3%   -3.92%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     175ns ± 1%   -1.57%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.3ns ± 5%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     262ns ± 1%   -3.26%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8      949ns ± 0%     886ns ± 7%     ~     (p=0.329 n=5+6)
RegexpMatchMedium_1K-8     27.1µs ± 7%    28.1µs ± 6%     ~     (p=0.394 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.29µs ± 0%     ~     (p=0.056 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.4µs ± 0%   -0.25%  (p=0.009 n=6+5)
Revcomp-8                   397ms ± 0%     396ms ± 0%     ~     (p=0.429 n=6+5)
Template-8                 48.1ms ± 1%    48.1ms ± 0%     ~     (p=0.222 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.210 n=4+6)
TimeFormat-8                295ns ± 1%     259ns ± 0%  -12.22%  (p=0.002 n=6+6)
[Geo mean]                 40.5µs         40.1µs        -1.00%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.61%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   252MB/s ± 0%   +0.79%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%     ~     (p=0.351 n=5+6)
Gunzip-8                  687MB/s ± 0%   687MB/s ± 0%     ~     (p=0.662 n=5+6)
JSONEncode-8              242MB/s ± 0%   242MB/s ± 0%   -0.31%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.3MB/s ± 0%   +0.71%  (p=0.008 n=5+5)
GoParse-8                19.1MB/s ± 1%  19.3MB/s ± 1%     ~     (p=0.143 n=6+6)
RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 3%   +4.10%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  5.85GB/s ± 1%   +1.90%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   663MB/s ± 4%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.91GB/s ± 1%   +3.38%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  36.2MB/s ± 7%     ~     (p=0.268 n=5+6)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  36.5MB/s ± 6%     ~     (p=0.411 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  24.8MB/s ± 0%     ~     (p=0.063 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.7MB/s ± 0%   +0.25%  (p=0.009 n=6+5)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=0.429 n=6+5)
Template-8               40.4MB/s ± 1%  40.3MB/s ± 0%     ~     (p=0.222 n=5+5)
[Geo mean]                175MB/s        177MB/s        +1.05%
nimelehin added a commit to nimelehin/go that referenced this issue Oct 6, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(105). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10454800 -> 10475120, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%     ~     (p=0.065 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.69s ± 0%   -0.25%  (p=0.010 n=6+4)
FmtFprintfEmpty-8          31.9ns ± 0%    31.4ns ± 0%   -1.61%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    57.1ns ± 0%   +0.26%  (p=0.013 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    63.9ns ± 0%   -1.95%  (p=0.008 n=5+5)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -1.01%  (p=0.000 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.50%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     174ns ± 0%   +2.75%  (p=0.008 n=5+5)
FmtManyArgs-8               445ns ± 0%     447ns ± 0%   +0.46%  (p=0.002 n=6+6)
GobDecode-8                4.37ms ± 1%    4.40ms ± 0%   +0.62%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.04ms ± 0%   -0.78%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.429 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.2ms ± 0%     ~     (p=0.662 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%     ~     (p=0.093 n=6+6)
JSONEncode-8               8.01ms ± 0%    8.03ms ± 0%   +0.31%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.1ms ± 0%   -0.72%  (p=0.008 n=5+5)
Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 1%     ~     (p=0.937 n=6+6)
GoParse-8                  3.03ms ± 1%    3.00ms ± 1%     ~     (p=0.180 n=6+6)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 3%   -3.92%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     175ns ± 1%   -1.57%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.3ns ± 5%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     262ns ± 1%   -3.26%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8      949ns ± 0%     886ns ± 7%     ~     (p=0.329 n=5+6)
RegexpMatchMedium_1K-8     27.1µs ± 7%    28.1µs ± 6%     ~     (p=0.394 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.29µs ± 0%     ~     (p=0.056 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.4µs ± 0%   -0.25%  (p=0.009 n=6+5)
Revcomp-8                   397ms ± 0%     396ms ± 0%     ~     (p=0.429 n=6+5)
Template-8                 48.1ms ± 1%    48.1ms ± 0%     ~     (p=0.222 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.210 n=4+6)
TimeFormat-8                295ns ± 1%     259ns ± 0%  -12.22%  (p=0.002 n=6+6)
[Geo mean]                 40.5µs         40.1µs        -1.00%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.61%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   252MB/s ± 0%   +0.79%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%     ~     (p=0.351 n=5+6)
Gunzip-8                  687MB/s ± 0%   687MB/s ± 0%     ~     (p=0.662 n=5+6)
JSONEncode-8              242MB/s ± 0%   242MB/s ± 0%   -0.31%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.3MB/s ± 0%   +0.71%  (p=0.008 n=5+5)
GoParse-8                19.1MB/s ± 1%  19.3MB/s ± 1%     ~     (p=0.143 n=6+6)
RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 3%   +4.10%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  5.85GB/s ± 1%   +1.90%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   663MB/s ± 4%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.91GB/s ± 1%   +3.38%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  36.2MB/s ± 7%     ~     (p=0.268 n=5+6)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  36.5MB/s ± 6%     ~     (p=0.411 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  24.8MB/s ± 0%     ~     (p=0.063 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.7MB/s ± 0%   +0.25%  (p=0.009 n=6+5)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=0.429 n=6+5)
Template-8               40.4MB/s ± 1%  40.3MB/s ± 0%     ~     (p=0.222 n=5+5)
[Geo mean]                175MB/s        177MB/s        +1.05%
nimelehin added a commit to nimelehin/go that referenced this issue Oct 19, 2021
As already Than McIntosh mentioned it's a common practise to boost
inlining to FORs, since the callsite could be "hotter". This patch
implements this functionality.

The implementation uses a stack of FORs to recognise calls which are
in a loop. The stack is maintained alongside inlnode function works
and contains information about ancenstor FORs relative to a current
node in inlnode.

There is "big" FOR which cost is >= inlineBigForCost(105). In such FORs
no boost is applied.

Updates golang#17566

The following results on GO1, while binary size not increased significantly
10454800 -> 10475120, which is less than 0.3%.

goos: linux
goarch: amd64
pkg: test/bench/go1
cpu: Intel(R) Xeon(R) Gold 6230N CPU @ 2.30GHz
name                     old time/op    new time/op    delta
BinaryTree17-8              2.15s ± 1%     2.17s ± 1%     ~     (p=0.065 n=6+6)
Fannkuch11-8                2.70s ± 0%     2.69s ± 0%   -0.25%  (p=0.010 n=6+4)
FmtFprintfEmpty-8          31.9ns ± 0%    31.4ns ± 0%   -1.61%  (p=0.008 n=5+5)
FmtFprintfString-8         57.0ns ± 0%    57.1ns ± 0%   +0.26%  (p=0.013 n=6+5)
FmtFprintfInt-8            65.2ns ± 0%    63.9ns ± 0%   -1.95%  (p=0.008 n=5+5)
FmtFprintfIntInt-8          103ns ± 0%     102ns ± 0%   -1.01%  (p=0.000 n=5+4)
FmtFprintfPrefixedInt-8     119ns ± 0%     118ns ± 0%   -0.50%  (p=0.008 n=5+5)
FmtFprintfFloat-8           169ns ± 0%     174ns ± 0%   +2.75%  (p=0.008 n=5+5)
FmtManyArgs-8               445ns ± 0%     447ns ± 0%   +0.46%  (p=0.002 n=6+6)
GobDecode-8                4.37ms ± 1%    4.40ms ± 0%   +0.62%  (p=0.009 n=6+6)
GobEncode-8                3.07ms ± 0%    3.04ms ± 0%   -0.78%  (p=0.004 n=5+6)
Gzip-8                      195ms ± 0%     195ms ± 0%     ~     (p=0.429 n=5+6)
Gunzip-8                   28.2ms ± 0%    28.2ms ± 0%     ~     (p=0.662 n=5+6)
HTTPClientServer-8         45.0µs ± 1%    45.4µs ± 1%     ~     (p=0.093 n=6+6)
JSONEncode-8               8.01ms ± 0%    8.03ms ± 0%   +0.31%  (p=0.008 n=5+5)
JSONDecode-8               35.3ms ± 1%    35.1ms ± 0%   -0.72%  (p=0.008 n=5+5)
Mandelbrot200-8            4.50ms ± 0%    4.49ms ± 1%     ~     (p=0.937 n=6+6)
GoParse-8                  3.03ms ± 1%    3.00ms ± 1%     ~     (p=0.180 n=6+6)
RegexpMatchEasy0_32-8      55.4ns ± 0%    53.2ns ± 3%   -3.92%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8       178ns ± 0%     175ns ± 1%   -1.57%  (p=0.004 n=5+6)
RegexpMatchEasy1_32-8      50.1ns ± 0%    48.3ns ± 5%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8       271ns ± 1%     262ns ± 1%   -3.26%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8      949ns ± 0%     886ns ± 7%     ~     (p=0.329 n=5+6)
RegexpMatchMedium_1K-8     27.1µs ± 7%    28.1µs ± 6%     ~     (p=0.394 n=6+6)
RegexpMatchHard_32-8       1.28µs ± 2%    1.29µs ± 0%     ~     (p=0.056 n=6+6)
RegexpMatchHard_1K-8       38.5µs ± 0%    38.4µs ± 0%   -0.25%  (p=0.009 n=6+5)
Revcomp-8                   397ms ± 0%     396ms ± 0%     ~     (p=0.429 n=6+5)
Template-8                 48.1ms ± 1%    48.1ms ± 0%     ~     (p=0.222 n=5+5)
TimeParse-8                 213ns ± 0%     213ns ± 0%     ~     (p=0.210 n=4+6)
TimeFormat-8                295ns ± 1%     259ns ± 0%  -12.22%  (p=0.002 n=6+6)
[Geo mean]                 40.5µs         40.1µs        -1.00%

name                     old speed      new speed      delta
GobDecode-8               176MB/s ± 1%   174MB/s ± 0%   -0.61%  (p=0.009 n=6+6)
GobEncode-8               250MB/s ± 0%   252MB/s ± 0%   +0.79%  (p=0.004 n=5+6)
Gzip-8                    100MB/s ± 0%   100MB/s ± 0%     ~     (p=0.351 n=5+6)
Gunzip-8                  687MB/s ± 0%   687MB/s ± 0%     ~     (p=0.662 n=5+6)
JSONEncode-8              242MB/s ± 0%   242MB/s ± 0%   -0.31%  (p=0.008 n=5+5)
JSONDecode-8             54.9MB/s ± 1%  55.3MB/s ± 0%   +0.71%  (p=0.008 n=5+5)
GoParse-8                19.1MB/s ± 1%  19.3MB/s ± 1%     ~     (p=0.143 n=6+6)
RegexpMatchEasy0_32-8     578MB/s ± 0%   601MB/s ± 3%   +4.10%  (p=0.004 n=5+6)
RegexpMatchEasy0_1K-8    5.74GB/s ± 1%  5.85GB/s ± 1%   +1.90%  (p=0.002 n=6+6)
RegexpMatchEasy1_32-8     639MB/s ± 0%   663MB/s ± 4%     ~     (p=0.082 n=5+6)
RegexpMatchEasy1_1K-8    3.78GB/s ± 1%  3.91GB/s ± 1%   +3.38%  (p=0.004 n=6+5)
RegexpMatchMedium_32-8   33.7MB/s ± 0%  36.2MB/s ± 7%     ~     (p=0.268 n=5+6)
RegexpMatchMedium_1K-8   37.9MB/s ± 6%  36.5MB/s ± 6%     ~     (p=0.411 n=6+6)
RegexpMatchHard_32-8     24.9MB/s ± 2%  24.8MB/s ± 0%     ~     (p=0.063 n=6+6)
RegexpMatchHard_1K-8     26.6MB/s ± 0%  26.7MB/s ± 0%   +0.25%  (p=0.009 n=6+5)
Revcomp-8                 640MB/s ± 0%   641MB/s ± 0%     ~     (p=0.429 n=6+5)
Template-8               40.4MB/s ± 1%  40.3MB/s ± 0%     ~     (p=0.222 n=5+5)
[Geo mean]                175MB/s        177MB/s        +1.05%
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance ToolSpeed
Projects
None yet
Development

No branches or pull requests