Skip to content

Get rid of fallback to process ids enumeration in ProcessManager.IsProcessRunning (Windows) - #65041

Merged
adamsitnik merged 2 commits into
dotnet:mainfrom
epeshk:is-process-running
Mar 14, 2022
Merged

Get rid of fallback to process ids enumeration in ProcessManager.IsProcessRunning (Windows)#65041
adamsitnik merged 2 commits into
dotnet:mainfrom
epeshk:is-process-running

Conversation

@epeshk

@epeshk epeshk commented Feb 9, 2022

Copy link
Copy Markdown
Contributor

Currently, when process Handle can't be opened for any reason (local machine case), ProcessManager.IsProcessRunning enumerates all processes in the system to ensure that no process with given Id exists. This enumeration implemented via EnumProcesses call which is very slow (~10ms) compared to good case when handle is successfully opened

I want to suggest some improvements to (mostly) get rid of this fallback to achieve better performance.

Main suggestion is assume that process doesn't exists when OpenProcess failed not due to lack of permissions (ERROR_ACCESS_DENIED).

But there are some special cases should be considered.

Handle to process couldn't be opened:

  • for Idle processes (id=0) (ERROR_INVALID_PARAMETER)
  • for protected (e.g. csrss.exe) processes (ERROR_ACCESS_DENIED)
  • any other cases when our process is limited? maybe there is something special on Nano Server or old/future versions of Windows (who knows?)

In these cases we could (1 OR 2 OR 3):

  1. fall back to slow enumeration (looks like the safest way, cases when enumeration does happen don't seem to be common)
  2. optimistically assume that process is still running (allows to fully remove enumeration for local machine, but who knows if any other corner cases exists)
  3. other suggestions?

System.Diagnostics.ProcessManager.OpenProcess still assumes ERROR_ACCESS_DENIED means still running process. So second way doesn't look completely wrong.

What do you think, which way should be used? In this PR, I've implemented the first way, but it's not a problem to rewrite with second way if these optimistic assumptions are reasonable.

@ghost ghost added area-System.Diagnostics.Process community-contribution Indicates that the PR has been added by a community member labels Feb 9, 2022
@ghost

ghost commented Feb 9, 2022

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
See info in area-owners.md if you want to be subscribed.

Issue Details

Currently, when process Handle can't be opened for any reason (local machine case), ProcessManager.IsProcessRunning enumerates all processes in the system to ensure that no process with given Id exists. This enumeration implemented via EnumProcesses call which is very slow (~10ms) compared to good case when process exists and handle is successfully opened

I want to suggest some improvements to (mostly) get rid of this fallback to achieve better performance.

Main suggestion is assume that process doesn't exists when OpenProcess failed not due to lack of permissions (ERROR_ACCESS_DENIED).

But there are some special cases should be considered.

Handle to process couldn't be opened:

  • for Idle processes (id=0) (ERROR_INVALID_PARAMETER)
  • for protected (e.g. csrss.exe) processes (ERROR_ACCESS_DENIED)
  • any other cases when our process is limited? maybe there is something special on Nano Server or old/future versions of Windows (who knows?)

In these cases we could (1 OR 2 OR 3):

  1. fall back to slow enumeration (looks like the safest way, cases when enumeration does happen don't seem to be common)
  2. optimistically assume that process is still running (allows to fully remove enumeration for local machine, but who knows if any other corner cases exists)
  3. other suggestions?

System.Diagnostics.ProcessManager.OpenProcess still assumes ERROR_ACCESS_DENIED means still running process. So second way doesn't look completely wrong.

What do you think, which way should be used? In this PR, I've implemented the first way, but it's not a problem to rewrite with second way if these optimistic assumptions are reasonable.

Author: epeshk
Assignees: -
Labels:

area-System.Diagnostics.Process, community-contribution

Milestone: -

@adamsitnik adamsitnik 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.

Hi @epeshk

Big thanks for your contribution and providing a very descriptive explanation. Please take a look at my comment and let me know what do you think about it.

Could you please say a little bit more about the scenario in which you are using this method and the optimization would help? Are you frequently calling Process.GetProcessById for pid that does not exist? If so, may I ask why? (I am trying to get a better understanding)

Comment on lines 41 to 44

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.

The OpenProcess method can fail for multiple reasons. I am not 100% sure that all errors except ERROR_ACCESS_DENIED mean that the process does not exist. However, I think that it's safe to assume that when the method fails with ERROR_INVALID_PARAMETER the process does not exist and we can safely return false (I've tested it locally).

Suggested change
if (error != Interop.Errors.ERROR_ACCESS_DENIED)
return false;
if (error == Interop.Errors.ERROR_INVALID_PARAMETER)
{
Debug.Assert(processId != 0, "OpenProcess fails with ERROR_INVALID_PARAMETER for Idle Process");
return false;
}

…rate processes on local machine only when handle check failed
@epeshk
epeshk force-pushed the is-process-running branch from 4965a88 to cce266a Compare March 13, 2022 22:32

@adamsitnik adamsitnik 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.

LGTM, thank you @epeshk !

@adamsitnik
adamsitnik merged commit 39fb7f7 into dotnet:main Mar 14, 2022
@adamsitnik adamsitnik added this to the 7.0.0 milestone Mar 14, 2022
@adamsitnik adamsitnik added the tenet-performance Performance related issue label Mar 14, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 13, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Diagnostics.Process community-contribution Indicates that the PR has been added by a community member tenet-performance Performance related issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants