So I'm writing a task manager clone, and right now I'm using this to calculate the CPU usage %s of each process. The problem is this is very slow; I was just wondering if there is a way to speed this up.
Also, I'm not allowed to use PerformanceCounter's methods and/or WMI.
//Omitted:
// - Process[] processes just holds the currently running processes
// - rows[] is a list of the rows I have in a table which shows the tables data
// - rows[2] is the column for CPU usage
// - rows[0] is the column for PID
//========
//Do CPU usages
double totalCPUTime = 0;
foreach (Process p in processes)
{
try
{
totalCPUTime += p.TotalProcessorTime.TotalMilliseconds;
}
catch (System.ComponentModel.Win32Exception e)
{
//Some processes do not give access rights to view their time.
}
}
foreach (Process p in processes)
{
double millis = 0;
try
{
millis = p.TotalProcessorTime.TotalMilliseconds;
}
catch (System.ComponentModel.Win32Exception e)
{
//Some processes do not give access rights to view their time.
}
double pct = 100 * millis / totalCPUTime;
for (int i = 0; i < rows.Count; i++)
{
if(rows[i].Cells[0].Value.Equals(p.Id))
{
rows[i].Cells[2].Value = pct;
break;
}
}
}
Use PerformanceCounter components to get different performance statistics:
var cpuCounter = new PerformanceCounter("Process", "% Processor Time", p.ProcessName);
double value = cpuCounter.NextValue();
And here is sample of creating something like task manager.
Also consider using Win API function GetProcessTimes.
Related
I'm trying to get CPU and network usage information from a process.In my example, I will use the process chromeHere is how im calling the method using an IEnumerable<String>
foreach (string p in GetProcessStatistics(new string[] { "chrome" }))
{
Console.WriteLine(p);
}
And here is the method.
private static IEnumerable<String> GetProcessStatistics(String[] processesTosearch)
{
Process[] processList = Process.GetProcesses();
foreach (string process in processesTosearch)
{
foreach (Process p in processList)
{
if (p.ProcessName == process)
{
StringBuilder sb = new StringBuilder();
PerformanceCounter CPUperformanceCounter = new PerformanceCounter("Process", "% Processor Time", p.ProcessName);
double cpuData = CPUperformanceCounter.NextValue();
PerformanceCounter NETWORKperformanceCounter = new PerformanceCounter("Process", "IO Data Operations/Sec", p.ProcessName);
double networkData = NETWORKperformanceCounter.NextValue();
sb.AppendLine("ID: " + p.Id.ToString());
sb.AppendLine("NAME: " + p.ProcessName);
sb.AppendLine("CPU USAGE: " + cpuData);
sb.AppendLine("RAM USAGE: " + ConvertToReadableSize(p.PrivateMemorySize64));
sb.AppendLine("NETWORK USAGE: " + networkData);
yield return sb.ToString();
}
}
}
}
And here is the output of one of the results
ID: 17624
NAME: chrome
CPU USAGE: 0
RAM USAGE: 23.2MB
NETWORK USAGE: 0
When I look at Performance Monitor, the cpu and network values are not 0, however in the console, they are.I understand from some research that the values will never be perfect, but why are they showing 0 in the console application and not on performance monitor?
You'll need at least two reads for every counter, at least a second apart to get a usable reading.
Rearrange as needed but you would need to do something like this:
private static IEnumerable<String> GetProcessStatistics(String[] processesTosearch)
{
Process[] processList = Process.GetProcesses();
foreach (string process in processesTosearch)
{
foreach (Process p in processList)
{
if (p.ProcessName == process)
{
StringBuilder sb = new StringBuilder();
PerformanceCounter CPUperformanceCounter = new PerformanceCounter("Process", "% Processor Time", p.ProcessName);
PerformanceCounter NETWORKperformanceCounter = new PerformanceCounter("Process", "IO Data Operations/Sec", p.ProcessName);
// set a baseline
CPUperformanceCounter.NextValue();
NETWORKperformanceCounter.NextValue();
Thread.Sleep(1000);
double cpuData = CPUperformanceCounter.NextValue();
double networkData = NETWORKperformanceCounter.NextValue();
sb.AppendLine("ID: " + p.Id.ToString());
sb.AppendLine("NAME: " + p.ProcessName);
sb.AppendLine("CPU USAGE: " + cpuData);
sb.AppendLine("RAM USAGE: " + ConvertToReadableSize(p.PrivateMemorySize64));
sb.AppendLine("NETWORK USAGE: " + networkData);
yield return sb.ToString();
}
}
}
}
I like Jeff's solution, but for me I wanted an average. There were a couple problems getting CPU utilization that seemed like there should be an easy package to solve but I didn't see one.
The first is of course that a value of 0 on the first request is useless. Since you already know that the first response is 0, why doesn't the function just take that into account and return the true .NextValue()?
The second problem is that an instantaneous reading may be wildly inacurrate when trying to make decisions on what resources your app may have available to it since it could be spiking, or between spikes.
My solution was to do a for loop that cycles through and gives you an average for the past few seconds. you can adjust the counter to make it shorter or longer (as long as it is more than 2).
public static float ProcessorUtilization;
public static float GetAverageCPU()
{
PerformanceCounter cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);
for (int i = 0; i < 11; ++i)
{
ProcessorUtilization += (cpuCounter.NextValue() / Environment.ProcessorCount);
}
// Remember the first value is 0, so we don't want to average that in.
Console.Writeline(ProcessorUtilization / 10);
return ProcessorUtilization / 10;
}
Well, I am trying to fetch memory (Private working set) for all running instance of Notepad .
for example lets say 4 Process of Notepad is running, and now I want total memory consumed by all 4 instance of Notepad.
Till now I have tried for single to get memory (Private working set) for single
Process[] proc = Process.GetProcessesByName(Notepad);
foreach (var kl in proc)
{
idnuml = kl.Id; // fetching pid for Notepad running instance.
}
PerformanceCounter PC = new PerformanceCounter( "Process", "Working Set - Private", InstanceName);
memsize = Convert.ToInt32(PC.NextValue()) / 1024;
I dont know why PerformanceCounter doesn't works with PID.
on each iteration it is able to detect Notepad pid for different instance, but at end same Working Set value for all instance.
Please help me .
Thanx in advance
I know it has been answered before here, but just for the sake of complete working code I'm posting this solution. Please note this code based on the method submitted by M4N in the link chain:
public static long GetProcessPrivateWorkingSet64Size(int process_id)
{
long process_size = 0;
Process process = Process.GetProcessById(process_id);
if (process == null) return process_size;
string instanceName = GetProcessInstanceName(process.Id);
var counter = new PerformanceCounter("Process", "Working Set - Private", instanceName, true);
process_size = Convert.ToInt32(counter.NextValue()) / 1024;
return process_size;
}
public static string GetProcessInstanceName(int process_id)
{
PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
string[] instances = cat.GetInstanceNames();
foreach (string instance in instances)
{
using (PerformanceCounter cnt = new PerformanceCounter("Process", "ID Process", instance, true))
{
int val = (int)cnt.RawValue;
if (val == process_id)
return instance;
}
}
throw new Exception("Could not find performance counter ");
}
Also, if you want to get the total memory of multiple instances of the same process use the above methods with the following one:
public static long GetPrivateWorkingSetForAllProcesses(string ProcessName)
{
long totalMem = 0;
Process[] process = Process.GetProcessesByName(ProcessName);
foreach (Process proc in process)
{
long memsize = GetProcessPrivateWorkingSet64Size(proc.Id);
totalMem += memsize;
}
return totalMem;
}
Finally I got the output,
If there are multiple instance of same process..
like Notepad has 4 instance, then it will be consider as
Notepad
Notepad#1
Notepad#2
Notepad#3
well, I am posting my code, people are requested to debug there own and comment it before I close it.
public int m_PMmonitor()
{
int count = 0,sum=0;
int[] lm = new int[10];
while (true)
{
try
{
Process[] proc = Process.GetProcessesByName(InstanceName);
PerformanceCounter PC;
sum = proc.Count();
int k = 0;
string pname;
foreach (var pro in proc)
{
lm[count] = pro.Id;
if ((sum-1) == count)
{
for (int i = 0; i <= (sum - 1); i++)
{
Process p = Process.GetProcessById(lm[i]);
pname = p.ProcessName;
if (k == 0)
{
PC = new PerformanceCounter("Process", "Working Set - Private", pname, true);
memsize = Convert.ToInt32(PC.NextValue()) / 1024;
Console.WriteLine(memsize);
k++;
}
else
{
PC = new PerformanceCounter("Process", "Working Set - Private", pname + "#" + (k).ToString(), true);
memsize = Convert.ToInt32(PC.NextValue()) / 1024;
Console.WriteLine(memsize);
k++;
}
memsize = Convert.ToInt32(PC.NextValue()) / 1024;
}
}
count++;
}
Thread.Sleep(800);
return memsize ;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Thread.Sleep(800);
return 0;
}
}
}
Ok So, Here is the optimized code,
This is to check "Working Set - Private" for a process running N instance.
like suppose 4 instance of Notepad is running, then it will be consider as
Notepad
Notepad#1
Notepad#2
Notepad#3
NOTE: InstanceName name is without extension , you can verify it by your Task Manager.
"Working Set - Private" will be use while coding,
but for verifying you can check with column Memory (Private Working Set ) under Processes tab in Task Manager
public int m_PMmonitor()
{
int count = 0, sum = 0,buff=0;
while (true)
{
try
{
Process[] proc = Process.GetProcessesByName(InstanceName);
PerformanceCounter PC;
sum = proc.Count();
int k = 0;
foreach (var pro in proc)
{
if (k == 0)
{
PC = new PerformanceCounter("Process", "Working Set - Private", InstanceName, true);
}
else
{
PC = new PerformanceCounter("Process", "Working Set - Private", InstanceName + "#" + (k).ToString(), true);
}
memsize = Convert.ToInt32(PC.NextValue()) / 1024;
Console.WriteLine(memsize);
buff = buff + memsize; //adding memsize of current running instance
PC.Dispose();
PC.Close();
count++;
k++;
}
Thread.Sleep(800);
return buff;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Thread.Sleep(800);
return 0;
}
}
}
The code you posted is just painful. Try this:
public int m_PMmonitor() {
var processes = Process.GetProcessByName("notepad.exe");
int memory = 0;
foreach (var process in processes) {
memory += process.WorkingSet / (1024^2); // convert bytes to MB
}
return memory;
}
Or if you like LINQ:
var memory = (from p in Process.GetProcessesByName("notepad.exe") select p.WorkingSet).Sum();
I mainly followed what was discussed in the second answer to this thread. I want to run a program that will continuously check for CPU usage above 5% for 10 seconds and alert me every time it happens.
How to get the CPU Usage in C#?
And my code is as follows:
static void Main(string[] args)
{
Console.WriteLine("Checking for CPU usage");
int totalhits = 0;
float cpuPercent = getCPUValue();
while (true)
{
if (cpuPercent >= 5)
{
totalhits += 1;
if (totalhits == 10)
{
Console.WriteLine("Alert Usage has exceeded");
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
totalhits = 0;
}
}
else
{
totalhits = 0;
}
}
}
private static float getCPUValue()
{
PerformanceCounter cpuCounter = new PerformanceCounter();
cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor time";
cpuCounter.InstanceName = "_Total";
float firstValue = cpuCounter.NextValue();
System.Threading.Thread.Sleep(50);
float secondValue = cpuCounter.NextValue();
return secondValue;
}
My problem is that it never hits that threshold and if I take out the totalhits = 0; statement inside the innermost if statement then it hits the threshold in less than 5 seconds.
What am I doing wrong?
First of all the
float cpuPercent = getCPUValue();
line should be inside the loop. Otherwise you will read the CPU usage only once. and will iterate over the same value.
You should create Only one PerformanceCounter object, and just call cpuCounter.NextValue() again and again inside the loop.
DON'T create the same CPU PerformanceCounter in every iteration.
PerformanceCounter counter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
while (true)
{
float cpuPercent = counter.nextValue();
if (cpuPercent >= 5)
{
totalhits += 1;
if (totalhits == 10)
{
Console.WriteLine("Alert Usage has exceeded");
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
totalhits = 0;
}
}
else
{
totalhits = 0;
}
}
As stated in MSDN
To obtain performance data for counters that required an initial or previous value for performing the necessary calculation, call the NextValue method twice and use the information returned as your application requires.
So you should call the cpuCounter.NextValue() twice (with about a 1 second delay between the calls) to start getting correct CPU Usage results.
BTW, You should wait about a 1 second between each read operation from the CPU PerformanceCounter (to ensure update).
As shown in this post Retriving Accurate CPU Usate In C#
Use the DispatcherTimer as stated in the below msdn and get the results as you needed.
DispatcherTimer
I have written a small program (ProcessSample) to launch another programs that are defined in the .txt file (separated by new line).
The code is mostly taken from MSDN. I am just starting my programming adventure but I want to write something useful.
I don't know the smart way to run for example two programs simultaneously from my ProcessSample program.
In my .txt file I have just paths to programs with .exe. It's all working fine but my program is only running one program at the time. I thought I would run foreach but of course it won't work here as it just runs the first program and it waits till I exit it, then it will run the next one.
So I know the reason why is it not working. I just want to know how could I make it work the way I would like.
My C# code:
using System;
using System.Diagnostics;
using System.Threading;
namespace ProcessSample
{
class ProcessMonitorSample
{
public static void Main()
{
Console.BufferHeight = 25;
// Define variables to track the peak memory usage of the process.
long peakWorkingSet = 0;
string[] Programs = System.IO.File.ReadAllLines(#"C:\Programs\list.txt");
foreach (string Program in Programs)
{
Process myProcess = null;
// Start the process.
myProcess = Process.Start(#Program);
// Display the process statistics until
// the user closes the program.
do
{
if (!myProcess.HasExited)
{
// Refresh the current process property values.
myProcess.Refresh();
// Display current process statistics.
Console.WriteLine();
Console.WriteLine("Path: {0}, RAM: {1}", Program, (myProcess.WorkingSet64 / 1024 / 1024));
// Update the values for the overall peak memory statistics.
peakWorkingSet = myProcess.PeakWorkingSet64;
if (myProcess.Responding)
{
Console.WriteLine("Status: Running");
}
else
{
Console.WriteLine("Status: Not Responding!");
}
// Wait 2 seconds
Thread.Sleep(2000);
} // if
} // do
while (!myProcess.WaitForExit(1000));
Console.WriteLine();
Console.WriteLine("Process exit code: {0}", myProcess.ExitCode);
Console.WriteLine("Peak physical memory usage of the process: {0}", (peakWorkingSet / 1024 / 1024));
Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
} // foreach
} // public
} //class
} // namespace
The problem is in the inner while loop. There you are getting statistics from the running process and displaying them in the console. As far as I understand from your post, you don't need this feature so you can remove it and you would get:
using System;
using System.Diagnostics;
using System.Threading;
namespace ProcessSample
{
class ProcessMonitorSample
{
public static void Main()
{
Console.BufferHeight = 25;
// Define variables to track the peak memory usage of the process.
long peakWorkingSet = 0;
string[] Programs = System.IO.File.ReadAllLines(#"C:\Programs\list.txt");
foreach (string Program in Programs)
{
Process myProcess = null;
// Start the process.
myProcess = Process.Start(#Program);
Console.WriteLine("Program started: {0}", Program);
}
}
}
}
Actually I have learned about Threads and I have used them for my program like this:
class Program
{
static void Main(string[] args)
{
string[] myApps = { "notepad.exe", "calc.exe", "explorer.exe" };
Thread w;
ParameterizedThreadStart ts = new ParameterizedThreadStart(StartMyApp);
foreach (var myApp in myApps)
{
w = new Thread(ts);
w.Start(myApp);
Thread.Sleep(1000);
}
}
private static void StartMyApp(object myAppPath)
{
ProcessStartInfo myInfoProcess = new ProcessStartInfo();
myInfoProcess.FileName = myAppPath.ToString();
myInfoProcess.WindowStyle = ProcessWindowStyle.Minimized;
Process myProcess = Process.Start(myInfoProcess);
do
{
if (!myProcess.HasExited)
{
myProcess.Refresh(); // Refresh the current process property values.
Console.WriteLine(myProcess.ProcessName+" RAM: "+(myProcess.WorkingSet64 / 1024 / 1024).ToString()+"\n");
Thread.Sleep(1000);
}
}
while (!myProcess.WaitForExit(1000));
}
}
You can replace your foreach with Parallel.ForEach to achieve what you want.
Parallel.ForEach<String>(Programs, Program =>
{
Process myProcess = null;
// Start the process.
myProcess = Process.Start(#Program);
// Display the process statistics until
// the user closes the program.
do
{
if (!myProcess.HasExited)
{
// Refresh the current process property values.
myProcess.Refresh();
// Display current process statistics.
Console.WriteLine();
Console.WriteLine("Path: {0}, RAM: {1}", Program, (myProcess.WorkingSet64 / 1024 / 1024));
// Update the values for the overall peak memory statistics.
peakWorkingSet = myProcess.PeakWorkingSet64;
if (myProcess.Responding)
{
Console.WriteLine("Status: Running");
}
else
{
Console.WriteLine("Status: Not Responding!");
}
// Wait 2 seconds
Thread.Sleep(2000);
}
}
while (!myProcess.WaitForExit(1000));
Console.WriteLine();
Console.WriteLine("Process exit code: {0}", myProcess.ExitCode);
Console.WriteLine("Peak physical memory usage of the process: {0}", (peakWorkingSet / 1024 / 1024));
Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
});
The following nunit test compares performance between running a single thread versus running 2 threads on a dual core machine. Specifically, this is a VMWare dual core virtual Windows 7 machine running on a quad core Linux SLED host with is a Dell Inspiron 503.
Each thread simply loops and increments 2 counters, addCounter and readCounter. This test was original testing a Queue implementation which was discovered to perform worse on a multi-core machine. So in narrowing down the problem to the small reproducible code, you have here no queue only incrementing variables and to shock and dismay, it's far slower with 2 threads then one.
When running the first test, the Task Manager shows 1 of the cores 100% busy with the other core almost idle. Here's the test output for the single thread test:
readCounter 360687000
readCounter2 0
total readCounter 360687000
addCounter 360687000
addCounter2 0
You see over 360 Million increments!
Next the dual thread test shows 100% busy on both cores for the whole 5 seconds duration of the test. However it's output shows only:
readCounter 88687000
readCounter2 134606500
totoal readCounter 223293500
addCounter 88687000
addCounter2 67303250
addFailure0
That's only 223 Million read increments. What is god's creation are those 2 CPU's doing for those 5 seconds to get less work done?
Any possible clue? And can you run the tests on your machine to see if you get different results? One idea is that perhaps the VMWare dual core performance isn't what you would hope.
using System;
using System.Threading;
using NUnit.Framework;
namespace TickZoom.Utilities.TickZoom.Utilities
{
[TestFixture]
public class ActiveMultiQueueTest
{
private volatile bool stopThread = false;
private Exception threadException;
private long addCounter;
private long readCounter;
private long addCounter2;
private long readCounter2;
private long addFailureCounter;
[SetUp]
public void Setup()
{
stopThread = false;
addCounter = 0;
readCounter = 0;
addCounter2 = 0;
readCounter2 = 0;
}
[Test]
public void TestSingleCoreSpeed()
{
var speedThread = new Thread(SpeedTestLoop);
speedThread.Name = "1st Core Speed Test";
speedThread.Start();
Thread.Sleep(5000);
stopThread = true;
speedThread.Join();
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
Console.Out.WriteLine("readCounter " + readCounter);
Console.Out.WriteLine("readCounter2 " + readCounter2);
Console.Out.WriteLine("total readCounter " + (readCounter + readCounter2));
Console.Out.WriteLine("addCounter " + addCounter);
Console.Out.WriteLine("addCounter2 " + addCounter2);
}
[Test]
public void TestDualCoreSpeed()
{
var speedThread1 = new Thread(SpeedTestLoop);
speedThread1.Name = "Speed Test 1";
var speedThread2 = new Thread(SpeedTestLoop2);
speedThread2.Name = "Speed Test 2";
speedThread1.Start();
speedThread2.Start();
Thread.Sleep(5000);
stopThread = true;
speedThread1.Join();
speedThread2.Join();
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
Console.Out.WriteLine("readCounter " + readCounter);
Console.Out.WriteLine("readCounter2 " + readCounter2);
Console.Out.WriteLine("totoal readCounter " + (readCounter + readCounter2));
Console.Out.WriteLine("addCounter " + addCounter);
Console.Out.WriteLine("addCounter2 " + addCounter2);
Console.Out.WriteLine("addFailure" + addFailureCounter);
}
private void SpeedTestLoop()
{
try
{
while (!stopThread)
{
for (var i = 0; i < 500; i++)
{
++addCounter;
}
for (var i = 0; i < 500; i++)
{
readCounter++;
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
private void SpeedTestLoop2()
{
try
{
while (!stopThread)
{
for (var i = 0; i < 500; i++)
{
++addCounter2;
i++;
}
for (var i = 0; i < 500; i++)
{
readCounter2++;
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
}
}
Edit: I tested the above on a quad core laptop w/o vmware and got similar degraded performance. So I wrote another test similar to the above but which has each thread method in a separate class. My purpose in doing that was to test 4 cores.
Well that test showed excelled results which improved almost linearly with 1, 2, 3, or 4 cores.
With some experimentation now on both machines it appears that the proper performance only happens if main thread methods are on different instances instead of the same instance.
In other words, if multiple threads main entry method on on the same instance of a particular class, then the performance on a multi-core will be worse for each thread you add, instead of better as you might assume.
It almost appears that the CLR is "synchronizing" so only one thread at a time can run on that method. However, my testing says that isn't the case. So it's still unclear what's happening.
But my own problem seems to be solved simply by making separate instances of methods to run threads as their starting point.
Sincerely,
Wayne
EDIT:
Here's an updated unit test that tests 1, 2, 3, & 4 threads with them all on the same instance of a class. Using arrays with variables uses in the thread loop at least 10 elements apart. And performance still degrades significantly for each thread added.
using System;
using System.Threading;
using NUnit.Framework;
namespace TickZoom.Utilities.TickZoom.Utilities
{
[TestFixture]
public class MultiCoreSameClassTest
{
private ThreadTester threadTester;
public class ThreadTester
{
private Thread[] speedThread = new Thread[400];
private long[] addCounter = new long[400];
private long[] readCounter = new long[400];
private bool[] stopThread = new bool[400];
internal Exception threadException;
private int count;
public ThreadTester(int count)
{
for( var i=0; i<speedThread.Length; i+=10)
{
speedThread[i] = new Thread(SpeedTestLoop);
}
this.count = count;
}
public void Run()
{
for (var i = 0; i < count*10; i+=10)
{
speedThread[i].Start(i);
}
}
public void Stop()
{
for (var i = 0; i < stopThread.Length; i+=10 )
{
stopThread[i] = true;
}
for (var i = 0; i < count * 10; i += 10)
{
speedThread[i].Join();
}
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
}
public void Output()
{
var readSum = 0L;
var addSum = 0L;
for (var i = 0; i < count; i++)
{
readSum += readCounter[i];
addSum += addCounter[i];
}
Console.Out.WriteLine("Thread readCounter " + readSum + ", addCounter " + addSum);
}
private void SpeedTestLoop(object indexarg)
{
var index = (int) indexarg;
try
{
while (!stopThread[index*10])
{
for (var i = 0; i < 500; i++)
{
++addCounter[index*10];
}
for (var i = 0; i < 500; i++)
{
++readCounter[index*10];
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
}
[SetUp]
public void Setup()
{
}
[Test]
public void SingleCoreTest()
{
TestCores(1);
}
[Test]
public void DualCoreTest()
{
TestCores(2);
}
[Test]
public void TriCoreTest()
{
TestCores(3);
}
[Test]
public void QuadCoreTest()
{
TestCores(4);
}
public void TestCores(int numCores)
{
threadTester = new ThreadTester(numCores);
threadTester.Run();
Thread.Sleep(5000);
threadTester.Stop();
threadTester.Output();
}
}
}
That's only 223 Million read increments. What is god's creation are those 2 CPU's doing for those 5 seconds to get less work done?
You're probably running into cache contention -- when a single CPU is incrementing your integer, it can do so in its own L1 cache, but as soon as two CPUs start "fighting" over the same value, the cache line it's on has to be copied back and forth between their caches each time each one accesses it. The extra time spent copying data between caches adds up fast, especially when the operation you're doing (incrementing an integer) is so trivial.
A few things:
You should probably test each setup at least 10 times and take the average
As far as I know, Thread.sleep is not exact - it depends on how the OS switches your threads
Thread.join is not immediate. Again, it depends on how the OS switches your threads
A better way to test would be to run a computationally intensive operation (say, sum from one to a million) on two configurations and time them. For example:
Time how long it takes to sum from one to a million
Time how long it takes to sum one to 500000 on one thread and one 500001 to 1000000 on another
You were right when you thought that two threads would work faster than one thread. But yours are not the only threads running - the OS has threads, your browser has threads, and so on. Keep in mind that your timings will not be exact and may even fluctuate.
Lastly, there are other reasons(see slide 24) why threads work slower.