Error when running PMML service with native image

177 views
Skip to first unread message

Jan Urbanek

unread,
Aug 16, 2021, 5:45:14 AM8/16/21
to Kogito development mailing list

Hello,
I created a simple PMML service with Quarkus. Direct PMML invocation through REST endpoints didn't work because the model wasn't supported.
Therefore I used JPMML implementation (https://mvnrepository.com/artifact/org.jpmml/pmml-evaluator and https://mvnrepository.com/artifact/org.jpmml/pmml-model libraries) to invoke PMML using DMN.
Such setup works when running in Local Dev Mode. However there is failure when trying to generate native executable with GraalVM.  
After using workaround and successful image build service fails at runtime with NoSuchMethodException.
It only occurs when evaluating PMML MiningModel.

Error at image build:

Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Detailed message:
Trace:
        at parsing com.google.common.cache.Striped64.retryUpdate(Striped64.java:184)
Call path from entry point to com.google.common.cache.Striped64.retryUpdate(long, int[], boolean):
        at com.google.common.cache.Striped64.retryUpdate(Striped64.java:182)
        at com.google.common.cache.LongAdder.add(LongAdder.java:73)
        at com.google.common.cache.AbstractCache$SimpleStatsCounter.recordLoadException(AbstractCache.java:230)
        at com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2322)
        at com.google.common.cache.LocalCache$Segment$1.run(LocalCache.java:2293)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:553)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
        at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)

com.oracle.svm.core.util.UserError$UserException: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Detailed message:
Trace:
        at parsing com.google.common.cache.Striped64.retryUpdate(Striped64.java:184)
Call path from entry point to com.google.common.cache.Striped64.retryUpdate(long, int[], boolean):
        at com.google.common.cache.Striped64.retryUpdate(Striped64.java:182)
        at com.google.common.cache.LongAdder.add(LongAdder.java:73)
        at com.google.common.cache.AbstractCache$SimpleStatsCounter.recordLoadException(AbstractCache.java:230)
        at com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2322)
        at com.google.common.cache.LocalCache$Segment$1.run(LocalCache.java:2293)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:553)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
        at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)

        at com.oracle.svm.core.util.UserError.abort(UserError.java:82)
        at com.oracle.svm.hosted.FallbackFeature.reportAsFallback(FallbackFeature.java:233)
        at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:798)
        at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:582)
        at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$2(NativeImageGenerator.java:495)
        at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
Detailed message:
Trace:
        at parsing com.google.common.cache.Striped64.retryUpdate(Striped64.java:184)
Call path from entry point to com.google.common.cache.Striped64.retryUpdate(long, int[], boolean):
        at com.google.common.cache.Striped64.retryUpdate(Striped64.java:182)
        at com.google.common.cache.LongAdder.add(LongAdder.java:73)
        at com.google.common.cache.AbstractCache$SimpleStatsCounter.recordLoadException(AbstractCache.java:230)
        at com.google.common.cache.LocalCache$Segment.getAndRecordStats(LocalCache.java:2322)
        at com.google.common.cache.LocalCache$Segment$1.run(LocalCache.java:2293)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:553)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
        at com.oracle.svm.core.code.IsolateEnterStub.PosixJavaThreads_pthreadStartRoutine_e1f4a8c0039f8337338252cd8734f63a79b5e3df(generated:0)

        at com.oracle.graal.pointsto.constraints.UnsupportedFeatures.report(UnsupportedFeatures.java:126)
        at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:795)
        ... 8 more
Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected an instance of Random/SplittableRandom class in the image heap. Instances created during image generation have cached seed values and don't behave as expected.  To see how this object got instantiated use --trace-object-instantiation=java.util.Random. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
        at com.oracle.svm.hosted.image.DisallowedImageHeapObjectFeature.error(DisallowedImageHeapObjectFeature.java:163)        at com.oracle.svm.core.image.DisallowedImageHeapObjects.check(DisallowedImageHeapObjects.java:65)
        at com.oracle.svm.hosted.image.DisallowedImageHeapObjectFeature.replacer(DisallowedImageHeapObjectFeature.java:139)
        at com.oracle.graal.pointsto.meta.AnalysisUniverse.replaceObject(AnalysisUniverse.java:565)
        at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.replaceObject(AnalysisConstantReflectionProvider.java:213)
        at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.interceptValue(AnalysisConstantReflectionProvider.java:184)
        at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.readValue(AnalysisConstantReflectionProvider.java:98)
        at com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider.readFieldValue(AnalysisConstantReflectionProvider.java:77)
        at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.util.ConstantFoldUtil$1.readValue(ConstantFoldUtil.java:51)
        at jdk.internal.vm.compiler/org.graalvm.compiler.core.common.spi.JavaConstantFieldProvider.readConstantField(JavaConstantFieldProvider.java:84)
        at com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider.readConstantField(AnalysisConstantFieldProvider.java:70)
        at jdk.internal.vm.compiler/org.graalvm.compiler.nodes.util.ConstantFoldUtil.tryConstantFold(ConstantFoldUtil.java:47)
        at com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin.tryConstantFold(ConstantFoldLoadFieldPlugin.java:61)        at com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin.handleLoadStaticField(ConstantFoldLoadFieldPlugin.java:57)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genGetStatic(BytecodeParser.java:4972)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genGetStatic(BytecodeParser.java:4939)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5442)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3451)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3258)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1125)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:1019)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:84)
        at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase.run(SharedGraphBuilderPhase.java:76)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.run(Phase.java:49)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:212)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
        at com.oracle.graal.pointsto.flow.AnalysisParsedGraph.parseBytecode(AnalysisParsedGraph.java:113)
        at com.oracle.svm.hosted.SVMHost.parseBytecode(SVMHost.java:647)
        at com.oracle.graal.pointsto.meta.AnalysisMethod.ensureGraphParsed(AnalysisMethod.java:592)
        at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:163)
        at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:304)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.createTypeFlow(MethodTypeFlow.java:313)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureTypeFlowCreated(MethodTypeFlow.java:302)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:103)
        at com.oracle.graal.pointsto.DefaultAnalysisPolicy$DefaultSpecialInvokeTypeFlow.onObservedUpdate(DefaultAnalysisPolicy.java:368)
        at com.oracle.graal.pointsto.flow.TypeFlow.notifyObservers(TypeFlow.java:470)
        at com.oracle.graal.pointsto.flow.TypeFlow.update(TypeFlow.java:542)
        at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:547)
        at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:173)
        at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
        ... 5 more
Error: Image build request failed with exit status 1


Steps to reproduce issue:


At reproducer root directory run:

mvn clean package -Pnative -Dquarkus.log.level=ALL

The workaround:

Make GraalVM initialize classes that are causing error at runtime.
The classes are:
    com.google.common.cache.LongAdder
    com.google.common.cache.Striped64
    com.google.common.cache.LongAddables
    com.google.common.cache.Striped64$Cell

File src/main/resources/META-INF/native-image/native-image.properties contains setting required to do that.

Steps to reproduce issue after workaround:

Uncomment first line in src/main/resources/META-INF/native-image/native-image.properties
You can now build native image using the same command.

Run native executable:

./target/pmml_example-1.0-SNAPSHOT-runner

Send correct JSON using OpenAPI UI or curl, for example:

curl -X 'POST' \
  'http://localhost:8080/iris' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "Sepal length": 5.4,
  "Sepal width": 3.7,
  "Petal length": 1.5,
  "Petal width": 0.2
}'

Error at runtime:

Error invoking function 'ML model' on node 'ML model': java.lang.IllegalArgumentException: java.lang.NoSuchMethodException
        at org.jpmml.evaluator.ModelManagerFactory.newModelManager(ModelManagerFactory.java:125)
        at org.jpmml.evaluator.ModelEvaluatorFactory.newModelEvaluator(ModelEvaluatorFactory.java:38)
        at org.jpmml.evaluator.mining.MiningModelEvaluator.createSegmentModelEvaluator(MiningModelEvaluator.java:816)
        at org.jpmml.evaluator.mining.MiningModelEvaluator.ensureSegmentModelEvaluator(MiningModelEvaluator.java:765)
        at org.jpmml.evaluator.mining.MiningModelEvaluator.evaluateSegmentation(MiningModelEvaluator.java:505)
        at org.jpmml.evaluator.mining.MiningModelEvaluator.evaluateClassification(MiningModelEvaluator.java:304)
        at org.jpmml.evaluator.ModelEvaluator.evaluateInternal(ModelEvaluator.java:449)
        at org.jpmml.evaluator.mining.MiningModelEvaluator.evaluateInternal(MiningModelEvaluator.java:237)
        at org.jpmml.evaluator.ModelEvaluator.evaluate(ModelEvaluator.java:302)
        at org.kie.dmn.jpmml.DMNjPMMLInvocationEvaluator.evaluate(DMNjPMMLInvocationEvaluator.java:78)
        at org.kie.dmn.core.ast.DMNFunctionDefinitionEvaluator$DMNFunction.invoke(DMNFunctionDefinitionEvaluator.java:175)
        at org.kie.dmn.feel.runtime.functions.BaseFEELFunction.invokeReflectively(BaseFEELFunction.java:130)
        at org.kie.dmn.core.ast.DMNInvocationEvaluator.evaluate(DMNInvocationEvaluator.java:177)
        at org.kie.dmn.core.impl.DMNRuntimeImpl.evaluateDecision(DMNRuntimeImpl.java:666)
        at org.kie.dmn.core.impl.DMNRuntimeImpl.evaluateAll(DMNRuntimeImpl.java:114)
        at org.kie.kogito.dmn.DmnDecisionModel.evaluateAll(DmnDecisionModel.java:61)
        at https_58_47_47kiegroup_46org_47dmn_47__11917DDF_451295_4546B3_45BA00_457E1738EDF88A.IrisResource.dmn(IrisResource.java:57)
        at java.lang.reflect.Method.invoke(Method.java:566)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
        at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
        at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:35)
        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63)
        at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:67)
        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133)
        at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65)
        at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
        at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
        at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:247)
        at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:56)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:111)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:108)
        at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
        at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1.call(UndertowDeploymentRecorder.java:587)
        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227)
        at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:152)
        at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$1.handleRequest(UndertowDeploymentRecorder.java:119)
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290)
        at io.undertow.server.DefaultExchangeHandler.handle(DefaultExchangeHandler.java:18)
        at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$5$1.run(UndertowDeploymentRecorder.java:413)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:481)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2442)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1476)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:553)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: java.lang.NoSuchMethodException
        at org.jpmml.evaluator.ModelManagerFactory.findConstructor(ModelManagerFactory.java:258)
        at org.jpmml.evaluator.ModelManagerFactory.newModelManager(ModelManagerFactory.java:93)
        ... 77 more

Expected behaviour:

In native_error_reproducer run:

mvn clean compile quarkus:dev

Send correct JSON using OpenAPI UI or curl, for example:

curl -X 'POST' \
  'http://localhost:8080/iris' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "Sepal length": 5.4,
  "Sepal width": 3.7,
  "Petal length": 1.5,
  "Petal width": 0.2
}'

You can also change "RandomForest predictor" (iris_randomforest.pmml) to "LogReg predictor" (iris_logreg.pmml) in DMN and build & run native image.


Additional information:

PMML file "iris_randomforest.pmml" was generated by converting simple Scikit-learn RandomForestClassifier using SkLearn2PMML library.

Tests using the same code but with other PMML models (RegressionModel, NearestNeighborModel, NeuralNetwork, SupportVectorMachineModel) did not reproduce the issue.

All kinds of models work when using Local Dev Mode.
All kinds of models fail when building native image without workaround.

Environment:

Operating system:
Ubuntu 20.04 LTS on Windows 10

Java:
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing)

GraalVM: 21.1.0

Quarkus: 2.0.0.Final

Kogito: 1.9.1.Final

PMML version: 4.4

SkLearn2PMML: 0.73.5

Scikit-learn: 0.24.2

kie-dmn-jpmml: 7.57.0.Final

JPMML-Evaluator: 1.5.15

JPMML-Model: 1.5.15

Daniele Zonca

unread,
Aug 26, 2021, 4:30:45 AM8/26/21
to Kogito development mailing list, Gabriele Cardosi
Hi Jan,

Thanks for the detailed reproducer.

Kogito enables the usage of jPMML as an alternative PMML implementation (used via DMN) but it is not a component of the Kogito ecosystem so we mainly use it as a library and we don't test native compilation compatibility. 

As far as I can see the problem is that jPMML library is not compatible with native compilation (via GraalVM) so even if you configure that property to move at runtime some initialization, the engine is probably performing some reflection/introspection (like ServiceLoader) to load the model and it breaks.
If the problem is the reflection this is usually solvable listing with a specific file all the classes to introspect (see this Quarkus guide and the official GraalVM documentation) but to be honest native compilation configuration and fixes can be not trivial.

My suggestion is to raise this issue to the jPMML project to see if they have interest in making the library compatible with native compilation: in the best case scenario it is enough to add a reflect-config.json file with the list of the classes like DMN engine does.

In parallel I added in cc the main developer of our PMML implementation to check your reproducer and see if it is possible (or how hard is) to make these PMMLs work with it that works also in native mode.

HTH
Daniele


--
You received this message because you are subscribed to the Google Groups "Kogito development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kogito-developm...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kogito-development/2cf63abd-9b77-4c34-9e8a-44094f347c99n%40googlegroups.com.

Gabriele Cardosi

unread,
Aug 26, 2021, 5:07:35 AM8/26/21
to Daniele Zonca, Kogito development mailing list
Hi Jan, Daniele,
I cloned and adapted the reproducer to work with our PMML implementation.
The iris_logreg.pmml works without issue.
The iris_randomforset.pmml not work due to a lacking feature we are going to fix next week (https://issues.redhat.com/browse/DROOLS-6561) but not available, yet.

I'll let you know ASAP as it is done and available.


Best Regards

Gabriele

--

GABRIELE CARDOSI

SENIOR SOFTWARE ENGINEERS, MW

Red Hat Ltd

gcar...@redhat.com    M: +39-3461717132    

Reply all
Reply to author
Forward
0 new messages