Jump to content

Need 64-bit Memory Monitor


Cat

Recommended Posts

I am in dire need of a way to get the available physical memory on a 64-bit computer. I've always used lvwutil32.dll, but obviously that won't work on a 64-bit machine. I thought I had figured out a .NET widget to use for both 32-bit and 64-bit (System.Diagnostics.PerformanceCounter-->Available Physical Memory). It works, but it is sloooooooow. Takes 30 seconds to do what lvutil32.dll would do in a couple seconds. I am admittedly a complete newbie at .NET, so I could be doing something wrong.

I would love something that will work for both 32/64-bit, but at this point would settle for it just working on a 64-bit machine. Anyone out there have anything?

Cat

Link to comment

Have you tried using the Windows API? The function GetProcessMemoryInfo is a likely candidate.

Well, right, tho I would probably use GlobalMemoryStatusEx, since it is overall system free physical memory that I am looking for. It, however, uses kernel32.dll and I'm going to have to keep my fingers crossed that it's going to work on a 64-bit machine (with more than 4GB memory).

Looks like I'm going to have to dust off my notes on how to code up a Call Library Function node. :book:

Link to comment

This isn't a terribly complex API call, so I doubt you'll need this, but I had a play at it. The cluster should be typedef'd, but ehhhh. If you use this and your computer explodes, I am not liable, etc etc. I've only tested it on Windows 7 x86, LV 8.6 and LV2009.

A customer has had me doing a lot of API-based stuff lately, so I've developed a sick fascination with these. I had a pipe-dream of developing a ShellIcon library in LV, that might come to fruition soon.

GlobalMemoryStatusEx.vi

Get Win32 Error Message.vi

Edited by asbo
  • Like 1
Link to comment

This isn't a terribly complex API call, so I doubt you'll need this, but I had a play at it.

Excellent! I have to have the huge piece of code this will be integrated into working by monday, and will be out of the office until sunday, so I wasn't sure when I was going to find the time to do it. Thank you!

Link to comment
  • 10 months later...

This isn't a terribly complex API call, so I doubt you'll need this, but I had a play at it. The cluster should be typedef'd, but ehhhh. If you use this and your computer explodes, I am not liable, etc etc. I've only tested it on Windows 7 x86, LV 8.6 and LV2009.

Talk about taking my time getting back to someone... :)

asbo, obviously I never got a chance to try your code out. A few months ago I started getting complaints about longer than normal wait times on starting up my Big Project. Most of my users had recently upgraded to 64-bit Win7 machines. This problem was worse on those than the 32-bit WinXP machines. I finally tracked the problem down to a delay being caused when I opened a reference to a vi that was using .NET to get the available physical memory. Hoping someone here had solved this problem, I hopped on to LAVA, did a search, and ended up at this thread... :lol:

I think I'm getting senile!

Anywho, to make a long story even longer, I tried the code you wrote and it works perfectly, on both types of platforms. Thanks again!

Link to comment

Anywho, to make a long story even longer, I tried the code you wrote and it works perfectly, on both types of platforms. Thanks again!

One or two nitpicks. GetLastError() queries a thread global variable in kernel32.dll and therefore can and usually only does return the right answer if called in the same thread than the function that caused the error. This might seem like being guaranteed by running the actual function call and GetLastError() in the UI thread, BUT unfortunately that doesn't work like that. LabVIEW is free to schedule other UI calls between the two CLNs such as drawing something in the front panel and many of those functions can also set the last error so the actual error caused by the first CLN might be already overwritten, when this VI tries to read it.

The solution is to make the VI subroutine priority, which will tell LabVIEW to execute the entire VI in the same thread without scheduling anything in between but that also requires to make the CLNs run in any thread, as subroutine VIs can not contain code that can run asynchronously such as CLNs set to run in the UI thread. Also GetErrorStatus needs to be changed to subroutine as well as a subroutine can only contain subroutine VIs.

Last but not least, GlobalMemoryStatusEx() returns a status of FALSE (0) on error and TRUE (<>0) on success. The GetLastError() and CO should only be executed when GlobalMemoryStatusEx() indicated a failure as Windows functions are not supposed to change the last error value on success at all, and you might retrieve a last error value from a previous API call somewhere in LabVIEW.

Get Win32 Error Message.vi

GlobalMemoryStatusEx.vi

  • Like 1
Link to comment

This is a very good point about the subroutine requirement, rolf, and I'll admit that that particular nuance of CLNs is something I learned after writing those VIs. However, my experience is different regarding GetLastError() in that applications can and will call SetLastError(0). In fact, from MSDN:

Functions executed by the calling thread set this value by calling the SetLastError[/url] function. You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.

However, I agree in principle that GetLastError should not be called unless the initial API call indicates an error was generated, as it could lead to mismatched error conditions.

Cat: glad this still ended up being useful for you. :)

Link to comment

This is a very good point about the subroutine requirement, rolf, and I'll admit that that particular nuance of CLNs is something I learned after writing those VIs. However, my experience is different regarding GetLastError() in that applications can and will call SetLastError(0). In fact, from MSDN:

MSDN only says that some functions might do that, not that it is how it should be done. Officially it is an error to do that, yet Microsoft tries often to accommodate even misbehaving applications for compatibility sake. In this case it is of course always safer to call GetLastError() immediately after a function indicated an error (and that function contract says it returns an error status in GetLastError()). Assuming however that GetLastError() returning non-null means the previous API did go wrong is ALWAYS wrong, since most APIs behave like MS meant it to be and do not overwrite the GetLastError() error status when they succeed.

Also you have to take LabVIEW into account here. A typical Windows API call is done from a C program and the C programmer controls thread execution completely and knows exactly what was called between any API call and the possible GetLastError() call. First if he doesn't explicitly pass control between the API call and the GetLastError() call to a different thread, (and which C programmer would do such a stupidity, since it is a lot of work and sweat to do multi-threading programming, so it doesn't happen accidentally?), he is sure that both calls are executed in the same thread. And he is exactly sure what other functions he may have called in between in that thread. In LabVIEW the only way to have a similar sure way of knowing is to use subroutines.

If two CLNs are set to execute in the UI, they will execute in the same thread but have to share that thread with a lot of other things in LabVIEW, especially UI execution. So there could be 200 other API calls in between done by LabVIEW, that all might have altered GetLastError(). If the CLNs are set to execute in any thread, they can and often will execute in different threads, so GetLastError() won't necessarily see the error code that the API possible has set, since Windows goes through a lot of trouble to make the GetLastError() value only thread global and not process global. In fact in Windows every thread has its own GetLastError() variable. The only way to guarantee that GetLastError() will see the error set by the previous API is to use subroutine, since LabVIEW guarantees, that the entire subroutine call will execute in the same thread and without any other interruption than what the OS might do to preempt a thread for its proper multi-threading operation.

Another point is of course that it's a rather brain dead idea to have an API that returns a boolean status to indicate one should call GetLastError() to get more information about the error, since GetLastError() also only returns a DWORD value which would just as well fit into the BOOL returned by the API. It made maybe a little sense in Win 3.1 where BOOL and DWORD were not the same size, but it could have been depreciated for any API that was introduced in Win95 or later. In fact the underlaying NT Kernel all returns HRESULT values, and the kernel32 and user32 API convert them to GetLastError(), since kernel32 and user32 are only really thin wrappers around ntdll.dll and similar other kernel APIs since Windows NT 4.

Link to comment

Well, maybe it's not "perfect". Would you take "good enough"? :P

Seriously, thanks for the warning, Rolf. I'll take a look at these calls more closely when I get back to that project.

Well as long as the API call doesn't run into an error, there is in fact not much which can go wrong in an application, depending how you react on the error output of that VI, of course. But likely you haven't really done anything with that. :P

And the changes that GlobalMemoryStatusEx() encounters an error are not that big, respectively if it does you are likely to be in more serious problems already, than that worrying about the GlobalMemoryStatusEx() function return value will make much of a difference.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.