We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you a podcast all about Citrix Workspace, moving to the cloud, and analytics & intelligence. Episode 2 coming soon!Listen Now

x

JNI — UnsatisfiedLinkError

InteractiveMind
on
Medium Priority
590 Views
Last Modified: 2013-11-23
Here's my Java class:


public class CJ_CpuUsage
{
      private native int JCpuUsage() ;
      
      
      public CJ_CpuUsage()
      {
            int c = this.JCpuUsage() ;
            System.out.println( c+"%" ) ;
      }
      
      public static void main( String [] args )
      {
            new CJ_CpuUsage() ;
      }
      
      static
      {
            System.loadLibrary( "JCpuUsage" ) ;
      }
}


I've compiled a C++ DLL, called JCpuUsage -- with a CPP file and header called JCpuUsage, with the following function sig:

JNIEXPORT jint JNICALL Java_JCpuUsage_JCpuUsage
  (JNIEnv *, jobject);

The DLL is in the same directory as my class.

I've added both the DLL itself, and the current directory to the PATH variable, and have tried running it...

However, I keep getting the following error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: JCpuUsage
      at CJ_CpuUsage.JCpuUsage(Native Method)
      at CJ_CpuUsage.<init>(CJ_CpuUsage.java:8)
      at CJ_CpuUsage.main(CJ_CpuUsage.java:14)

Line 8 obviously being:

    int c = this.JCpuUsage() ;


Any ideas why ?!

Thanks very much.
Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2016
Commented:
Is the library in java.library.path?

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
Top Expert 2006

Author

Commented:
Well, I've tried executing like so:

java -Djava.library.path=. CJ_CpuUsage

But same problem.
CERTIFIED EXPERT
Top Expert 2016

Commented:
You can determine that property by

System.out.println(System.getProperty("java.library.path"));
new CJ_CpuUsage() ;
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010
Commented:
check that you've implemented the method sig correctly, and that you have included it in the JNI dll
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010
Commented:
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
> java -Djava.library.path=. CJ_CpuUsage

and thats fine :)
CERTIFIED EXPERT
Top Expert 2016

Commented:
Make sure your package structure is correct
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010
Commented:
the code isn't in a package.
Might be a good idea to add it to one though, its a good habit to get into.
CERTIFIED EXPERT
Top Expert 2016

Commented:
>>Java_JCpuUsage_JCpuUsage

should be more like

Java_CJ_CpuUsage_JCpuUsage

i think, so make sure you have updated the native code
Top Expert 2006

Author

Commented:
Have shoved it in a package - and it's made no difference.


Here's my JCpuUsage.h file:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JCpuUsage */

#ifndef _Included_JCpuUsage
#define _Included_JCpuUsage
/*
 * Class:     JCpuUsage
 * Method:    JCpuUsage
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_JCpuUsage_JCpuUsage
  (JNIEnv *, jobject);

#endif


And my JCpuUsage.cpp:

#include <jni.h>
#include "JCpuUsage.h"
#include "CpuUsage.h"

JNIEXPORT jint JNICALL Java_JCpuUsage_JCpuUsage(JNIEnv * env, jobject obj)
{
    //CCpuUsage cpu ;
    //int usage = cpu.GetCpuUsage() ;
    ////convert 'usage' to jint instance
    jint i = 0 ;
    return i ;
}
CERTIFIED EXPERT
Top Expert 2016

Commented:
What's your package declaration?
Top Expert 2006

Author

Commented:
package rob;

?
CERTIFIED EXPERT
Top Expert 2016

Commented:
With that package, you should get something more like:


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class rob_CJ_CpuUsage */

#ifndef _Included_rob_CJ_CpuUsage
#define _Included_rob_CJ_CpuUsage
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     rob_CJ_CpuUsage
 * Method:    JCpuUsage
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_rob_CJ_1CpuUsage_JCpuUsage
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
CERTIFIED EXPERT
Top Expert 2016

Commented:
(Generated by the following command):

javah rob.CJ_CpuUsage
Top Expert 2006

Author

Commented:
Okay, thanks very much — I will have to try this stuff tomorrow now .. am getting sleepy.  :(

Cheers so far.
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
> Okay, thanks very much — I will have to try this stuff tomorrow now .. am getting sleepy.  :(

see the link I posted above, it covers step by step whats needed to create the dll
Top Expert 2006

Author

Commented:
Yay, after a good nights sleep, and starting from scrap (using a package, and giving more appropriate names to the classes etc to avoid confusion) it's interfacing nicely with the native code :)

It is strange however -- my CCpuUsage class (which is the native code that returns the actual CPU usage value) keeps returning 0; although it worked fine when I used it in a test EXE yesterday...

Any guesses as to why this is playing up? Could it be anything to do with JNI?

If not, then that's cool — I'll just bug jkr again ;)


Thanks :)
CERTIFIED EXPERT
Top Expert 2016

Commented:
Well the last code you posted seemed to be largely commented out - apart from the bit that was returning zero ;-)
Top Expert 2006

Author

Commented:
lol No no, I've edited that portion of the code, so that it does return what I want ;)

JNIEXPORT jint JNICALL Java_rob_OutputCpuUsage_CpuUsage( JNIEnv * env, jobject obj )
{
    CCpuUsage cpu ;
    jint usage = cpu.GetCpuUsage() ;
   
    printf( "From Library: %i%s\n", usage, "%" ) ;
   
    return usage ;
}


The output is:

From Library: 0%
Current CPU Usage: 0%
CERTIFIED EXPERT
Top Expert 2016

Commented:
Incidentally, in case you're not aware, you can do this in pure Java >= 1.5:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/MemoryUsage.html
Top Expert 2006

Author

Commented:
That's memory usage isn't it?
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
Well, it depends :) sometimes if the CPU usage is less than 1% (like 0.5%), it might return a 0. Can you try returning a double?
Top Expert 2006

Author

Commented:
My CPU usage is definitely above 0.
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
>> That's memory usage isn't it?

Yes. Its not CPU utilization.
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
Above 0 but what it if it is less than 1? Is there a harm trying to make it a double?
Top Expert 2006

Author

Commented:
Have tested -- it's definitely not returning some value below 0.

Besides, the GetCpuUsage() function that I'm calling doesn't even return that data type.. it should be returning an integer from 0-100.
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
>> printf( "From Library: %i%s\n", usage, "%" ) ;
>> From Library: 0%

Then maybe that part is worth: >> I'll just bug jkr again ;)
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
>> Have tested -- it's definitely not returning some value below 0.

But that's not what the printf () prints?
Top Expert 2006

Author

Commented:
What do you mean?
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
I mean the printf () also prints 0%, right? So with what did you test that you got a value different than 0?
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
What does the C++ code return when it is executed directly?
CERTIFIED EXPERT
Top Expert 2016

Commented:
CERTIFIED EXPERT
Top Expert 2016

Commented:
Can you show the native code?
Top Expert 2006

Author

Commented:
wowowowow...

You can retrieve the CPU usage (as a percentage) using pure Java ?!

Okay, I can get the CPU time:

long cpu_time = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime() ;

How to turn this into a percentage of use?
CERTIFIED EXPERT
Top Expert 2016

Commented:
>>How to turn this into a percentage of use?

Well that's a good question ;-) And I don't know the answer
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
I don't think Java lets you get the CPU usage directly because there could be multiple processors. All you can get is the number of processors you have (Runtime.getRuntime ().getAvailableProcessors () or something similar), and the time associated with each thread....
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
Top Expert 2006

Author

Commented:
I've tried existing ones (including that one from JavaWorld), but they never compile for me... I don't know if my IDE just doesn't like them, or what..

So, jkr helped me adapt an existing one online yesterday, such that it does compile fine (and work) in my IDE, Dev-C++.


Hmm, uh oh...

I just tested my CCpuUsage class using some native code (compiled and ran as an EXE), and it's returning 0 as well... :(

That's really strange. That class was working fine yesterday...


I think I'll go bug jkr then....  :-\
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
>> and it's returning 0 as well...
>> That class was working fine yesterday...

Maybe your CPU utilization has gone down ;-) he he.... try keeping some 100 applications on and then try :)
Top Expert 2006

Author

Commented:
same prob
Mayank SPrincipal Technologist
CERTIFIED EXPERT

Commented:
Try on another machine.
CERTIFIED EXPERT
Top Expert 2016

Commented:
Check your arithmetic in your native code and make sure it's  using types large enough to hold the large numbers involved or you may get overflow
Top Expert 2006

Author

Commented:
Okay, I just went through the C++ code, and think I've found what the problem is (but am not sure how to fix it)...

Here's the function that I'm calling (which in turn calls other functions):


int CCpuUsage::GetCpuUsage()
{
      static PLATFORM Platform = GetPlatform();

      if (m_bFirstTime)
            EnablePerformaceCounters();
      
      // Cpu usage counter is 8 byte length.
      CPerfCounters<LONGLONG> PerfCounters;
      char szInstance[256] = {0};

//            Note:
//            ====
//            On windows NT, cpu usage counter is '% Total processor time'
//            under 'System' object. However, in Win2K/XP Microsoft moved
//            that counter to '% processor time' under '_Total' instance
//            of 'Processor' object.
//            Read 'INFO: Percent Total Performance Counter Changes on Windows 2000'
//            Q259390 in MSDN.

      DWORD dwObjectIndex;
      DWORD dwCpuUsageIndex;
      switch (Platform)
      {
      case WINNT:
            dwObjectIndex = SYSTEM_OBJECT_INDEX;
            dwCpuUsageIndex = TOTAL_PROCESSOR_TIME_COUNTER_INDEX;
            break;
      case WIN2K_XP:
            dwObjectIndex = PROCESSOR_OBJECT_INDEX;
            dwCpuUsageIndex = PROCESSOR_TIME_COUNTER_INDEX;
            strcpy(szInstance,"_Total");
            break;
      default:
            return -1;
      }

      int                        CpuUsage = 0;
      LONGLONG            lnNewValue = 0;
      PPERF_DATA_BLOCK pPerfData = NULL;
      LARGE_INTEGER      NewPerfTime100nSec = {0};
   
      lnNewValue = PerfCounters.GetCounterValue(&pPerfData, dwObjectIndex, dwCpuUsageIndex, szInstance);
      NewPerfTime100nSec = pPerfData->PerfTime100nSec;

      if (m_bFirstTime)
      {
            m_bFirstTime = false;
            m_lnOldValue = lnNewValue;
            m_OldPerfTime100nSec = NewPerfTime100nSec;
            return 0;
      }
   
      LONGLONG lnValueDelta = lnNewValue - m_lnOldValue;
      double DeltaPerfTime100nSec = (double)NewPerfTime100nSec.QuadPart - (double)m_OldPerfTime100nSec.QuadPart;

      m_lnOldValue = lnNewValue;
      m_OldPerfTime100nSec = NewPerfTime100nSec;

      double a = (double)lnValueDelta / DeltaPerfTime100nSec;

      double f = (1.0 - a) * 100.0;
      CpuUsage = (int)(f + 0.5);      // rounding the result
      
      if (CpuUsage < 0)
            return 0;
      return CpuUsage;
}


Take note to this section:

      if (m_bFirstTime)
      {
            m_bFirstTime = false;
            m_lnOldValue = lnNewValue;
            m_OldPerfTime100nSec = NewPerfTime100nSec;
            return 0;
      }

It doesn't seem to get past this -- it would seem that m_bFirstTime is true all the time... it is initialized to true when I create an instance of the CCpuUsage class. It only seems to be set to false on the second call of that function.

So, I thought that I'd change my function to:

JNIEXPORT jint JNICALL Java_rob_OutputCpuUsage_CpuUsage( JNIEnv * env, jobject obj )
{
    CCpuUsage cpu ;
    jint usage = cpu.GetCpuUsage() ;
    usage = cpu.GetCpuUsage() ;        // Call GetCpuUsage() a second time
   
    printf( "From Library: %i%s\n", usage, "%" ) ;
   
    return usage ;
}

When I run this several times, it _sometimes_ output 100% -- but still, most of the time, it's still 0%.

Any ideas?

Thanks
Top Expert 2006

Author

Commented:
Well, I bugged Jkr, and it turned out that the interval between the first call, and the second call of the native function was not large enough — so, he worked his magic, and added some struct etc etc, and somehow, it all works fine now !

Thanks for all the help with the initial problem guys — points to objects and CEHJ  =)
CERTIFIED EXPERT
Top Expert 2016

Commented:
The API documentsexplain that
CERTIFIED EXPERT
Top Expert 2016

Commented:
Sorry - wrong Q ;-)
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
glad to help :)
CERTIFIED EXPERT
Top Expert 2016

Commented:
:-)
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.