Re: BiCollector

2018-06-19 Thread Kirk Pepperdine


> On Jun 19, 2018, at 9:11 AM, Zheka Kozlov  wrote:
> 
> The function you propose is just a binary variant of mapping:
> 
> Collector mapping(
>  Function mapper,
>  Collector downstream);
> 
> (omitted '? super' for readability)
> 
> So, it is logical to use the name biMapping:
> 
> Collector biMapping(
>  Function mapper1,
>  Function mapper2,
>  Collector downstream1,
>  Collector downstream2,
>  BiFunction finisher);

+1


> 
> 
> 2018-06-19 7:38 GMT+07:00 John Rose :
> 
>> On Jun 18, 2018, at 2:29 PM, Brian Goetz  wrote:
>>> 
>>> "bisecting" sounds like it sends half the elements to one collector and
>> half to the other …
>> 
>> The main bisection or splitting operation that's relevant to a stream is
>> what
>> a spliterator does, so this is a concern.
>> 
>> Nobody has mentioned "unzipping" yet; this is a term of art which applies
>> to streams
>> of tuples.  The image of a zipper is relatively clear and unambiguous, and
>> the tradition
>> is pretty strong.  https://en.wikipedia.org/wiki/
>> Convolution_(computer_science)
>> 
>> The thing we are looking at differs in two ways from classic "unzipping":
>> First, the
>> two collectors themselves convert the same T elements to whatever internal
>> value
>> (T1, T2) is relevant.  Second, we are looking at a new terminal operation
>> (a collector) which
>> consolidates the results from both of streams (a notional Stream and
>> Stream,
>> if you like), rather than delivering the streams as a pair of outputs.
>> 
>> The classic "unzip" operation applies "fst" and "snd" (or some other
>> conventional
>> set of access functions) to each T-element of the input stream.  Since we
>> don't
>> have a privileged 2-tuple type (like Pair) in Java, the user would
>> need
>> to nominate those two functions explicitly, either by folding them into a
>> "mapping"
>> on each collector, or as a utility overloading like this:
>> 
>>   unzipping(
>>Function f1,  // defaults to identity
>>Collector c1,
>>Function f2,  // defaults to identity
>>Collector c2,
>>BiFunction finisher) {
>> return toBoth(mapping(f1, c1), mapping(f2, c2));
>>  }
>> 
>> 
>>> "tee" might be a candidate, though it doesn't follow the `ing
>> convention.  "teeing" sounds dumb.
>> 
>> 
>> "tee" sounds asymmetrical.  "diverting" or "detouring" are "*ing" words
>> that might
>> express asymmetrical disposition of derivative streams.
>> 
>> An asymmetrical operation might be interesting if it could fork off a
>> stream of
>> its own.  It would have to have a side-effecting void-producing terminal
>> operation,
>> so the main (undiverted) stream could continue to progress at the top
>> level of
>> the expression.
>> 
>> interface Stream {
>>  default Stream diverting(Consumer> tee) { … }
>> }
>> 
>> values.stream().diverting(s2->s2.forEach(System.out::
>> println)).filter(…).collect(…);
>> 
>> Or (and this might be a sweet spot) a symmetric stream-tee operation could
>> materialize two sibling streams and rejoin their results with a bifunction:
>> 
>> class Collectors {
>>  static  Stream unzipping(
>>Function, R1> f1,
>>Function, R2> f2,
>>BiFunction finisher)
>> { … }
>> }
>> 
>> values.stream().unzipping(
>>s1->s1.forEach(System.out::println),
>>s2->s2.filter(…).collect(…),
>>(void1, r2)->r2
>>);
>> 
>> This would allow each "fork child" of the stream to continue to use the
>> Stream API instead of the more restrictive Collector operators.
>> 
>> Optimal code generation for forked/unzipped/teed streams would be tricky,
>> requiring simultaneous loop control logic for each stream.
>> To me that's a feature, not a bug, since hand-writing ad hoc
>> simultaneous loops is a pain.
>> 
>> My $0.02.
>> 
>> — John



Re: BiCollector

2018-06-18 Thread Kirk Pepperdine


> On Jun 19, 2018, at 1:21 AM, Brian Goetz  wrote:
> 
> distributing?
> 
> On 6/18/2018 6:04 PM, Chris Hegarty wrote:
>> 
>>> On 18 Jun 2018, at 22:29, Brian Goetz  wrote:
>>> 
>>> "bisecting" sounds like it sends half the elements to one collector and 
>>> half to the other ...
>>> 
>>> "tee" might be a candidate, though it doesn't follow the `ing convention.  
>>> "teeing" sounds dumb.

But teeing (https://en.wikipedia.org/wiki/Tee_(command) 
) is sort of what you’re doing so 
it sounds just fine. .. I’ve always thought it like tapping but this maybe less 
descriptive than split which of course would be confused with Spliterator.

— Kirk



Re: BiCollector

2018-06-11 Thread Kirk Pepperdine
Hi,

I’ve created one of my own and I’d happily toss it for a standard 
implementation.

— Kirk

> On Jun 11, 2018, at 8:10 PM, Paul Sandoz  wrote:
> 
> Hi Peter,
> 
> I like it and can see it being useful, thanks for sharing. 
> 
> I am hesitating a little about it being in the JDK because there is the 
> larger abstraction of a BiStream, where a similar form of collection would 
> naturally fit (but perhaps without the intersection constraints for the 
> characteristics?). We experimented a few times with BiStream and got quite 
> far but decided pull back due to the lack of value types and specialized 
> generics. So i dunno how this might turn out in the future and if your 
> BiCollector fits nicely into such a future model.
> 
> What are you thoughts on this?
> 
> FWIW i would call it a “splitting” or “bisecting" collector e.g. 
> “s.collect(bisecting(…))”
> 
> Paul.
> 
> 
> 
> 
>> On Jun 11, 2018, at 5:39 AM, Peter Levart  wrote:
>> 
>> Hi,
>> 
>> Have you ever wanted to perform a collection of the same Stream into two 
>> different targets using two Collectors? Say you wanted to collect Map.Entry 
>> elements into two parallel lists, each of them containing keys and values 
>> respectively. Or you wanted to collect elements into  groups by some key, 
>> but also count them at the same time? Currently this is not possible to do 
>> with a single Stream. You have to create two identical streams, so you end 
>> up passing Supplier to other methods instead of bare Stream.
>> 
>> I created a little utility Collector implementation that serves the purpose 
>> quite well:
>> 
>> /**
>> * A {@link Collector} implementation taking two delegate Collector(s) and 
>> producing result composed
>> * of two results produced by delegating collectors, wrapped in {@link 
>> Map.Entry} object.
>> *
>> * @param  the type of elements collected
>> * @param  the type of 1st delegate collector collected result
>> * @param  tye type of 2nd delegate collector collected result
>> */
>> public class BiCollector implements Collector> Object>, Map.Entry> {
>>private final Collector keyCollector;
>>private final Collector valCollector;
>> 
>>@SuppressWarnings("unchecked")
>>public BiCollector(Collector keyCollector, Collector 
>> valCollector) {
>>this.keyCollector = (Collector) Objects.requireNonNull(keyCollector);
>>this.valCollector = (Collector) Objects.requireNonNull(valCollector);
>>}
>> 
>>@Override
>>public Supplier> supplier() {
>>Supplier keySupplier = keyCollector.supplier();
>>Supplier valSupplier = valCollector.supplier();
>>return () -> new 
>> AbstractMap.SimpleImmutableEntry<>(keySupplier.get(), valSupplier.get());
>>}
>> 
>>@Override
>>public BiConsumer, T> accumulator() {
>>BiConsumer keyAccumulator = keyCollector.accumulator();
>>BiConsumer valAccumulator = valCollector.accumulator();
>>return (accumulation, t) -> {
>>keyAccumulator.accept(accumulation.getKey(), t);
>>valAccumulator.accept(accumulation.getValue(), t);
>>};
>>}
>> 
>>@Override
>>public BinaryOperator> combiner() {
>>BinaryOperator keyCombiner = keyCollector.combiner();
>>BinaryOperator valCombiner = valCollector.combiner();
>>return (accumulation1, accumulation2) -> new 
>> AbstractMap.SimpleImmutableEntry<>(
>>keyCombiner.apply(accumulation1.getKey(), accumulation2.getKey()),
>>valCombiner.apply(accumulation1.getValue(), 
>> accumulation2.getValue())
>>);
>>}
>> 
>>@Override
>>public Function, Map.Entry> finisher() {
>>Function keyFinisher = keyCollector.finisher();
>>Function valFinisher = valCollector.finisher();
>>return accumulation -> new AbstractMap.SimpleImmutableEntry<>(
>>keyFinisher.apply(accumulation.getKey()),
>>valFinisher.apply(accumulation.getValue())
>>);
>>}
>> 
>>@Override
>>public Set characteristics() {
>>EnumSet intersection = 
>> EnumSet.copyOf(keyCollector.characteristics());
>>intersection.retainAll(valCollector.characteristics());
>>return intersection;
>>}
>> }
>> 
>> 
>> Do you think this class is general enough to be part of standard Collectors 
>> repertoire?
>> 
>> For example, accessed via factory method Collectors.toBoth(Collector coll1, 
>> Collector coll2), bi-collection could then be coded simply as:
>> 
>>Map map = ...
>> 
>>Map.Entry, List> keys_values =
>>map.entrySet()
>>   .stream()
>>   .collect(
>>   toBoth(
>>   mapping(Map.Entry::getKey, toList()),
>>   mapping(Map.Entry::getValue, toList())
>>   )
>>   );
>> 
>> 
>>Map.Entry, Long> histogram_count =
>>ThreadLocalRandom
>>.current()
>>.ints(100, 0, 10)
>>  

Re: stripIndent() behavior

2018-04-11 Thread Kirk Pepperdine
Hi,

Mind if I bike shed on this one since everyone else it? 

A tab is white space of undefined length. Traditionally, tabs are the 
responsibility of the device (move forward software) to implement. This is why 
you *set* tabs. As such… it seems very reasonable that people don’t expect nor 
shouldn’t expect tabs to behave the same on all different devices. Meaning, if 
you want consistent behavior, a tab is not the signal you want to be sending. 
If we want the indent in our code to be the same all over then the correct 
signal is a space. That (for fixed width fonts) offers a uniformly sized white 
space. Note there is no tab/anti-tab rhetoric in here. Tabs are useful, so are 
spaces. You just need to know what they are so that you can know when it is 
appropriate to use one of the other.

Kind regards,
Kirk Pepperdine

> On Apr 10, 2018, at 11:18 PM, Kevin Bourrillion <kev...@google.com> wrote:
> 
> On Tue, Apr 10, 2018 at 1:50 PM, Brian Goetz <brian.go...@oracle.com> wrote:
>> 
>> 
>> 3. If the input contains *any* tab characters at all (except any that are
>>> part of the trailing whitespace), then this method cannot know that it
>>> isn't jumbling the end result, and maybe it should just throw.
>>> 
>> I think there's a middle ground, where it strips any common whitespace
>> prefix.  So if every line starts with tab-tab-space-space, it can safely
>> strip this.
> 
> 
> My point is that this is *not* safe, if by "safe" we mean "you will see the
> same relative indentation you saw in the source". *Any* tab has the
> potential to suddenly be worth a different number of spaces, once some
> prefix of any kind has been removed.
> 
> I would *like* to not worry about this, but we have to accept that the
> programmers who will be hurt most will be the most novice.
> 
> 
> 5. If we do end up in a world where we have to call this for almost every
>>> one of our tens of thousands of multi-line RSLs... is it strange that I
>>> feel like I would prefer it was static? It seems like it would look a lot
>>> more normal that way visually. Ugh...
>>> 
>> I think this is likely to vary subjectively a lot.  Some people like that
>> the instance method is mostly out of the way; others like the up-front
>> shouting of the static method.
>> 
> 
> Is it just potayto, potahto, or does one of the snippets above appear a lot
> more consistent with how Java code has always looked?
> 
> 
> On top of *that*, I have no idea what "right markers" are good for, nor
>>> what customizing the marker choice is good for (other than creating more
>>> needless variation between different pieces of code).
>>> 
>>> 
>> String asciiArtFTW =
>> `
>>`  BOO  `
>>`.trimMarkers("`", "`");
>> 
>> 
> Ha, well, I did say "good" for :-)
> 
> 
> -- 
> Kevin Bourrillion | Java Librarian | Google, Inc. | kev...@google.com



Re: Getting a live view of environment variables (Gradle and JDK 9)

2017-10-12 Thread Kirk Pepperdine
Hi,

> On Oct 12, 2017, at 2:54 PM, Mario Torre <neugens.limasoftw...@gmail.com> 
> wrote:
> 
> 2017-10-12 11:58 GMT+02:00 Cédric Champeau <cedric.champ...@gmail.com>:
> 
>> 1. an API in 18.3 which would let us refresh the environment variables,
>> even if inherently unsafe (we can take the risk, if the Javadocs explains
>> that if you're really unlucky calling such a method could kill your VM).
> 
> Being a public API we would expose everyone to this risk, and the API
> should be supported on all platforms maybe forever. I know other
> people have different opinion here, but this seems to be high risk,
> high impact to be worth.

As I have stated in post postings, this is behavior is unexpected and IMHO 
shouldn’t be supported.
> 
>> 2. we change the way Gradle works and force explicit declaration of all
>> environment variables a user script can use. Then, we would only spawn a
>> new VM if the current daemon environment variables do not match those
>> required found by the client.

This describes a more appropriate behavior.

Kind regards,
Kirk Pepperdine



Re: Getting a live view of environment variables (Gradle and JDK 9)

2017-05-18 Thread Kirk Pepperdine

> On May 18, 2017, at 6:15 AM, David Holmes  wrote:
> 
> On 18/05/2017 2:36 AM, Martin Buchholz wrote:
>> Stop trying to add APIs to mutate environment variables.  It's not going
>> to happen!
> 
> Not sure who or what you are directing this at Martin. Certainly I'm not 
> suggesting any API to mutate environment variables. This is about an API to 
> re-read an already potentially mutated external environment.
> 
>> There is no known way to mutate environment variables in a
>> multithreaded Unix process without risk of native crashes (and I have
>> worn the hat of poor support engineer trying to diagnose SEGV in
>> getenv).  IIRC we made the decision 13 years ago to cache the
>> environment on first access, and that was before the thread-unsafety of
>> putenv was fully appreciated.
>> 
>> Yes, Java still has a serious startup performance problem; that should
>> be attacked more directly.
> 
> ?? Not sure what startup has to do with the topic here.

The reason to use a daemon is to avoid multiple starts of a JVM in-between 
steps in a build. It is a great idea but the proposed implementation is at 
issue because it requires a highly questionable API be added to the JDK.

Kind regards,
Kirk



Re: Getting a live view of environment variables (Gradle and JDK 9)

2017-05-18 Thread Kirk Pepperdine
Hi Cedric,

I understand what you are trying to do, it is my opinion that you are trying to 
do this in a completely unexpected way. That the environment variables in the 
JVM are read only once is an issue in that a nohup should refresh them That all 
the code in the JVM may (or may not) react to this change is another question. 
In your case I believe you have painted yourself into a corner by assuming the 
JVM would be able to read and write shell environment variables. To back off of 
this assumption 
In this case you will need the client to inform the server of it’s environment 
and then one possibility is to fork the server with the new variables.

Shells are isolated for a reason. IMHO, changing the JVM to write environment 
variables based on settings in another shell is a potential security issue.

Kind regards,
Kirk

> On May 17, 2017, at 4:21 PM, Cédric Champeau  
> wrote:
> 
>> 
>> 
>>> I disagree, this would be totally expected behavior. The daemon and this
>>> process would run in different shells and I am unaware of any daemon
>>> process that auto-magically reconfigures it’s self to adapt to any other
>>> arbitrary shell’s changed environment variables.
>> 
>> 
> The thing is that the daemon is an "implementation detail". The user
> doesn't even need to know there's one. It's here for performance reasons.
> If we could get the same level of performance, and startup time, right from
> the process start, there wouldn't be any need for a daemon. But the truth
> is different: with classloading, in-memory dependency management caches,
> and the JIT, the daemon is required. So imagine the surprise if a user just
> does a "cd subproject" and start Gradle, and we spawn a new daemon, just
> because the "PWD" environment variable has changed. It doesn't make sense.
> Also it can lead to surprising behaviors: if you run 2 builds concurrently
> (this happens, yes, we have thousands of users so all scenarios exist in
> the wild), then depending on whether the daemon was busy when you start the
> build, you would get different environment variables: the busy one would
> get the environment variables when it was started, and the fresh one to run
> the 2d build would get the refreshed ones, because started at a different
> point in time.
> 
> Another scenario: one might think (we do) that it's better to use project
> properties than environment variables to communicate runtime specific
> configuration. But the reality is always more complex. For example, our
> build scripts may require calling a Perl library at some point (imagine,
> for example, calling FlameGraph). If that library is configured through
> environment variables (say, it requires FLAMEGRAPH_HOME to be set), then
> it's better to check beforehand if the environment variable is set, rather
> than executing the build and failing when we try to call it. So, the build
> script needs to check that this environment variable is set. If we don't
> propagage the client environment variables to the daemon, then 2 things
> happen:
> 
> 1. the check to verify that the environment variable is set would fail,
> even if it has been set in the CLI
> 2. we wouldn't be able to set the environment variables of the forked
> process running Perl to the appropriate set of variables



Re: Getting a live view of environment variables (Gradle and JDK 9)

2017-05-16 Thread Kirk Pepperdine
Hi,


> On May 17, 2017, at 3:11 AM, Cédric Champeau  
> wrote:
> 
> Hi Uwe,
> 
> I already explained multiple times why we need this. Short answer: because
> we must. Slightly longer answer: because the build environment, the daemon,
> has to reflect the environment from the CLI (or the IDE, in case we call
> using the tooling API), at the moment the build is executed. Why? Because a
> user wouldn't understand that a script which does:
> 
> println System.getenv('MY_VAR')
> 
> doesn't print "foo" after doing:
> 
> MY_VAR=foo gradle printVar

I disagree, this would be totally expected behavior. The daemon and this 
process would run in different shells and I am unaware of any daemon process 
that auto-magically reconfigures it’s self to adapt to any other arbitrary 
shell’s changed environment variables. In fact, IMHO, this seems like a 
fundamentally flawed way for the deamon process to behave. I believe the client 
communicating with the deamon that should be providing information to the 
daemon.

Kind regards,
Kirk



Re: Accessing module internals from bytecode rewriting agent

2017-05-05 Thread Kirk Pepperdine
Hi Jeremy,

I think your email points out *why* turning this on out of the blocks is going 
to make things a ton more difficult. IMHO, 9 needs to be opt-in rather than 
opt-out. By 10 I think we’ll be ready for opt-out rather than opt-in.

Kind regards,
Kirk Pepperdine

> On May 5, 2017, at 8:39 AM, Jeremy Manson <jeremyman...@google.com> wrote:
> 
> Thanks, Dalibor.
> 
> I know it may sound surprising, but I'm not actually complaining.  I do
> understand that most everything we're doing that requires workarounds for
> modules is unsupported (with the possible exception of the changes to
> instrumentation agents), and we were always doing them at our own risk.
> This is far from limited to Xbootclasspath - we have all sorts of hacks,
> including, to pick two things at random among many, code that introspects a
> Thread's Runnable to pick a good name to report for a thread, and code that
> introspects an AbstractInterruptibleChannel to stop the owning thread from
> closing the channel when it gets an interrupt.
> 
> It's our problem to fix these issues, and I'm unlikely to claim otherwise.
> Frankly, it doesn't seem all that difficult to find other ways to
> introspect into the JDK - it's just busywork and more awkward than it used
> to be.
> 
> Mostly, I'm telling you all because I think it makes an interesting case
> study - a large Java installation and the issues it faces trying to roll
> out JDK 9.
> 
> If other installations do the kinds of things that we do, the path to a JDK
> 9 without lots of add-exports and kill switch options is likely to be slow
> and laborious for them.  We're comparatively well situated to do it - we
> have our own JDK build and a staffed team to do / help with the migration,
> and are likely to roll it out to everyone with the kill switch turned on by
> default so that our awful hacks can stay put until we finish fixing them.
> 
> (Also, if I were complaining, there would have been a lot of choice things
> I would have said that I'm not going to say. :) )
> 
> Jeremy
> 
> On Thu, May 4, 2017 at 4:35 AM, dalibor topic <dalibor.to...@oracle.com>
> wrote:
> 
>> On 02.05.2017 18:46, Jeremy Manson wrote:
>> 
>>> People
>>> are using Xbootclasspath for a variety of things.
>>> 
>> 
>> It's worth keeping in mind when using such options that
>> 
>> "Non-standard options are general purpose options that are specific to the
>> Java HotSpot Virtual Machine, so they are not guaranteed to be supported by
>> all JVM implementations, and are subject to change. These options start
>> with -X."
>> 
>> http://docs.oracle.com/javase/8/docs/technotes/tools/unix/ja
>> va.html#BABHDABI
>> 
>> cheers,
>> dalibor topic
>> --
>> <http://www.oracle.com> Dalibor Topic | Principal Product Manager
>> Phone: +494089091214 <tel:+494089091214> | Mobile: +491737185961
>> <tel:+491737185961>
>> 
>> ORACLE Deutschland B.V. & Co. KG | Kühnehöfe 5 | 22761 Hamburg
>> 
>> ORACLE Deutschland B.V. & Co. KG
>> Hauptverwaltung: Riesstr. 25, D-80992 München
>> Registergericht: Amtsgericht München, HRA 95603
>> 
>> Komplementärin: ORACLE Deutschland Verwaltung B.V.
>> Hertogswetering 163/167, 3543 AS Utrecht, Niederlande
>> Handelsregister der Handelskammer Midden-Niederlande, Nr. 30143697
>> Geschäftsführer: Alexander van der Ven, Jan Schultheiss, Val Maher
>> 
>> <http://www.oracle.com/commitment> Oracle is committed to developing
>> practices and products that help protect the environment
>> 



Re: Accessing module internals from bytecode rewriting agent

2017-05-02 Thread Kirk Pepperdine
Hi Alan,

One of the techniques that I’ve used in the past for troubleshooting is to 
prepend modified classes to the bootstrap class path. I fear all this mucking 
about with modularization is going to leave the road to diagnostics littered 
with a ton of tools that will not longer work. As it is, 8 broke all the 
techniques and tooling used to diagnose class loader leaks… without fixing the 
fundamental problems that caused them to leak in the first place..and added a 
new sources for performance regressions for which there is little in the way of 
tooling and certainly much less of an understanding of the fundamental issues 
out in the general developer population. The availability of high quality 
tooling is a huge bonus in the Java eco structure…. Please, don’t send us back 
to the Stone Age.

Kind regards,
Kirk Pepperdine

> On May 2, 2017, at 9:48 AM, Alan Bateman <alan.bate...@oracle.com> wrote:
> 
> On 02/05/2017 07:50, Jeremy Manson wrote:
>> :
>> 
>> If we follow this path, before we migrate to Java 9, we would need to make 
>> sure all of our code builds and the tests pass with Java 9 and Java 8.  We 
>> can't make all of the code build and the tests pass with Java 9 as-is, 
>> because many of them use options like Xbootclasspath, which have been 
>> dropped.  We can't migrate those tests to use the new command line flags 
>> before we migrate to Java 9, because if we do, they will stop working with 
>> Java 8.  Due to the size of our code base, it's pretty much impossible to 
>> migrate all of the users to a new set of command line flags at the same time 
>> as we migrate to Java 9.
> So I'm curious about -Xbootclasspath as that completely overrides the runtime 
> classes. Is this static instrumentation or combining the VM/launcher from one 
> build with the classes from a different JDK build? In any case, and as you 
> have found, -Xbootclasspath  and -Xbootclasspath/p are meaningless now, a 
> consequence of moving all the core APIs to modules. The -Xbootclasspath/a 
> option works as before with the caveat that not all platform classes are 
> visible to the boot class loader now (a consequence of ongoing security work 
> to move non-core components away from the fully privileged boot loader).
> 
> It might be that you mean the `javac -bootclasspath,  this works as before 
> when you target 8 or older.
> 
> -Alan
> 



Re: JEP 132: More-prompt finalization

2015-06-02 Thread Kirk Pepperdine
Hi Moh,

 
 However, I was hoping this would have the effect of improving 
 (non-finalizable) reference handling. We've seen serious issues in 
 WeakReference handling and have had to write some twisted code to deal with 
 this.

Better reference life-cycle handling would actually be beneficial IMHO as many 
cache implementations suffer because of certain aspects of the current 
implementation. SoftReference is very difficult to use.
 
 So I guess the question I have to Kirk and David is: do you feel a GC load of 
 10K WeakReferences per cycle is also doing something else wrong”?

Hard to say as this really has to be eval’ed on a case by case basis. But I’d 
wonder if the WeakReference was actually needed if you are recycling them so 
quickly.

Regards,
Kirk

 
 Sorry if this is going off-topic.
 
 Thanks
 Moh
 
 -Original Message-
 From: core-libs-dev [mailto:core-libs-dev-boun...@openjdk.java.net] On Behalf
 Of Kirk Pepperdine
 Sent: Thursday, May 28, 2015 11:58 PM
 To: david.hol...@oracle.com Holmes
 Cc: hotspot-gc-...@openjdk.java.net openjdk.java.net; core-libs-
 d...@openjdk.java.net
 Subject: Re: JEP 132: More-prompt finalization
 
 Hi Peter,
 
 It is a very interesting proposal but to further David's comments, the life-
 cycle costs of reference objects is horrendous of which the actual process of
 finalizing an object is only a fraction of that total cost. Unfortunately 
 your
 micro-benchmark only focuses on one aspect of that cost. In other words, it
 isn't very representative of a real concern. In the real world the finalizer
 *must compete with mutator threads and since F-J is an all threads on deck
 implementation, it doesn't play well with others. It creates a tragedy of 
 the
 commons. That is situations where everyone behaves rationally with a common
 resource but to the detriment of the whole group. In short, parallelizing 
 (F-
 Jing) *everything* in an application is simply not a good idea. We do not 
 live
 in an infinite compute environment which means to have to consider the impact
 of our actions to the entire group.
 
 This was one of the points of my recent article in Java Magazine which I 
 wrote
 to try to counter some of the rhetoric I was hearing in conference about the
 universal benefits of being able easily parallelize streams in Java 8. Yes, I
 agree it's a great feature but it must be used with discretion. Case in 
 point.
 After I finished writing the article, I started running into a couple of 
 early
 adopters that had swallowed the parallel message whole indiscriminately
 parallelizing all of their streams. As you can imagine, they were quite
 surprised by the results and quickly worked to de-parallelize *all* of the
 streams in the application.
 
 To add some ability to parallelize the handling of reference objects seems
 like a good idea if you are collecting large numbers of reference objects
 (10,000 per GC cycle). However if you are collecting large numbers of
 reference objects you're most likely doing something else wrong. IME,
 finalization is extremely useful but really only for a limited number of use
 cases and none of them (to date) have resulted in the app burning through
 1000s of final objects / sec.
 
 It would be interesting to know why why you picked on this particular issue.
 
 Kind regards,
 Kirk
 
 
 
 On May 29, 2015, at 5:18 AM, David Holmes david.hol...@oracle.com wrote:
 
 Hi Peter,
 
 I guess I'm very concerned about the premise that finalization should scale
 to millions of objects and be performed highly concurrently. To me that's
 sending the wrong message about finalization. It also isn't the most 
 effective
 use of cpu resources - most people would want to do useful work on most cpu's
 most of the time.
 
 Cheers,
 David
 
 On 29/05/2015 3:12 AM, Peter Levart wrote:
 Hi,
 
 Did you know that the following simple loop:
 
 public class FinalizableBottleneck {
static boolean no;
 
@Override
protected void finalize() throws Throwable {
// empty finalize() method does not make the object finalizable
// (it is not even registered on the finalizer's list)
if (no) {
throw new AssertionError();
}
}
 
public static void main(String[] args) {
while (true) {
new FinalizableBottleneck();
}
}
 }
 
 
 ...quickly fills the entire heap with FinalizableBottleneck and internal
 Finalizer objects and brings the JVM to a halt? After a few seconds of
 running the above program, jmap -histo:live reports:
 
 num #instances #bytes  class name
 --
   1:  50048325 2001933000  java.lang.ref.Finalizer
   2:  50048278  800772448  FinalizableBottleneck
 
 
 There are a couple of bottlenecks that make this happen:
 
 - ReferenceHandler thread synchronizes with VM to unhook Reference(s)
 from the pending chain one be one and dispatches them to their respected
 ReferenceQueue(s) which also use

Re: JEP 132: More-prompt finalization

2015-06-02 Thread Kirk Pepperdine
Hi Peter,

Interesting email. I think it is a thoughtful contribution and these are great 
responses to concerns and questions. I hope it receives the due consideration 
it deserves.

Kind regards,
Kirk

On May 31, 2015, at 9:32 PM, Peter Levart peter.lev...@gmail.com wrote:

 Hi,
 
 Thanks for views and opinions. I'll try to confront them in-line...
 
 On 05/29/2015 04:18 AM, David Holmes wrote:
 Hi Peter, 
 
 I guess I'm very concerned about the premise that finalization should scale 
 to millions of objects and be performed highly concurrently. To me that's 
 sending the wrong message about finalization. It also isn't the most 
 effective use of cpu resources - most people would want to do useful work on 
 most cpu's most of the time. 
 
 Cheers, 
 David 
 
 @David
 
 Ok, fair enough. It shouldn't be necessary to scale finalization to millions 
 of objects and be performed concurrently. Normal programs don't need this. 
 But there is a diagnostic command being developed at this moment that 
 displays the finalization queue. The utility of such command, as I 
 understand, is precisely to display when the finalization thread can not cope 
 and Finalizer(s) accumulate. So there must be that some hypothetical programs 
 (ab)use finalization or are buggy (deadlock) so that the queue builds up. To 
 diagnose this, a diagnostic command is helpful. To fix it, one has to fix the 
 code. But what if the problem is not that much about the allocation/death 
 rate of finalizable instances then it is about the heavy code of finalize() 
 methods of those instances. I agree that such programs have a smell and 
 should be rewritten to not use finalization but other means of cleanup such 
 as multiple threads removing WeakReferences from the queue for example or 
 something completely different and not based on Reference(s). But wouldn't it 
 be nice if one could simply set a system property for the max. number of 
 threads processing Finalizer(s)?
 
 I have prepared an improved variant of the prototype that employs a single 
 ReferenceHandler thread and adds a ForkJoinPool that by default has a single 
 worker thread which replaces the single finalization thread. So by default, 
 no more threads are used than currently. If one wants (s)he can increase the 
 concurrency of finalization with a system property.
 
 I have also improved the benchmarks that now focus on CPU overhead when 
 processing references at more typical rates, rather than maximum throughput. 
 They show that all changes taken together practically half the CPU time 
 overhead of the finalization processing. So freed CPU time can be used for 
 more useful work. I have also benchmarked the typical asynchronous 
 WeakReference processing scenario where one thread removes enqueued 
 WeakReferences from the queue. Results show about 25% decrease of CPU time 
 overhead.
 
 Why does the prototype reduce more overhead for finalization than 
 WeakReference processing? The main improvement in the change is the use of 
 multiple doubly-linked lists for registration of Finalizer(s) and the use of 
 lock-less algorithm for the lists. The WeakReference processing benchmark 
 also uses such lists internally to handle registration/deregistration of 
 WeakReferences so that the impact of this part is minimal and the difference 
 of processing overheads between original and changed JDK code more obvious. 
 (De)registration of Finalizer(s) OTOH is part of JDK infrastructure, so the 
 improvement to registration list(s) also shows in the results. The results of 
 WeakReferece processing benchmark also indicate that reverting to the use of 
 a single finalization thread that just removes Finalizer(s) from the 
 ReferenceQueue could lower the overhead even a bit further, but then it would 
 not be possible to leverage FJ pool to simply configure the parallelism of 
 finalization. If parallel processing of Finalizer(s) is an undesirable 
 feature, I could restore the single finalization thread and the CPU 
 overhead of finalization would be reduced to about 40% of current overhead 
 with just the changes to data structures.
 
 So, for the curious, here's the improved prototype:
 
 
 http://cr.openjdk.java.net/~plevart/misc/JEP132/ReferenceHandling/webrev.02/
 
 And here are the improved benchmarks (with some results inline):
 
 http://cr.openjdk.java.net/~plevart/misc/JEP132/ReferenceHandling/refproc/
 
 
 The benchmark results in the ThroughputBench.java show the output of the 
 test(s) when run with the Linux time command which shows the elapsed real 
 time and the consumed user and system CPU times. I think this is relevant for 
 measuring CPU overhead.
 
 So my question is: Is it or is it not desirable to have a configurable means 
 to parallelize the finalization processing? The reduction of CPU overhead of 
 infrastructure code should always be desirable, right?
 
 On 05/29/2015 05:57 AM, Kirk Pepperdine wrote:
 Hi Peter,
 
 It is a very interesting

Re: JEP 132: More-prompt finalization

2015-05-29 Thread Kirk Pepperdine
Hi Peter,

It is a very interesting proposal but to further David’s comments, the 
life-cycle costs of reference objects is horrendous of which the actual process 
of finalizing an object is only a fraction of that total cost. Unfortunately 
your micro-benchmark only focuses on one aspect of that cost. In other words, 
it isn’t very representative of a real concern. In the real world the finalizer 
*must compete with mutator threads and since F-J is an “all threads on deck” 
implementation, it doesn’t play well with others. It creates a “tragedy of the 
commons”. That is situations where everyone behaves rationally with a common 
resource but to the detriment of the whole group”. In short, parallelizing 
(F-Jing) *everything* in an application is simply not a good idea. We do not 
live in an infinite compute environment which means to have to consider the 
impact of our actions to the entire group.

This was one of the points of my recent article in Java Magazine which I wrote 
to try to counter some of the rhetoric I was hearing in conference about the 
universal benefits of being able easily parallelize streams in Java 8. Yes, I 
agree it’s a great feature but it must be used with discretion. Case in point. 
After I finished writing the article, I started running into a couple of early 
adopters that had swallowed the parallel message whole indiscriminately 
parallelizing all of their streams. As you can imagine, they were quite 
surprised by the results and quickly worked to de-parallelize *all* of the 
streams in the application.

To add some ability to parallelize the handling of reference objects seems like 
a good idea if you are collecting large numbers of reference objects (10,000 
per GC cycle). However if you are collecting large numbers of reference objects 
you’re most likely doing something else wrong. IME, finalization is extremely 
useful but really only for a limited number of use cases and none of them (to 
date) have resulted in the app burning through 1000s of final objects / sec.

It would be interesting to know why why you picked on this particular issue.

Kind regards,
Kirk



On May 29, 2015, at 5:18 AM, David Holmes david.hol...@oracle.com wrote:

 Hi Peter,
 
 I guess I'm very concerned about the premise that finalization should scale 
 to millions of objects and be performed highly concurrently. To me that's 
 sending the wrong message about finalization. It also isn't the most 
 effective use of cpu resources - most people would want to do useful work on 
 most cpu's most of the time.
 
 Cheers,
 David
 
 On 29/05/2015 3:12 AM, Peter Levart wrote:
 Hi,
 
 Did you know that the following simple loop:
 
 public class FinalizableBottleneck {
 static boolean no;
 
 @Override
 protected void finalize() throws Throwable {
 // empty finalize() method does not make the object finalizable
 // (it is not even registered on the finalizer's list)
 if (no) {
 throw new AssertionError();
 }
 }
 
 public static void main(String[] args) {
 while (true) {
 new FinalizableBottleneck();
 }
 }
 }
 
 
 ...quickly fills the entire heap with FinalizableBottleneck and internal
 Finalizer objects and brings the JVM to a halt? After a few seconds of
 running the above program, jmap -histo:live reports:
 
  num #instances #bytes  class name
 --
1:  50048325 2001933000  java.lang.ref.Finalizer
2:  50048278  800772448  FinalizableBottleneck
 
 
 There are a couple of bottlenecks that make this happen:
 
 - ReferenceHandler thread synchronizes with VM to unhook Reference(s)
 from the pending chain one be one and dispatches them to their respected
 ReferenceQueue(s) which also use synchronization for equeueing each
 Reference.
 - Enqueueing synchronizes with the finalization thread which removes the
 Finalizer(s) (FinalReferences) from the finalization queue and executes
 them.
 - Executing the Finalizer(s) removes them from the doubly-linked list of
 all Finalizer(s) which is used to retain them until they are needed and
 this synchronizes with the threads that link new Finalizer(s) into the
 doubly-linked list as new finalizable objects get registered.
 
 We see that the creation of a finalizable object only takes one
 synchronization (registering into the doubly-linked list) and is
 performed synchronously, while finalization takes 4 synchronizations
 among 4 different threads (in pairs) and happens when the Finalizer
 instance travels over from VM thread to ReferenceHandler thread and
 then to finalization thread. No wonder that finalization can not keep up
 with allocation in a single thread. The situation is even worse when
 finalize() methods do some actual work.
 
 I have experimented with various approaches to widen these bottlenecks
 and found out that I can not beat the ForkJoinPool when combined with
 some improvements to 

Re: PhantomReference: why not cleared by GC when enqueued?

2013-06-06 Thread Kirk Pepperdine
The only useful use case that I've come up with for PhantomReference is to 
subclass it. In one case it was used as a wrapper so that we'd know when an 
object was being collected so that we could reap life-cycle information from 
it. The behaviour was triggered by an JMX control. I suppose there were other 
ways to do this but given I only wanted to collect when the object was about to 
be GC'ed.

Regards,
Kirk

On 2013-05-30, at 1:32 PM, Dmytro Sheyko dmytro_she...@hotmail.com wrote:

 Mark,
 
 You are listed as an author of java.lang.ref classes. So you must know more 
 than others. Could you shed light on this?
 
 Thank you,
 Dmytro
 
 From: dmytro_she...@hotmail.com
 To: hotspot-gc-...@openjdk.java.net; core-libs-dev@openjdk.java.net
 Subject: PhantomReference: why not cleared by GC when enqueued?
 Date: Wed, 29 May 2013 14:45:54 +0300
 
 Hello,
 
 Why phantom references are not automatically cleared by the garbage collector 
 as they are enqueued?
 
 Keeping phantom reachable objects in heap has some drawbacks:
 1. At least 2 GC are required in order to reclaim them, even in case when 
 application code pulls references from reference queue and clears them 
 promptly.
 2. GC pauses are increased since phantom reachable objects are still to be 
 marked.
 
 On the other hand, benefits are not obvious. How we can use referent if it's 
 not accessible?
 
 Regards,
 Dmytro
 



Re: Request for review: 6896617: Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() on x86

2013-01-30 Thread Kirk Pepperdine

On 2013-01-23, at 1:14 AM, Vitaly Davidovich vita...@gmail.com wrote:

 Personally, optimizing for interpreter (or even C1) doesn't seem worth it.  
 If something's truly hot and best perf is desired then use C2 or tiered.  If 
 the method isn't hot enough to trigger the C2 threshold, then why bother? 
 You're already behind the 8 ball in terms of performance.  Maybe this is 
 heresy though :).
 
 
Maybe, maybe not.. what I can say is this is a case of an optimization that 
doesn't scale down. In cases where scale down was needed I have recommended to 
customers that they flash their system just to push the counter beyond the 
compile threshold. In those cases naively compiled code was still a lot better 
than interrupting byte code. I've also turned off decay in a number of 
applications where loads weren't quite enough to beat the decay behaviour. Yeah 
I know this is at the risk of filling code cache but code cache occupancy is 
something that I regularly recommend people monitor for (check my VisualVM 
memory pool plug-in). In fact, I just tuned an app where I used -Xcomp to 
estimate how big the code cache needed to be to avoid filling it. Production 
settings had decay turned off. So, I can't say your wrong and I generally don't 
like fiddling with these setting but I will if I have to and I've had to in a 
number of instances where ensuring a compile beat leaving it alone.

Regards,
Kirk