• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Who called?

 
Ranch Hand
Posts: 344
Oracle Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have a method called "whoCalled". It returns the classname, methodname and line number of the method that called the original method. For instance say method A calls method B. If method B executes the whoCalled method, it will get the class/method name of method A.

Below is an example:


The output of above program is:

Basically in order to determine the calling method, I take the StackTrace (array of StackTraceElements) from a new Throwable instance, and return the 3rd item in that array (first item would the the whoCalled method itself, 2nd item the method that called it, etc.).

Are there other, perhaps more efficient or cleaner ways to achieve the same result, or is this it?
 
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As far as I know there isn't a much better / cleaner / more efficient way to do this.

I hope you're only using this for diagnostics (debug logging, for example). Your program will quickly become an entangled ball of spaghetti if the behaviour of methods changes depending on who's calling them. (You're adding nasty dependencies which will make the program very hard to understand).
 
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There's no need to create the Throwable instance. The Thread class has a method for giving you a stack trace.
 
Koen Aerts
Ranch Hand
Posts: 344
Oracle Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I tested the 2 different ways by timing "new Throwable()" vs "Thread.currentThread()" statements. It seems calling "new Throwable()" performs faster than "Thread.currentThread()" calls:

The result:

Not sure why that would be the case?
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Or to convert that to the cost of a single call:



Or to put it another way, you're saving 0.8 microseconds by creating a new Throwable object. That doesn't seem like a savings I would be actively seeking, since presumably in real life you wouldn't be doing this process millions of times anyway. (Right?) However you haven't included the cost of having that Throwable object garbage-collected, so your savings are less than 0.8 microseconds per call and possibly even negative.
 
Joanne Neal
Rancher
Posts: 3742
16
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:Or to convert that to the cost of a single call:



Or to put it another way, you're saving 0.8 microseconds by creating a new Throwable object. That doesn't seem like a savings I would be actively seeking, since presumably in real life you wouldn't be doing this process millions of times anyway. (Right?) However you haven't included the cost of having that Throwable object garbage-collected, so your savings are less than 0.8 microseconds per call and possibly even negative.


Except that the Thread method does this

which means they are doing the same thing except the Thread method checks if the thread it's being called on is the current thread which I assume is what causes it to be slighly slower
 
Koen Aerts
Ranch Hand
Posts: 344
Oracle Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The differences are probably negligible enough to be ignored. I just like to understand why things behave the way they do. For instance I had found that the String compareTo method is slighty faster than the equals method, however the equalsIgnoreCase method is significantly slower than equals.
 
Jesper de Jong
Java Cowboy
Posts: 16084
88
Android Scala IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Koen Aerts wrote:The differences are probably negligible enough to be ignored. I just like to understand why things behave the way they do. For instance I had found that the String compareTo method is slighty faster than the equals method, however the equalsIgnoreCase method is significantly slower than equals.


Micro-benchmarking is very difficult to do correctly on the JVM.

The JIT (Just In Time) compiler, that compiles Java bytecode to native machine code at runtime, contains many very sophisticated optimizations. It contains complicated logic to determine when to compile what parts of the code to native machine code, does inlining and a whole list of other optimizations, and can even in some special cases de-optimize code and then recompile it again to machine code.

Simply calling a method N times and measuring how long it takes often doesn't give you a timing number that's accurate to the last digit. It depends heavily on what decisions the JIT makes and can be different on different machines, at different times or across different JVM versions.

If you know what the methods of the String class do exactly, you could lookup the source code of class String; you'll find the source code in the file src.zip in your JDK installation directory.
 
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You ought to use the nanoseconds method of the System class. And you will find that performance varies considerably on repeated runs.
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:You ought to use the nanoseconds method of the System class. And you will find that performance varies considerably on repeated runs.


Except that System.nanoTime() takes about 5 times as long to run as System.currentTimeMillis() (at least on my machine).

Good old Heisenberg

Winston
 
Campbell Ritchie
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Earlier, I wrote: . . . you will find that performance varies considerably on repeated runs.

See, told you so.
 
Koen Aerts
Ranch Hand
Posts: 344
Oracle Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jesper de Jong wrote:

Koen Aerts wrote:The differences are probably negligible enough to be ignored. I just like to understand why things behave the way they do. For instance I had found that the String compareTo method is slighty faster than the equals method, however the equalsIgnoreCase method is significantly slower than equals.


Micro-benchmarking is very difficult to do correctly on the JVM.


That's true. And I did find that consecutive runs give slightly different results each time; however I do think in some cases it provides useful information, especially in cases where the performance difference between similar functions is fairly large. For instance 1 billion iterations over the String equals() method took about 500ms, but about 27 seconds for the equalsIgnoreCase() method. But you're right; millisecond differences are probably in most cases negligible.
 
Ranch Hand
Posts: 4716
9
Scala Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
don't you listen to them Koen. you had it pretty right from the start
 
Paul Clapham
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Following on from what Jesper mentioned about the JIT: if you're going to do a micro-benchmark where you time A and then time B, you should also do a similar micro-benchmark where you time B and then time A. That's because the JIT will wait for a while before it starts optimizing your code, so that earlier code can be less optimized.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic