GWT: How to avoiding calls to dynamicCast and canCastUnsafe in generated JavaScript code? - gwt

I'm writing some special purpose data structures in Java, intended for use in the browser, (compiled to JavaScript with GWT).
I'm trying to match the performance of some of the built-in JDK classes I'm noticing things run reasonably fast, but when I compare my code trace to some of the emulated JDK code, mine has lots of calls to dynamicCast and canCastUnsafe, while the JDK emulated classes do not. And it just about accounts for the difference in performance too...
Any GWT gurus out there know how to avoid this? It's amounting to a 20% overhead :-(
Details:
Here's the profile output (captured in Firebug) for 10,000 insertions of random integers, between 0 and 100,000 into two different data structures:
Google's TreeMap implementation for java.util.TreeMap (a red-black tree):
Profile (4058.602ms, 687545 calls)
Function Calls Percent Own Time
$insert_1 129809 41.87% 1699.367ms
$compare_0 120290 16% 649.209ms
$isRed 231166 13.33% 540.838ms
compareTo_0 120290 8.96% 363.531ms
$put_2 10000 6.02% 244.493ms
wrapArray 10000 3.46% 140.478ms
createFromSeed 10000 2.91% 118.038ms
$TreeMap$Node 10000 2.38% 96.706ms
initDim 10000 1.92% 77.735ms
initValues 10000 1.49% 60.319ms
$rotateSingle 5990 0.73% 29.55ms
TreeMap$Node 10000 0.47% 18.92ms
My Code (An AVL tree):
Profile (5397.686ms, 898603 calls)
Function Calls Percent Own Time
$insert 120899 25.06% 1352.827ms
$compare 120899 17.94% 968.17ms
dynamicCast 120899 14.12% 762.307ms <--------
$balanceTree 120418 13.64% 736.096ms
$setHeight 126764 8.93% 482.018ms
compareTo_0 120899 7.76% 418.716ms
canCastUnsafe 120899 6.99% 377.518ms <--------
$put 10000 2.59% 139.936ms
$AVLTreeMap$Node 9519 1.04% 56.403ms
$moveLeft 2367 0.36% 19.602ms
AVLTreeMap$State 9999 0.36% 19.429ms
$moveRight 2378 0.34% 18.295ms
AVLTreeMap$Node 9519 0.34% 18.252ms
$swingRight 1605 0.26% 14.261ms
$swingLeft 1539 0.26% 13.856ms
Additional observations:
Same problem for another data structure I made (SkipList).
dynamicCast is being applied in the compare function:
cmp = dynamicCast(right.key, 4).compareTo$(key);
dynamicCast goes away if the class does not implement Map (ie: just removing " implements Map" from the class. Doesn't matter if it's accessed through the interface or directly. This results in the same line compiling to:
cmp = right.key.compareTo$(key);
This is the relevant section of Java source from SkipList:
private int compare(Node a, Object o) {
if (comparator != null)
return comparator.compare((K) a.key, (K) o);
return ((Comparable<K>) a.key).compareTo((K) o);
}
public V get(Object k) {
K key = (K) k;
Node<K, V> current = head;
for (int i = head.height - 1; i >= 0; i--) {
Node<K, V> right;
while ((right = current.right[i]) != null) {
int cmp = compare(right, key);
...
}
}
}

Unfortunately I'm still not exactly clear on the cause, but from my experience, it seems from explicit casts, like:
((Comparable) obj).compareTo(other)
The Javascript generated looks like:
dynamicCast(obj, 1).compareTo(other);
Where 1 is a generated typeId representing the target of the cast. dynamicCast in turn calls canCastUnsafe and if false, it throws a ClassCastException. The value of this has been debated, since this would already be caught in hosted mode.
It can be sidestepped with JSNI:
public static native int compare(Object a, Object b) /*-{
return a.#java.lang.Comparable::compareTo(Ljava/lang/Object;)(b);
}-*/;

Dunno if you've seen this thread in the GWT Contributor's forum...
Basically, it starts with the same problem you've identified, proposes some new compiler flags, and goes on to show how to use some JSNI to get around the casts.
Edit In the GWT trunk there's a new compiler flag. See the wiki...

An updated answer for GWT version 2.1 and later:
Since GWT 2.1 (at least that's the first mention), the GWT compiler has a new compiler argument called -XdisableCastChecking that disables all runtime checking of casts.
Note, this option is marked as experimental (probably because this would make class cast exceptions very hard to debug).
In my app dynamicCast was called thousands of times in a short profile run, and were the the 3rd most time consuming method in the Firebug profiler. Using this compiler argument significantly reduced the number of "Long Duration Events" messages in the Chrome Speed Tracer.
See GWT Compiler Options for this and other Compiler arguments.

It's definitely a compiler problem: I have the problem on the following line:
final DefaultIconedSuggestBox<SuggestValueProxy, IconedValueHolderItem<SuggestValueProxy>> fieldValueWidget = getCategoryWidget().getFieldValueWidget();
I don't really know how I can workaround it: this line happens in a moment I'm changing from a module to another (it is maybe related to the code splitter issue: even though I'm not using code split: I'm just loading another page with another module)

Does the use of java 1.5 generics and wildcards could avoid this ?

Related

EntityQueryBuilder.ForEach is not compiling with two ComponentData and one BufferElementData

I'm using the Unity Entity Component System. When I try to write the following code:
Entities.WithAll<SomeComponentData, SomeComponentData2, SomeBufferElementData>()
.ForEach((Entity entity, ref SomeComponentData componentData, ref SomeComponentData2 componentData2, DynamicBuffer<SomeBufferElementData> buffer) => {
});
I get the following error error CS0315: The type 'Unity.Entities.Entity' cannot be used as type parameter 'T0' in the generic type or method 'EntityQueryBuilder.ForEach<T0>(EntityQueryBuilder.F_D<T0>)'. There is no boxing conversion from 'Unity.Entities.Entity' to 'Unity.Entities.IComponentData'.
It compiled fine when I was just using one ComponentData and one BufferElementData i.e. the following worked:
Entities.WithAll<SomeComponentData, SomeBufferElementData>()
.ForEach((Entity entity, ref SomeComponentData componentData, DynamicBuffer<SomeBufferElementData> buffer) => {
});
I had a look at the ForEach code, which is generated code with lots of permutations of components and dynamicbuffers, but I couldn't find this one. (see answer - I just wasn't looking hard enough!) What happens in this situation where the permutation of ComponentData and BufferElementData is not supported?
Turns out this permutation was supported but I had to put the DynamicBuffer first. That is:
Entities.WithAll<SomeBufferElementData, SomeComponentData, SomeComponentData2>()
.ForEach((Entity entity, DynamicBuffer<SomeBufferElementData> buffer, ref SomeComponentData componentData, ref SomeComponentData2 componentData2) => {
});
I found this out by looking at the IJobForEachWithEntity_XXX interfaces. I found that there was an IJobForEachWithEntity_EBCC interface, which tipped me off to the fact that the buffer had to go before the components.
Hope this will save someone a few hours of their time!

Kryo serialisation in Chronicle Map - slow byte reading

I'm using Chronicle Map extensively in Scala and recently decided to experiment with Kryo serialisation. I added custom marshallers (code below) and while it reduced the size of my stores by 14G (roughly 62%), and everything still works, the speed was unacceptable.
I created a sample usecase and did a few runs on the same data
[Using kryo] took 6883, and then 7187, 6954, 7225, 13051
[Not using kryo] took 2326, and then 1352, 1493, 1500, 1187
So it's several times slower. Here's the marshaller for reading:
class KryoMarshallerReader[T] extends BytesReader[T] {
val kryo = // Reference to KryoPool from Twitter's Chill library
override def read(in: Bytes[_], using: T): T = {
val bytes = benchmark("array allocation") {
new Array[Byte](in.readRemaining().toInt)
}
benchmark("reading bytes") {
in.read(bytes)
}
benchmark("deserialising") {
kryo.fromBytes(bytes).asInstanceOf[T]
}
}
override def readMarshallable(wire: WireIn): Unit = {}
override def writeMarshallable(wire: WireOut): Unit = {}
}
I then averaged execution times (all in ms) over those three stages and realised that reading the bytes is the slowest:
stage Average time (ms)
(fctr) (dbl)
1 [array allocation] 0.9432907
2 [deserialising] 0.9944112
3 [reading bytes] 13.2367265
Now the question is - what am I doing wrong?
I looked through the interface of Bytes[_] and it looks like it reads bytes one by one - is there a way to use a buffer or something magically capable of bulk loading?
Update: Eventually I changed array allocation + reading bytes to in.toByteArray but it's still slow because under the hood it copies bytes one by one. Just running reads on the map shows that byte reading is the bottleneck:
in.readRemaining() of the Bytes, passed into BytesReader.read(), is not your object in serialized form, it's more than that. The serialized form of your object is guaranteed to start from in.readPosition(), but it typically end much earlier than in.readLimit() (as readRemaining() = readLimit() - readPosition()). Generally BytesReader/BytesWriter pair of implementations should care of determining the end of the object bytes itself (if it needs), e. g. see the implementation of CharSequenceArrayBytesMarshaller in BytesReader and BytesWriter section of the Chronicle Map tutorial:
public final class CharSequenceArrayBytesMarshaller
implements BytesWriter<CharSequence[]>, BytesReader<CharSequence[]> {
...
#Override
public void write(Bytes out, #NotNull CharSequence[] toWrite) {
out.writeInt(toWrite.length); // care about writing the size ourselves!
...
}
#NotNull
#Override
public CharSequence[] read(Bytes in, #Nullable CharSequence[] using) {
int len = in.readInt(); // care about reading the size ourselves!
...
}
}
But since your are implementing Kryo serialization which should be conceptually similar to Java standard serialization, you should probably take the source of SerializableReader and SerializableDataAccess and modify it to use Kryo instead of standard Java serialization (but note that those sources are LGPLv3 licensed). In particular those implementations use Bytes.inputStream() and Bytes.outputStream() to bridge the standard Java serialization, which doesn't know about Bytes, but knows about InputStream/OutputStream, without needlessly copying bytes. I'm pretty sure Kryo supports InputStream/OutputStream as well.
Be very careful with kryo as an instance field of any serializer interface (BytesReader in your case) without implementing StatefulCopyable. You may easily introduce concurrency bottlenecks, or concurrency bugs (data races). Check Understanding StatefulCopyable section in the Chronicle Map tutorial and Chronicle Map custom serialization checklist.

Using std::bind to capture a parameter pack "by move"

I'm attempting to implement std::async from scratch, and have run into a hiccup with arguments of move-only type. The gist of it is, C++14 init-captures allow us to capture single variables "by move" or "by perfect forwarding", but they do not appear to let us capture parameter packs "by move" nor "by perfect forwarding", because you can't capture a parameter pack by init-capture — only by named capture.
I've found what appears to be a workaround, by using std::bind to capture the parameter pack "by move", and then using a wrapper to move the parameters out of the bind object's storage into the parameter slots of the function I really want to call. It even looks elegant, if you don't think too much about it. But I can't help thinking that there must be a better way — ideally one that doesn't rely on std::bind at all.
(Worst case, I'd like to know how much of std::bind I'd have to reimplement on my own in order to get away from it. Part of the point of this exercise is to show how things are implemented all the way down to the bottom, so having a dependency as complicated as std::bind really sucks.)
My questions are:
How do I make my code work, without using std::bind? (I.e., using only core language features. Generic lambdas are fair game.)
Is my std::bind workaround bulletproof? That is, can anybody show an example where the STL's std::async works and my Async fails?
Pointers to discussion and/or proposals to support parameter-pack capture in C++1z will be gratefully accepted.
Here's my code:
template<typename UniqueFunctionVoidVoid>
auto FireAndForget(UniqueFunctionVoidVoid&& uf)
{
std::thread(std::forward<UniqueFunctionVoidVoid>(uf)).detach();
}
template<typename Func, typename... Args>
auto Async(Func func, Args... args)
-> std::future<decltype(func(std::move(args)...))>
{
using R = decltype(func(std::move(args)...));
std::packaged_task<R(Args...)> task(std::move(func));
std::future<R> result = task.get_future();
#ifdef FAIL
// sadly this syntax is not supported
auto bound = [task = std::move(task), args = std::move(args)...]() { task(std::move(args)...) };
#else
// this appears to work
auto wrapper = [](std::packaged_task<R(Args...)>& task, Args&... args) { task(std::move(args)...); };
auto bound = std::bind(wrapper, std::move(task), std::move(args)...);
#endif
FireAndForget(std::move(bound));
return result;
}
int main()
{
auto f3 = [x = std::unique_ptr<int>{}](std::unique_ptr<int> y) -> bool { sleep(2); return x == y; };
std::future<bool> r3 = Async(std::move(f3), std::unique_ptr<int>{});
std::future<bool> r4 = Async(std::move(f3), std::unique_ptr<int>(new int));
assert(r3.get() == true);
assert(r4.get() == false);
}
It was suggested to me offline that another approach would be to capture the args pack in a std::tuple, and then re-expand that tuple into the argument list of task using something like std::experimental::apply (coming soon to a C++17 standard library near you!).
auto bound = [task = std::move(task), args = std::make_tuple(std::move(args)...)]() {
std::experimental::apply(task, args);
};
This is much cleaner. We've reduced the amount of library code involved, down from bind to "merely" tuple. But that's still a big dependency that I'd love to be able to get rid of!

Java 8 Optional.ifPresent is my code wrong or is it eclipse?

I am new to Java 8 and trying out Null type annotations and Optional.
For my example below, I have used String rather than my class and am calling toUpperCase just to call something, in my case I actually call a function passing in a parameter (so don't think I can use :: operator and/or maps).
In Eclipse I have the Java - Compiler - Errors/Warnings - Null Analysis Errors turned on.
My test code below:
public void test1(#Nullable String s) {
// the 2nd s2 has a Potential null pointer access error.
// I was hoping ifPresent would imply NonNull
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
#Nullable
public String getSomeString() {
return null;
}
public void test2() {
String s = getSomeString();
// This is fine, unlike the first example, I would have assumed that
// it would know s was still nullable and behave the same way.
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
It would seem that using Eclipse type null annotations and Optional.ifPresent doesn't go well together.
Am I wasting my time trying to get something like this to work? Should I just revert back to assigning the getter to a temp var then checking if null, and if not call my function?
JDT's null analysis cannot know about the semantics of each and every method in JRE and other libraries. Therefore, no conclusions are drawn from seeing a call to ifPresent. This can be remedied by adding external annotations to Optional so that the analysis will see method ofNullable as
<T> Optional<#NonNull T> ofNullable(#Nullable T value)
External annotations are supported starting with Eclipse Mars, released June, 24, 2015. See Help: Using external null annotations.
The difference between the two variants in the question is due to how null analysis is integrated with Java 8 type inference: In variant (1) s has type #Nullable String. When this type is used during type inference, it is concluded that the argument to ifPresent is nullable, too. In variant (2) s has type String (although flow analysis can see that is may be null after the initialization from getSomeString). The unannotated type String is not strong enough to aid type inference to the same conclusion as variant (1) (although this could possibly be improved in a future version of JDT).
First of: #Nullable seams not to be part of the public Java 8 SDK. Have a look at the package you imported: com.sun.istack.internal.Nullable.
Second: I have run both of your methods: test1(null) and test2() and nothing out of the ordinary happened. Everything was fine (as expected). So what did you observe?
run test1(null) => no execution of lambda expression.
run test2() => no execution of lambda expression.
I changed your code for testing in the following way:
public void test1(#Nullable String s) {
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}
public void test2() {
String s = getSomeString();
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}

Why is generic instantiation syntax disallowed in Hack?

From the docs:
Note: HHVM allows syntax such as $x = Vector<int>{5,10};, but Hack
disallows the syntax in this situation, instead opting to infer
it.
Is there a specific reason for this? Isn't this a violation of the fail-fast rule?
There are some situations in which this would cause error to be deffered, which in turn leads to harder backtracing.
For example:
<?hh // strict
function main() : void {
$myVector = new Vector([]); // no generic syntax
$myVector->addAll(require 'some_external_source.php');
}
The above code causes no errors until it is used in a context where the statically-typed collection is actually in place:
class Foo
{
public ?Vector<int> $v;
}
$f = new Foo();
$f->v = $myVector;
Now there is an error if the vector contains something else then int. But one must trace back the error to the point where the flawed data was actually imported. This would not be necessary if one could instantiate the vector using generic syntax in the first place:
$myVector = new Vector<int>([]);
$myVector->addAll(require 'some_external_source.php'); // fail immediately
I work on the Hack type system and typechecker at Facebook. This question has been asked a few times internally at FB, and it's good to have a nice, externally-visible place to have an answer to it written down.
So first of all, your question is premised on the following code:
<?hh // strict
function main() : void {
$myVector = new Vector([]); // no generic syntax
$myVector->addAll(require 'some_external_source.php');
}
However, that code does not pass the typechecker due to the usage of require outside toplevel, and so any result of actually executing it on HHVM is undefined behavior, rendering this whole discussion moot for that code.
But it's still a legitimate question for other potential pieces of code that do actually typecheck, so let me go ahead and actually answer it. :)
The reason that it's unsupported is because the typechecker is actually able to infer the generic correctly, unlike many other languages, and so we made the judgement call that the syntax would get in the way, and decided to disallow it. It turns out that if you just don't worry about, we'll infer it right, and still give useful type errors. You can certainly come up with contrived code that doesn't "fail fast" in the way you want, but it's, well, contrived. Take for example this fixup of your example:
<?hh // strict
function main(): void {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
}
You might argue that this is bad, because you intended to have a Vector<int> but actually have a Vector<mixed> with no type error; you would have liked to be able to express this when creating it, so that adding 'oops' into it would cause such an error.. But there is no type error only because you never actually tried to use $myVector! If you tried to pull out any of its values, or return it from the function, you'd get some sort of type compatibility error. For example:
<?hh // strict
function main(): Vector<int> {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
return $myVector; // Type error!
}
The return statement will cause a type error, saying that the 'oops' is a string, incompatible with the int return type annotation -- exactly what you wanted. So the inference is good, it works, and you don't ever actually need to explicitly annotate the type of locals.
But why shouldn't you be able to if you really want? Because annotating only generics when instantiating new objects isn't really the right feature here. The core of what you're getting at with "but occasionally I really want to annotate Vector<int> {}" is actually "but occasionally I really want to annotate locals". So the right language feature is not to let you write $x = Vector<int> {}; but let you explicitly declare variables and write Vector<int> $x = Vector {}; -- which also allows things like int $x = 42;. Adding explicit variable declarations to the language is a much more general, reasonable addition than just annotating generics at object instantiation. (It's however not a feature being actively worked on, nor can I see it being such in the near to medium term future, so don't get your hopes up now. But leaving the option open is why we made this decision.)
Furthermore, allowing either of these syntaxes would be actively misleading at this point in time. Generics are only enforced by the static typechecker and are erased by the runtime. This means that if you get untyped values from PHP or Hack partial mode code, the runtime cannot possibly check the real type of the generic. Noting that untyped values are "trust the programmer" and so you can do anything with them in the static typechecker too, consider the following code, which includes the hypothetical syntax you propose:
<?hh // partial
function get_foo() /* unannotated */ {
return 'not an int';
}
<?hh // strict
function f(): void {
$v = Vector<int> {};
$v[] = 1; // OK
// $v[] = 'whoops'; // Error since explicitly annotated as Vector<int>
// No error from static typechecker since get_foo is unannotated
// No error from runtime since generics are erased
$v[] = get_foo();
}
Of course, you can't have unannotated values in 100% strict mode code, but we have to think about how it interacts with all potential usages, including untyped code in partial mode or even PHP.