This is an automated email from the ASF dual-hosted git repository.

mboehm7 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/systemds.git


The following commit(s) were added to refs/heads/main by this push:
     new 7440ef7ff1 [SYSTEMDS-3892] Initial out-of-core base instruction and 
parser
7440ef7ff1 is described below

commit 7440ef7ff129542af8811854df9d8debec802dd1
Author: Jessica Priebe <jessica.pri...@web.de>
AuthorDate: Sat Jul 12 01:36:58 2025 +0200

    [SYSTEMDS-3892] Initial out-of-core base instruction and parser
    
    Closes #2289.
---
 src/main/java/org/apache/sysds/api/DMLOptions.java |   6 ++
 src/main/java/org/apache/sysds/api/DMLScript.java  |   3 +
 src/main/java/org/apache/sysds/common/Types.java   |   4 +-
 src/main/java/org/apache/sysds/hops/Hop.java       |   3 +
 .../sysds/runtime/instructions/Instruction.java    |   6 +-
 .../runtime/instructions/InstructionParser.java    |   5 +
 .../runtime/instructions/InstructionUtils.java     |   5 +
 .../runtime/instructions/OOCInstructionParser.java |  56 +++++++++++
 .../runtime/instructions/ooc/OOCInstruction.java   |  85 +++++++++++++++++
 .../functions/ooc/SumScalarMultiplicationTest.java | 103 +++++++++++++++++++++
 .../functions/ooc/SumScalarMultiplication.dml      |  24 +++++
 11 files changed, 298 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/sysds/api/DMLOptions.java 
b/src/main/java/org/apache/sysds/api/DMLOptions.java
index 763ac7b938..97d5f54a4a 100644
--- a/src/main/java/org/apache/sysds/api/DMLOptions.java
+++ b/src/main/java/org/apache/sysds/api/DMLOptions.java
@@ -65,6 +65,7 @@ public class DMLOptions {
        public ExecMode             execMode      = 
OptimizerUtils.getDefaultExecutionMode();  // Execution mode standalone, MR, 
Spark or a hybrid
        public boolean              gpu           = false;            // 
Whether to use the GPU
        public boolean              forceGPU      = false;            // 
Whether to ignore memory & estimates and always use the GPU
+       public boolean              ooc           = false;            // 
Whether to use the OOC backend
        public boolean              debug         = false;            // to go 
into debug mode to be able to step through a program
        public String               filePath      = null;             // path 
to script
        public String               script        = null;             // the 
script itself
@@ -109,6 +110,7 @@ public class DMLOptions {
                        ", execMode=" + execMode +
                        ", gpu=" + gpu +
                        ", forceGPU=" + forceGPU +
+                       ", ooc=" + ooc +
                        ", debug=" + debug +
                        ", filePath='" + filePath + '\'' +
                        ", script='" + script + '\'' +
@@ -182,6 +184,7 @@ public class DMLOptions {
                                }
                        }
                }
+               dmlOptions.ooc = line.hasOption("ooc");
                if (line.hasOption("exec")){
                        String execMode = line.getOptionValue("exec");
                        if (execMode.equalsIgnoreCase("singlenode")) 
dmlOptions.execMode = ExecMode.SINGLE_NODE;
@@ -388,6 +391,8 @@ public class DMLOptions {
                Option gpuOpt = OptionBuilder.withArgName("force")
                        .withDescription("uses CUDA instructions when 
reasonable; set <force> option to skip conservative memory estimates and use 
GPU wherever possible; default off")
                        .hasOptionalArg().create("gpu");
+               Option oocOpt = OptionBuilder.withDescription("uses OOC 
backend")
+                       .create("ooc");
                Option debugOpt = OptionBuilder.withDescription("runs in debug 
mode; default off")
                        .create("debug");
                Option pythonOpt = OptionBuilder
@@ -441,6 +446,7 @@ public class DMLOptions {
                options.addOption(explainOpt);
                options.addOption(execOpt);
                options.addOption(gpuOpt);
+               options.addOption(oocOpt);
                options.addOption(debugOpt);
                options.addOption(lineageOpt);
                options.addOption(fedOpt);
diff --git a/src/main/java/org/apache/sysds/api/DMLScript.java 
b/src/main/java/org/apache/sysds/api/DMLScript.java
index d6853891e2..2bc8d3b816 100644
--- a/src/main/java/org/apache/sysds/api/DMLScript.java
+++ b/src/main/java/org/apache/sysds/api/DMLScript.java
@@ -147,6 +147,8 @@ public class DMLScript
        public static boolean           FORCE_ACCELERATOR    = 
DMLOptions.defaultOptions.forceGPU;
        // Enable synchronizing GPU after every instruction
        public static boolean           SYNCHRONIZE_GPU      = true;
+       // Set OOC backend
+       public static boolean           USE_OOC              = 
DMLOptions.defaultOptions.ooc;
        // Enable eager CUDA free on rmvar
        public static boolean           EAGER_CUDA_FREE      = false;
 
@@ -266,6 +268,7 @@ public class DMLScript
                        JMLC_MEM_STATISTICS   = dmlOptions.memStats;
                        USE_ACCELERATOR       = dmlOptions.gpu;
                        FORCE_ACCELERATOR     = dmlOptions.forceGPU;
+                       USE_OOC               = dmlOptions.ooc;
                        EXPLAIN               = dmlOptions.explainType;
                        EXEC_MODE             = dmlOptions.execMode;
                        LINEAGE               = dmlOptions.lineage;
diff --git a/src/main/java/org/apache/sysds/common/Types.java 
b/src/main/java/org/apache/sysds/common/Types.java
index e69ad375b2..c5ad9ded2b 100644
--- a/src/main/java/org/apache/sysds/common/Types.java
+++ b/src/main/java/org/apache/sysds/common/Types.java
@@ -32,7 +32,7 @@ public interface Types {
         * Execution mode for entire script. This setting specify which {@link 
ExecType}s are allowed.
         */
        public enum ExecMode {
-               /** Execute all operations in {@link ExecType#CP} and if 
available {@link ExecType#GPU} */
+               /** Execute all operations in {@link ExecType#CP}, {@link 
ExecType#OOC} and if available {@link ExecType#GPU} */
                SINGLE_NODE,
                /**
                 * The default and encouraged ExecMode. Execute operations 
while leveraging all available options:
@@ -58,6 +58,8 @@ public interface Types {
                GPU,
                /** FED: indicate that the instruction should be executed as a 
Federated instruction */
                FED,
+               /** Out of Core: indicate that the operation should be executed 
out of core. */
+               OOC,
                /** invalid is used for debugging or if it is undecided where 
the current instruction should be executed */
                INVALID
        }
diff --git a/src/main/java/org/apache/sysds/hops/Hop.java 
b/src/main/java/org/apache/sysds/hops/Hop.java
index b32a1a74aa..68e5bc94c0 100644
--- a/src/main/java/org/apache/sysds/hops/Hop.java
+++ b/src/main/java/org/apache/sysds/hops/Hop.java
@@ -263,6 +263,9 @@ public abstract class Hop implements ParseInfo {
                                if(_etypeForced != ExecType.CP && _etypeForced 
!= ExecType.GPU)
                                        _etypeForced = ExecType.CP;
                        }
+                       else if (DMLScript.USE_OOC){
+                               _etypeForced = ExecType.OOC;
+                       }
                        else {
                                // enabled with -exec singlenode option
                                _etypeForced = ExecType.CP;
diff --git 
a/src/main/java/org/apache/sysds/runtime/instructions/Instruction.java 
b/src/main/java/org/apache/sysds/runtime/instructions/Instruction.java
index 50238aadd8..6d27df34ed 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/Instruction.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/Instruction.java
@@ -35,7 +35,8 @@ public abstract class Instruction
                BREAKPOINT,
                SPARK,
                GPU,
-               FEDERATED
+               FEDERATED,
+               OUT_OF_CORE
        }
        
        protected static final Log LOG = 
LogFactory.getLog(Instruction.class.getName());
@@ -53,6 +54,7 @@ public abstract class Instruction
        public static final String SP_INST_PREFIX = "sp_";
        public static final String GPU_INST_PREFIX = "gpu_";
        public static final String FEDERATED_INST_PREFIX = "fed_";
+       public static final String OOC_INST_PREFIX = "ooc_";
        
        //basic instruction meta data
        protected String instString = null;
@@ -184,6 +186,8 @@ public abstract class Instruction
                                extendedOpcode = GPU_INST_PREFIX + getOpcode();
                        else if( getType() == IType.FEDERATED)
                                extendedOpcode = FEDERATED_INST_PREFIX + 
getOpcode();
+                       else if( getType() == IType.OUT_OF_CORE)
+                               extendedOpcode = OOC_INST_PREFIX + getOpcode();
                        else
                                extendedOpcode = getOpcode();
                }
diff --git 
a/src/main/java/org/apache/sysds/runtime/instructions/InstructionParser.java 
b/src/main/java/org/apache/sysds/runtime/instructions/InstructionParser.java
index fbe7c1d757..85ab05cf34 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/InstructionParser.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/InstructionParser.java
@@ -53,6 +53,11 @@ public class InstructionParser
                                if( fedtype == null )
                                        throw new DMLRuntimeException("Unknown 
FEDERATED instruction: " + str);
                                return 
FEDInstructionParser.parseSingleInstruction (fedtype, str);
+                       case OOC:
+                               InstructionType ooctype = 
InstructionUtils.getOOCType(str);
+                               if( ooctype == null )
+                                       throw new DMLRuntimeException("Unknown 
OOC instruction: " + str);
+                               return 
OOCInstructionParser.parseSingleInstruction (ooctype, str);
                        default:
                                throw new DMLRuntimeException("Unknown 
execution type in instruction: " + str);
                }
diff --git 
a/src/main/java/org/apache/sysds/runtime/instructions/InstructionUtils.java 
b/src/main/java/org/apache/sysds/runtime/instructions/InstructionUtils.java
index 3c1cf9d775..e244e9cd27 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/InstructionUtils.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/InstructionUtils.java
@@ -281,6 +281,11 @@ public class InstructionUtils {
                return Opcodes.getTypeByOpcode(op, Types.ExecType.FED);
        }
 
+       public static InstructionType getOOCType(String str) {
+               String op = getOpCode(str);
+               return Opcodes.getTypeByOpcode(op, Types.ExecType.OOC);
+       }
+
        public static boolean isBuiltinFunction( String opcode ) {
                Builtin.BuiltinCode bfc = 
Builtin.String2BuiltinCode.get(opcode);
                return (bfc != null);
diff --git 
a/src/main/java/org/apache/sysds/runtime/instructions/OOCInstructionParser.java 
b/src/main/java/org/apache/sysds/runtime/instructions/OOCInstructionParser.java
new file mode 100644
index 0000000000..191976f094
--- /dev/null
+++ 
b/src/main/java/org/apache/sysds/runtime/instructions/OOCInstructionParser.java
@@ -0,0 +1,56 @@
+/*
+ * 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.sysds.runtime.instructions;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.sysds.common.InstructionType;
+import org.apache.sysds.runtime.DMLRuntimeException;
+import org.apache.sysds.runtime.instructions.ooc.OOCInstruction;
+
+public class OOCInstructionParser extends InstructionParser {
+       protected static final Log LOG = 
LogFactory.getLog(OOCInstructionParser.class.getName());
+
+       public static OOCInstruction parseSingleInstruction(String str) {
+               if(str == null || str.isEmpty())
+                       return null;
+               InstructionType ooctype = InstructionUtils.getOOCType(str);
+               if(ooctype == null)
+                       throw new DMLRuntimeException("Unable derive ooctype 
for instruction: " + str);
+               OOCInstruction oocinst = parseSingleInstruction(ooctype, str);
+               if(oocinst == null)
+                       throw new DMLRuntimeException("Unable to parse 
instruction: " + str);
+               return oocinst;
+       }
+
+       public static OOCInstruction parseSingleInstruction(InstructionType 
ooctype, String str) {
+               if(str == null || str.isEmpty())
+                       return null;
+               switch(ooctype) {
+
+                       // TODO:
+                       case AggregateUnary:
+                       case Binary:
+
+                       default:
+                               throw new DMLRuntimeException("Invalid OOC 
Instruction Type: " + ooctype);
+               }
+       }
+}
diff --git 
a/src/main/java/org/apache/sysds/runtime/instructions/ooc/OOCInstruction.java 
b/src/main/java/org/apache/sysds/runtime/instructions/ooc/OOCInstruction.java
new file mode 100644
index 0000000000..83cc972135
--- /dev/null
+++ 
b/src/main/java/org/apache/sysds/runtime/instructions/ooc/OOCInstruction.java
@@ -0,0 +1,85 @@
+/*
+ * 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.sysds.runtime.instructions.ooc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.sysds.api.DMLScript;
+import org.apache.sysds.runtime.controlprogram.context.ExecutionContext;
+import org.apache.sysds.runtime.instructions.Instruction;
+import org.apache.sysds.runtime.matrix.operators.Operator;
+
+public abstract class OOCInstruction extends Instruction {
+       protected static final Log LOG = 
LogFactory.getLog(OOCInstruction.class.getName());
+
+       public enum OOCType {
+               AggregateUnary, Binary
+       }
+
+       protected final OOCInstruction.OOCType _ooctype;
+       protected final boolean _requiresLabelUpdate;
+
+       protected OOCInstruction(OOCInstruction.OOCType type, String opcode, 
String istr) {
+               this(type, null, opcode, istr);
+       }
+
+       protected OOCInstruction(OOCInstruction.OOCType type, Operator op, 
String opcode, String istr) {
+               super(op);
+               _ooctype = type;
+               instString = istr;
+               instOpcode = opcode;
+
+               _requiresLabelUpdate = super.requiresLabelUpdate();
+       }
+
+       @Override
+       public IType getType() {
+               return IType.OUT_OF_CORE;
+       }
+
+       public OOCInstruction.OOCType getOOCInstructionType() {
+               return _ooctype;
+       }
+
+       @Override
+       public boolean requiresLabelUpdate() {
+               return _requiresLabelUpdate;
+       }
+
+       @Override
+       public String getGraphString() {
+               return getOpcode();
+       }
+
+       @Override
+       public Instruction preprocessInstruction(ExecutionContext ec) {
+               // TODO
+               return super.preprocessInstruction(ec);
+       }
+
+       @Override
+       public abstract void processInstruction(ExecutionContext ec);
+
+       @Override
+       public void postprocessInstruction(ExecutionContext ec) {
+               if(DMLScript.LINEAGE_DEBUGGER)
+                       ec.maintainLineageDebuggerInfo(this);
+       }
+}
diff --git 
a/src/test/java/org/apache/sysds/test/functions/ooc/SumScalarMultiplicationTest.java
 
b/src/test/java/org/apache/sysds/test/functions/ooc/SumScalarMultiplicationTest.java
new file mode 100644
index 0000000000..d9d42c913b
--- /dev/null
+++ 
b/src/test/java/org/apache/sysds/test/functions/ooc/SumScalarMultiplicationTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sysds.test.functions.ooc;
+
+import org.apache.sysds.common.Opcodes;
+import org.apache.sysds.common.Types;
+import org.apache.sysds.runtime.instructions.Instruction;
+import org.apache.sysds.runtime.matrix.data.MatrixValue;
+import org.apache.sysds.test.AutomatedTestBase;
+import org.apache.sysds.test.TestConfiguration;
+import org.apache.sysds.test.TestUtils;
+import org.apache.sysds.utils.Statistics;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class SumScalarMultiplicationTest extends AutomatedTestBase {
+
+       private static final String TEST_NAME = "SumScalarMultiplication";
+       private static final String TEST_DIR = "functions/ooc/";
+       private static final String TEST_CLASS_DIR = TEST_DIR + 
SumScalarMultiplicationTest.class.getSimpleName() + "/";
+       private static final String INPUT_NAME = "X";
+       private static final String OUTPUT_NAME = "res";
+
+       @Override
+       public void setUp() {
+               TestUtils.clearAssertionInformation();
+               TestConfiguration config = new 
TestConfiguration(TEST_CLASS_DIR, TEST_NAME);
+               addTestConfiguration(TEST_NAME, config);
+       }
+
+       /**
+        * Test the sum of scalar multiplication, "sum(X*7)", with OOC backend.
+        */
+       @Test
+       @Ignore
+       public void testSumScalarMult() {
+
+               Types.ExecMode platformOld = rtplatform;
+               rtplatform = Types.ExecMode.SINGLE_NODE;
+
+               try {
+                       getAndLoadTestConfiguration(TEST_NAME);
+                       String HOME = SCRIPT_DIR + TEST_DIR;
+                       fullDMLScriptName = HOME + TEST_NAME + ".dml";
+                       programArgs = new String[] {"-explain", "-stats", 
"-ooc", "-args", input(INPUT_NAME), output(OUTPUT_NAME)};
+
+                       int rows = 3;
+                       int cols = 4;
+                       double sparsity = 0.8;
+
+                       double[][] X = getRandomMatrix(rows, cols, -1, 1, 
sparsity, 7);
+                       writeInputMatrixWithMTD(INPUT_NAME, X, true);
+
+                       runTest(true, false, null, -1);
+
+                       HashMap<MatrixValue.CellIndex, Double> dmlfile = 
readDMLMatrixFromOutputDir(OUTPUT_NAME);
+                       // only one entry
+                       Double result = dmlfile.get(new 
MatrixValue.CellIndex(1, 1));
+
+                       double expected = 0.0;
+                       for(int i = 0; i < rows; i++) {
+                               for(int j = 0; j < cols; j++) {
+                                       expected += X[i][j] * 7;
+                               }
+                       }
+
+                       Assert.assertEquals(expected, result, 1e-10);
+
+                       String prefix = Instruction.OOC_INST_PREFIX;
+
+                       boolean usedOOCMult = 
Statistics.getCPHeavyHitterOpCodes().contains(prefix + Opcodes.MULT);
+                       Assert.assertTrue("OOC wasn't used for MULT", 
usedOOCMult);
+
+                       boolean usedOOCSum = 
Statistics.getCPHeavyHitterOpCodes().contains(prefix + Opcodes.UAKP);
+                       Assert.assertTrue("OOC wasn't used for SUM", 
usedOOCSum);
+
+               }
+               finally {
+                       // reset
+                       rtplatform = platformOld;
+               }
+       }
+}
diff --git a/src/test/scripts/functions/ooc/SumScalarMultiplication.dml 
b/src/test/scripts/functions/ooc/SumScalarMultiplication.dml
new file mode 100644
index 0000000000..d8cf9c8494
--- /dev/null
+++ b/src/test/scripts/functions/ooc/SumScalarMultiplication.dml
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+X = read($1);
+res = as.matrix(sum(X*7))
+write(res, $2);

Reply via email to