Skip to content

Commit

Permalink
Updated README and help (#39) and fixed install commands (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
lowleveldesign committed May 30, 2022
1 parent f7ab3b7 commit 024f04d
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 19 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Options:
-? Show this message and exit
```

You may set limits on a newly created process or on an already running one. To **attach to a process** use the **-p|--pid** switch, eg. `procgov --maxmem 40M --pid 1234`. To **start a new process** with the limits applied, just pass the process image path and its arguments as procgov arguments, eg. `procgov --maxmem 40M c:\temp\test.exe arg1 arg2"`.
You may set limits on a newly created process or on an already running one. To **attach to a process** use the **-p|--pid** switch, eg. `procgov32 --maxmem 40M --pid 1234`. To **start a new process** with the limits applied, just pass the process image path as a procgov argument, eg. `procgov32 --maxmem 40M c:\temp\test.exe`. If you need to **pass any parameters to the target process**, it's best to use `--` to separate procgov parameters from the target process ones, for example, `procgov32 -m 100M -- test.exe -arg1 -arg2=val2 arg3`.

Starting from version 2.8, it is possible to **update once set limits**. Simply run procgov providing new limits and the target process ID. Procgov will update only the specified limits. Let's have a look at an example to understand this behavior better:

Expand All @@ -101,7 +101,7 @@ PS> procgov64 -m 120M -p 1234
# - max committed memory: 120MB
```

Finally, you may **run procgov always when a given process starts**. When you use the **--install** switch Process Governor will add a special key to the **Image File Execution Options** in the registry, so that it will always start before your chosen process. To install Process Governor for a test.exe process, use the following command: `procgov --install --maxmem 40M test.exe`. You may later remove this installation by using the **--uninstall** switch, eg. `procgov --uninstall test.exe`.
Finally, you may **run procgov always when a given process starts**. When you use the **--install** switch Process Governor will add a special key to the **Image File Execution Options** in the registry, so that it will always start before your chosen process. To install Process Governor for a test.exe process, use the following command: `procgov64 --install --maxmem 40M test.exe`. You may later remove this installation by using the **--uninstall** switch, eg. `procgov64 --uninstall test.exe`.

## Limit memory of a process

Expand All @@ -114,7 +114,7 @@ With the **--maxws** and **--minws** switches you may control the maximum and mi
With the **--cpu** switch you may control on which cores your application will run. If you provide the CPU core number as **a decimal value**, your application will be allowed to use the specified number of cores. If you provide the CPU core number as **a hex value (with 0x prefix)**, this number will be treated as an affinity mask - where each bit represents a CPU core (starting from the least significant bit). Let's have a look at two example usages on a CPU intensive application. In a first one we set the CPU core limit to two cores:

```
> procgov --cpu=2 TestLimit.exe
> procgov64 --cpu=2 TestLimit.exe
```

A CPU usage graph on my machine looks as follows:
Expand All @@ -124,7 +124,7 @@ A CPU usage graph on my machine looks as follows:
In a second we set the CPU affinity mask (with the hex notation):

```
> procgov --cpu=0x2 TestLimit.exe
> procgov64 --cpu=0x2 TestLimit.exe
```

A CPU graph in this case looks as follows (notice only the second core is used):
Expand Down Expand Up @@ -157,7 +157,7 @@ COR_PROFILER={32E2F4DA-1BEA-47ea-88F9-C5DAF691C94A}
Starting from version 2.10, you can enable privileges in the target process with the **--enable-privileges** switch. You may specify multiple privileges, separated by a comma, for example:

```
procgov --enable-privileges=SeDebugPrivilege,SeShutdownPrivilege notepad
procgov64 --enable-privileges=SeDebugPrivilege,SeShutdownPrivilege notepad
```

Keep in mind that in Windows, you can't add new privileges to the process token. You may only enable existing ones. You may check the available process privileges in Process Hacker or Process Explorer. Check the documentation for a given privilege to learn how to make it available for a given user (for example, you may need to update group policies).
Expand Down
24 changes: 20 additions & 4 deletions procgov-tests/ProcessGovernorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,25 @@ public void PrepareDebuggerCommandStringTest()
{
var session = new SessionSettings() {
CpuAffinityMask = 0x2,
MaxProcessMemory = 1024 * 1024
MaxProcessMemory = 1024 * 1024,
MaxJobMemory = 2048 * 1024,
ProcessUserTimeLimitInMilliseconds = 500,
JobUserTimeLimitInMilliseconds = 1000,
ClockTimeLimitInMilliseconds = 2000,
CpuMaxRate = 90,
MaxBandwidth = 100,
MinWorkingSetSize = 1024,
MaxWorkingSetSize = 1024 * 1024,
NumaNode = 1,
Privileges = new[] { "SeDebugPrivilege", "SeShutdownPrivilege" },
PropagateOnChildProcesses = true,
SpawnNewConsoleWindow = true
};
session.AdditionalEnvironmentVars.Add("TEST", "TESTVAL");
session.AdditionalEnvironmentVars.Add("TEST2", "TESTVAL2");

var appImageExe = Path.GetFileName(@"C:\temp\test.exe");
var debugger = Program.PrepareDebuggerCommandString(session, appImageExe);
var debugger = Program.PrepareDebuggerCommandString(session, appImageExe, true);

var envFilePath = Program.GetAppEnvironmentFilePath(appImageExe);
Assert.True(File.Exists(envFilePath));
Expand All @@ -95,8 +107,12 @@ public void PrepareDebuggerCommandStringTest()
var txt = File.ReadAllText(envFilePath);
Assert.AreEqual("TEST=TESTVAL\r\nTEST2=TESTVAL2\r\n", txt);

Assert.AreEqual(string.Format("\"{0}\" --nogui --debugger --env=\"{1}\" --cpu=0x2 --maxmem=1048576",
Environment.GetCommandLineArgs()[0], envFilePath), debugger);
var expectedCmdLine =
$"\"{Environment.GetCommandLineArgs()[0]}\" --nogui --debugger --env=\"{envFilePath}\" --cpu=0x2 --maxmem=1048576 " +
"--maxjobmem=2097152 --maxws=1048576 --minws=1024 --node=1 --cpurate=90 --bandwidth=100 --recursive " +
"--timeout=2000 --process-utime=500 --job-utime=1000 --enable-privileges=SeDebugPrivilege,SeShutdownPrivilege --nowait";

Assert.AreEqual(expectedCmdLine, debugger);
} finally {
File.Delete(envFilePath);
}
Expand Down
65 changes: 55 additions & 10 deletions procgov/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public static int Main(string[] args)
Console.Error.WriteLine("ERROR: please provide an image name for a process you would like to intercept.");
return 1;
}
SetupRegistryForProcessGovernor(session, procargs[0], registryOperation);
SetupRegistryForProcessGovernor(session, procargs[0], registryOperation, nowait);
return 0;
}

Expand Down Expand Up @@ -335,13 +335,13 @@ static void ShowHelp(OptionSet p)
Console.WriteLine();
Console.WriteLine("EXAMPLES:");
Console.WriteLine("Limit memory of a test.exe process to 200MB:");
Console.WriteLine("> procgov --maxmem 200M test.exe");
Console.WriteLine("> procgov64 --maxmem 200M -- test.exe");
Console.WriteLine();
Console.WriteLine("Limit CPU usage of a test.exe process to first three CPU cores:");
Console.WriteLine("> procgov --cpu 3 test.exe");
Console.WriteLine("> procgov64 --cpu 3 -- test.exe -arg1 -arg2=val2");
Console.WriteLine();
Console.WriteLine("Always run a test.exe process only on the first three CPU cores:");
Console.WriteLine("> procgov --install --cpu 3 test.exe");
Console.WriteLine("> procgov64 --install --cpu 3 test.exe");
Console.WriteLine();
}

Expand Down Expand Up @@ -416,7 +416,7 @@ public enum RegistryOperation
NONE
}

public static void SetupRegistryForProcessGovernor(SessionSettings session, string appImageExe, RegistryOperation oper)
public static void SetupRegistryForProcessGovernor(SessionSettings session, string appImageExe, RegistryOperation oper, bool nowait)
{
if (!IsUserAdmin())
{
Expand All @@ -430,7 +430,7 @@ public static void SetupRegistryForProcessGovernor(SessionSettings session, stri
if (oper == RegistryOperation.INSTALL)
{
regkey = regkey.CreateSubKey(appImageExe);
regkey.SetValue("Debugger", PrepareDebuggerCommandString(session, appImageExe));
regkey.SetValue("Debugger", PrepareDebuggerCommandString(session, appImageExe, nowait));
}
else if (oper == RegistryOperation.UNINSTALL)
{
Expand All @@ -444,13 +444,12 @@ public static void SetupRegistryForProcessGovernor(SessionSettings session, stri
}
}

public static string PrepareDebuggerCommandString(SessionSettings session, string appImageExe)
public static string PrepareDebuggerCommandString(SessionSettings session, string appImageExe, bool nowait)
{
var buffer = new StringBuilder();
var procgovPath = Path.GetFullPath(Environment.GetCommandLineArgs()[0]);
buffer.Append('"').Append(procgovPath).Append('"').Append(" --nogui --debugger");

// FIXME: add other missing parameters!
if (session.AdditionalEnvironmentVars.Count > 0)
{
// we will create a file in the procgov folder with the environment variables
Expand All @@ -464,16 +463,62 @@ public static string PrepareDebuggerCommandString(SessionSettings session, strin
}
buffer.AppendFormat(" --env=\"{0}\"", appEnvironmentFilePath);
}

if (session.CpuAffinityMask != 0)
{
buffer.AppendFormat(" --cpu=0x{0:X}", session.CpuAffinityMask);
}

if (session.MaxProcessMemory > 0)
{
buffer.AppendFormat(" --maxmem={0}", session.MaxProcessMemory);
}
if (session.MaxJobMemory > 0)
{
buffer.AppendFormat(" --maxjobmem={0}", session.MaxJobMemory);
}
if (session.MaxWorkingSetSize > 0)
{
buffer.AppendFormat(" --maxws={0}", session.MaxWorkingSetSize);
}
if (session.MinWorkingSetSize > 0)
{
buffer.AppendFormat(" --minws={0}", session.MinWorkingSetSize);
}
if (session.NumaNode != 0xffff)
{
buffer.AppendFormat(" --node={0}", session.NumaNode);
}
if (session.CpuMaxRate > 0)
{
buffer.AppendFormat(" --cpurate={0}", session.CpuMaxRate);
}
if (session.MaxBandwidth > 0)
{
buffer.AppendFormat(" --bandwidth={0}", session.MaxBandwidth);
}
if (session.PropagateOnChildProcesses)
{
buffer.AppendFormat(" --recursive");
}
if (session.ClockTimeLimitInMilliseconds > 0)
{
buffer.AppendFormat(" --timeout={0}", session.ClockTimeLimitInMilliseconds);
}
if (session.ProcessUserTimeLimitInMilliseconds > 0)
{
buffer.AppendFormat(" --process-utime={0}", session.ProcessUserTimeLimitInMilliseconds);
}
if (session.JobUserTimeLimitInMilliseconds > 0)
{
buffer.AppendFormat(" --job-utime={0}", session.JobUserTimeLimitInMilliseconds);
}
if (session.Privileges.Length > 0)
{
buffer.AppendFormat(" --enable-privileges={0}", string.Join(',', session.Privileges));
}
if (nowait)
{
buffer.AppendFormat(" --nowait");
}

return buffer.ToString();
}
Expand Down

0 comments on commit 024f04d

Please sign in to comment.