0

I have an app that uses performance counters to get the cores/threads load and finding the highest value. Since there are 12/16/36 etc. threads normally in our days, I used a List and Math.Max to find the highest load.

However, the refresh interval is 100ms, so it must make calculations 600 times per minute and I want to optimize the code as much as possible, to be able to go with the even faster refresh rate.

What is the most efficient way to do that? I read the THREAD about it where people tested the efficiency, and while some say there is nearly no difference between Math.Max and for/while/if implementation, others say that when you work with doubles or float (which is what I have), the difference is huge, 0.3465041 sec for inline implementation and 6 sec for Math.Max.

So, what will be the best way to do the calculations in your opinion and how it can be done with a List? Thank you in advance! Here is what I use ATM:

 private void maxThreadTimer_Tick(object sender, EventArgs e) //Max Thread Timer
    {
    float allCores1 = coreLoad1.NextValue();
    float allCores2 = coreLoad2.NextValue();
    float allCores3 = coreLoad3.NextValue();
    float allCores4 = coreLoad4.NextValue();
    float allCores5 = coreLoad5.NextValue();
    float allCores6 = coreLoad6.NextValue();
    float allCores7 = coreLoad7.NextValue();
    float allCores8 = coreLoad8.NextValue();
    float allCores9 = coreLoad9.NextValue();
    float allCores10 = coreLoad10.NextValue();
    float allCores11 = coreLoad11.NextValue();
    float allCores12 = coreLoad12.NextValue();
    float allCores13 = coreLoad13.NextValue();
    float allCores14 = coreLoad14.NextValue();
    float allCores15 = coreLoad15.NextValue();
    float allCores16 = coreLoad16.NextValue();

    List<float> valuesList = new List<float> { allCores1, allCores2, 
    allCores3, allCores4, allCores5, allCores6, allCores7, allCores8, 
    allCores9, allCores10, allCores11, allCores12, allCores13, allCores14, 
    allCores15, allCores16 };

    float tMax = valuesList.Max();
    }
DIY Mods
  • 79
  • 2
  • 9
  • The article you referred to is about `Math.Max()`, not `IEnumerable.Max()`. – Andrew Morton Feb 27 '20 at 16:11
  • ...which would be like doing `float max = coreLoad1.NextValue(); max = Math.Max(max, coreLoad2.NextValue(); max = Math.Max(max, coreLoad3.NextValue();` etc. You would have to measure the performance to see if it made any meaningful difference. – Andrew Morton Feb 27 '20 at 16:13
  • I'm not sure if it makes a difference. Bare with me, please, I'm a noob. So, the question remains intact - What is the most efficient way to implement it? – DIY Mods Feb 27 '20 at 16:14
  • @DIYMods Is the List only created for the purpose of finding the maximum value, or is it used again? – Andrew Morton Feb 27 '20 at 16:18
  • @ AndrewMorton Only to find a max value – DIY Mods Feb 27 '20 at 16:27
  • @DIYMods And what is done with that max value afterwards? – Andrew Morton Feb 27 '20 at 16:28
  • @ AndrewMorton It is used to draw the chart which shows the highest thread load – DIY Mods Feb 27 '20 at 16:31
  • @DIYMods The time taken to update the chart probably vastly outweighs finding the max value. You should profile your program to find where real, useful speed gains can be made; the [built-in tools](https://learn.microsoft.com/en-us/visualstudio/profiling/beginners-guide-to-performance-profiling?view=vs-2019) might be enough. – Andrew Morton Feb 27 '20 at 18:28

3 Answers3

2

I would have thought that the vast majority of the overhead was coming from the individual calls to coreLoadX.NextValue() and that any optimisations you make to the code that's trying to find the maximum value will have little noticeable effect.

Having said that, for the code you gave the most performant solution is likely to be:

float max = coreLoad1.NextValue();

float value = coreLoad2.NextValue();

if (value > max)
    max = value;

value = coreLoad3.NextValue();

if (value > max)
    max = value;

value = coreLoad4.NextValue();

if (value > max)
    max = value;

value = coreLoad5.NextValue();

if (value > max)
    max = value;

value = coreLoad6.NextValue();

if (value > max)
    max = value;

value = coreLoad7.NextValue();

if (value > max)
    max = value;

value = coreLoad8.NextValue();

if (value > max)
    max = value;

value = coreLoad9.NextValue();

if (value > max)
    max = value;

value = coreLoad10.NextValue();

if (value > max)
    max = value;

value = coreLoad11.NextValue();

if (value > max)
    max = value;

value = coreLoad12.NextValue();

if (value > max)
    max = value;

value = coreLoad13.NextValue();

if (value > max)
    max = value;

value = coreLoad14.NextValue();

if (value > max)
    max = value;

value = coreLoad15.NextValue();

if (value > max)
    max = value;

value = coreLoad16.NextValue();

if (value > max)
    max = value;

That's just your common-or-garden variety of "unroll the loop".

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • I'm just curious about a concept. Assuming it's possible to make an ArrayList of coreLoad instead of having 16 seperate coreLoad objects, would a for loop be as efficient, or possibly even more efficient than using so many if statements? Or would calling values through ArrayList and the extra step of having to change the reference through the ArrayList slow it down? – Josh Heaps Feb 27 '20 at 17:48
  • 1
    @JoshHeaps Each access to an item in the ArrayList would require a call to an indexing method to return the value (which, given an ArrayList, would be boxed which would further mean an unboxing operation - although using a List instead of ArrayList would avoid that). Then when looping through the list, you would need to check an index against the array size for each iteration. And finally, you would STILL need to do the comparison of the current max value with each value in the array. So using an ArrayList (or List) would for sure make it slower. – Matthew Watson Feb 27 '20 at 18:49
  • that's what I was thinking. I've just been told by so many people that using so many if statements is a bad thing that I'm always curious to find out whether or not a way with more if statements can be better. I'm looking for those cases, and here is a great one. Thank you! – Josh Heaps Feb 27 '20 at 19:16
1

Creating any collection just to perform a Max operation is going to be overhead you don't need, especially if you're not going to use the collection later. Make a local method that tracks the max as items are evaluated. This ends up being ~150ms over a million iterations:

private void maxThreadTimer_Tick(object sender, EventArgs e)
{
    float tMax = 0;
    void TrackMax(float value)
    {
        if (value > tMax)
            tMax = value;
    }

    TrackMax(coreLoad1.NextValue());
    TrackMax(coreLoad2.NextValue());
    // etc etc etc
}
Chaos
  • 250
  • 2
  • 10
  • Unfortunately, this method loads the single-core to the extreme. "if" method - 4-5%, this method 95-100% – DIY Mods Feb 27 '20 at 19:12
  • Then you have something else involved, or are doing something wrong. 100 million iterations over both this method and the "if" method shows the exact same cpu profile. – Chaos Feb 27 '20 at 19:25
0

I think that what you need is a SortedSet<T>. This has several advantages:

  1. No duplicates
  2. Always sorted
  3. Generic, which means you can use any type
  4. You have the Max and Min properties

See more here: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.sortedset-1.

Ricardo Peres
  • 13,724
  • 5
  • 57
  • 74