Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Deduplicate LSDA data in the object writer - #97972

Merged
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup
Feb 7, 2024
Merged

Deduplicate LSDA data in the object writer#97972
MichalStrehovsky merged 2 commits into
dotnet:mainfrom
MichalStrehovsky:lsdadedup

Conversation

@MichalStrehovsky

@MichalStrehovskyMichalStrehovsky commented Feb 5, 2024

Copy link
Copy Markdown
Member

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

Cc @dotnet/ilc-contrib

Extracting a piece of dotnet#87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.
@ghost

ghost commented Feb 5, 2024

Copy link
Copy Markdown

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

Issue Details

Extracting a piece of #87045 that I had to revert in that PR. Native linkers don't like when LSDA is in a COMDAT so fold these in the object writer instead. Seems to save about 1.2% in the Stage1 app. Obviously Unix only.

I only tested it with the Stage1 app so opening as draft so that I don't embarrass myself if the CI is all red.

Author:MichalStrehovsky
Assignees:-
Labels:

area-NativeAOT-coreclr

Milestone:-

Comment on lines +241 to +242
if (emittedLsdaSymbols == null)
EmitLsda(nodeWithCodeInfo, frameInfos, i, _lsdaSectionWriter, ref mainLsdaOffset);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be folded into the previous if on line 217. It was originally split to support prepending additional data in the LSDA section but that's solved in a different way for ARM32 now.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

@filipnavara what's the preferred way to exclude this for Mach-O? Mach-O seems to have opinions (or bugs) about this so I'd disable this there.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@filipnavara

Copy link
Copy Markdown
Member

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

what's the preferred way to exclude this for Mach-O?

No strong preferences. I would probably use the same pattern as UseFrameNames. Maybe we can even key it off the same property since I assume the underlying reason for the failure is similar.

From a quick look at https://opensource.apple.com/source/ld64/ld64-609/src/ld/parsers/macho_relocatable_file.cpp and the assert in question (cfiStartsArray[i] != cfiStartsArray[i-1]), it looks like ld64 puts LSDAs in the same collection as FDEs and then we hit an assert that is supposed to guard FDEs are unique. The FDEs are unique. LSDAs are not...

 // scan for FDEs claming the same function
for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
}

UseFrameNames sounds good. It can just mean "Apple weirdness".

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-nativeaot-outerloop

@MichalStrehovsky
MichalStrehovsky marked this pull request as ready for review February 6, 2024 11:06
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@am11

am11 commented Feb 6, 2024

Copy link
Copy Markdown
Member

Seems to save about 1.2% in the Stage1 app

👍
For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

@filipnavara

Copy link
Copy Markdown
Member

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

It’s hard to separate noise and improvements on this. There’s a dashboard that tracks it over time - https://aka.ms/aspnet/nativeaot/benchmarks - and possibly a system that auto-files issues on large changes.

@MichalStrehovsky

Copy link
Copy Markdown
MemberAuthor

Seems to save about 1.2% in the Stage1 app

👍 For awareness, would it make sense to add a size test (next to dwarfdump one) so every time some observable reduction/regression is introduced, we see it in the CI and adjust the limits accordingly?

AssertInRange(new FileInfo(Environment.ProcessPath).Length, GetLowerUpperLimitsForCurrentOS())

We have a "is size in range" test that has a big range that prevents the most egregious regressions (like if someone drags in the reflection stack into a hello world):

Console.WriteLine("****************************************************");
Console.WriteLine("* Size test *");
longfileSize=newSystem.IO.FileInfo(Environment.ProcessPath).Length;
Console.WriteLine($"* Size of the executable is {fileSize/1024,7:n0} kB *");
Console.WriteLine("****************************************************");
longlowerBound,upperBound;
lowerBound=1300*1024;// ~1.3 MB
upperBound=1750*1024;// ~1.75 MB
if(fileSize<lowerBound||fileSize>upperBound)
{
Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?");
return1;
}

And like Filip said, the rest is checked elsewhere.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks

@MichalStrehovsky
MichalStrehovsky merged commit 0cbbe7e into dotnet:mainFeb 7, 2024
@MichalStrehovsky
MichalStrehovsky deleted the lsdadedup branch February 7, 2024 06:20
@eerhardt

Copy link
Copy Markdown
Member

I can confirm we are seeing 1.3% and 1.7% size on disk reduction in Stage1 and Stage2 AOT apps in our benchmarks. (3% if you include symbol size).

dotnet/aspnetcore#53906
dotnet/aspnetcore#53907
dotnet/aspnetcore#53908
dotnet/aspnetcore#53909

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@MichalStrehovsky@filipnavara@am11@eerhardt@jkotas