Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
EclipseLink/Examples/JPA/Simulation
< EclipseLink | Examples | JPA
Contents
Simulation JPA Application Example
DISCLAIMER: This page reflects investigation into how EclipseLink technology can used as part of - or benefit from integration with other projects. It does NOT imply any formal certification from EclipseLink on these technologies or make any assumptions on the direction of the API. This page is purely experimental speculation.
Purpose
- This sumulation will serve as a near real world enterprise application that showcases utilizing JPA as the persistence or integration layer of a major hardware/software system application - specifically using EclipseLink JPA as the JPA provider.
- The software will also showcase the distributed performance capabilities of EclipseLink by using the 1st level cache and an optional 2nd level distributed memory cache in clustered mode using either TopLink Grid or Terracotta EhCache.
- Additionally, the process and result of this analysis will use and showcase an example UML based design approach.
- This enterprise application will offer the services of a simulated SIMD Parallel Processor somewhat like the Connection Machine (Ref: Thinking Machines CM-2, MIT Cosmic Cube (MIMD), Burroughs Illiac IV etc.).
- Why are we choosing an older architecture to simulate?
- a) The architecture is very clean and closed and even though it is very large - is simple enough to implement.
- b) The Design by Danny Hillis in his dissertation is out of print as of 2005 and Thinking Machines no longer exists in whole but was partially acquired by Oracle - so we are free to simulate the device in software and hardware.
- b) The design is proven and static - as it has been superceeded by and incorporated in more powerfull designs).
- c) The massively parallel processing design of the CM-2 matches our goal of utilizing parallelism at both the thread and multi-core processor level on our plain host machine - an 8 core Intel i7-920 - although at a more granular level.
- Why are we choosing an older architecture to simulate?
Goals
- We would like to explore the following limits of the JPA provider and hosting application server.
- Performance and Volumetrics: We require 65536 processor objects - but will likely simulate a Kilo (1024) core machine.
Infrastructure
- OS: Windows 7 64 bit
- Database: Derby 10.5.3.0
- JPA provider: EclipseLink 2.2
- JDK: Sun 1.6.0_17
Analysis
Data Model 1: Dynamic Routing Hypercube
Processor Architecture 1: Finite Element Space
- Each CM-2 processor is composed of up to 64k (65536) 1-bit processors arranged in a 12-dimensional hypercube of 16 processors per node.
- There are 16 1-bit cores per chip along with 1 routing core per chip.
- There are 32 cpu chips and 32 ram chips per backplane board
- There are 16 boards per quadrant
- There are 8 quadrands to a CM-2
- There are 16 boards per quadrant
- There are 32 cpu chips and 32 ram chips per backplane board
- We therefore have (2^4=16) x (2^5=32) x (2^4=16) x (2^3=8) = 2^16 = 65536 possible cores in a fully configured system.
- There are 16 1-bit cores per chip along with 1 routing core per chip.
Static Class Hierarchy
- Hypercube (quadrants(1:M), input, output, program)
- Quadrant (boards(1:M), hypercube(1:1))
- Board (processorChips(1:M), ramChips(1:M))
- Chip(A)
- ProcessorChip (processors (1:M), router (1:1))
- MemoryChip
- Processor(A)
- VectorProcessor(alu, stateMachine, uProgram)
- RouterProcessor (routers(1:M))
Data Model 2: Static Routing Planar Array
Processor Architecture 2: Cellular Automata
- Each CAS processor is composed of an open number of 1 bit processors arranged in a rectangular grid either bounded or toroidal. Here will will simulate a minimum 44' x 24 array of 1056 cores so we can fit a minimum size Gosper glider gun.
- There are 8 1-bit cores per chip - each core manages its own nearest neighboor routing
- The chips are arranged logically in a 44 x 24 grid totalling 1056 cores (a Kilocore).
- There are 8 1-bit cores per chip - each core manages its own nearest neighboor routing
Static Class Hierarchy
- Hypercube (quadrants(1:M), input, output, program)
- Quadrant (boards(1:M), hypercube(1:1))
- Board (processorChips(1:M), ramChips(1:M))
- Chip(A)
- ProcessorChip (processors (1:M), router (1:1))
- MemoryChip
- Processor(A)
- VectorProcessor(alu, stateMachine, uProgram)
- RouterProcessor (routers(1:M))
Design
Software
JPA Data Model
Hardware
Block Diagrams
Prototype Three Dimensional Hypercube
- The following diagram illustrates via block diagram the layout of a prototype 3 dimensional hypercube architecture at the bottom hardware end of the implementation stack where EclipseLink acts as the ORM persistence layer for both the design and runtime parts of the system.
Prototype Planar SIMD Array
- The following diagrams discuss design issues surrounding a 2 dimensional array of processing module cores - their layout, connection topology and synchronization protocols.
Design Issue 1: Minimizing Inter-module Connections
- The following 2 x 8 layout of 2 chips of 8 cores forming a 16 core module is not optimum.
- The following 4 x 4 layout of 2 chips of 8 cores forming a 16 core module is optimum.
- We can reduce the 8 connection paths to 4 by reusing the corner values of the NEWS primary connectors - which is only required for the incoming connections - not the outgoing ones.
Schematics
Implementation
Software
Business Logic Client
Schema Model
Board.java
@Entity @Table(name="CM_BOARD") public class Board implements Serializable { @Id @GeneratedValue(strategy=TABLE, generator="BOARD_CM_TABLE_GENERATOR") @TableGenerator( name="BOARD_CM_TABLE_GENERATOR", table="CM_BOARD_SEQ", pkColumnName="SEQ_CM_NAME", valueColumnName="SEQ_CM_COUNT", pkColumnValue="CUST_CM_SEQ" ) @Column(name="BOARD_ID") private Integer id; @Version @Column(name="BOARD_VERSION") private int version; // If a JoinTable with a JoinColumn is used - then we need a mappedBy on the inverse side here @OneToMany(cascade=ALL, mappedBy="board") private List<ProcessorChip> processorChips = new ArrayList<ProcessorChip>(); // The M:1 side is the owning side @ManyToOne(fetch=EAGER)//LAZY) @JoinTable(name="CM_QUADRANT_CM_BOARD", joinColumns = @JoinColumn(name="BOARD_ID"), inverseJoinColumns =@JoinColumn(name="QUADRANT_ID")) private Quadrant quadrant; public List<VectorProcessor> getVectorProcessors() { List<VectorProcessor> allProcessors = new ArrayList<VectorProcessor>(); for(ProcessorChip aProcessorChip : processorChips) { allProcessors.addAll(aProcessorChip.getVectorProcessors()); } return allProcessors; }
Chip.java
@MappedSuperclass public abstract class Chip implements Serializable { @Id @GeneratedValue(strategy=TABLE, generator="CHIP_CM_TABLE_GENERATOR") @TableGenerator( name="CHIP_CM_TABLE_GENERATOR", table="CM_CHIP_SEQ", pkColumnName="SEQ_CM_NAME", valueColumnName="SEQ_CM_COUNT", pkColumnValue="CUST_CM_SEQ" ) @Column(name="CHIP_ID") private Integer id; // The M:1 side is the owning side @ManyToOne(fetch=EAGER)//LAZY) @JoinTable(name="CM_BOARD_CM_CHIP", joinColumns = @JoinColumn(name="CHIP_ID"), inverseJoinColumns =@JoinColumn(name="BOARD_ID")) private Board board;
Hypercube.java
@Entity @Table(name="CM_HYPERCUBE") public class Hypercube implements Serializable { @Id @GeneratedValue(strategy=TABLE, generator="HYPERCUBE_CM_TABLE_GENERATOR") @TableGenerator( name="HYPERCUBE_CM_TABLE_GENERATOR", table="CM_HYPERCUBE_SEQ", pkColumnName="SEQ_CM_NAME", valueColumnName="SEQ_CM_COUNT", pkColumnValue="CUST_CM_SEQ" ) @Column(name="HYPERCUBE_ID") private Integer id; // If a JoinTable with a JoinColumn is used - then we need a mappedBy on the inverse side here @OneToMany(cascade=ALL, mappedBy="hypercube") private List<Quadrant> quadrants = new ArrayList<Quadrant>(); public List<VectorProcessor> getVectorProcessors() { List<VectorProcessor> allProcessors = new ArrayList<VectorProcessor>(); for(Quadrant aQuadrant : quadrants) { allProcessors.addAll(aQuadrant.getVectorProcessors()); } return allProcessors; }
Processor.java
@MappedSuperclass public abstract class Processor implements Serializable { @Id @GeneratedValue(strategy=TABLE, generator="PROCESSOR_CM_TABLE_GENERATOR") @TableGenerator( name="PROCESSOR_CM_TABLE_GENERATOR", table="CM_PROCESSOR_SEQ", pkColumnName="SEQ_CM_NAME", valueColumnName="SEQ_CM_COUNT", pkColumnValue="CUST_CM_SEQ" ) @Column(name="PROCESSOR_ID") private Integer id;
ProcessorChip.java
@Entity @Table(name="CM_PROCESSORCHIP") public class ProcessorChip extends Chip implements Serializable { private List<Boolean> stateMachine; private boolean input; private boolean output; private ProcessorChip leftChip; private ProcessorChip rightChip; private ProcessorChip upChip; @OneToOne @JoinColumn(name="PROCESSOR_ID") private ProcessorChip downChip; // If a JoinTable with a JoinColumn is used - then we need a mappedBy on the inverse side here @OneToMany(cascade=ALL, mappedBy="besideProcessorChip") private List<ProcessorChip> adjacentChips = new ArrayList<ProcessorChip>(); // The M:1 side is the owning side @ManyToOne(fetch=EAGER)//LAZY) @JoinTable(name="CM_PROCESSOR_CM_PROCESSOR", joinColumns = @JoinColumn(name="PROCESSOR_ID"), inverseJoinColumns =@JoinColumn(name="PROCESSOR_ID")) private ProcessorChip besideProcessorChip; // If a JoinTable with a JoinColumn is used - then we need a mappedBy on the inverse side here @OneToMany(cascade=ALL, mappedBy="processorChip") private List<VectorProcessor> vectorProcessors = new ArrayList<VectorProcessor>();
Quadrant.java
@Entity @Table(name="CM_QUADRANT") public class Quadrant implements Serializable { @Id @GeneratedValue(strategy=TABLE, generator="QUADRANT_CM_TABLE_GENERATOR") @TableGenerator( name="QUADRANT_CM_TABLE_GENERATOR", table="CM_QUADRANT_SEQ", pkColumnName="SEQ_CM_NAME", valueColumnName="SEQ_CM_COUNT", pkColumnValue="CUST_CM_SEQ" ) @Column(name="QUADRANT_ID") private Integer id; // If a JoinTable with a JoinColumn is used - then we need a mappedBy on the inverse side here @OneToMany(cascade=ALL, mappedBy="quadrant") private List<Board> boards = new ArrayList<Board>(); // The M:1 side is the owning side @ManyToOne(fetch=EAGER)//LAZY) @JoinTable(name="CM_HYPERCUBE_CM_QUADRANT", joinColumns = @JoinColumn(name="QUADRANT_ID"), inverseJoinColumns =@JoinColumn(name="HYPERCUBE_ID")) private Hypercube hypercube; public List<VectorProcessor> getVectorProcessors() { List<VectorProcessor> allProcessors = new ArrayList<VectorProcessor>(); for(Board aBoard : boards) { allProcessors.addAll(aBoard.getVectorProcessors()); } return allProcessors; }
VectorProcessor.java
@Entity @Table(name="CM_VECTORPROCESSOR") public class VectorProcessor extends Processor implements Serializable { // The M:1 side is the owning side @ManyToOne(fetch=EAGER)//LAZY) @JoinTable(name="CM_CHIP_CM_PROCESSOR", joinColumns = @JoinColumn(name="PROCESSOR_ID"), inverseJoinColumns =@JoinColumn(name="CHIP_ID")) private ProcessorChip processorChip;
CM2Console.java
- This is a minimum Java SE JPA client
package org.eclipse.persistence.example.jpa.cm.presentation; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import javax.persistence.metamodel.Metamodel; import org.eclipse.persistence.example.jpa.cm.business.Board; import org.eclipse.persistence.example.jpa.cm.business.Hypercube; import org.eclipse.persistence.example.jpa.cm.business.ProcessorChip; import org.eclipse.persistence.example.jpa.cm.business.Quadrant; import org.eclipse.persistence.example.jpa.cm.business.VectorProcessor; import org.eclipse.persistence.example.jpa.cm.integration.CM2; public class CM2Console { CM2 connectionMachine; public CM2Console() { connectionMachine = new CM2(); } public CM2 getConnectionMachine() { return connectionMachine; } public void setConnectionMachine(CM2 connectionMachine) { this.connectionMachine = connectionMachine; } // Application managed EMF and EM public EntityManagerFactory emf = null; public EntityManager entityManager = null; // Reference the database specific persistence unit in persistence.xml public static final String PU_NAME_CREATE = "CMJPA_create"; /** * Create the EMF and EM and start a transaction (out of container context) * @param puName */ private void initialize(String puName) { try { // Initialize an application managed JPA emf and em via META-INF emf = Persistence.createEntityManagerFactory(puName); entityManager = emf.createEntityManager(); } catch (Exception e) { e.printStackTrace(); } } /** * Close the application managed EM and EMF */ @Override public void finalize() { // close JPA try { if(null != getEntityManager()) { getEntityManager().close(); getEmf().close(); } } catch (Exception e) { e.printStackTrace(); } } private void populate(PrintWriter out) { // register atomic entities first before creating relationships try { EntityManager em = getEntityManager(); if(null == em) { System.out.println("EntityManager is null: Check your persistence.xml properties"); } else { EntityTransaction transaction = em.getTransaction(); if(null == transaction) { System.out.println("Cannot get a transaction from entityManager: " + em); } else { transaction.begin(); // Insert schema and classes into the database CM2 cm2 = new CM2(); // 1 Hypercube Hypercube hypercube = new Hypercube(); // 8 Quadrants List<Quadrant> quadrants = new ArrayList<Quadrant>(); for(int i=0; i<8; i++) { Quadrant aQuadrant = new Quadrant(); aQuadrant.setHypercube(hypercube); quadrants.add(aQuadrant); // 16 Backplane Boards List<Board> boards = new ArrayList<Board>(); for(int j=0; j<16; j++) { Board aBoard = new Board(); aBoard.setQuadrant(aQuadrant); boards.add(aBoard); // 32 processor chips per board List<ProcessorChip> chips = new ArrayList<ProcessorChip>(); for(int k=0; k<32; k++) { ProcessorChip aChip = new ProcessorChip(); aChip.setBoard(aBoard); chips.add(aChip); // 16 vector processors per chip List<VectorProcessor> processors = new ArrayList<VectorProcessor>(); for(int l=0; l<16; l++) { VectorProcessor aProcessor = new VectorProcessor(); aProcessor.setProcessorChip(aChip); processors.add(aProcessor); em.merge(aProcessor); } aChip.setProcessors(processors); em.merge(aChip); } aBoard.setChips(chips); em.merge(aBoard); } aQuadrant.setBoards(boards); em.merge(aQuadrant); } hypercube.setQuadrants(quadrants); cm2.setHypercube(hypercube); em.merge(hypercube); // 8 Quadrants long processorCount = 0; em.persist(hypercube); for(Quadrant aQuadrant : hypercube.getQuadrants()) { em.persist(aQuadrant); // 16 Backplane Boards for(Board aBoard : aQuadrant.getBoards()) { em.persist(aBoard); // 32 processor chips per board for(ProcessorChip aChip : aBoard.getProcessorChips()) { em.persist(aChip); // 16 vector processors per chip for(VectorProcessor aProcessor : aChip.getVectorProcessors()) { //System.out.println("_persisting: " + count++ + " : " + aProcessor); em.persist(aProcessor); processorCount++; } } } } System.out.println("_persisted " + processorCount + " Processor Entities"); System.out.println("_All Processors: " + hypercube.getVectorProcessors().size()); Metamodel aMetamodel = em.getMetamodel(); System.out.println("_Metamodel: " + aMetamodel); } // Store objects transaction.commit(); } } catch (Exception e) { e.printStackTrace(); } } public EntityManagerFactory getEmf() { return emf; } public void setEmf(EntityManagerFactory emf) { this.emf = emf; } public EntityManager getEntityManager() { return entityManager; } public void setEntifyManager(EntityManager entityManager) { this.entityManager = entityManager; } public static void main(String[] args) { CM2Console aConsole = new CM2Console(); aConsole.initialize(PU_NAME_CREATE); aConsole.populate(null); aConsole.finalize(); System.out.println(aConsole.getConnectionMachine()); System.exit(0); } }
Persistence Unit
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="CMJPA_create" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>org.eclipse.persistence.example.jpa.cm.business.Board</class> <class>org.eclipse.persistence.example.jpa.cm.business.Hypercube</class> <class>org.eclipse.persistence.example.jpa.cm.business.MemoryChip</class> <class>org.eclipse.persistence.example.jpa.cm.business.ProcessorChip</class> <class>org.eclipse.persistence.example.jpa.cm.business.Quadrant</class> <class>org.eclipse.persistence.example.jpa.cm.business.RouterProcessor</class> <class>org.eclipse.persistence.example.jpa.cm.business.VectorProcessor</class> <properties> <property name="eclipselink.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.oracle.OraclePlatform"/> <property name="eclipselink.jdbc.url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> <property name="eclipselink.jdbc.user" value="scott"/> <property name="eclipselink.jdbc.password" value="pw"/> <!-- property name="eclipselink.logging.level" value="ALL"/--> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> <property name="eclipselink.ddl-generation.output-mode" value="database"/> </properties> </persistence-unit> </persistence>
Hardware
Bill Of Materials
Testing
- In order to accommidate a 65MB heap size use the JVM parameter
- -Xmx1024m
Console Output
Logs
_persisted 65536 Processor Entities _All Processors: 65536 _Metamodel: MetamodelImpl@31301308 [ 11 Types: , 9 ManagedTypes: , 7 EntityTypes: , 2 MappedSuperclassTypes: , 0 EmbeddableTypes: ] [EL Info]: 2009-09-01 15:52:30.633--ServerSession(23979164)--file:/E:/wse/view_w35a/CM2JPA/bin/-CMJPA_create logout successful org.eclipse.persistence.example.jpa.cm.integration.CM2@2a72b6