첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ CPUHelper.cs

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;

namespace TestProject
{
    /// <summary>
    /// CPU 헬퍼
    /// </summary>
    public class CPUHelper : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region Field

        /// <summary>
        /// CPU 사용률 배열
        /// </summary>
        public int[] CPUUsageRatioArray;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 백그라운드 작업자
        /// </summary>
        private BackgroundWorker worker;

        /// <summary>
        /// 성능 카운터 배열
        /// </summary>
        private PerformanceCounter[] performanceCounterArray;

        /// <summary>
        /// 리소스 해제 여부
        /// </summary>
        private bool isDisposed = false;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 프로세서 카운트 - ProcessorCount

        /// <summary>
        /// 프로세서 카운트
        /// </summary>
        public int ProcessorCount { get; private set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CPUHelper()

        /// <summary>
        /// 생성자
        /// </summary>
        public CPUHelper()
        {
            ProcessorCount = Environment.ProcessorCount;

            this.performanceCounterArray = new PerformanceCounter[ProcessorCount];

            for(int i = 0; i < ProcessorCount; i++)
            {
                this.performanceCounterArray[i] = new PerformanceCounter();

                this.performanceCounterArray[i].CategoryName = "Processor";
                this.performanceCounterArray[i].CounterName  = "% Processor Time";
                this.performanceCounterArray[i].InstanceName = i.ToString();
            }

            CPUUsageRatioArray = new int[ProcessorCount];

            this.worker = new BackgroundWorker();

            this.worker.WorkerSupportsCancellation = true;

            this.worker.DoWork += worker_DoWork;

            this.worker.RunWorkerAsync();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Destructor

        #region 소멸자 - ~CPUHelper()

        /// <summary>
        /// 소멸자
        /// </summary>
        ~CPUHelper()
        {
            Dispose(false);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region CPU 사용률 구하기 - GetCPUUsageRatio(processorID)

        /// <summary>
        /// CPU 사용률 구하기
        /// </summary>
        /// <param name="processorID">프로세서 ID</param>
        /// <returns>CPU 사용률</returns>
        public int GetCPUUsageRatio(int processorID)
        {
            return CPUUsageRatioArray[processorID];
        }

        #endregion

        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 리소스 해제하기 - Dispose(isDisposing)

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        /// <param name="isDisposing">리소스 해제 여부</param>
        protected virtual void Dispose(bool isDisposing)
        {
            if(isDisposed)
            {
                return;
            }

            this.worker.CancelAsync();

            this.worker.Dispose();

            for(int i = 0; i < this.performanceCounterArray.Length; i++)
            {
                this.performanceCounterArray[i].Dispose();
            }

            this.isDisposed = true;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 백그라운드 작업자 작업시 처리하기 - worker_DoWork(sender, e)

        /// <summary>
        /// 백그라운드 작업자 작업시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            while(true)
            {
                for(int i = 0; i < ProcessorCount; i++)
                {
                    SetCPUUsageRatio(i);
                }

                Thread.Sleep(1000);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region CPU 사용률 설정하기 - SetCPUUsageRatio(processorID)

        /// <summary>
        /// CPU 사용률 설정하기
        /// </summary>
        /// <param name="processorID">프로세서 ID</param>
        private void SetCPUUsageRatio(int processorID)
        {
            float value = this.performanceCounterArray[processorID].NextValue();

            CPUUsageRatioArray[processorID] = (int)value;
        }

        #endregion
    }
}

 

▶ CPULoadHelper.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;

namespace TestProject
{
    /// <summary>
    /// CPU 부하 헬퍼
    /// </summary>
    public class CPULoadHelper : IDisposable
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// CPU 헬퍼
        /// </summary>
        private CPUHelper cpuHelper;

        /// <summary>
        /// 리셋 이벤트 배열
        /// </summary>
        private ManualResetEvent[] resetEventArray;

        /// <summary>
        /// 스레드 배열
        /// </summary>
        private Thread[] threadArray;

        /// <summary>
        /// 타겟 CPU 사용률 배열
        /// </summary>
        private int[] targetCPUUsageRatioArray = new int[Environment.ProcessorCount];

        /// <summary>
        /// 프로세서 스레드 딕셔너리
        /// </summary>
        private Dictionary<int, int> processorThreadDictionary;

        /// <summary>
        /// 리소스 해제 여부
        /// </summary>
        private bool isDisposed = false;

        /// <summary>
        /// 백그라운드 작업자
        /// </summary>
        private BackgroundWorker worker;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 프로세서 카운트 - ProcessorCount

        /// <summary>
        /// 프로세서 카운트
        /// </summary>
        private int ProcessorCount { get; set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - CPULoadHelper()

        /// <summary>
        /// 생성자
        /// </summary>
        public CPULoadHelper()
        {
            ProcessorCount = Environment.ProcessorCount;

            this.threadArray = new Thread[ProcessorCount];

            this.worker = new BackgroundWorker();

            this.worker.DoWork += worker_DoWork;

            this.cpuHelper = new CPUHelper();

            this.processorThreadDictionary = new Dictionary<int, int>();

            SetAffinityForAllThreads();

            this.resetEventArray = new ManualResetEvent[ProcessorCount];

            for(int i = 0; i < ProcessorCount; i++)
            {
                this.resetEventArray[i] = new ManualResetEvent(false);
            }

            this.worker.RunWorkerAsync();
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        #region 소멸자 - ~CPULoadHelper()

        /// <summary>
        /// 소멸자
        /// </summary>
        ~CPULoadHelper()
        {
            Dispose(false);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 타겟 CPU 사용률 설정하기 - SetTargetCPUUsageRatio(processorID, cpuUsageRatio)

        /// <summary>
        /// 타겟 CPU 사용률 설정하기
        /// </summary>
        /// <param name="processorID">프로세서 ID</param>
        /// <param name="cpuUsageRatio">CPU 사용률</param>
        public void SetTargetCPUUsageRatio(int processorID, int cpuUsageRatio)
        {
            this.targetCPUUsageRatioArray[processorID] = cpuUsageRatio;
        }

        #endregion

        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Protected
        //////////////////////////////////////////////////////////////////////////////// Function

        #region 리소스 해제하기 - Dispose(isDisposing)

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        /// <param name="isDisposing">리소스 해제 여부</param>
        protected virtual void Dispose(bool isDisposing)
        {
            if(isDisposed)
            {
                return;
            }

            this.cpuHelper.Dispose();

            for(int i = 0; i < this.threadArray.Length; i++)
            {
                try
                {
                    this.threadArray[i].Abort();
                }
                catch
                {
                }
            }

            for(int i = 0; i < this.resetEventArray.Length; i++)
            {
                this.resetEventArray[i].Dispose();
            }

            isDisposed = true;
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 백그라운드 작업자 작업시 처리하기 - worker_DoWork(sender, e)

        /// <summary>
        /// 백그라운드 작업자 작업시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            for(int i = 0; i < ProcessorCount; i++)
            {
                this.threadArray[i] = CreateThreadOnProcessor(i);

                Thread.Sleep(500);
            }

            while(true)
            {
                for(int i = 0; i < ProcessorCount; i++)
                {
                    if(this.cpuHelper.GetCPUUsageRatio(i) > this.targetCPUUsageRatioArray[i])
                    {
                        this.resetEventArray[i].Reset();
                    }
                    else
                    {
                        this.resetEventArray[i].Set();
                    }
                }

                Thread.Sleep(2000);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 모든 스레드에 대한 선호도 설정하기 - SetAffinityForAllThreads()

        /// <summary>
        /// 모든 스레드에 대한 선호도 설정하기
        /// </summary>
        private void SetAffinityForAllThreads()
        {
            ProcessThreadCollection collection = Process.GetCurrentProcess().Threads;

            IEnumerator enumerator = collection.GetEnumerator();

            int x = 1 << (0);

            while(enumerator.MoveNext())
            {
                try
                {
                    ProcessThread processThread = (ProcessThread)enumerator.Current;

                    processThread.ProcessorAffinity = new IntPtr(x);
                }
                catch(Exception exception)
                {
                    Console.WriteLine(exception.Message);
                }
            }
        }

        #endregion
        #region 현재 프로세스의 스레드 ID 리스트 구하기 - GetCurrentProcessThreadIDList()

        /// <summary>
        /// 현재 프로세스의 스레드 ID 리스트 구하기
        /// </summary>
        /// <returns>스레드 ID 리스트</returns>
        private List<int> GetCurrentProcessThreadIDList()
        {
            ProcessThreadCollection collection = Process.GetCurrentProcess().Threads;

            IEnumerator enumerator = collection.GetEnumerator();

            List<int> list = new List<int>();

            while(enumerator.MoveNext())
            {
                ProcessThread processThread = (ProcessThread)enumerator.Current;

                list.Add(processThread.Id);
            }

            return list;
        }

        #endregion
        #region 스레드 ID로 프로세스 스레드 구하기 - GetProcessThreadByThreadID(threadID)

        /// <summary>
        /// 스레드 ID로 프로세스 스레드 구하기
        /// </summary>
        /// <param name="threadID">스레드 ID</param>
        /// <returns>프로세스 스레드</returns>
        private ProcessThread GetProcessThreadByThreadID(int threadID)
        {
            ProcessThreadCollection collection = Process.GetCurrentProcess().Threads;

            IEnumerator enumerator = collection.GetEnumerator();

            ProcessThread processThread = null;

            while(enumerator.MoveNext())
            {
                ProcessThread currentProcessThread = (ProcessThread)enumerator.Current;

                if(currentProcessThread.Id == threadID)
                {
                    processThread = currentProcessThread;

                    break;
                }
            }

            return processThread;
        }

        #endregion
        #region CPU 로드 생성하기 - CreateCPULoad(processorID)

        /// <summary>
        /// CPU 로드 생성하기
        /// </summary>
        private void CreateCPULoad(int processorID)
        {
            while(true)
            {
                this.resetEventArray[processorID].WaitOne();

                int time = 10000 - this.targetCPUUsageRatioArray[processorID] * 100;

                Thread.Sleep(new TimeSpan(time));
            }
        }

        #endregion
        #region 프로세서 스레드 생성하기 - CreateThreadOnProcessor(processorID)

        /// <summary>
        /// 프로세서 스레드 생성하기
        /// </summary>
        /// <param name="processorID">프로세서 ID</param>
        /// <returns>스레드</returns>
        private Thread CreateThreadOnProcessor(int processorID)
        {
            List<int> currentList = GetCurrentProcessThreadIDList();

            Thread thread = new Thread(() => CreateCPULoad(processorID));

            thread.Start();

            List<int> newList = GetCurrentProcessThreadIDList();

            newList.RemoveAll(Item => currentList.Contains(Item));

            ProcessThread processThread = GetProcessThreadByThreadID(newList[0]);

            processThread.ProcessorAffinity = new IntPtr(1 << processorID);

            processorThreadDictionary.Add(processThread.Id, processorID);

            return thread;
        }

        #endregion
    }
}

 

▶ MainForm.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TestProject
{
    /// <summary>
    /// 메인 폼
    /// </summary>
    public partial class MainForm : Form
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// CPU 부하 헬퍼
        /// </summary>
        private CPULoadHelper cpuLoadHelper;

        /// <summary>
        /// 프로세서 카운트
        /// </summary>
        private int processorCount = Environment.ProcessorCount;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            #region 이벤트를 설정한다.

            Load += Form_Load;
            FormClosing            += Form_FormClosing;
            this.closeButton.Click += closeButton_Click;

            #endregion
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

        /// <summary>
        /// 폼 로드시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Load(object sender, EventArgs e)
        {
            Label[]    cpuLabelArray    = new Label[this.processorCount];
            TrackBar[] trackBarArray    = new TrackBar[this.processorCount];
            GroupBox[] cpuGroupBoxArray = new GroupBox[this.processorCount];

            for(int i = 0; i < this.processorCount; i++)
            {
                int yOffset = 20;

                cpuGroupBoxArray[i] = new GroupBox();

                cpuGroupBoxArray[i].Text     = "CPU" + i.ToString();
                cpuGroupBoxArray[i].Size     = new Size(350, 50);
                cpuGroupBoxArray[i].Location = new Point(20, i * 60 + 20);

                RadioButton minimumRadioButton = new RadioButton();
                RadioButton medianRadioButton  = new RadioButton();
                RadioButton maximumRadioButton = new RadioButton();

                cpuGroupBoxArray[i].Controls.Add(minimumRadioButton);
                cpuGroupBoxArray[i].Controls.Add(medianRadioButton );
                cpuGroupBoxArray[i].Controls.Add(maximumRadioButton);

                minimumRadioButton.Text     = "Minimum";
                minimumRadioButton.AutoSize = true;
                minimumRadioButton.Location = new Point(40, yOffset);
                minimumRadioButton.Checked  = true;
                minimumRadioButton.Tag      = i.ToString() + ",0";

                minimumRadioButton.Click += radioButton_Click;

                medianRadioButton.Text     = "Medium";
                medianRadioButton.AutoSize = true;
                medianRadioButton.Location = new Point(130, yOffset);
                medianRadioButton.Tag      = i.ToString() + ",50";

                medianRadioButton.Click += radioButton_Click;

                maximumRadioButton.Text     = "Maximum";
                maximumRadioButton.AutoSize = true;
                maximumRadioButton.Location = new Point(220, yOffset);
                maximumRadioButton.Tag      = i.ToString() + ",100";

                maximumRadioButton.Click += radioButton_Click;

                this.contentPanel.Controls.Add(cpuGroupBoxArray[i]);
            }

            this.cpuLoadHelper = new CPULoadHelper();
        }

        #endregion
        #region 폼을 닫을 경우 처리하기 - Form_FormClosing(sender, e)

        /// <summary>
        /// 폼을 닫을 경우 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.cpuLoadHelper.Dispose();
        }

        #endregion
        #region 라디오 버튼 클릭시 처리하기 - radioButton_Click(sender, e)

        /// <summary>
        /// 라디오 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void radioButton_Click(object sender, EventArgs e)
        {
            RadioButton radioButton = sender as RadioButton;

            if(radioButton != null)
            {
                string   valueList  = radioButton.Tag.ToString();
                string[] valueArray = valueList.Split(new char[] { ',' });

                this.cpuLoadHelper.SetTargetCPUUsageRatio(int.Parse(valueArray[0]), int.Parse(valueArray[1]));
            }
        }

        #endregion
        #region 종료 버튼 클릭시 처리하기 - closeButton_Click(sender, e)

        /// <summary>
        /// 종료 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void closeButton_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion
    }
}

※ 테스트 결과 Windows 10 라이젠 CPU에서는 정상 작동하지 않았다.

728x90
반응형
그리드형
Posted by 사용자 icodebroker
TAG , ,

댓글을 달아 주세요