JNI — UnsatisfiedLinkError

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.
LVL 25
InteractiveMindAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
Is the library in java.library.path?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
InteractiveMindAuthor Commented:
Well, I've tried executing like so:

java -Djava.library.path=. CJ_CpuUsage

But same problem.
CEHJCommented:
You can determine that property by

System.out.println(System.getProperty("java.library.path"));
new CJ_CpuUsage() ;
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

Mick BarryJava DeveloperCommented:
check that you've implemented the method sig correctly, and that you have included it in the JNI dll
Mick BarryJava DeveloperCommented:
Mick BarryJava DeveloperCommented:
> java -Djava.library.path=. CJ_CpuUsage

and thats fine :)
CEHJCommented:
Make sure your package structure is correct
Mick BarryJava DeveloperCommented:
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.
CEHJCommented:
>>Java_JCpuUsage_JCpuUsage

should be more like

Java_CJ_CpuUsage_JCpuUsage

i think, so make sure you have updated the native code
InteractiveMindAuthor 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 ;
}
CEHJCommented:
What's your package declaration?
InteractiveMindAuthor Commented:
package rob;

?
CEHJCommented:
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
CEHJCommented:
(Generated by the following command):

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

Cheers so far.
Mick BarryJava DeveloperCommented:
> 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
InteractiveMindAuthor 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 :)
CEHJCommented:
Well the last code you posted seemed to be largely commented out - apart from the bit that was returning zero ;-)
InteractiveMindAuthor 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%
CEHJCommented:
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
InteractiveMindAuthor Commented:
That's memory usage isn't it?
Mayank SAssociate Director - Product EngineeringCommented:
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?
InteractiveMindAuthor Commented:
My CPU usage is definitely above 0.
Mayank SAssociate Director - Product EngineeringCommented:
>> That's memory usage isn't it?

Yes. Its not CPU utilization.
Mayank SAssociate Director - Product EngineeringCommented:
Above 0 but what it if it is less than 1? Is there a harm trying to make it a double?
InteractiveMindAuthor 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 SAssociate Director - Product EngineeringCommented:
>> printf( "From Library: %i%s\n", usage, "%" ) ;
>> From Library: 0%

Then maybe that part is worth: >> I'll just bug jkr again ;)
Mayank SAssociate Director - Product EngineeringCommented:
>> Have tested -- it's definitely not returning some value below 0.

But that's not what the printf () prints?
InteractiveMindAuthor Commented:
What do you mean?
Mayank SAssociate Director - Product EngineeringCommented:
I mean the printf () also prints 0%, right? So with what did you test that you got a value different than 0?
Mayank SAssociate Director - Product EngineeringCommented:
What does the C++ code return when it is executed directly?
CEHJCommented:
Can you show the native code?
InteractiveMindAuthor 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?
CEHJCommented:
>>How to turn this into a percentage of use?

Well that's a good question ;-) And I don't know the answer
Mayank SAssociate Director - Product EngineeringCommented:
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 SAssociate Director - Product EngineeringCommented:
InteractiveMindAuthor 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 SAssociate Director - Product EngineeringCommented:
>> 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 :)
InteractiveMindAuthor Commented:
same prob
Mayank SAssociate Director - Product EngineeringCommented:
Try on another machine.
CEHJCommented:
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
InteractiveMindAuthor 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
InteractiveMindAuthor 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  =)
CEHJCommented:
The API documentsexplain that
CEHJCommented:
Sorry - wrong Q ;-)
Mick BarryJava DeveloperCommented:
glad to help :)
CEHJCommented:
:-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.