You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemml.apache.org by mb...@apache.org on 2017/11/05 22:29:55 UTC

[3/3] systemml git commit: [SYSTEMML-1988] JMLC API extension for cloning prepared scripts

[SYSTEMML-1988] JMLC API extension for cloning prepared scripts 

In complex applications and micro services, the need to reuse prepared
scripts in a thread-local manner in order to amortize the compilation
overhead, creates sometimes an unnecessary burden. Without dynamic
recompilation, this is unnecessary because a single compiled program can
be shared across concurrent invocations of PreparedScript.execute. This
patch extends the JMLC API by cloning functionality, which allows to
statically initialize a single prepared script and create cheap shallow
copies of the script's program and meta data.


Project: http://git-wip-us.apache.org/repos/asf/systemml/repo
Commit: http://git-wip-us.apache.org/repos/asf/systemml/commit/f7fe4342
Tree: http://git-wip-us.apache.org/repos/asf/systemml/tree/f7fe4342
Diff: http://git-wip-us.apache.org/repos/asf/systemml/diff/f7fe4342

Branch: refs/heads/master
Commit: f7fe4342005ec0da383f359b70fbab48a25dff7a
Parents: e888cce
Author: Matthias Boehm <mb...@gmail.com>
Authored: Sat Nov 4 23:33:43 2017 -0700
Committer: Matthias Boehm <mb...@gmail.com>
Committed: Sun Nov 5 14:27:44 2017 -0800

----------------------------------------------------------------------
 .../org/apache/sysml/api/jmlc/Connection.java   |  15 +++
 .../apache/sysml/api/jmlc/PreparedScript.java   |  37 ++++++
 .../jmlc/JMLCClonedPreparedScriptTest.java      | 113 +++++++++++++++++++
 .../functions/jmlc/ZPackageSuite.java           |   2 +
 4 files changed, 167 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/systemml/blob/f7fe4342/src/main/java/org/apache/sysml/api/jmlc/Connection.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/api/jmlc/Connection.java b/src/main/java/org/apache/sysml/api/jmlc/Connection.java
index e96e0aa..2568977 100644
--- a/src/main/java/org/apache/sysml/api/jmlc/Connection.java
+++ b/src/main/java/org/apache/sysml/api/jmlc/Connection.java
@@ -161,6 +161,21 @@ public class Connection implements Closeable
 	 * @param script string representing the DML or PyDML script
 	 * @param inputs string array of input variables to register
 	 * @param outputs string array of output variables to register
+	 * @return PreparedScript object representing the precompiled script
+	 * @throws DMLException if DMLException occurs
+	 */
+	public PreparedScript prepareScript( String script, String[] inputs, String[] outputs) 
+		throws DMLException 
+	{
+		return prepareScript(script, inputs, outputs, false);
+	}
+	
+	/**
+	 * Prepares (precompiles) a script and registers input and output variables.
+	 * 
+	 * @param script string representing the DML or PyDML script
+	 * @param inputs string array of input variables to register
+	 * @param outputs string array of output variables to register
 	 * @param parsePyDML {@code true} if PyDML, {@code false} if DML
 	 * @return PreparedScript object representing the precompiled script
 	 * @throws DMLException if DMLException occurs

http://git-wip-us.apache.org/repos/asf/systemml/blob/f7fe4342/src/main/java/org/apache/sysml/api/jmlc/PreparedScript.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/sysml/api/jmlc/PreparedScript.java b/src/main/java/org/apache/sysml/api/jmlc/PreparedScript.java
index c712bb2..c23ef92 100644
--- a/src/main/java/org/apache/sysml/api/jmlc/PreparedScript.java
+++ b/src/main/java/org/apache/sysml/api/jmlc/PreparedScript.java
@@ -23,7 +23,9 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map.Entry;
 
+import org.apache.commons.lang.NotImplementedException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.sysml.api.DMLException;
@@ -75,6 +77,21 @@ public class PreparedScript
 	private final DMLConfig _dmlconf;
 	private final CompilerConfig _cconf;
 	
+	private PreparedScript(PreparedScript that) {
+		//shallow copy, except for a separate symbol table
+		//and related meta data of reused inputs
+		_prog = that._prog;
+		_vars = new LocalVariableMap();
+		for(Entry<String, Data> e : that._vars.entrySet())
+			_vars.put(e.getKey(), e.getValue());
+		_vars.setRegisteredOutputs(that._outVarnames);
+		_inVarnames = that._inVarnames;
+		_outVarnames = that._outVarnames;
+		_inVarReuse = new HashMap<>(that._inVarReuse);
+		_dmlconf = that._dmlconf;
+		_cconf = that._cconf;
+	}
+	
 	/**
 	 * Meant to be invoked only from Connection.
 	 * 
@@ -481,4 +498,24 @@ public class PreparedScript
 			}
 		}
 	}
+	
+	/**
+	 * Creates a cloned instance of the prepared script, which
+	 * allows for concurrent execution without side effects.
+	 * 
+	 * @param deep indicator if a deep copy needs to be created;
+	 *   if false, only a shallow (i.e., by reference) copy of the 
+	 *   program and read-only meta data is created. 
+	 * @return an equivalent prepared script
+	 */
+	public PreparedScript clone(boolean deep) {
+		if( deep )
+			throw new NotImplementedException();
+		return new PreparedScript(this);
+	}
+	
+	@Override
+	public Object clone() {
+		return clone(true);
+	}
 }

http://git-wip-us.apache.org/repos/asf/systemml/blob/f7fe4342/src/test/java/org/apache/sysml/test/integration/functions/jmlc/JMLCClonedPreparedScriptTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/sysml/test/integration/functions/jmlc/JMLCClonedPreparedScriptTest.java b/src/test/java/org/apache/sysml/test/integration/functions/jmlc/JMLCClonedPreparedScriptTest.java
new file mode 100644
index 0000000..d0667e0
--- /dev/null
+++ b/src/test/java/org/apache/sysml/test/integration/functions/jmlc/JMLCClonedPreparedScriptTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysml.test.integration.functions.jmlc;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.apache.sysml.api.DMLException;
+import org.apache.sysml.api.DMLScript;
+import org.apache.sysml.api.jmlc.Connection;
+import org.apache.sysml.api.jmlc.PreparedScript;
+import org.apache.sysml.runtime.controlprogram.parfor.stat.InfrastructureAnalyzer;
+import org.apache.sysml.test.integration.AutomatedTestBase;
+import org.apache.sysml.utils.Statistics;
+
+public class JMLCClonedPreparedScriptTest extends AutomatedTestBase 
+{
+	@Override
+	public void setUp() {
+		//do nothing
+	}
+	
+	@Test
+	public void testSinglePreparedScript128() throws IOException {
+		runJMLCClonedTest(128, false);
+	}
+	
+	@Test
+	public void testClonedPreparedScript128() throws IOException {
+		runJMLCClonedTest(128, true);
+	}
+
+	private void runJMLCClonedTest(int num, boolean clone) 
+		throws IOException
+	{
+		int k = InfrastructureAnalyzer.getLocalParallelism();
+		
+		boolean failed = false;
+		try( Connection conn = new Connection() ) {
+			String script =
+				"  X = matrix(7, 10, 10);"
+				+ "R = matrix(0, 10, 1)"
+				+ "parfor(i in 1:nrow(X))"
+				+ "  R[i,] = sum(X[i,])"
+				+ "out = sum(R)"
+				+ "write(out, 'tmp/out')";
+			DMLScript.STATISTICS = true;
+			Statistics.reset();
+			PreparedScript pscript = conn.prepareScript(
+				script, new String[]{}, new String[]{"out"}, false);
+			
+			ExecutorService pool = Executors.newFixedThreadPool(k);
+			ArrayList<JMLCTask> tasks = new ArrayList<>();
+			for(int i=0; i<num; i++)
+				tasks.add(new JMLCTask(pscript, clone));
+			List<Future<Double>> taskrets = pool.invokeAll(tasks);
+			for(Future<Double> ret : taskrets)
+				if( ret.get() != 700 )
+					throw new RuntimeException("wrong results: "+ret.get());
+			pool.shutdown();
+		}
+		catch(Exception ex) {
+			failed = true;
+		}
+		
+		//check expected failure
+		Assert.assertTrue(failed==!clone || k==1);
+	}
+	
+	private static class JMLCTask implements Callable<Double> 
+	{
+		private final PreparedScript _pscript;
+		private final boolean _clone;
+		
+		protected JMLCTask(PreparedScript pscript, boolean clone) {
+			_pscript = pscript;
+			_clone = clone;
+		}
+		
+		@Override
+		public Double call() throws DMLException
+		{
+			if( _clone )
+				return _pscript.clone(false).executeScript().getDouble("out");
+			else
+				return _pscript.executeScript().getDouble("out");
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/systemml/blob/f7fe4342/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
----------------------------------------------------------------------
diff --git a/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java b/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
index 3d5c13a..05fa8bc 100644
--- a/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
+++ b/src/test_suites/java/org/apache/sysml/test/integration/functions/jmlc/ZPackageSuite.java
@@ -34,8 +34,10 @@ import org.junit.runners.Suite;
 	FrameLeftIndexingTest.class,
 	FrameReadMetaTest.class,
 	FrameTransformTest.class,
+	JMLCClonedPreparedScriptTest.class,
 	JMLCInputOutputTest.class,
 	JMLCInputStreamReadTest.class,
+	JMLCParfor2ForCompileTest.class,
 	ReuseModelVariablesTest.class,
 	MulticlassSVMScoreTest.class
 })