แสดงข้อมูล Memory CPU Disk ด้วย C# EP.1

ในช่วงที่ผ่านมาผู้เขียนได้รับมอบหมายให้พัฒนาเครื่องมือสำหรับมอนิเตอร์การใช้งานทรัพยากรต่างๆ บน Server ที่ให้บริการลูกค้า ทั้งในส่วน Memory CPU และ Disk โดยโจทย์คือพัฒนา Service ขึ้นมาตัวนึงด้วยเครื่องมือที่เราใช้งานกันอยู่แล้วคือ Visual Studio.NET ด้วยภาษ C# สำหรับอ่านทรัพยากรต่างๆ บน Server แล้วจึงเขียนค่าเหล่านั้นลงไฟล์ จากนั้นจะมีเครื่องมืออีกตัวเข้ามาอ่านไฟล์ดังกล่าวแล้วนำไปแสดงผลเป็นกราฟในรูปแบบที่ต้องการต่อไป

เริ่มต้นเรามาดูวิธีการดึงข้อมูลหน่วยความจำ Available (คงเหลือ) กันก่อน ซึ่งโชคดีที่ .NET มี object ตัวนึงที่ชื่อ PerformanceCounter ที่จะคอยเก็บข้อมูลต่างๆ ของ Server และเราสามารถดึงค่าต่างๆ มาใช้งานได้โดยการระบุ parameter ที่เราต้องการ อย่างเช่นในกรณีของหน่วยความจำ จะต้องระบุ parameter 2 ตัว คือ “Memory”, “Available MBytes” ดังโค้ดตัวอย่าง

PerformanceCounter availMemory = new PerformanceCounter("Memory", "Available MBytes", null);

โดยเราจะดึงข้อมูลออกมาผ่านเมทธอด NextValue() อย่างเช่น

availMemory.NextValue();

เมื่อทดลองรันโค้ดดังกล่าว โดยผู้เขียนได้ทดลองสร้างโปรเจ็คแบบ Console Application ได้ผลลัพธ์ดังต่อไปนี้

โดยข้อมูลที่ได้อยู่ในรูปแบบ Megabytes ดังนั้นถ้าต้องการให้อยู่ในรูปแบบ Gigabytes จะต้องนำไปหารด้วย 1,024 เสียก่อน (ในส่วนนี้ผู้เขียนไม่แน่ใจว่า ในทางเทคนิคควรจะหารด้วย 1,024 หรือ 1,000)

แต่ด้วยข้อจำกัด เราไม่สามารถหาหน่วยความจำทั้งหมดจาก PerformanceCounter โดยจะต้องดึงข้อมูลผ่านวิธีการอื่น นั่นคือการเรียกผ่าน Windows API Function และต้องประกาศ Structure เพิ่มเติมเพื่อให้รองรับข้อมูลที่ Windows API ส่งกลับมา ดังนี้

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class MEMORYSTATUSEX
{
	public uint dwLength;
	public uint dwMemoryLoad;
	public ulong ullTotalPhys;
	public ulong ullAvailPhys;
	public ulong ullTotalPageFile;
	public ulong ullAvailPageFile;
	public ulong ullTotalVirtual;
	public ulong ullAvailVirtual;
	public ulong ullAvailExtendedVirtual;
	
	public MEMORYSTATUSEX()
	{
		this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
	}
}

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

และตัวอย่างวิธีการเรียกใช้งานฟังก์ชัน

ulong totalMemory;
MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
if( GlobalMemoryStatusEx(memStatus))
{ 
   totalMemory = memStatus.ullTotalPhys;
}

เมื่อนำโค้ดไปทดสอบ จะได้ผลลัพธ์ดังภาพ

โดยข้อมูลที่ได้จากฟังก์ชันนี้จะเป็นหน่วย byte ถ้าเราต้องการแปลงให้เป็น gigabyte ก็จะต้องหารด้วย (1024 * 1024 * 1024)

ซึ่งก็จะได้ผลลัพธ์ประมาณ 4 gigabytes และจากโค้ดในส่วนแรกที่ใช้งานหน่วยความจำคงเหลือ เมื่อนำมาผนวกกัน และมีการคำนวณอีกนิดหน่อย ก็จะได้ผลลัพธ์ดังภาพ

ตัวอย่างโค้ดทั้งหมด

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private class MEMORYSTATUSEX
        {
            public uint dwLength;
            public uint dwMemoryLoad;
            public ulong ullTotalPhys;
            public ulong ullAvailPhys;
            public ulong ullTotalPageFile;
            public ulong ullAvailPageFile;
            public ulong ullTotalVirtual;
            public ulong ullAvailVirtual;
            public ulong ullAvailExtendedVirtual;
            public MEMORYSTATUSEX()
            {
                this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
            }
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

        static void Main(string[] args)
        {
            float totalMemory = 0;
            MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
            if (GlobalMemoryStatusEx(memStatus))
            {
                totalMemory = memStatus.ullTotalPhys;
                totalMemory = totalMemory / (1024 * 1024 * 1024);
            }

            PerformanceCounter pAvailMemory = new PerformanceCounter("Memory", "Available MBytes", null);
            
            Console.WriteLine("Total : " + totalMemory.ToString("0.00"));
            Console.WriteLine("Available : " + (pAvailMemory.NextValue() / 1024).ToString("0.00"));
            Console.WriteLine("Usage : " + (totalMemory - (pAvailMemory.NextValue() / 1024)).ToString("0.00"));
        }
    }
}

สำหรับวิธีการดึงหน่วยความจำของเครื่องก็คงจบลงเพียงเท่านี้ ครั้งหน้าเราจะมาดูวิธีการดึงข้อมูลการใช้งาน CPU กัน

สวัสดีครับ


อ้างอิง