private void SetupCommandLine()

in src/PerfView/CommandLineArgs.cs [251:668]


        private void SetupCommandLine(CommandLineParser parser)
        {
            // #CommandLineDefinitions
            parser.ParameterSetsWhereQualifiersMustBeFirst = new string[] { "run", "UserCommand" };
            parser.NoDashOnParameterSets = true;

            parser.DefineOptionalQualifier("LogFile", ref LogFile, "Send messages to this file instead launching the GUI.  Intended for batch scripts and other automation.");

            // These apply to start, collect and run
            parser.DefineOptionalQualifier("BufferSize", ref BufferSizeMB, "The size the buffers (in MB) the OS should use to store events waiting to be written to disk."); // TODO remove eventually. 
            parser.DefineOptionalQualifier("Circular", ref CircularMB, "Do Circular logging with a file size in MB.  Zero means non-circular.");  // TODO remove eventually. 
            parser.DefineOptionalQualifier("BufferSizeMB", ref BufferSizeMB, "The size the buffers (in MB) the OS should use to store events waiting to be written to disk.");
            parser.DefineOptionalQualifier("CircularMB", ref CircularMB, "Do Circular logging with a file size in MB.  Zero means non-circular.");
            parser.DefineOptionalQualifier("InMemoryCircularBuffer", ref InMemoryCircularBuffer, "Keeps the circular buffer in memory until the session is stopped.");
            parser.DefineOptionalQualifier("StackCompression", ref StackCompression, "Use stack compression (only on Win 8+) to make collected file smaller.");
            parser.DefineOptionalQualifier("MaxCollectSec", ref MaxCollectSec,
                "Turn off collection (and kill the program if perfView started it) after this many seconds. Zero means no timeout.");
            parser.DefineOptionalQualifier("StopOnPerfCounter", ref StopOnPerfCounter,
                "This is of the form CATEGORY:COUNTERNAME:INSTANCE OP NUM  where CATEGORY:COUNTERNAME:INSTANCE, identify " +
                "a performance counter (same as PerfMon), OP is either < or >, and NUM is a number.  " +
                "When that condition is true then collection will stop.  You can specify this qualifier more than once (logical OR).  See 'Stop Trigger' in the users guide for more.");
            parser.DefineOptionalQualifier("StopOnEventLogMessage", ref StopOnEventLogMessage,
                "Stop when an event log message that matches the given (ignore case) regular expression is written to the Windows 'Application' event log.  " +
                "You can specify a particular event log with the syntax eventLogName@RegExp.   Can be specified more than once (logical OR).");

            parser.DefineOptionalQualifier("StopOnEtwEvent", ref StopOnEtwEvent,
                "This is of the form PROVIDER/EVENTNAME;key1=value1;key2=value2... " +
                "This option is quite powerful, See the users guide for more details.");

            int StopOnRequestOverMsec = 0;
            int StopOnGCSuspendOverMSec = 0;

            // These are basically special cases of the /StopOnEtwEvent
            parser.DefineOptionalQualifier("StopOnRequestOverMsec", ref StopOnRequestOverMsec,
                "Trigger a stop of a collect command if there is any IIS request that is longer than the given number of MSec.");
            parser.DefineOptionalQualifier("StopOnGCOverMsec", ref StopOnGCOverMsec,
                "Trigger a stop of a collect command if there is a .NET Garbage Collection (GC) is longer than the given number of MSec.");
            parser.DefineOptionalQualifier("StopOnGCSuspendOverMSec", ref StopOnGCSuspendOverMSec,
                "Trigger a stop of a collect command if there is a .NET Garbage Collection (GC) where suspending for the GC took over the given number of MSec.");
            parser.DefineOptionalQualifier("StopOnBGCFinalPauseOverMsec", ref StopOnBGCFinalPauseOverMsec,
               "Trigger a stop of a collect command if there is a background .NET Garbage Collection (GC) whose final pause is longer than the given number of MSec. To work correctly, " +
               "this requires that heap survival and movement tracking is not enabled.");
            parser.DefineOptionalQualifier("StopOnAppFabricOverMsec", ref StopOnAppFabricOverMsec,
                "Trigger a stop of a collect command if there is a AppFabric request is longer than the given number of MSec.");

            parser.DefineOptionalQualifier("StopOnException", ref StopOnException,
                "Where the text is a regular expression that will be used to match the full name and message of the .NET Exception thrown." +
                "The empty string represents any exception.");
            parser.DefineOptionalQualifier("StopOnGen2GC", ref StopOnGen2GC,
                "This will stop on any non-background Gen2 GC from the given process (can be a process ID or a process Name (exe file name without path or extension) or * (any process)");

            parser.DefineOptionalQualifier("Process", ref Process, "A process name (exe file name without directory or extension) or the Decimal Process ID.  " +
                "If used with the /StopOn* qualifiers using ETW events, will restrict events to only that process.");
            parser.DefineOptionalQualifier("DecayToZeroHours", ref DecayToZeroHours,
                "The trigger value used in StopOnPerfCounter or StopOn*OverMSec will decay to zero in this interval of time.");
            parser.DefineOptionalQualifier("MinSecForTrigger", ref MinSecForTrigger,
                "The number of seconds a perf Counter has to be above threshold before it is considered triggered.");
            parser.DefineOptionalQualifier("DelayAfterTriggerSec", ref DelayAfterTriggerSec,
                "Wait this number of seconds after a trigger before actually stopping the trace.");
            parser.DefineOptionalQualifier("CollectMultiple", ref CollectMultiple, "Collect Multiple instance (used in conjunction with StopTrigger).");
            parser.DefineOptionalQualifier("StartOnPerfCounter", ref StartOnPerfCounter,
                "This is of the form CATEGORY:COUNTERNAME:INSTANCE OP NUM  where CATEGORY:COUNTERNAME:INSTANCE, identify " +
                "a performance counter (same as PerfMon), OP is either < or >, and NUM is a number.  " +
                "When that condition is true then collection will start.  You can specify this qualifier more than once.  Search for 'MonitorPerfCounter' in the users guide for more.");
            parser.DefineOptionalQualifier("StopCommand", ref StopCommand,
                "If present this command is executed when a PerfView stops.  It is useful to stopping other tracing logic external to PerfView.");

            List<string> etwStopEvents = new List<string>();
            if (StopOnRequestOverMsec != 0)
            {
                etwStopEvents.Add("Microsoft-Windows-IIS/EventID(1);Level=Critical;TriggerMSec=" + StopOnRequestOverMsec);
            }

            if (StopOnGCSuspendOverMSec != 0)
            {
                etwStopEvents.Add("E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4/GC/SuspendEEStart;StopEvent=GC/SuspendEEStop;StartStopID=ThreadID;Keywords=0x1;TriggerMSec=" + StopOnGCSuspendOverMSec);
            }

            if (0 < etwStopEvents.Count)
            {
                if (StopOnEtwEvent != null)
                {
                    etwStopEvents.AddRange(StopOnEtwEvent);
                }

                StopOnEtwEvent = etwStopEvents.ToArray();
            }

            // Respect the /Process and /DecayToZeroHours options by tacking them on the end if they are not already present.  
            if (StopOnEtwEvent != null && (Process != null || DecayToZeroHours != 0))
            {
                etwStopEvents.Clear();
                foreach (var stopEtwEvent in StopOnEtwEvent)
                {
                    var newStopEtwEvent = stopEtwEvent;
                    if (Process != null && !stopEtwEvent.Contains(";Process="))
                    {
                        newStopEtwEvent += ";Process=" + Process;
                    }

                    if (DecayToZeroHours != 0 && !stopEtwEvent.Contains(";DecayToZeroHours="))
                    {
                        newStopEtwEvent += ";DecayToZeroHours=" + DecayToZeroHours;
                    }

                    etwStopEvents.Add(newStopEtwEvent);
                }
                StopOnEtwEvent = etwStopEvents.ToArray();
            }

            parser.DefineOptionalQualifier("MonitorPerfCounter", ref MonitorPerfCounter,
                "This is of the form CATEGORY:COUNTERNAME:INSTANCE@NUM  where CATEGORY:COUNTERNAME:INSTANCE, identify " +
                "a performance counter (same as PerfMon), and NUM is a number representing seconds.  The @NUM part is " +
                 "optional and defaults to 2.   The value of the performance counter is logged to the ETL file as an " +
                 "event ever NUM seconds");
            parser.DefineOptionalQualifier("CpuSampleMSec", ref CpuSampleMSec,
                "The interval (MSec) between CPU samples (.125Msec min).");

            // These apply to Stop Collect and Run 
            parser.DefineOptionalQualifier("Merge", ref Merge, "Do a merge after stopping collection.");
            parser.DefineOptionalQualifier("Zip", ref Zip, "Zip the ETL file (implies /Merge).");
            parser.DefineOptionalQualifier("Wpr", ref Wpr, "Make output mimic WPR (Windows Performance Recorder). Don't ZIP, make a .ngenpdbs directory.  " +
                "This also enables threadTime as well as user mode providers WPR would normally collect by default.   This option can also be used " +
                "On the unzip command.   See 'Working with WPA' in the help for more.");
            parser.DefineOptionalQualifier("LowPriority", ref LowPriority, "Do merging and ZIPing at low priority to minimize impact to system.");
            parser.DefineOptionalQualifier("NoRundown", ref NoRundown, "Don't collect rundown events.  Use only if you know the process of interest has exited.");
            parser.DefineOptionalQualifier("FocusProcess", ref FocusProcess, "Either a decimal process ID or a process name (exe name without path but WITH extension) to focus ETW commands." +
                "All NON-KERNEL providers are only send to this process (and rundown is only done on this process) which can cut overhead significantly in some cases.");

            parser.DefineOptionalQualifier("NoNGenPdbs", ref NoNGenPdbs, "Don't generate NGEN Pdbs");
            parser.DefineOptionalQualifier("NoNGenRundown", ref NoNGenRundown,
                "Don't do rundown of symbolic information in NGEN images (only needed pre V4.5).");
            parser.DefineOptionalQualifier("NoClrRundown", ref NoClrRundown,
                "Don't do rundown .NET (CLR) rundown information )(for symbolic name lookup).");
            parser.DefineOptionalQualifier("RundownTimeout", ref RundownTimeout,
                "Maximum number of seconds to wait for CLR rundown to complete.");
            parser.DefineOptionalQualifier("MinRundownTime", ref MinRundownTime,
                "Minimum number of seconds to wait for CLR rundown to complete.");
            parser.DefineOptionalQualifier("KeepAllEvents", ref KeepAllEvents,
                "A debug option to keep all events, even symbolic rundown events.");
            parser.DefineOptionalQualifier("MaxEventCount", ref MaxEventCount, "Limits the total number of events.  " +
                "Useful for trimming large ETL files. 1M typically yields 300-400 Meg of data considered.");
            parser.DefineOptionalQualifier("SkipMSec", ref SkipMSec, "Skips the first N MSec of the trace.  " +
                "Useful for trimming large ETL files in conjunction with the /MaxEventCount qualifier.");
            parser.DefineOptionalQualifier("StartTime", ref StartTime, "The start date and time used to filter events of the input trace for formats that support this.");
            parser.DefineOptionalQualifier("EndTime", ref EndTime, "The end date and time used to filter events of the input trace for formats that support this.");
            parser.DefineOptionalQualifier("ContinueOnError", ref ContinueOnError, "Processes bad traces as best it can.");

            parser.DefineOptionalQualifier("CpuCounters", ref CpuCounters,
                "A comma separated list of hardware CPU counters specifications NAME:COUNT to turn on.  " +
                "See Users guide for details.  See ListCpuCounters for available sources (Win8 only)");

            parser.DefineOptionalQualifier("Providers", ref Providers,
                "Additional providers.  This is comma separated list of ProviderGuid:Keywords:Level:Stack specs.  " +
                "This qualifier has the same syntax as the Additional Providers TextBox in the collection window.  " +
                " See help on that for more.");

            string[] onlyProviders = null;
            parser.DefineOptionalQualifier("OnlyProviders", ref onlyProviders,
                "Like the Providers qualifier, but also turns off the default Kernel and CLR providers.");
            if (onlyProviders != null)
            {
                // Allow stack traces to work if 'stacks' was specified.  
                bool hasStacks = false;
                bool hasTpl = false;
                foreach (var provider in onlyProviders)
                {
                    if (0 <= provider.IndexOf("@StacksEnabled=true", StringComparison.OrdinalIgnoreCase))
                    {
                        hasStacks = true;
                    }

                    if (0 <= provider.IndexOf("@EventIDStacksToEnable", StringComparison.OrdinalIgnoreCase))
                    {
                        hasStacks = true;
                    }

                    if (provider.StartsWith(".NETTasks", StringComparison.OrdinalIgnoreCase))
                    {
                        hasTpl = true;
                    }
                }

                if (hasStacks)
                {
                    KernelEvents = KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread | KernelTraceEventParser.Keywords.ImageLoad;
                    ClrEvents = ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.Loader;
                }
                else
                {
                    KernelEvents = KernelTraceEventParser.Keywords.None;
                    ClrEvents = ClrTraceEventParser.Keywords.None;
                    NoNGenRundown = true;   // We still do normal rundown because EventSource rundown is done there.   
                    NoClrRundown = true;
                }

                if (!hasTpl)
                {
                    // Turn on causality tracking.
                    TplEvents = TplEtwProviderTraceEventParser.Keywords.TasksFlowActivityIds;
                }

                Providers = onlyProviders;
            }
            parser.DefineOptionalQualifier("ThreadTime", ref ThreadTime, "Shortcut for turning on context switch and readyThread events");
            if (ThreadTime)
            {
                KernelEvents = KernelTraceEventParser.Keywords.ThreadTime;
            }

            parser.DefineOptionalQualifier("GCOnly", ref GCOnly, "Turns on JUST GC collections an allocation sampling.");
            if (GCOnly)
            {
                // TODO this logic is cloned.  We need it in only one place.  If you update it do the other location as well
                // For stack parsing.  
                KernelEvents = KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread | KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.VirtualAlloc;
                ClrEvents = ClrTraceEventParser.Keywords.GC | ClrTraceEventParser.Keywords.GCHeapSurvivalAndMovement | ClrTraceEventParser.Keywords.Stack |
                            ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.StopEnumeration | ClrTraceEventParser.Keywords.SupressNGen |
                            ClrTraceEventParser.Keywords.Loader | ClrTraceEventParser.Keywords.Exception | ClrTraceEventParser.Keywords.Type | ClrTraceEventParser.Keywords.GCHeapAndTypeNames;
                TplEvents = TplEtwProviderTraceEventParser.Keywords.None;

                // This is not quite correct if you have providers of your own, but this covers the most important case.  
                if (Providers == null)
                {
                    Providers = new string[] { "Microsoft-Windows-Kernel-Memory:0x60" };
                }

                CommandProcessor.s_UserModeSessionName = "PerfViewGCSession";
                DataFile = "PerfViewGCOnly.etl";
            }
            parser.DefineOptionalQualifier("GCCollectOnly", ref GCCollectOnly, "Turns on GC collections (no allocation sampling).");
            if (GCCollectOnly)
            {
                ConfigureForGCCollectOnly(this);
                CommandProcessor.s_UserModeSessionName = "PerfViewGCSession";
                DataFile = "PerfViewGCCollectOnly.etl";
            }

            // WPR option implies a bunch of kernel events.  
            if (Wpr)
            {
                KernelEvents = KernelTraceEventParser.Keywords.ThreadTime |
                    KernelTraceEventParser.Keywords.DeferedProcedureCalls |
                    KernelTraceEventParser.Keywords.Driver |
                    KernelTraceEventParser.Keywords.Interrupt;
            }

            parser.DefineOptionalQualifier("DumpHeap", ref DumpHeap, "Capture a heap snapshot on profile stop");
            parser.DefineOptionalQualifier("ClrEventLevel", ref ClrEventLevel, "The verbosity for CLR events");
            parser.DefineOptionalQualifier("ClrEvents", ref ClrEvents,
                "A comma separated list of .NET CLR events to turn on.  See Users guide for details.");
            parser.DefineOptionalQualifier("KernelEvents", ref KernelEvents,
                "A comma separated list of windows OS kernel events to turn on.  See Users guide for details.");
            parser.DefineOptionalQualifier("TplEvents", ref TplEvents,
                "A comma separated list of Task Parallel Library (TPL) events to turn on.  See Users guide for details.");

            parser.DefineOptionalQualifier("DotNetAlloc", ref DotNetAlloc, "Turns on per-allocation .NET profiling.");
            parser.DefineOptionalQualifier("DotNetAllocSampled", ref DotNetAllocSampled, "Turns on per-allocation .NET profiling, sampling types in a smart way to keep overhead low.");
            parser.DefineOptionalQualifier("DotNetCalls", ref DotNetCalls, "Turns on per-call .NET profiling.");
            parser.DefineOptionalQualifier("DotNetCallsSampled", ref DotNetCallsSampled, "Turns on per-call .NET profiling, sampling types in a smart way to keep overhead low.");
            parser.DefineOptionalQualifier("DisableInlining", ref DisableInlining, "Turns off inlining (but only affects processes that start after trace start.");
            parser.DefineOptionalQualifier("JITInlining", ref JITInlining, "Turns on logging of successful and failed JIT inlining attempts.");
            parser.DefineOptionalQualifier("CCWRefCount", ref CCWRefCount, "Turns on logging of information about .NET Native CCW reference counting.");
            parser.DefineOptionalQualifier("RuntimeLoading", ref RuntimeLoading, "Turn on logging of runtime loading operations.");
            parser.DefineOptionalQualifier("OSHeapProcess", ref OSHeapProcess, "Turn on per-allocation profiling of allocation from the OS heap for the process with the given process ID.");
            parser.DefineOptionalQualifier("OSHeapExe", ref OSHeapExe, "Turn on per-allocation profiling of allocation from the OS heap for the process with the given EXE (only filename WITH extension).");

            parser.DefineOptionalQualifier("NetworkCapture", ref NetworkCapture, "Captures the full data of every network packet entering or leaving the OS.");
            parser.DefineOptionalQualifier("NetMonCapture", ref NetMonCapture, "Create _netmon.etl file that NetMon.exe can read, along with the standard ETL file.   Implies /NetworkCapture.");

            parser.DefineOptionalQualifier("ForceNgenRundown", ref ForceNgenRundown,
                "By default on a V4.0 runtime NGEN rundown is suppressed, because NGEN PDB are a less expensive way of getting symbolic " +
                "information for NGEN images.  This option forces NGEN rundown, so NGEN PDBs are not needed.  This can be useful " +
                "in some scenarios where NGEN PDB are not working properly.");
            parser.DefineOptionalQualifier("NoV2Rundown", ref NoV2Rundown,
                "Don't do rundown for .NET (CLR) V2 processes.");
            parser.DefineOptionalQualifier("TrustPdbs", ref TrustPdbs, "Normally PerfView does not trust PDBs outside the _NT_SYMBOL_PATH and pops a dialog box.  Suppress this.");
            parser.DefineOptionalQualifier("AcceptEULA", ref AcceptEULA, "Accepts the EULA associated with PerfView.");
            parser.DefineOptionalQualifier("DataFile", ref DataFile,
                "FileName of the profile data to generate.");
            parser.DefineOptionalQualifier("NoView", ref NoView,
                "Normally after collecting data the data is viewed.  This suppresses that.");
            parser.DefineOptionalQualifier("UnsafePDBMatch", ref UnsafePDBMatch,
                "Allow the use of PDBs even when the trace does not contain PDB signatures.");
            parser.DefineOptionalQualifier("ShowUnknownAddresses", ref ShowUnknownAddresses,
                "Displays the hexadecimal address rather than ? when the address is unknown.");
            parser.DefineOptionalQualifier("ShowOptimizationTiers", ref ShowOptimizationTiers,
                "Displays the optimization tier of each code version executed for the method.");
            parser.DefineOptionalQualifier("NoGui", ref NoGui,
                "Use the Command line version of the command (like on ARM).  Brings up a console window.  For batch scripts/automation use /LogFile instead (see users guide under 'Scripting' for more).");
            parser.DefineOptionalQualifier("SafeMode", ref SafeMode, "Turn off parallelism and other risky features.");
            parser.DefineOptionalQualifier("RestartingToElevelate", ref RestartingToElevelate, "Internal: indicates that perfView is restarting to get Admin privileges.");

            string sessionName = null;
            parser.DefineOptionalQualifier("SessionName", ref sessionName, "Define the name for the user mode session (kernel session will also be named analogously) Useful for collecting traces when another ETW profiler (including PerfView) is being used.");
            if (sessionName != null)
            {
                if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62)
                    throw new ApplicationException("SessionName qualifier only works on Windows 8 and above.");
                CommandProcessor.s_UserModeSessionName = sessionName;
                CommandProcessor.s_KernelessionName = sessionName + "Kernel";
            }

            parser.DefineOptionalQualifier("MaxNodeCountK", ref MaxNodeCountK,
                "The maximum number of objects (in K or thousands) that will even be examined when dumping the heap.  Avoids memory use at collection time.  " +
                 "This is useful if heap dumping causes out of memory exceptions.");

            parser.DefineOptionalQualifier("EnableEventsInContainers", ref EnableEventsInContainers,
                "Enable user mode events inside of containers to flow back to the host for collection.");
            parser.DefineOptionalQualifier("EnableSourceContainerTracking", ref EnableSourceContainerTracking,
                "Emit the container ID as part of the payload of each usermode event emitted inside of a container.");

            /* end of qualifier that apply to more than one parameter set (command) */
            /****************************************************************************************/
            /* Parameter set (command) definitions */
            parser.DefineParameterSet("run", ref DoCommand, App.CommandProcessor.Run,
                "Starts data collection, runs a command and stops.");
            parser.DefineParameter("CommandAndArgs", ref CommandAndArgs,
                "Command to run and arguments (PerfView options must come before run command).");

            parser.DefineParameterSet("collect", ref DoCommand, App.CommandProcessor.Collect,
                "Starts data collection, wait for user input, then stops.");
            parser.DefineOptionalParameter("DataFile", ref DataFile,
                "ETL file containing profile data.");

            parser.DefineParameterSet("start", ref DoCommand, App.CommandProcessor.Start,
                "Starts machine wide profile data collection.");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data.");

            parser.DefineParameterSet("stop", ref DoCommand, App.CommandProcessor.Stop,
                "Stop collecting profile data (machine wide).  If you specified EventSources with the /Providers qualifier on start you should repeat them here to ensure manifest rundown.");

            parser.DefineParameterSet("mark", ref DoCommand, App.CommandProcessor.Mark,
                "Add a PerfView 'Mark' event to the event stream with a optional string message");
            parser.DefineOptionalParameter("Message", ref Message, "The string message to attach to the PerfView Mark event.");

            parser.DefineParameterSet("abort", ref DoCommand, App.CommandProcessor.Abort,
                "Ensures that any active PerfView sessions are stopped.");

            parser.DefineParameterSet("merge", ref DoCommand, App.CommandProcessor.Merge,
                "Combine separate ETL files into a single ETL file (that can be decoded on another machine).");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data.");
            parser.DefineOptionalQualifier("ImageIDsOnly", ref ImageIDsOnly,
                "Only perform image ID injection during the merge operation.");

            parser.DefineParameterSet("unzip", ref DoCommand, App.CommandProcessor.Unzip,
                "Unpack a ZIP file into its ETL file (and possibly its NGEN PDBS) /WPR option can be specified.");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data.");

            parser.DefineParameterSet("listSessions", ref DoCommand, App.CommandProcessor.ListSessions,
                "Lists active ETW sessions.");

            parser.DefineParameterSet("ListCpuCounters", ref DoCommand, App.CommandProcessor.ListCpuCounters,
                "Lists the ListCpuCounters CPU counters available on the system (win8+ only).");

            parser.DefineParameterSet("EnableKernelStacks", ref DoCommand, App.CommandProcessor.EnableKernelStacks,
                "On X64 machines if you have problems with broken stacks when the code is executing in the kernel," +
                " setting this option and rebooting may improve things");

            parser.DefineParameterSet("DisableKernelStacks", ref DoCommand, App.CommandProcessor.DisableKernelStacks,
                "Resets the registry keys set by EnableKernelStack.");

            string ProcessParam = null;
            parser.DefineParameterSet("HeapSnapshot", ref DoCommand, App.CommandProcessor.HeapSnapshot,
                "Take a snapshot of the CLR GC heap of a process.");
            parser.DefineParameter("Process", ref ProcessParam, "The process ID or Process Name (Exe without extension) of the process  take a heap snapshot.");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "The name of the file to place the heap snapshot.");
            parser.DefineOptionalQualifier("SaveETL", ref SaveETL, "Save an ETL file along with the GCDump file when dumping the JS Heap.");
            parser.DefineOptionalQualifier("MaxDumpCountK", ref MaxDumpCountK,
                "The maximum number of objects (in K or thousands) to place int the .gcDump file.   Sample sufficiently to hit this metric.");
            parser.DefineOptionalQualifier("Freeze", ref Freeze, "Freeze the dump while data is taken.");

            parser.DefineParameterSet("ForceGC", ref DoCommand, App.CommandProcessor.ForceGC,
                    "Forces a GC on the specified process");
            parser.DefineParameter("Process", ref ProcessParam, "The process ID or Process Name (Exe without extension) of the process to force a GC.");

            // We have both a qualifier and a parameter named Process. It is OK that they use the same variable, but the parameter should not
            // overwrite the qualifier if it is null.  
            if (ProcessParam != null)
            {
                Process = ProcessParam;
            }

            parser.DefineParameterSet("HeapSnapshotFromProcessDump", ref DoCommand, App.CommandProcessor.HeapSnapshotFromProcessDump,
                "Extract the CLR GC heap from a process dump file specified.");
            parser.DefineParameter("ProcessDumpFile", ref ProcessDumpFile, "The name of the input process dump file.");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "The name of the file to place the heap snapshot.");
            // TODO FIX NOW parser.DefineOptionalQualifier("DumpData", ref DumpData, "Dump the data as well as the connectivity information.");

            parser.DefineParameterSet("GuiRun", ref DoCommand, App.CommandProcessor.GuiRun, "Opens the 'Run' dialog box.");
            parser.DefineParameterSet("GuiCollect", ref DoCommand, App.CommandProcessor.GuiCollect, "Opens the 'Collect' dialog box.");
            parser.DefineParameterSet("GuiHeapSnapshot", ref DoCommand, App.CommandProcessor.GuiHeapSnapshot,
                "Opens the 'TakeHeapSnapshot' dialog box.");

            parser.DefineParameterSet("UserCommand", ref DoCommand, App.CommandProcessor.UserCommand,
                "Runs a user defined command.  Type 'PerfView UserCommandHelp' to see the help for all the user commands. " +
                "See PerfView Extensions in the users guide for more on creating user commands.");
            parser.DefineParameter("CommandAndArgs", ref CommandAndArgs, "User command to run and any arguments.");

            parser.DefineParameterSet("UserCommandHelp", ref DoCommand, App.CommandProcessor.UserCommandHelp,
                "Displays help for user commands.  Also see Help->User Command Help in the GUI.");

            parser.DefineParameterSet("CreateExtensionProject", ref DoCommand, App.CommandProcessor.CreateExtensionProject,
                "Creates a VS project for creates a perfView extension.");
            parser.DefineOptionalParameter("ExtensionName", ref ExtensionName, "The name of the extension (no .DLL)");

#if CROSS_GENERATION_LIVENESS
            parser.DefineParameterSet("CollectCrossGenerationLiveness", ref DoCommand, App.CommandProcessor.CollectCrossGenerationLiveness,
                "Collect a heap snapshot that can be used to do cross-generation liveness analysis.");
            parser.DefineQualifier("PID", ref CGL_PID, "The process ID of the process to snapshot.");
            parser.DefineQualifier("Generation", ref CGL_Generation, "The generation of the GC to collect.");
            parser.DefineQualifier("PromotedBytesThreshold", ref CGL_PromotedBytesThreshold, "The threshold of promoted bytes after which a snapshot of the heap should be collected.");
            parser.DefineQualifier("OutputFile", ref CGL_PathToOutputFile, "The full path including filename where the resulting gcdump file should be stored.");
#endif

            parser.DefineDefaultParameterSet(ref DoCommand, App.CommandProcessor.View, "View profile data.");
            parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL or ETLX file containing profile data.");
        }