Skip to content

Conversation

@timcassell
Copy link
Collaborator

@timcassell timcassell commented Apr 15, 2024

This doesn't fix the zero-alloc measurement, but it does fix a bug from the threading diagnoser interfering with the results. The other changes give us the highest confidence that any errant measurements are not our fault. The rest is up to the runtime.

Fixes #1542

@timcassell
Copy link
Collaborator Author

It looks like I may have resolved the zero-alloc issue!

New results (using the same benchmark from #1543):

Method Runtime Allocated
Benchmark1 .NET 6.0 2 B
Benchmark2 .NET 6.0 2 B
Benchmark3 .NET 6.0 2 B
Benchmark4 .NET 6.0 2 B
Benchmark5 .NET 6.0 2 B
Benchmark1 .NET 7.0 -
Benchmark2 .NET 7.0 -
Benchmark3 .NET 7.0 -
Benchmark4 .NET 7.0 -
Benchmark5 .NET 7.0 -
Benchmark1 .NET 8.0 -
Benchmark2 .NET 8.0 -
Benchmark3 .NET 8.0 -
Benchmark4 .NET 8.0 -
Benchmark5 .NET 8.0 -

The resolution ended up being moving the GcStats measurement to its own method, and removing GC.Collect() from the allocation measurement. Doing only 1 of those still wasn't getting the expected results.

I was unable to repro the issue in a plain console application, so I'm not sure why GC.Collect() interferes with the results (I would have reported a bug in the runtime repo if I could).

PTAL @adamsitnik

@timcassell timcassell changed the title Try to stabilize memory diagnoser Fix memory diagnoser Apr 15, 2024
@timcassell timcassell force-pushed the stabilize-memorydiagnoser branch from 3518d50 to ce134ab Compare April 22, 2024 23:56
@timcassell
Copy link
Collaborator Author

I added the thread sleep from #1543 in Core runtimes 3.0 to 6.0, and now I'm getting 0 measurements across the board:

Method Runtime Allocated
Benchmark1 .NET 6.0 -
Benchmark2 .NET 6.0 -
Benchmark3 .NET 6.0 -
Benchmark4 .NET 6.0 -
Benchmark5 .NET 6.0 -
Benchmark1 .NET 7.0 -
Benchmark2 .NET 7.0 -
Benchmark3 .NET 7.0 -
Benchmark4 .NET 7.0 -
Benchmark5 .NET 7.0 -
Benchmark1 .NET 8.0 -
Benchmark2 .NET 8.0 -
Benchmark3 .NET 8.0 -
Benchmark4 .NET 8.0 -
Benchmark5 .NET 8.0 -
Benchmark1 .NET Core 2.1 -
Benchmark2 .NET Core 2.1 -
Benchmark3 .NET Core 2.1 -
Benchmark4 .NET Core 2.1 -
Benchmark5 .NET Core 2.1 -
Benchmark1 .NET Core 3.0 -
Benchmark2 .NET Core 3.0 -
Benchmark3 .NET Core 3.0 -
Benchmark4 .NET Core 3.0 -
Benchmark5 .NET Core 3.0 -

@timcassell timcassell force-pushed the stabilize-memorydiagnoser branch 3 times, most recently from 0624a8c to 917988c Compare April 23, 2024 00:53
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big thanks for working on improving the accuracy of the memory diagnoser @timcassell !

Let's wait for the response from @Maoni0.

@timcassell timcassell force-pushed the stabilize-memorydiagnoser branch from c192cb5 to 07d4c4c Compare April 24, 2024 00:56
@timcassell

This comment was marked as outdated.

@timcassell

This comment was marked as outdated.

@timcassell
Copy link
Collaborator Author

Update: I found the culprit and opened an issue in dotnet/runtime. dotnet/runtime#101536

@timcassell
Copy link
Collaborator Author

I disabled the flaky tests and left a todo to re-enable them when that issue is fixed.

This is as accurate as we can make the memory diagnoser from our side. I think this should be good to merge now, unless you have any further feedback @adamsitnik.

@timcassell timcassell force-pushed the stabilize-memorydiagnoser branch 2 times, most recently from 060ce34 to 63b62a9 Compare April 25, 2024 16:06
@timcassell
Copy link
Collaborator Author

Ok, I re-enabled the tests and added a finalizer thread blocker to make the tests less flaky (nice idea @jkotas). This does not have any effect on real world measurements, though.

@timcassell timcassell force-pushed the stabilize-memorydiagnoser branch from 2548395 to f6a4194 Compare April 28, 2024 00:31
@timcassell
Copy link
Collaborator Author

Wow, even with tiered jit disabled and finalizer thread blocked, the CI is still flaky.

2024-04-28T00:50:55.0136465Z   Failed AllocationQuantumIsNotAnIssueForNetCore21Plus(toolchain: .NET 8.0) [9 s]
2024-04-28T00:50:55.0137358Z   Error Message:
2024-04-28T00:50:55.0137773Z    Assert.Equal() Failure: Values differ
2024-04-28T00:50:55.0138293Z Expected: 88
2024-04-28T00:50:55.0138634Z Actual:   176

I don't know what causes that behavior, but I just moved the MemoryDiagnoserTests to ManualRunning to stabilize the CI.

@jkotas
Copy link
Member

jkotas commented Apr 28, 2024

Wow, even with tiered jit disabled and finalizer thread blocked, the CI is still flaky.

My guess is that the next problem are the event source background threads.

@timcassell
Copy link
Collaborator Author

My guess is that the next problem are the event source background threads.

Can you provide more details? I couldn't find information about it from google.

@jkotas
Copy link
Member

jkotas commented Apr 28, 2024

EventSource and EventPipe create background threads that may allocate. These background threads should be only doing work if there is something listening to the events. It turns out that there is pretty much always something listening to .NET runtime events in typical machine configs these days.

@timcassell
Copy link
Collaborator Author

You mentioned disabling that in the other issue. How can we do that?

This was referenced Nov 10, 2025
agocke pushed a commit to serdedotnet/serde.cmdline that referenced this pull request Nov 16, 2025
Updated [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet)
from 0.14.0 to 0.15.6.

<details>
<summary>Release notes</summary>

_Sourced from [BenchmarkDotNet's
releases](https://github.com/dotnet/BenchmarkDotNet/releases)._

## 0.15.6

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.6.html


## 0.15.5

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.5.html



## 0.15.4

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.4.html

## Highlights

Allow override method/property for ParamsSource
([#​2832](dotnet/BenchmarkDotNet#2832))


## 0.15.3

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.3.html

## Highlights

Improvements:

- Naot instruction set support for .NET 10+, migrate to ISA groupings in
CPU summary
[#​2828](dotnet/BenchmarkDotNet#2828)
- Support benchmark filtering for TestAdapter
[#​2662](dotnet/BenchmarkDotNet#2662)
[#​2788](dotnet/BenchmarkDotNet#2788)
- Support non-primitive external types in `ArgumentsSource`
[#​2820](dotnet/BenchmarkDotNet#2820)
- Enable MSBuild parallel build via `--nodeReuse:false`
[#​2693](dotnet/BenchmarkDotNet#2693)
[#​2814](dotnet/BenchmarkDotNet#2814)
- Improve CPU detection
[#​2747](dotnet/BenchmarkDotNet#2747)
[#​2749](dotnet/BenchmarkDotNet#2749)
- Enable assembly signing for debug build
[#​2774](dotnet/BenchmarkDotNet#2774)

Deprecations:

- Deprecated `WithNuget`
[#​2812](dotnet/BenchmarkDotNet#2812)

Bug fixes:

- Fix `InvalidOperationException` in diagnosers
[#​2758](dotnet/BenchmarkDotNet#2758)
[#​2805](dotnet/BenchmarkDotNet#2805)
- Fix file detection in `NativeMemoryProfiler`
[#​2794](dotnet/BenchmarkDotNet#2794)
[#​2795](dotnet/BenchmarkDotNet#2795)
- Fix long file paths issue in `EtwProfiler`
[#​2807](dotnet/BenchmarkDotNet#2807)
[#​2808](dotnet/BenchmarkDotNet#2808)
- Fix log duplications in TestAdapter
[#​2790](dotnet/BenchmarkDotNet#2790)
- Fix x86 disassembler error for net462
[#​2792](dotnet/BenchmarkDotNet#2792)
- Fix `IsNetCore` and `IsNativeAOT` for single-file apps without AOT
[#​2799](dotnet/BenchmarkDotNet#2799)
- Fix density plot generation in `RPlotExporter` for latest version of R
[#​2809](dotnet/BenchmarkDotNet#2809)


## 0.15.2

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.2.html

## Highlights

- The most significant update in this release is the enhanced accuracy
of the memory diagnoser
([#​2562](dotnet/BenchmarkDotNet#2562)). This
improvement resolves the issue of incorrectly reported memory
allocations
([#​1542](dotnet/BenchmarkDotNet#1542),
[#​2582](dotnet/BenchmarkDotNet#2582)).
- We have introduced a new feature that allows users to sort benchmark
jobs in numerical order
([#​2768](dotnet/BenchmarkDotNet#2768),
[#​2770](dotnet/BenchmarkDotNet#2770)).
- Benchmark validation has been improved
([#​2771](dotnet/BenchmarkDotNet#2771)).
- An issue with non-persistent auto-generated JobId has been fixed
([#​2777](dotnet/BenchmarkDotNet#2777)).


## 0.15.1

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.1.html

## Highlights

- Added support for *.slnx
([#​2763](dotnet/BenchmarkDotNet#2763),
[#​2764](dotnet/BenchmarkDotNet#2764))
- Enabled ArgumentsSource to reference methods in other types
([#​2744](dotnet/BenchmarkDotNet#2744),
[#​2748](dotnet/BenchmarkDotNet#2748))
- Resolved fatal errors for ARM CPUs
([#​2745](dotnet/BenchmarkDotNet#2745),
[#​2756](dotnet/BenchmarkDotNet#2756))
- Fixed bugs related to support for Android, browser, iOS, and tvOS
([#​2739](dotnet/BenchmarkDotNet#2739),
[#​2741](dotnet/BenchmarkDotNet#2741),
[#​2740](dotnet/BenchmarkDotNet#2740),
[#​2742](dotnet/BenchmarkDotNet#2742))



## 0.15.0

Full changelog: https://benchmarkdotnet.org/changelog/v0.15.0.html



Commits viewable in [compare
view](dotnet/BenchmarkDotNet@v0.14.0...v0.15.6).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=BenchmarkDotNet&package-manager=nuget&previous-version=0.14.0&new-version=0.15.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

6 participants