Closed skippernl closed 4 years ago
I couldn't figure out the best area label to add to this issue. Please help me learn by adding exactly one area label.
cc: @AaronRobinsonMSFT
@skippernl Thanks for reaching out. It would be helpful if you could collect a ETW trace using PerfView. This will allow us to understand your scenario better and observe precisely what aspect of the script is taking so long. Two hours would result in a large file, but we can probably get away with collecting data for no more than 30 to 60 seconds. A trace for pwsh5.1 would also be helpful, but we can start with pwsh7.
/cc @jkoritzinsky @elinor-fung
Will try that tomorrow.
Thanx
Op ma 25 mei 2020 18:50 schreef Aaron Robinson notifications@github.com:
@skippernl https://github.com/skippernl Thanks for reaching out. It would be helpful if you could collect a ETW trace using PerfView https://github.com/microsoft/perfview. This will allow us to understand your scenario better and observe precisely what aspect of the script is taking so long. Two hours would result in a large file, but we can probably get away with collecting data for no more than 30 to 60 seconds. A trace for pwsh5.1 would also be helpful, but we can start with pwsh7.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/runtime/issues/36944#issuecomment-633650251, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIWZN5MHCIHLBTFTSTDHZDRTKOUVANCNFSM4NIZ24BA .
Ran both. https://1drv.ms/u/s!AikuTJDzUoogh8Y6FT2qYZfu43LWIw?e=Z3Bjz8 [image: afbeelding.png]
You should be able to download the files from the onedrive location. If needed I can add a test file for a fortigate config file so you can test on your machine.
The configuration is just the interfaces and a routing table.
Skippernl
Op ma 25 mei 2020 om 18:50 schreef Aaron Robinson <notifications@github.com
:
@skippernl https://github.com/skippernl Thanks for reaching out. It would be helpful if you could collect a ETW trace using PerfView https://github.com/microsoft/perfview. This will allow us to understand your scenario better and observe precisely what aspect of the script is taking so long. Two hours would result in a large file, but we can probably get away with collecting data for no more than 30 to 60 seconds. A trace for pwsh5.1 would also be helpful, but we can start with pwsh7.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/runtime/issues/36944#issuecomment-633650251, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIWZN5MHCIHLBTFTSTDHZDRTKOUVANCNFSM4NIZ24BA .
-- Xander
@skippernl Thank you much for the collected traces. The traces identified the issue very quickly. Unfortunately, this appears to be an issue in PowerShell. The slow down is due to code paths in System.Management.Automation and from the trace appears to be because the code path when run on .NET Core falls back to expression tree evaluation instead of directly making the COM calls. I am not a PowerShell user nor have any experience with it as a developer so don't know why this code path is being taken, but it is because of this expression tree usage that the call is so expensive.
We can leave this issue open here since the runtime may need to respond or help the PowerShell run time. However, we need someone from PowerShell to interpret the trace on why this is occurring. Can you tag the person you were talking to?
Sure,
Steve Lee pointed me in you're direction.
SkipperNL
Op di 26 mei 2020 19:42 schreef Aaron Robinson notifications@github.com:
@skippernl https://github.com/skippernl Thank you much for the collected traces. The traces identified the issue very quickly. Unfortunately, this appears to be an issue in PowerShell. The slow down is due to code paths in System.Management.Automation https://docs.microsoft.com/dotnet/api/system.management.automation and from the trace appears to be because the code path when run on .NET Core falls back to expression tree evaluation instead of directly making the COM calls. I am not a PowerShell user nor have any experience with it as a developer so don't know why this code path is being taken, but it is because of this expression tree usage that the call is so expensive.
We can leave this issue open here since the runtime may need to respond or help the PowerShell run time. However, we need someone from PowerShell to interpret the trace on why this is occurring. Can you tag the person you were talking to?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/runtime/issues/36944#issuecomment-634173364, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIWZN5MGEOTJJTW5Q45YTDRTP5R3ANCNFSM4NIZ24BA .
@SteveL-MSFT Can you or a college chime in?
Hi any progress on this issue? If needed I can produce a small config file for testing.
@skippernl I'm from the PowerShell team and is investigating this issue.
A small config file would absolutely be helpful. Can you please confirm the repro step is .\Fortigate2Excel.ps1 -fortiGateConfig "<your-small-config-file>"
on both PS7 and PS5.1?
The slow down is due to code paths in System.Management.Automation and from the trace appears to be because the code path when run on .NET Core falls back to expression tree evaluation instead of directly making the COM calls.
@AaronRobinsonMSFT Thanks for the investigation and the insight. The differences between PS5.1 (on .NET) and PS7 (on .NET Core 3.1) is due to not having ComBinder
in the latter. Windows PowerShell basically copied the .NET code in the namespace Microsoft.CSharp.RuntimeBinder.ComInterop
to help dealing with COM interop in PowerShell. You will find the following pattern used throughout binders.cs:
public override DynamicMetaObject FallbackXXXX(...)
{
....
// Check if this is a COM Object
DynamicMetaObject result;
if (ComInterop.ComBinder.TryBindGetMember(this, target, out result))
{
result = new DynamicMetaObject(WrapGetMemberInTry(result.Expression), result.Restrictions);
return result.WriteToDebugLog(this);
}
...
}
In PS7, ComBinder.TryBindGetMember
is stub code that always returns false
. Without the ComBinder
, PowerShell handles COM interop through IDispatch.Invoke
, and thus needs to get metadata through calls like ITypeInfo.GetDocumentation
and ITypeInfo.GetFuncDesc
, which took more than 76% of the CPU time as shown in the PS7 trace.
@AaronRobinsonMSFT Last time I checked, the ComBinder
didn't work in .NET Core, but that was over half a year ago. It seems dynamic
keyword still doesn't work for COM object in .NET Core 3.1, but will it be back in .NET 5?
The differences between PS5.1 (on .NET) and PS7 (on .NET Core 3.1) is due to not having ComBinder in the latter.
@daxian-dbw Yay. I was hoping this was the issue. Yep, the support for dynamic
and COM was added in https://github.com/dotnet/runtime/pull/33060. This shipped in .NET 5.0 Preview 2. Yes, this is a .NET 5.0 feature and there are no plans to port it to .NET Core 3.1. Will PS7 be able to upgrade to .NET 5.0 when it is relased?
/cc @elinor-fung
Fantastic! Our master branch is current targeting .NET 5 preview 5, so I can go ahead enable the COM binder code in our code base.
Are there a lot changes to the code in the namespace Microsoft.CSharp.RuntimeBinder.ComInterop
? I guess I probably will have to refresh the code we copied years ago.
Are there a lot changes to the code in the namespace Microsoft.CSharp.RuntimeBinder.ComInterop? I guess I probably will have to refresh the code we copied years ago.
That is a great question for @elinor-fung. If memory serves she was able to optimize a few code paths.
I opened https://github.com/PowerShell/PowerShell/issues/12842 to track the work.
@skippernl and @daxian-dbw I am going to close this issue based on https://github.com/PowerShell/PowerShell/issues/12842. Please do let us know if there is any issues with the support/performance and we will do what we can to get back to the PS5.1 numbers.
I think the most interesting change was ripping out a bunch of the code that created a dynamic assembly to convert different types to pointers and switching to Unsafe.AsPointer
. Beyond that, it was mostly general cleanup and making it fit nicely in the runtime repo. In that PR #33060, the switch to Unsafe.AsPointer
was in commit 1bf8c6a3.
@elinor-fung Thanks for the additional info! I will refresh the code in our repo and do necessary refactoring as we did last time years back.
@skippernl I'm working on refreshing the ComInterop
code that PowerShell uses and I would like to test it using a real world script. Can you please share one or more fortigate configuration file so that I can test my work using Fortigate2Excel.ps1
? Thank you in advance!
@skippernl Ha, never mind, I just found you already shared a sample config file at https://onedrive.live.com/?authkey=%21ABU9qmGX7uNy1iM&id=208A52F3904C2E29%21123706&cid=208A52F3904C2E29. Appreciate it!
Let me know if you need more. Wil be waiting for the results.
Thanx for the update
Op wo 29 jul. 2020 17:04 schreef Dongbo Wang notifications@github.com:
@skippernl https://github.com/skippernl Ha, never mind, I just found you already shared a sample config file at https://onedrive.live.com/?authkey=%21ABU9qmGX7uNy1iM&id=208A52F3904C2E29%21123706&cid=208A52F3904C2E29. Appreciate it!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dotnet/runtime/issues/36944#issuecomment-665719586, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIWZN6AL6AK2K4JA5K2Z4LR6A3ANANCNFSM4NIZ24BA .
Hi I was pointed in this direction by the pwsh7 team.
I have a powershell script that takes the config of a firewall and creates an excel document from it. On powershell 5.1 this takes about 5 minutes depending on the size of the config. On powershell 7 this takes more that 2 hours. The main function that slows down is writing to excel $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $false $workbook = $excel.Workbooks.Add() $TocSheet = $workbook.Worksheets.Item(1) $MainSheet = $workbook.Worksheets.Add() $TocSheet.Name = "ToC"
Commenting the firstline out (The new-object) Makes the script run on pwsh7 in 49 seconds to 2 minutes and 35 seconds in powershell 5.
As the main function of this script is converting a config file to excel tabs it is higly depending on the -ComObject.
Full script can be found here https://github.com/skippernl/Fortigate2Excel