Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointer already mapped #1268

Merged

Conversation

fpapai
Copy link

@fpapai fpapai commented Nov 13, 2020

Regarding #326,

Changes are the following:

  • map of pointer-to-callback is replaced with a map of pointer-to-array-of-callbacks to handle callbacks with different signatures mapped to the same native pointer.
  • modified related unit test

Not sure if this was the best solution, I hope that you can give me feedback on it.
I did not benchmark it.

Copy link
Member

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. In general this looks sane to me. I would like to understand though, when the same pointer can sanely assigned to different Callback signatures?

It would be great if you could come up with a microbenchmark, that helps to understand the impact of the change.

Callback existingCb = getTypeAssignableCallback(cbClass, array);
if (existingCb == null) {
pointerCallbackMap.put(cbref.getTrampoline(), addCallback(array, cb));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this logic is necessary? Shouldn't a direct addition work?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right.
As in native-to-java callback using JNA practically it is not possible to create such situation.
The code can just create the array[1] with the reference.
I'll modify the code shortly.

return null;
}

private static Reference<Callback>[] addCallback(Reference<Callback>[] array, Callback cb) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about switching the signature of this to:

private static void addCallback(Map<Pointer, Reference<Callback>[]> pointerCallbackMap, Pointer pointer, Callback cb)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not change it, as your proposal suggests that it will do more than now: to update pointerCallbackMap.
That update is in a synchronized block on that object. It is nice to see the related get / put in one location.
If all sync block is extracted as well, then there is an extra map-removal operation in that block that would not belong.
The code for reference:

...
        Map<Callback, CallbackReference> map = direct ? directCallbackMap : callbackMap;
        synchronized(pointerCallbackMap) {
            Reference<Callback>[] array = pointerCallbackMap.get(p);
            Callback cb = getTypeAssignableCallback(type, array);
            if (cb != null) {
                return cb;
            }
            cb = createCallback(type, p);
            pointerCallbackMap.put(p, addCallback(array, cb));

            // No CallbackReference for this callback
            map.remove(cb);
            return cb;
        }
...

However I'd find a better name for the current addCallback. Perhaps 'expandArrayWithCallback'.

@twall
Copy link
Contributor

twall commented Nov 22, 2020 via email

@matthiasblaesing
Copy link
Member

I can see an approach where a callback takes a structure as a reference and the library defines, that all argument candidates contain a marker as the first element of the structure. The callback could then safely examine the first elements and dispatch based on that content. In my idea the base implementation is implemented by a single callback, but on the outside, typesafe callbacks are defined.

In that case the java side could validly encounter the same function pointer as a callback with different signatures. I admit, that this is kind of constructed, but I'm pretty sure, that if I can come up with this, others have done so too.

@fpapai
Copy link
Author

fpapai commented Nov 29, 2020

Thank you. In general this looks sane to me. I would like to understand though, when the same pointer can sanely assigned to different Callback signatures?

It would be great if you could come up with a microbenchmark, that helps to understand the impact of the change.

Regarding your question:
the use case is an API defined in a C header, one java application code that uses that API to talk to many 'external' (not under my control) DLLs implementing the API. Those DLLs for various reasons may reuse function pointers (feature incompleteness, compiler optimizations). They have the right to reuse them.

Does the project have a benchmarking setup or examples?

@matthiasblaesing
Copy link
Member

I ran benchmarked this with jmh on this code:

public class StructureInstantiationBenchmark {
    static interface DummyCallback extends Callback {
        public void dummy();
    }


    @Benchmark
    public Callback[] testExceptionPointerConstructor() throws IOException, URISyntaxException {
        Callback[] cr = new Callback[1000];
        for(int i = 1; i <= cr.length; i++) {
            cr[i - 1] = CallbackReference.getCallback(DummyCallback.class, Pointer.createConstant(i));
        }
        return cr;
    }
}

The performance hit is somewhere between 2.5 and 5%, but the 5% has a wide error margin, so I would consider it minimal.

@fpapai it would be great if you could add an entry to CHANGES.md for this and squash the commits into a single one.

@fpapai
Copy link
Author

fpapai commented Dec 19, 2020

@fpapai it would be great if you could add an entry to CHANGES.md for this and squash the commits into a single one.

Thank you for the benchmark.
Done: updated CHANGES.md and squashed the commits.

@fpapai fpapai force-pushed the pointer-already-mapped branch from bbbd17e to 33a1c3e Compare December 19, 2020 02:26
@matthiasblaesing
Copy link
Member

Thank you for taking care of this - its appreciated.

@matthiasblaesing matthiasblaesing merged commit c44a545 into java-native-access:master Dec 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants