• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 575
  • Last Modified:

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.
0
InteractiveMind
Asked:
InteractiveMind
  • 16
  • 15
  • 11
  • +1
4 Solutions
 
CEHJCommented:
Is the library in java.library.path?
0
 
InteractiveMindAuthor Commented:
Well, I've tried executing like so:

java -Djava.library.path=. CJ_CpuUsage

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

System.out.println(System.getProperty("java.library.path"));
new CJ_CpuUsage() ;
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

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

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

should be more like

Java_CJ_CpuUsage_JCpuUsage

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

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

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

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

Yes. Its not CPU utilization.
0
 
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?
0
 
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.
0
 
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 ;)
0
 
Mayank SAssociate Director - Product EngineeringCommented:
>> Have tested -- it's definitely not returning some value below 0.

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

Well that's a good question ;-) And I don't know the answer
0
 
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....
0
 
Mayank SAssociate Director - Product EngineeringCommented:
0
 
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....  :-\
0
 
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 :)
0
 
InteractiveMindAuthor Commented:
same prob
0
 
Mayank SAssociate Director - Product EngineeringCommented:
Try on another machine.
0
 
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
0
 
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
0
 
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  =)
0
 
CEHJCommented:
The API documentsexplain that
0
 
CEHJCommented:
Sorry - wrong Q ;-)
0
 
objectsCommented:
glad to help :)
0
 
CEHJCommented:
:-)
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 16
  • 15
  • 11
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now