# GPU-Z Shared Memory Class in C#



## Kreij (Apr 15, 2012)

I wrote a C# class that reads the shared memory from GPU-Z.
It doesn't use DLLImport or PInvoke (but it does require .Net 4), as it uses the new MemoryMappedFiles (MMF) namespace they added in 4.0

The problem is that I can't think of anything useful to do with it that I can't get from just running GPU-Z. :/

Any thought fellow coders and users of GPU-Z?

I'll happily post the class source code when I nail down all the output requirements needed for any ideas you gents (and ladies) throw out.


----------



## FordGT90Concept (Apr 15, 2012)

Graph clockspeeds and memory usage.


----------



## Kreij (Apr 17, 2012)

134 views and only one suggestion? (Thanks Ford)
You guys suck at ideas as much as I do.


----------



## Mindweaver (Apr 17, 2012)

Yea.. I'm drawing blanks.. Oh course I've not had my full dose of caffeine yet... But I'm working on it...lol but right now.. I got nothing...


----------



## Kreij (Apr 17, 2012)

I could always just toss the class code out and let people play with it.
I just wanted to get some ideas what output formats (Arrays, Lists, etc.) might be useful for others and add them as methods to the class.

Curently what I have is ..

```
void ReadSharedMemory() // Reads data from shared mem into classes
List<KeyValuePair<string, string>> GetListOfRecords(); // Return a list of GPUZ_RECORD
KeyValuePair<string, string>[] GetArrayOfRecords(); // Returns an array of GPUZ_RECORD

List<GPUZ_SENSOR_RECORD> GetListOfSensors(); // Returns list of the sensor records.
GPUZ_SENSOR_RECORD[] GetArrayOfSensors(); // Returns an array of sensor records.

KeyValuePair<string, string> GetRecordByName (string name);
GPUZ_SENSOR_RECORD GetSensorByName (string name);

KeyValuePair<string, string> GetRecordByIndex (int index);
GPUZ_SENSOR_RECORD GetSensorByIndex (int index);
```

Anyone want to run a quick test on this stub program for me?
Launch program, hit button. See if records print out (no sensor records, just board records)
Try with GPU-Z running and not (It should detect if GPU-Z is running).
You need .Net 4

Thanks !!


----------



## Munki (Apr 18, 2012)

Without GPU-Z running:







With GPU-Z Running:


----------



## TissueBox (Apr 18, 2012)

Not running: 






Running:


----------



## Kreij (Apr 18, 2012)

Thanks kids !!
Munki sent me a PM pointing out my incorrect use of "it's" instead of "its" in the error message.
Please feel free to trash me if you are a grammar nazi.  (it's been corrected in the code)

If someone could try running it on a 32-bit box I would appreciate it. No need for screens, just let me know if you encounter any problems.

@TissueBox : Welcome to P&W, our little corner of the world. Are you a coder?


----------



## Munki (Apr 18, 2012)

Kreij said:


> Thanks kids !!
> Munki sent me a PM pointing out my incorrect use of "it's" instead of "its" in the error message.
> Please feel free to trash me if you are a grammar nazi.  (it's been corrected in the code)
> 
> ...



 I'm far from a grammar Nazi. I was born and raised in Georgia, my grammar is horrid


----------



## Kreij (Apr 18, 2012)

Sorry Munki ... I meant to say "if y'all a grammar nazi" 

I coded the class in a separate class file and removed the MessageBox error.
I replaced it with an accessor (property called GPUZ_Running) so you can handle the fact GPU-Z may not be running yourself.


```
GPUZ_SHMEM shMem = new GPUZ_SHMEM();
if (!shMem.GPUZ_Running)
{
    // handle it however you want
}
else shMem.ReadSharedMem();
```

Here's the class code if anyone want to take a look ...


Spoiler: Free Code Inside!





```
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace WindowsFormsApplication1
{
    public class GPUZ_SHMEM
    {
        private const int MAX_RECORDS = 128;
        private bool gPUZ_Running = false;

        public class GPUZ_SENSOR_RECORD
        {
            public string name;
            public string unit;
            public UInt32 digits;
            public Double value;
        };

        public class GPUZ_SH_MEM
        {
            public UInt32 version;
            public volatile Int32 busy;
            public UInt32 lastUpdate;
            public List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>(MAX_RECORDS);
            public List<GPUZ_SENSOR_RECORD> sensors = new List<GPUZ_SENSOR_RECORD>(MAX_RECORDS);
        };

        public GPUZ_SH_MEM shMem = new GPUZ_SH_MEM();

        public GPUZ_SHMEM()
        {
            // Check to see if GPU-Z is running.
            foreach (Process p in Process.GetProcesses())
            {
                if (p.ProcessName.Contains("GPU-Z")) gPUZ_Running = true;
            }
        }

        public bool GPUZ_Running { get { return gPUZ_Running; } }

        public void ReadSharedMemory()
        {

            string key, value;
            string name, unit;

            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("GPUZShMem"))
            {
                using (MemoryMappedViewStream mmvs = mmf.CreateViewStream())
                {
                    BinaryReader reader = new BinaryReader(mmvs, Encoding.Unicode);

                    shMem.version = reader.ReadUInt32();
                    shMem.busy = reader.ReadInt32();
                    shMem.lastUpdate = reader.ReadUInt32();

                    for (int i = 0; i < MAX_RECORDS; i++)
                    {
                        // Remove any null values in the key array
                        key = new string(reader.ReadChars(256)).Trim('\0');
                        if (key.Contains("\0")) key = key.Substring(0, key.IndexOf("\0"));

                        // Remove any null values in the value array
                        value = new string(reader.ReadChars(256)).Trim('\0');
                        if (value.Contains("\0")) value = value.Substring(0, value.IndexOf("\0"));

                        // Only add List item if there is a valid key
                        if (key != String.Empty)
                        {
                            KeyValuePair<string, string> dataItem = new KeyValuePair<string, string>(key, value);
                            shMem.data.Add(dataItem);
                        }
                    }

                    for (int i = 0; i < MAX_RECORDS; i++)
                    {
                        // Remove any null values in the name array
                        name = new string(reader.ReadChars(256)).Trim('\0');
                        if (name.Contains("\0")) name = name.Substring(0, name.IndexOf("\0"));

                        // Remove any null values in the unit array
                        unit = new string(reader.ReadChars(8)).Trim('\0');
                        if (unit.Contains("\0")) unit = unit.Substring(0, unit.IndexOf('\0'));

                        // Only add List item if there is a valid name
                        if (name != String.Empty)
                        {
                            GPUZ_SENSOR_RECORD sensorItem = new GPUZ_SENSOR_RECORD();
                            sensorItem.name = name;
                            sensorItem.unit = unit;
                            sensorItem.digits = reader.ReadUInt32();
                            sensorItem.value = reader.ReadDouble();

                            shMem.sensors.Add(sensorItem);
                        }
                    }
                }
            }
        }

        public List<KeyValuePair<string, string>> GetListOfRecords()
        {
            return shMem.data;
        }

        public KeyValuePair<string, string>[] GetArrayOfRecords()
        {
            KeyValuePair<string, string>[] kvpArray;
            return kvpArray = shMem.data.ToArray();
        }

        public List<GPUZ_SENSOR_RECORD> GetListOfSensors()
        {
            return shMem.sensors;
        }

        public GPUZ_SENSOR_RECORD[] GetArrayOfSensors()
        {
            GPUZ_SENSOR_RECORD[] sensorArrray;
            return sensorArrray = shMem.sensors.ToArray();
        }

        public KeyValuePair<string, string> GetRecordByName(string name)
        {
            foreach (KeyValuePair<string, string> k in shMem.data)
            {
                if (k.Key == name) return k;
            }

            // REturn a KVP with null values if name not found
            return new KeyValuePair<string, string>(null, null);
        }

        public GPUZ_SENSOR_RECORD GetSensorByName(string name)
        {
            foreach (GPUZ_SENSOR_RECORD r in shMem.sensors)
            {
                if (r.name == name) return r;
            }

            // Return a null class value if name not found
            return null;
        }

        public KeyValuePair<string, string> GetRecordByIndex(int index)
        {
            if (index >= 0 && index < shMem.data.Count) return shMem.data[index];
            else return new KeyValuePair<string, string>(null, null);

            // Returns a KVP with null values if index out of range
        }

        public GPUZ_SENSOR_RECORD GetSensorByIndex(int index)
        {
            if (index >= 0 && index < shMem.sensors.Count) return shMem.sensors[index];
            else return null;

            // Returns a null class value if index out of range.
        }
    }
}
```




It's C# code, I just used the php tags to give it a little color. 
As always, comments and suggestions appreciated !


----------



## TissueBox (Apr 19, 2012)

Kreij said:


> @TissueBox : Welcome to P&W, our little corner of the world. Are you a coder?



Unfortunately, I am not - I'm more of a guinea pig  

Looked at the "New Forum Posts" and decided to contribute something here


----------



## crazyeyesreaper (Apr 19, 2012)

hmm any chance you could set it to record and log memory usage kinda like fraps maybe? log min max avg memory usage i dont know lol maybe GPU-Z does that? i dont know drawing blanks just saying random shit that comes to mind


----------



## Aquinus (Apr 19, 2012)

Can GPU-Z run silently or minimized on start? If that can be done you could use the C# application to launch and close GPU-Z as needed.


----------



## librin.so.1 (Apr 19, 2012)

Kreij said:


> The problem is that I can't think of anything useful to do with it that I can't get from just running GPU-Z. :/
> 
> Any thought fellow coders and users of GPU-Z?



Idea! How 'bout such feature: "alert me if some monitored value goes above/beyond *value* and/or stays above/beyond *value* for more than *time interval*." ?
As far as I remember, GPU-Z can't do that.


----------



## Kreij (Apr 19, 2012)

TissueBox]Unfortunately said:


> hmm any chance you could set it to record and log memory usage kinda like fraps maybe? log min max avg memory usage i dont know lol maybe GPU-Z does that? i dont know drawing blanks just saying random shit that comes to mind



GPU-Z can log everything if you check the log to file CheckBox. It puts it in a CSV text file.



Aquinus said:


> Can GPU-Z run silently or minimized on start? If that can be done you could use the C# application to launch and close GPU-Z as needed.



You can start GPU-Z minimized by going into the shortcuts properties and set the run dropdown to minimized. It would be a simple thing to launch GPU-Z from any app.



Vinska said:


> Idea! How 'bout such feature: "alert me if some monitored value goes above/beyond *value* and/or stays above/beyond *value* for more than *time interval*." ?
> As far as I remember, GPU-Z can't do that.



That's a thought. A little, light wieght temp alarm utility. Any thoughts on how long it should read a "high" temp before alerting?

One of the current issues is that if you open two instances of GPU-Z (say for crossfired cards) it still writes the data to the same shared memory and it's kind of hit or miss what card readings you are going to get. Maybe one of these days W1zz will add full multi-GPU functionality to GPU-Z


----------



## librin.so.1 (Apr 19, 2012)

Kreij said:


> Any thoughts on how long it should read a "high" temp before alerting?



I would suggest two modes:
Monitor a user requested reading, with the ability to choose to trigger when going either below or above a user supplied value.
First mode: alert as soon as it is below/above the threshold.
Second mode: alert after it stays above/below the threshold longer than an interval which is also supplied by the user.
When monitoring more than one thing, the modes should be set "per rule". for example, with two rules: "alert if the GPU temp stays above 75°C for more than 300 seconds & alert immediately, if it goes above 90°"
or "immediately alert if the Vcore goes above 1.35V & alert if the GPU temp stays above 80°C for more than 60 seconds" and so on...

P.S. The "below" setting could be useful, for example, to spot a fan failure.


----------



## Kreij (Apr 19, 2012)

*Another Stub*

Here's another test stub.
It's should read the GPU Temp (only, not #1 - #3) for a single card or a crossfire pair.
You need to have two instances of GPU-Z running if using more than one card (and of course not have both instances pointing at the same card  )
It reads the shared mem every 500ms (this is somewhat problematic as it's still a bit of a crap shoot what card will be in the shared mem slot).

Anyone have a dual-GPU card they could try it on?

EDIT : No error checking to see if GPU-Z is running. It will throw an exception if no GPU-Z is available.

Thanks !


----------



## crazyeyesreaper (Apr 19, 2012)

well i was thinking more like if the card switches to 3D clocks then have it record memory usage,

GPU-Z tends to record constant makes it harder to pinpoint where Memory usage spikes im just being nitpicky tho as it would help pinpoint some of the harsher areas to test in games etc.

Still pretty cool stuff your doing here Kreij


----------



## Kreij (Apr 19, 2012)

I assume you mean memory on the GPU?
I have to look into this as only one of my corssfired cards shows dedicated and dynamic memory usage. Does the memory usage show up if you only have one card in?

I'm just throwing out little test programs right now to get a handle on what I can and cannot do with the shared memory.


----------



## crazyeyesreaper (Apr 19, 2012)

its no problem Kreij
and yea i ment Vram usage,

example i dont care what vram usage is when lvl is loading in BF3 for instance, as my GPU clocks are idle at the time, same goes for SHogun 2 it takes 5-6 mins to load a battle, so if it could trigger logging ONLY during 3D clocks it would be amazing as aka run a benchmark we know how long it is, can use fraps for instance to test frame rates but at the same time, i can log just 3D vram usage on a second by second basis, might be way to hard to do, just something i find interesting.

im only running 1 card right now and GPU-Z seems to be reporting memory usage properly


----------



## Paciente8159 (May 21, 2012)

I've made an overlay info display (small but practical) to run over a game or app on a corner of the screen.
I can have realtime info of my gpu without leaving the game.

Just an ideia..


----------



## librin.so.1 (May 23, 2012)

Kreij said:


> Here's another test stub.
> It's should read the GPU Temp (only, not #1 - #3) for a single card or a crossfire pair.
> You need to have two instances of GPU-Z running if using more than one card (and of course not have both instances pointing at the same card  )
> It reads the shared mem every 500ms (this is somewhat problematic as it's still a bit of a crap shoot what card will be in the shared mem slot).
> ...



So, I finally got some time to relax from my studies, so I booted up window$.
I checked how is that utility working... it doesn't look too well - monitors the max GPU clock reached.

Yet, it looks promising, if ever going to be completed ;]

I attached a screenshot:


----------



## Kreij (May 23, 2012)

LOL ... didn't do that before. Something must have changed in 0.6.2

I've put this project on hold at the moment.
It's really unreliable for reading two cards, unfortunately. I'm hoping W1zz decides to add mutli-card support to the shared mem one of these days.


----------



## FordGT90Concept (May 26, 2012)

I noticed the NVIDIA Quadro driver (version 29#) had an option to install a WMI library.  Has anyone taken a look into that?


----------



## pspost (Jun 2, 2012)

Hello!

Please tell me why do we have to deal with GPU-Z and SharedMem interface? Why don't just read sensors as GPU-Z does? Is there GPU-Z source code? Or source code for reading sensors?

I'm not familiar  with this stuff (sensors reading) hence such a question I asked.

Thanks.

Paul


----------



## Kreij (Jun 4, 2012)

Hi Paul, and welcome to TPU 

GPU-Z is free, but proprietary (no source available). W1zz added the shared mem so other apps could access what it's reading from the GCs.
Sure, you could write your own driver to replicate what GPU-Z does if you are so inclined, but that's not something I'm really interesting in doing since GPU-Z already does it.


----------



## pspost (Jun 4, 2012)

Kreij said:


> but that's not something I'm really interesting in doing since GPU-Z already does it.


That is the point: eliminate third parties(GPU-Z) from getting sensors data, so your application can standalone monitor GC state.

Why own driver? I thought there should be common WinAPI for doing this.


----------



## librin.so.1 (Jun 5, 2012)

pspost said:


> Why own driver? I thought there should be common WinAPI for doing this.



IIRC, You need to 'talk' to the graphics driver to do that.
The fun part is that there are several GPU vendors, along with various driver versions that take courtesy of changing/updating the way You can poll the data from it once in a while with new* versions of the driver. I suppose that includes asking the GPU makers to share with You how to access this data, probably under a NDA, or trying to figure it out Yourself  (probably the 'reverse-engineering' way).
Thus, it doesn't look like a trivial task.

*'new' is relative.


----------

