Skip to content

Commit 2d89c15

Browse files
richlanderjkotasmthalman
authored
Update samples for user and cgroup info (#4220)
* Update cgroup handling * Update dotnetapp sample * Add username * Apply suggestions from code review Co-authored-by: Jan Kotas <[email protected]> * Update samples/aspnetapp/aspnetapp/Views/Home/Index.cshtml * Update per feedback * Update per feedback * Adopt C# 11 string literals * Remove $ * Update samples/aspnetapp/aspnetapp/EnvironmentInfo.cs Co-authored-by: Matt Thalman <[email protected]> * Switch 88 to 42 Co-authored-by: Jan Kotas <[email protected]> Co-authored-by: Matt Thalman <[email protected]>
1 parent b14e1e0 commit 2d89c15

File tree

3 files changed

+117
-82
lines changed

3 files changed

+117
-82
lines changed
Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,59 @@
11
using System.Runtime.InteropServices;
22

3-
public class EnvironmentInfo
3+
public struct EnvironmentInfo
44
{
55
public EnvironmentInfo()
66
{
7-
RuntimeVersion = RuntimeInformation.FrameworkDescription;
8-
OSVersion = RuntimeInformation.OSDescription;
9-
OSArchitecture = RuntimeInformation.OSArchitecture.ToString();
10-
ProcessorCount = Environment.ProcessorCount;
117
GCMemoryInfo gcInfo = GC.GetGCMemoryInfo();
128
TotalAvailableMemoryBytes = gcInfo.TotalAvailableMemoryBytes;
13-
bool hasCgroup = RuntimeInformation.OSDescription.StartsWith("Linux") && Directory.Exists("/sys/fs/cgroup/memory");
149

15-
if (hasCgroup)
10+
if (!OperatingSystem.IsLinux())
1611
{
17-
string limit = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.limit_in_bytes")[0];
18-
string usage = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.usage_in_bytes")[0];
19-
MemoryLimit = long.Parse(limit);
20-
MemoryUsage = long.Parse(usage);
12+
return;
2113
}
14+
15+
string[] memoryLimitPaths = new string[]
16+
{
17+
"/sys/fs/cgroup/memory.max",
18+
"/sys/fs/cgroup/memory/memory.limit_in_bytes",
19+
};
20+
21+
string[] currentMemoryPaths = new string[]
22+
{
23+
"/sys/fs/cgroup/memory.current",
24+
"/sys/fs/cgroup/memory/memory.usage_in_bytes",
25+
};
26+
27+
MemoryLimit = GetBestValue(memoryLimitPaths);
28+
MemoryUsage = GetBestValue(currentMemoryPaths);
2229
}
2330

24-
public string RuntimeVersion { get; set; }
25-
public string OSVersion { get; set; }
26-
public string OSArchitecture { get; set; }
27-
public int ProcessorCount { get; set; }
28-
public long TotalAvailableMemoryBytes {get; set;}
29-
public long MemoryLimit {get; set;}
30-
public long MemoryUsage {get; set;}
31+
public string RuntimeVersion => RuntimeInformation.FrameworkDescription;
32+
public string OSVersion => RuntimeInformation.OSDescription;
33+
public string OSArchitecture => RuntimeInformation.OSArchitecture.ToString();
34+
public string User => Environment.UserName;
35+
public int ProcessorCount => Environment.ProcessorCount;
36+
public long TotalAvailableMemoryBytes { get; }
37+
public long MemoryLimit { get; }
38+
public long MemoryUsage { get; }
3139

40+
private static long GetBestValue(string[] paths)
41+
{
42+
string value = string.Empty;
43+
foreach (string path in paths)
44+
{
45+
if (Path.Exists(path))
46+
{
47+
value = File.ReadAllText(path);
48+
break;
49+
}
50+
}
51+
52+
if (int.TryParse(value, out int result))
53+
{
54+
return result;
55+
}
56+
57+
return 0;
58+
}
3259
}

samples/aspnetapp/aspnetapp/Views/Home/Index.cshtml

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,12 @@
22
@using System.IO
33
@using System.Diagnostics
44
@{
5-
ViewData["Title"] = "Home page";
6-
var hostName = System.Net.Dns.GetHostName();
5+
ViewData["Title"] = "Welcome to .NET";
6+
string hostName = System.Net.Dns.GetHostName();
77
var ipList = await System.Net.Dns.GetHostAddressesAsync(hostName);
8-
8+
EnvironmentInfo env = new();
99
const long Mebi = 1024 * 1024;
1010
const long Gibi = Mebi * 1024;
11-
GCMemoryInfo gcInfo = GC.GetGCMemoryInfo();
12-
string totalAvailableMemory = GetInBestUnit(gcInfo.TotalAvailableMemoryBytes);
13-
14-
bool cgroup = RuntimeInformation.OSDescription.StartsWith("Linux") && Directory.Exists("/sys/fs/cgroup/memory");
15-
string memoryUsage = string.Empty;
16-
string memoryLimit = string.Empty;
17-
18-
if (cgroup)
19-
{
20-
string usage = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.usage_in_bytes")[0];
21-
string limit = System.IO.File.ReadAllLines("/sys/fs/cgroup/memory/memory.limit_in_bytes")[0];
22-
memoryUsage = GetInBestUnit(long.Parse(usage));
23-
memoryLimit = GetInBestUnit(long.Parse(limit));
24-
}
2511
}
2612

2713
<div class="text-center">
@@ -51,20 +37,24 @@
5137
<td>@(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") is null ? "false" : "true")</td>
5238
</tr>
5339
<tr>
54-
<td>Memory, total available GC memory</td>
55-
<td>@totalAvailableMemory</td>
40+
<td>User</td>
41+
<td>@(Environment.UserName)</td>
5642
</tr>
57-
@if (cgroup)
43+
@if (env.MemoryLimit > 0)
5844
{
5945
<tr>
60-
<td>cgroup memory usage</td>
61-
<td>@memoryUsage</td>
46+
<td>cgroup memory limit</td>
47+
<td>@env.MemoryLimit (@GetInBestUnit(env.MemoryLimit))</td>
6248
</tr>
6349
<tr>
64-
<td>cgroup memory limit</td>
65-
<td>@memoryLimit</td>
50+
<td>cgroup memory usage</td>
51+
<td>@env.MemoryUsage (@GetInBestUnit(env.MemoryUsage))</td>
6652
</tr>
6753
}
54+
<tr>
55+
<td>Memory, total available GC memory</td>
56+
<td>@env.TotalAvailableMemoryBytes (@GetInBestUnit(env.TotalAvailableMemoryBytes))</td>
57+
</tr>
6858
<tr>
6959
<td>Host name</td>
7060
<td>@hostName</td>
@@ -94,13 +84,13 @@
9484
}
9585
else if (size < Gibi)
9686
{
97-
decimal mebibytes = Decimal.Divide(size, Mebi);
98-
return $"{mebibytes:F} MiB";
87+
double mebibytes = (double)size / Mebi;
88+
return $"{mebibytes:N2} MiB";
9989
}
10090
else
10191
{
102-
decimal gibibytes = Decimal.Divide(size, Gibi);
103-
return $"{gibibytes:F} GiB";
92+
double gibibytes = (double)size / Gibi;
93+
return $"{gibibytes:N2} GiB";
10494
}
10595
}
10696
}

samples/dotnetapp/Program.cs

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,17 @@
77
// Variant of https://github.com/dotnet/core/tree/main/samples/dotnet-runtimeinfo
88
// Ascii text: https://ascii.co.uk/text (Univers font)
99

10-
string nl = Environment.NewLine;
11-
12-
WriteLine(
13-
$" 42{nl}" +
14-
$" 42 ,d ,d{nl}" +
15-
$" 42 42 42{nl}" +
16-
$" ,adPPYb,42 ,adPPYba, MM42MMM 8b,dPPYba, ,adPPYba, MM42MMM{nl}" +
17-
$"a8\" `Y42 a8\" \"8a 42 42P\' `\"8a a8P_____42 42{nl}" +
18-
$"8b 42 8b d8 42 42 42 8PP\"\"\"\"\"\"\" 42{nl}" +
19-
$"\"8a, ,d42 \"8a, ,a8\" 42, 42 42 \"8b, ,aa 42,{nl}" +
20-
$" `\"8bbdP\"Y8 `\"YbbdP\"\' \"Y428 42 42 `\"Ybbd8\"\' \"Y428{nl}");
10+
WriteLine("""
11+
42
12+
42 ,d ,d
13+
42 42 42
14+
,adPPYb,42 ,adPPYba, MM42MMM 8b,dPPYba, ,adPPYba, MM42MMM
15+
a8" `Y42 a8" "8a 42 42P' `"8a a8P_____42 42
16+
8b 42 8b d8 42 42 42 8PP!!!!!!! 42
17+
"8a, ,d42 "8a, ,a8" 42, 42 42 "8b, ,aa 42,
18+
`"8bbdP"Y8 `"YbbdP"' "Y428 42 42 `"Ybbd8"' "Y428
2119
20+
""");
2221

2322
// .NET information
2423
WriteLine(RuntimeInformation.FrameworkDescription);
@@ -50,38 +49,37 @@
5049
const long Gibi = Mebi * 1024;
5150
GCMemoryInfo gcInfo = GC.GetGCMemoryInfo();
5251
long totalMemoryBytes = gcInfo.TotalAvailableMemoryBytes;
53-
string totalAvailableMemory = GetInBestUnit(totalMemoryBytes);
5452

5553
// Environment information
54+
WriteLine($"{nameof(Environment.UserName)}: {Environment.UserName}");
5655
WriteLine($"{nameof(RuntimeInformation.OSArchitecture)}: {RuntimeInformation.OSArchitecture}");
5756
WriteLine($"{nameof(Environment.ProcessorCount)}: {Environment.ProcessorCount}");
58-
WriteLine($"{nameof(GCMemoryInfo.TotalAvailableMemoryBytes)}: {totalAvailableMemory}");
57+
WriteLine($"{nameof(GCMemoryInfo.TotalAvailableMemoryBytes)}: {totalMemoryBytes} ({GetInBestUnit(totalMemoryBytes)})");
5958

60-
// cgroup information
61-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) &&
62-
Directory.Exists("/sys/fs/cgroup/cpu") &&
63-
Directory.Exists("/sys/fs/cgroup/memory") &&
64-
File.Exists("sys/fs/cgroup/cpu/cpu.cfs_quota_us"))
59+
string[] memoryLimitPaths = new string[]
6560
{
66-
// get cpu cgroup information
67-
string cpuquota = File.ReadAllLines("/sys/fs/cgroup/cpu/cpu.cfs_quota_us")[0];
68-
if (int.TryParse(cpuquota, out int quota) &&
69-
quota > 0)
70-
{
71-
WriteLine($"cfs_quota_us: {quota}");
72-
}
61+
"/sys/fs/cgroup/memory.max",
62+
"/sys/fs/cgroup/memory/memory.limit_in_bytes",
63+
};
7364

65+
string[] currentMemoryPaths = new string[]
66+
{
67+
"/sys/fs/cgroup/memory.current",
68+
"/sys/fs/cgroup/memory/memory.usage_in_bytes",
69+
};
70+
71+
// cgroup information
72+
if (OperatingSystem.IsLinux())
73+
{
7474
// get memory cgroup information
75-
string usageBytes = File.ReadAllLines("/sys/fs/cgroup/memory/memory.usage_in_bytes")[0];
76-
string limitBytes = File.ReadAllLines("/sys/fs/cgroup/memory/memory.limit_in_bytes")[0];
77-
if (long.TryParse(usageBytes, out long usage) &&
78-
long.TryParse(limitBytes, out long limit) &&
79-
// above this size is unlikely to be an intentionally constrained cgroup
80-
limit < 10 * Gibi)
75+
long memoryLimit = GetBestValue(memoryLimitPaths);
76+
long currentMemory = GetBestValue(currentMemoryPaths);
77+
78+
if (memoryLimit > 0)
8179
{
82-
WriteLine($"usage_in_bytes: {usageBytes} {GetInBestUnit(usage)}");
83-
WriteLine($"limit_in_bytes: {limitBytes} {GetInBestUnit(limit)}");
84-
WriteLine($"GC Hard limit %: {decimal.Divide(totalMemoryBytes,limit) * 100}");
80+
WriteLine($"cgroup memory limit: {memoryLimit} ({GetInBestUnit(memoryLimit)})");
81+
WriteLine($"cgroup memory usage: {currentMemory} ({GetInBestUnit(currentMemory)})");
82+
WriteLine($"GC Hard limit %: {(double)totalMemoryBytes/memoryLimit * 100:N0}");
8583
}
8684
}
8785

@@ -93,12 +91,32 @@ string GetInBestUnit(long size)
9391
}
9492
else if (size < Gibi)
9593
{
96-
decimal mebibytes = Decimal.Divide(size, Mebi);
94+
double mebibytes = (double)(size / Mebi);
9795
return $"{mebibytes:F} MiB";
9896
}
9997
else
10098
{
101-
decimal gibibytes = Decimal.Divide(size, Gibi);
99+
double gibibytes = (double)(size / Gibi);
102100
return $"{gibibytes:F} GiB";
103101
}
104102
}
103+
104+
long GetBestValue(string[] paths)
105+
{
106+
string value = string.Empty;
107+
foreach (string path in paths)
108+
{
109+
if (Path.Exists(path))
110+
{
111+
value = File.ReadAllText(path);
112+
break;
113+
}
114+
}
115+
116+
if (int.TryParse(value, out int result))
117+
{
118+
return result;
119+
}
120+
121+
return 0;
122+
}

0 commit comments

Comments
 (0)