Standalone compiled OCL [message #1777950] |
Wed, 06 December 2017 16:42 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hello,
I am having trouble running compiled OCL as a standalone Java application. I am using the derived genmodel as the metamodel (which includes the OCL standard library) and when I run the program, I get:
org.eclipse.emf.ecore.resource.Resource$IOWrappedException: Package with uri 'http://www.eclipse.org/emf/2002/GenModel' not found
I have tried running this configuration using standalone interpreted OCL and it works. I have attached the complete project. The main class is test/JavaMMLauncher. Here there is a boolean flag for switching between compiled (based on OCLinEcore) and interpreted OCL (based on Pivot CompleteOCL).
I presume the issue is that the GenModel has not been added to the EPackage.Registry, but GenModel is not accessible. I was wondering if there is a workaround for this, or if the way I'm trying to use the compiled OCL is wrong?
Thanks,
Sina
|
|
|
|
Re: Standalone compiled OCL [message #1778196 is a reply to message #1777962] |
Mon, 11 December 2017 18:27 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
Thanks for the solution. Strangely it seems to work on one PC but not on another, both of which have Eclipse Oxygen installed with the latest OCL patch applied. I tried regenerating the genmodel and Java code, even using the same model, metamodel, generated code etc. across both computers and still on one it doesn't fix the issue on the other it does. I presume it's some quirk with EMF or at least the version installed.
On the installation where it fixes the GenModel not found issue, I get another error:
Exception in thread "main" java.lang.ExceptionInInitializerError
at javaMM.impl.JavaMMFactoryImpl.createMethodDeclaration(JavaMMFactoryImpl.java:849)
at javaMM.impl.JavaMMFactoryImpl.create(JavaMMFactoryImpl.java:227)
at org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl.createObject(XMLHelperImpl.java:885)
at org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl.createObject(XMLHelperImpl.java:922)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createObjectFromFactory(XMLHandler.java:2222)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createObjectFromTypeName(XMLHandler.java:2132)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.createObject(XMLHandler.java:2067)
at org.eclipse.emf.ecore.xmi.impl.XMIHandler.createObject(XMIHandler.java:151)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.handleFeature(XMLHandler.java:1876)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.processElement(XMLHandler.java:1030)
at org.eclipse.emf.ecore.xmi.impl.XMIHandler.processElement(XMIHandler.java:82)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.startElement(XMLHandler.java:1008)
at org.eclipse.emf.ecore.xmi.impl.XMLHandler.startElement(XMLHandler.java:719)
at org.eclipse.emf.ecore.xmi.impl.XMIHandler.startElement(XMIHandler.java:190)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1359)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2784)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:327)
at org.eclipse.emf.ecore.xmi.impl.XMLLoadImpl.load(XMLLoadImpl.java:175)
at org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl.doLoad(XMLResourceImpl.java:261)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1518)
at org.eclipse.emf.ecore.resource.impl.ResourceImpl.load(ResourceImpl.java:1297)
at org.eclipse.epsilon.evl.engine.test.acceptance.equivalence.StandaloneOCL.preExecute(StandaloneOCL.java:186)
at org.eclipse.epsilon.profiling.ProfilableRunConfiguration.run(ProfilableRunConfiguration.java:44)
at test.JavaMMLauncher.main(JavaMMLauncher.java:28)
Caused by: org.eclipse.emf.common.util.BasicEList$BasicIndexOutOfBoundsException: index=-1, size=0
at org.eclipse.emf.common.util.BasicEList.get(BasicEList.java:346)
at javaMM.impl.JavaMMPackageImpl.getAbstractMethodDeclaration__ParametersEffectivelyFinal__DiagnosticChain_Map(JavaMMPackageImpl.java:1123)
at javaMM.impl.AbstractMethodDeclarationImpl.<clinit>(AbstractMethodDeclarationImpl.java:252)
... 32 more
Looking at the cause, the problem is in this method of JavaMMPackageImpl:
public EOperation getAbstractMethodDeclaration__ParametersEffectivelyFinal__DiagnosticChain_Map() {
return getAbstractMethodDeclaration().getEOperations().get(-1);
}
The associated OCL code with this invariant is as follows:
invariant parametersEffectivelyFinal:
(self._'body' <> null or self.parameters->isEmpty()) implies (
self._'body'.statements ->
selectByKind(ExpressionStatement) ->
collect(s | s.expression) ->
selectByKind(Assignment) ->
select(assignment |
assignment.leftHandSide.oclIsKindOf(SingleVariableAccess) and
assignment.operator = '='
) ->
isEmpty()
);
So the only way this could happen is either that the OCL code is wrong, in which case I would expect some error when running the interpretted version. Also given that an identical script was written in EVL and both the interpretted OCL and EVL version give identical results without exceptions, I doubt this could be the issue. Perhaps more likely is that the OCLinEcore version of the constraints is mis-specified, or there is a bug in the code generation.
|
|
|
|
|
|
|
|
Re: Standalone compiled OCL [message #1778359 is a reply to message #1778292] |
Wed, 13 December 2017 13:00 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
I was referring to the problem detailed in the third message, below the first stack trace. Sorry if this wasn't clear.
I tried regenerating again on the computer where everything works and get the same problem with "GenClass for Boolean not found". I'm not doing anything different to what I was before, and the Ecore model hasn't changed. However every time I generate the genmodel, I get HTTP 405 error, perhaps because it's trying to use the model URI as a URL, but this was happening before and the generated code didn't have any compilation errors. I haven't changed the installation of Eclipse with updates or anything of the sort though. Also I found a bug where there are NullPointerExceptions when performing the generation if the parent project has a space in its name. When I tried redoing everything in another project (without space in name), I got GenClass not found again. So finally I tried creating a new workspace and repeating the process. Again I got the same issue.
At this point I'm inclined to abandon using compiled OCL, as I seem to be getting different issues when repeating exactly the same actions on the same files under the same conditions. Once again thanks for your help, but using compiled OCL for a complex metamodel with many constraints in a standalone Java application has been more time-consuming and error-prone than I anticipated.
|
|
|
|
Re: Standalone compiled OCL [message #1778388 is a reply to message #1778361] |
Wed, 13 December 2017 16:41 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
I believe I have provided the necessary files to reproduce the problem in the original post. Everything else is derived from following instructions as outlined in the OCLinEcore code generation tutorial. Again testing with a new workspace using the latest version of Eclipse OCL (http://www.eclipse.org/modeling/download.php?file=/modeling/mdt/ocl/downloads/drops/6.4.0/N201712012043/mdt-ocl-Update-N201712012043.zip), I get these issues. Whilst it's true that anything could be a contributing factor, such as the location of files, operating system, other installed plug-ins, the Eclipse installation etc. it would be infeasible to upload everything.
I would be happy to assist in solving this issue however I do not have the time to learn the Eclipse OCL codebase and how it interacts with EMF, since it's not clear to me whether these issues are with Eclipse OCL or EMF.
Thanks,
Sina
|
|
|
|
|
Re: Standalone compiled OCL [message #1779162 is a reply to message #1778456] |
Wed, 03 January 2018 11:51 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
Having sorted out the OCL and code generation issues, I am now wondering how the generated EValidator should be used? Currently I am loading the model and recursively calling validate() on all contents. However this produces more unsatisfied constraints than expected (5138 vs 2599) and also takes 50 seconds to run (compared to 15 seconds for interpreted)! Clearly something about this approach is not right, but when I tried feeding in the root model element
the validator does not deeply check the containing elements, so it returns immediately with no unsatisfied constraints. Using the manual iteration approach (i.e. calling getAllContents() on the model Resource) and pruning when encountering an invalid element, the number of unsatisfied constraints is still greater than expected (3076) and takes a similar amount of time to run as without pruning.
I have attached a complete self-sufficient example. The method of interest is in javaMM.launch.JavaMMLauncher.loadModelAndCreateDiagnostician(). Here I create a custom Diagnostician and define the validation logic in the method "validateResource(DiagnosticChain diagnostics, Map context)".
Thanks in advance,
Sina
[Updated on: Wed, 03 January 2018 11:56] Report message to a moderator
|
|
|
|
|
|
|
Re: Standalone compiled OCL [message #1779216 is a reply to message #1779207] |
Thu, 04 January 2018 06:52 |
Ed Willink Messages: 7670 Registered: July 2009 |
Senior Member |
|
|
Hi
Your test model has 200,000 lines defining perhaps 20,000 model elements, so based on the performance results in Fig 16 of [1] where speeds approach 1million per second you might expect an execution time of 20 ms. This is only a very rough estimate since your computer may be faster/slower, you don't have to do any output creation, you may have more validation computation per element. Instead you see 20 seconds; a 1000-fold discrepancy.
It is very unlikely that 1000-fold overhead is consumed by necessary work. Something very bad is happening. [1] shows that poor transformation scheduling can go quadratic. In [2] you can see how bad OCL tooling can be on some operations. I already identified allInstances() as bad. It can be cubic in poor implementations. Stepping your example it looked like it was quadratic. The optimizations of [2] are not yet available in Eclipse OCL.
So long as any algorithm is quadratic or worse, that is likely to dominate your performance. But you first need to get a handle on your measuring. You have not yet resolved the difference between compiled/not-compiled tests. So first ensure that both have the same number of validations of the same nodes, and that the validations produce the same results. Depending on what you actually want to measure may affect how you measure it. For instance you might choose to have an unmeasured traversal that puts all the objects in a list so that the measurements of object validation are isolated from the confounding traversal effect, which could be separately instrumented. You might choose to have a very simple failure logging to isolate the cost of BasicDiagnostic maintenance.
First debug to get predictable relevant results for your alternative execution approaches.
Then isolate the non-linear contributors, possibly by commenting out to keep only one algorithm at a time.
While debugging it may help to have a much smaller test model so that you just printf what is happening.
Regards
Ed Willink
[1] http://www.eclipse.org/mmt/qvt/docs/ICMT2017/MicromappingMoC.pdf
[2] http://www.eclipse.org/modeling/mdt/ocl/docs/publications/OCL2017Evaluation/LazyDeterminism.pdf
|
|
|
Re: Standalone compiled OCL [message #1779264 is a reply to message #1779216] |
Thu, 04 January 2018 15:14 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
Thanks again for the suggestions and ideas. I removed calls to allInstances and now the performance is under 3 seconds with the same number of unsatisfied constraints as before (so still incorrect). Also lambdas have a negligible performance impact, especially as I'm not using them in a loop (see [1], for example of one of the optimisations supported at the bytecode level). Regarding the results, the only explanation I can think of for the differences is either a bug in the generated code or subtle differences between OCLinEcore and CompleteOCL semantics, since the former was derived from the latter.
I should also note that the only reason I'm doing this is to compare the performance of compiled and interpreted. It appears that theory and practice do not agree in this case, as the compiled version is apparently not doing the same thing as the interpreted despite seemingly identical inputs.
[1]https://stackoverflow.com/a/30002627/5870336
[Updated on: Thu, 04 January 2018 15:25] Report message to a moderator
|
|
|
|
Re: Standalone compiled OCL [message #1779285 is a reply to message #1779266] |
Thu, 04 January 2018 20:27 |
Sina Madani Messages: 160 Registered: November 2015 Location: York, UK |
Senior Member |
|
|
Hi Ed,
I tried as you suggested and the problem appears to be the difference in the outer loop. I even tried adding all the elements into a Set and yet all of the visited elements were indeed unique (at least according to EObject.equals). It seems that the lack of deep validation is a limitation of EObjectValidator rather than the code generated by OCL. It is puzzling why Diagnostician performs deep validation but EObjectValidator does not. I'll raise a bug in EMF.
Thanks,
Sina
[Updated on: Thu, 04 January 2018 20:28] Report message to a moderator
|
|
|
|
|
|
|
|
|
|