commons-lang icon indicating copy to clipboard operation
commons-lang copied to clipboard

LANG-1747: Measure the execution time of functional interfaces

Open obfischer opened this issue 1 year ago • 19 comments

https://issues.apache.org/jira/browse/LANG-1747

The StopWatch is now able to take the execution time for the execution of an implementation of the following interfaces:

  • java.util.function.BiConsumer
  • java.util.function.BiFunction
  • java.util.function.BiPredicate
  • java.util.function.Consumer
  • java.util.function.Function
  • java.util.function.Predicate
  • java.util.function.Supplier
  • org.apache.commons.lang3.function.FailableBiConsumer
  • org.apache.commons.lang3.function.FailableBiFunction
  • org.apache.commons.lang3.function.FailableBiPredicate
  • org.apache.commons.lang3.function.FailableConsumer
  • org.apache.commons.lang3.function.FailableFunction
  • org.apache.commons.lang3.function.FailablePredicate
  • org.apache.commons.lang3.function.FailableRunnable
  • org.apache.commons.lang3.function.FailableSupplier
  • org.apache.commons.lang3.function.TriConsumer
  • org.apache.commons.lang3.function.TriFunction

obfischer avatar Jul 26 '24 20:07 obfischer

@garydgregory Could you please review the first draft, so that I could have a early feedback before I continue?

obfischer avatar Jul 26 '24 20:07 obfischer

@garydgregory I nearly finished. I will ping you, if I am done.

obfischer avatar Aug 02 '24 22:08 obfischer

@garydgregory MR is ready for review

obfischer avatar Aug 11 '24 12:08 obfischer

  • Out of all of these new APIs, which ones do you actually need?

    • Let's not add every functional interface unless they are actually fulfill a use case

    • Use failable versions

All of them. Over the years I hat to measure some of them for statistics or debugging. So my decision was to provide an API which does not only covers my needs just in this monthm, but supports all standard interfaces in the JDK.

obfischer avatar Aug 14 '24 14:08 obfischer

@garydgregory I think I solved all open isssues. Ready for review again

obfischer avatar Aug 14 '24 14:08 obfischer

After looking some more at this PR, all the new methods "add" a duration to a stopwatch, which makes me wonder (as discussed on the mailing list), if all the new methods should be called "add". Food for thought...

Yes, I think we should consider this. add, takeTime or measure. But we should keep in mind, that the actual measurement is done during the execution of some of these methods. For example test(Predicate ..) does not measure any time at the moment of the method call. It returns only a wrapped instance, which will measure the time if executed once or multiple times.

What do you think?

obfischer avatar Aug 18 '24 11:08 obfischer

Hello @obfischer

  • The tests don't assert that the stopwatch measured time.
  • Another assertion would be that the lambda asserts that the stopwatch is running while it is invoked. For example:
            assertEquals("Foobar", watch.get((FailableSupplier<String, Throwable>) () -> {
                assertTrue(watch.isStarted());
                return "Foobar";
            }));
  • I don't understand your comment about test(Predicate..), what it supposed to be test(Predicate) or did you mean a vararg version of the API test(Predicate...)? What "wrapping" are you talking about? All the new methods don't "wrap" anything in the composition sense, they do delegate to the given lambda while managing the stopwatch state before and after the delegation. I must be missing something ;-)

garydgregory avatar Aug 20 '24 12:08 garydgregory

Hello @obfischer

* The tests don't assert that the stopwatch measured time.

* Another assertion would be that the lambda asserts that the stopwatch is running while it is invoked. For example:
            assertEquals("Foobar", watch.get((FailableSupplier<String, Throwable>) () -> {
                assertTrue(watch.isStarted());
                return "Foobar";
            }));
* I don't understand your comment about `test(Predicate..)`, what it supposed to be `test(Predicate)` or did you mean a vararg version of the API `test(Predicate...)`? What "wrapping" are you talking about? All the new methods don't "wrap" anything in the composition sense, they do delegate to the given lambda while managing the stopwatch state before and after the delegation. I must be missing something ;-)

Hi @garydgregory, could I use Mockito to verify that the measurement is done properly?

obfischer avatar Aug 20 '24 20:08 obfischer

@obfischer

Sure, I don't see why not.

garydgregory avatar Aug 20 '24 21:08 garydgregory

@obfischer

Sure, I don't see why not.

@garydgregory The project uses already EasyMock. I would, because I am lazy, prefer Mockito. Is it still fine to use Mockito or should I start to learn EasyMock= 😄

obfischer avatar Aug 23 '24 06:08 obfischer

I don't see why mocking is needed in the first place since the stopwatch state change can be asserted from the lambda, but let's see.

garydgregory avatar Aug 23 '24 11:08 garydgregory

Hi @garydgregory I am very busy at the moment. I will continue to work on it in some days...

obfischer avatar Aug 27 '24 20:08 obfischer

@obfischer

Run mvn by itself before you push to catch all builds failures.

garydgregory avatar Sep 04 '24 14:09 garydgregory

@obfischer Run mvn by itself to run all build checks.

garydgregory avatar Sep 10 '24 22:09 garydgregory

@obfischer Run mvn by itself to run all build checks.

No, my ping was for my last comment on the implementation of resumeOrStartStopWatch. I didn't change any line of code until now.

obfischer avatar Sep 11 '24 21:09 obfischer

@obfischer Run mvn by itself to run all build checks.

No, my ping was for my last comment on the implementation of resumeOrStartStopWatch. I didn't change any line of code until now.

Hello @obfischer Please make sure the build is green. I'll review again then.

garydgregory avatar Sep 11 '24 21:09 garydgregory

-1 as is, this is now deeply confusing, the functional methods should actually perform the measurement, not return a functional object that the user must then invoke to perform the measurement. Each time a functional method is called, the "start or resume" method is called but this measures time whether or the returned functional object is used or not. The functional methods should return the same value as their arguments, or void for the functional interfaces like consumers. I'll look over in more details over the next day or two.

garydgregory avatar Sep 13 '24 14:09 garydgregory

@obfischer

I took a simpler route than we previously discussed by only adding StopWatch.run([Failable]Runnable) and get([Failable]Supplier) which I believe should be able to handle the most common use cases.

You are credited in changes.xml.

If you there are some missing use cases, let's discuss.

garydgregory avatar Sep 22 '24 12:09 garydgregory

@obfischer Ping.

garydgregory avatar Sep 25 '24 19:09 garydgregory

Closing, no feedback in over a month.

garydgregory avatar Nov 04 '24 14:11 garydgregory