Skip to content

Slow module load caused by inefficient PSUtils.GetParentProcess #2578

@powercode

Description

@powercode

The current implementation for getting the parent id of the current process if extremely slow:
The parent Id is not even cached, but is retrieved over and over again. On several systems I see module load times of 5+ seconds, where almost all of the time is spent blocking on the wmi call, waiting for WmiPrvSe to enumerate all processes.
The Id of the process that created us will not change, so cache it and/or use a more efficient method of getting the parent id.

The check for process start time would still have to be done (not in the example).

/// suggested alternative (about 100 times faster)
public static class ProcessInfoUtil
{
	public static System.Diagnostics.Process GetParentProcess() { return ParentProcessId == 0 ? null : System.Diagnostics.Process.GetProcessById(ParentProcessId); }

	public static readonly int ParentProcessId = GetParentProcessId();

	private static int GetParentProcessId()
	{
		var pi = new PROCESS_BASIC_INFORMATION();
		int actual;
		if (0 == NativeMethods.NtQueryInformationProcess(new IntPtr(-1), 0/*processbasicInformation*/, ref pi, pi.Size, out actual))
		{
			return (int)pi.InheritedFromUniqueProcessId;
		}
		else 
		{
			return 0;
		}
	}

	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	private struct PROCESS_BASIC_INFORMATION
	{
		public IntPtr ExitStatus;
		public IntPtr PebBaseAddress;
		public IntPtr AffinityMask;
		public IntPtr BasePriority;
		public UIntPtr UniqueProcessId;
		public IntPtr InheritedFromUniqueProcessId;

		public int Size { get { return Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION));}}
	}

	static class NativeMethods
	{
	[DllImport("NtDll", SetLastError=true)]
	public static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int processInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, int processInformationLength, out int returnLength);
	}
}
/// this is the current implementation
 string wmiQuery = String.Format(CultureInfo.CurrentCulture,
                                            "Select * From Win32_Process Where Handle='{0}'",
                                            current.Id);

            using (CimSession cimSession = CimSession.Create(null))
            {
                IEnumerable<CimInstance> processCollection =
                    cimSession.QueryInstances("root/cimv2", "WQL", wmiQuery);

                int parentPid =
                    processCollection.Select(
                        cimProcess =>
                        Convert.ToInt32(cimProcess.CimInstanceProperties["ParentProcessId"].Value,
                                        CultureInfo.CurrentCulture)).FirstOrDefault();

                if (parentPid == 0)
                    return null;
...

Metadata

Metadata

Assignees

Labels

Resolution-FixedThe issue is fixed.WG-Enginecore PowerShell engine, interpreter, and runtime

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions