chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TVM API functions.
|
||||
*/
|
||||
public final class API {
|
||||
private static ThreadLocal<Map<String, Function>> apiFuncs =
|
||||
new ThreadLocal<Map<String, Function>>() {
|
||||
@Override
|
||||
protected Map<String, Function> initialValue() {
|
||||
return new HashMap<String, Function>();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a tvm api function according by name.
|
||||
* @param name function name.
|
||||
* @return a TVM Function.
|
||||
*/
|
||||
public static Function get(final String name) {
|
||||
Function func = apiFuncs.get().get(name);
|
||||
if (func == null) {
|
||||
func = Function.getFunction(name);
|
||||
apiFuncs.get().put(name, func);
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be instantiated.
|
||||
*/
|
||||
private API() {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
/**
|
||||
* Internal api functions.
|
||||
*/
|
||||
public final class APIInternal {
|
||||
/**
|
||||
* Get a tvm api function according by name.
|
||||
* @param name function name.
|
||||
* @return a TVM Function.
|
||||
*/
|
||||
public static Function get(final String name) {
|
||||
return API.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be instantiated.
|
||||
*/
|
||||
private APIInternal() {}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.apache.tvm.NativeLibraryLoader.Action;
|
||||
|
||||
/**
|
||||
* Initializing methods and types.
|
||||
*/
|
||||
final class Base {
|
||||
/**
|
||||
* Hold Long reference for JNI.
|
||||
*/
|
||||
public static class RefLong {
|
||||
public final long value;
|
||||
|
||||
public RefLong(final long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public RefLong() {
|
||||
this(0L);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold TVMValue reference for JNI.
|
||||
*/
|
||||
public static class RefTVMValue {
|
||||
public final TVMValue value;
|
||||
|
||||
public RefTVMValue(TVMValue value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public RefTVMValue() {
|
||||
this(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static final LibInfo _LIB = new LibInfo();
|
||||
|
||||
static {
|
||||
boolean loadNativeRuntimeLib = true;
|
||||
try {
|
||||
try {
|
||||
tryLoadLibraryOS("tvm4j");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("[WARN] TVM native library not found in path. "
|
||||
+ "Copying native library from the archive. "
|
||||
+ "Consider installing the library somewhere in the path "
|
||||
+ "(for Windows: PATH, for Linux: LD_LIBRARY_PATH), "
|
||||
+ "or specifying by Java cmd option -Djava.library.path=[lib path].");
|
||||
NativeLibraryLoader.loadLibrary("tvm4j");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
System.err.println("[WARN] Couldn't find native library tvm4j.");
|
||||
e.printStackTrace();
|
||||
System.err.println("Try to load tvm4j (runtime packed version) ...");
|
||||
try {
|
||||
System.loadLibrary("tvm4j_runtime_packed");
|
||||
// if tvm runtime is packed in libtvm4j, we do not need to dlopen libtvm_runtime.so.
|
||||
loadNativeRuntimeLib = false;
|
||||
} catch (UnsatisfiedLinkError errFull) {
|
||||
System.err.println("[ERROR] Couldn't find native library tvm4j_runtime_packed.");
|
||||
throw new RuntimeException(errFull);
|
||||
}
|
||||
}
|
||||
|
||||
System.err.println("libtvm4j loads successfully.");
|
||||
// always use linked lib
|
||||
_LIB.nativeLibInit(null);
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
_LIB.shutdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load JNI for different OS.
|
||||
* @param libname library name.
|
||||
* @throws UnsatisfiedLinkError if loading fails.
|
||||
*/
|
||||
private static void tryLoadLibraryOS(String libname) throws UnsatisfiedLinkError {
|
||||
try {
|
||||
System.err.println(String.format("Try loading %s from native path.", libname));
|
||||
System.loadLibrary(libname);
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
String os = System.getProperty("os.name");
|
||||
// ref: http://lopica.sourceforge.net/os.html
|
||||
if (os.startsWith("Linux")) {
|
||||
tryLoadLibraryXPU(libname, "linux-x86_64");
|
||||
} else if (os.startsWith("Mac")) {
|
||||
tryLoadLibraryXPU(libname, "osx-x86_64");
|
||||
} else {
|
||||
// TODO(yizhi) support windows later
|
||||
throw new UnsatisfiedLinkError("Windows not supported currently");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load native library for different architectures.
|
||||
* @param libname library name.
|
||||
* @param arch architecture.
|
||||
* @throws UnsatisfiedLinkError if loading fails
|
||||
*/
|
||||
private static void tryLoadLibraryXPU(String libname, String arch) throws UnsatisfiedLinkError {
|
||||
System.err.println(String.format("Try loading %s-%s from native path.", libname, arch));
|
||||
System.loadLibrary(String.format("%s-%s", libname, arch));
|
||||
}
|
||||
|
||||
// helper function definitions
|
||||
/**
|
||||
* Check the return value of C API call.
|
||||
* <p>
|
||||
* This function will raise exception when error occurs.
|
||||
* Wrap every API call with this function
|
||||
* </p>
|
||||
* @param ret return value from API calls
|
||||
*/
|
||||
public static void checkCall(int ret) throws TVMError {
|
||||
if (ret != 0) {
|
||||
throw new TVMError(_LIB.tvmFFIGetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TVM Runtime error.
|
||||
*/
|
||||
static class TVMError extends RuntimeException {
|
||||
public TVMError(String err) {
|
||||
super(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot be instantiated.
|
||||
*/
|
||||
private Base() {}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.tvm.rpc.RPC;
|
||||
|
||||
public class Device {
|
||||
/**
|
||||
* Provides the same information as the C++ enums DLDeviceType and
|
||||
* TVMDeviceExtType.
|
||||
*/
|
||||
static final int kDLCPU = 1;
|
||||
static final int kDLCUDA = 2;
|
||||
static final int kDLCUDAHost = 3;
|
||||
static final int kDLOpenCL = 4;
|
||||
static final int kDLVulkan = 7;
|
||||
static final int kDLMetal = 8;
|
||||
static final int kDLVPI = 9;
|
||||
static final int kDLROCM = 10;
|
||||
static final int kDLROCMHost = 11;
|
||||
static final int kDLExtDev = 12;
|
||||
static final int kDLCUDAManaged = 13;
|
||||
static final int kDLOneAPI = 14;
|
||||
static final int kDLWebGPU = 15;
|
||||
static final int kDLHexagon = 16;
|
||||
|
||||
private static final Map<Integer, String> DEVICE_TYPE_TO_NAME = new HashMap<Integer, String>();
|
||||
private static final Map<String, Integer> DEVICE_NAME_TO_TYPE = new HashMap<String, Integer>();
|
||||
|
||||
static {
|
||||
DEVICE_TYPE_TO_NAME.put(kDLCPU, "cpu");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLCUDA, "cuda");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLOpenCL, "opencl");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLVulkan, "vulkan");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLMetal, "metal");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLVPI, "vpi");
|
||||
DEVICE_TYPE_TO_NAME.put(kDLHexagon, "hexagon");
|
||||
|
||||
DEVICE_NAME_TO_TYPE.put("cpu", kDLCPU);
|
||||
DEVICE_NAME_TO_TYPE.put("cuda", kDLCUDA);
|
||||
DEVICE_NAME_TO_TYPE.put("cl", kDLOpenCL);
|
||||
DEVICE_NAME_TO_TYPE.put("opencl", kDLOpenCL);
|
||||
DEVICE_NAME_TO_TYPE.put("vulkan", kDLVulkan);
|
||||
DEVICE_NAME_TO_TYPE.put("metal", kDLMetal);
|
||||
DEVICE_NAME_TO_TYPE.put("vpi", kDLVPI);
|
||||
DEVICE_NAME_TO_TYPE.put("hexagon", kDLHexagon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CPU device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device cpu(int devId) {
|
||||
return new Device(kDLCPU, devId);
|
||||
}
|
||||
|
||||
public static Device cpu() {
|
||||
return cpu(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a CUDA GPU device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device cuda(int devId) {
|
||||
return new Device(kDLCUDA, devId);
|
||||
}
|
||||
|
||||
public static Device cuda() {
|
||||
return cuda(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a OpenCL device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device opencl(int devId) {
|
||||
return new Device(kDLOpenCL, devId);
|
||||
}
|
||||
|
||||
public static Device opencl() {
|
||||
return opencl(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Vulkan device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device vulkan(int devId) {
|
||||
return new Device(kDLVulkan, devId);
|
||||
}
|
||||
|
||||
public static Device vulkan() {
|
||||
return vulkan(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a metal device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device metal(int devId) {
|
||||
return new Device(kDLMetal, devId);
|
||||
}
|
||||
|
||||
public static Device metal() {
|
||||
return metal(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a VPI simulated device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device vpi(int devId) {
|
||||
return new Device(kDLVPI, devId);
|
||||
}
|
||||
|
||||
public static Device vpi() {
|
||||
return vpi(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Hexagon device.
|
||||
* @param devId The device id
|
||||
* @return The created device
|
||||
*/
|
||||
public static Device hexagon(int devId) {
|
||||
return new Device(kDLHexagon, devId);
|
||||
}
|
||||
|
||||
public static Device hexagon() {
|
||||
return hexagon(0);
|
||||
}
|
||||
|
||||
public final int deviceType;
|
||||
public final int deviceId;
|
||||
|
||||
public Device(int deviceType, int deviceId) {
|
||||
this.deviceType = deviceType;
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public Device(String deviceType, int deviceId) {
|
||||
this(DEVICE_NAME_TO_TYPE.get(deviceType), deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this device exists.
|
||||
* @return true if exists.
|
||||
*/
|
||||
public boolean exist() {
|
||||
TVMValue ret = APIInternal.get("runtime.GetDeviceAttr")
|
||||
.pushArg(deviceType)
|
||||
.pushArg(deviceId)
|
||||
.pushArg(0)
|
||||
.invoke();
|
||||
return ((TVMValueLong) ret).value != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of threads on each block.
|
||||
* @return the maximum thread number.
|
||||
*/
|
||||
public long maxThreadsPerBlock() {
|
||||
TVMValue ret = APIInternal.get("runtime.GetDeviceAttr")
|
||||
.pushArg(deviceType)
|
||||
.pushArg(deviceId)
|
||||
.pushArg(1)
|
||||
.invoke();
|
||||
return ((TVMValueLong) ret).value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of threads that executes in concurrent.
|
||||
* @return the thread number.
|
||||
*/
|
||||
public long warpSize() {
|
||||
TVMValue ret = APIInternal.get("runtime.GetDeviceAttr")
|
||||
.pushArg(deviceType)
|
||||
.pushArg(deviceId)
|
||||
.pushArg(2)
|
||||
.invoke();
|
||||
return ret.asLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize until jobs finished at the device.
|
||||
*/
|
||||
public void sync() {
|
||||
Base.checkCall(Base._LIB.tvmSynchronize(deviceType, deviceId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (deviceType << 16) | deviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other != null && other instanceof Device) {
|
||||
Device obj = (Device) other;
|
||||
return deviceId == obj.deviceId && deviceType == obj.deviceType;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (deviceType >= RPC.RPC_SESS_MASK) {
|
||||
int tblId = deviceType / RPC.RPC_SESS_MASK - 1;
|
||||
int devType = deviceType % RPC.RPC_SESS_MASK;
|
||||
return String.format("remote[%d]:%s(%d)", tblId, DEVICE_TYPE_TO_NAME.get(devType), deviceId);
|
||||
}
|
||||
return String.format("%s(%d)", DEVICE_TYPE_TO_NAME.get(deviceType), deviceId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TVM Packed Function.
|
||||
*/
|
||||
public class Function extends TVMObject {
|
||||
/**
|
||||
* Get registered function.
|
||||
* @param name full function name.
|
||||
* @return TVM function.
|
||||
*/
|
||||
public static Function getFunction(final String name) {
|
||||
return getGlobalFunc(name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of global functions registered.
|
||||
* @return List of global functions names.
|
||||
*/
|
||||
private static List<String> listGlobalFuncNames() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionListGlobalNames(names));
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a global function by name.
|
||||
* @param name The name of the function.
|
||||
* @param allowMissing Whether allow missing function or raise an error.
|
||||
* @return The function to be returned, None if function is missing.
|
||||
*/
|
||||
private static Function getGlobalFunc(String name, boolean allowMissing) {
|
||||
Base.RefLong handle = new Base.RefLong();
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionGetGlobal(name, handle));
|
||||
if (handle.value != 0) {
|
||||
return new Function(handle.value);
|
||||
} else {
|
||||
if (allowMissing) {
|
||||
return null;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot find global function " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function(long handle) {
|
||||
super(handle, TypeIndex.kTVMFFIFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Easy for user to get the instance from returned TVMValue.
|
||||
* @return this
|
||||
*/
|
||||
@Override
|
||||
public Function asFunction() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the function.
|
||||
* @return the result.
|
||||
*/
|
||||
public TVMValue invoke() {
|
||||
Base.RefTVMValue ret = new Base.RefTVMValue();
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionCall(handle, ret));
|
||||
return ret.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg int argument.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(int arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgLong(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg long argument.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(long arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgLong(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg float argument.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(float arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDouble(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg double argument.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(double arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDouble(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg String argument.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(String arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgString(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg Tensor.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(TensorBase arg) {
|
||||
if (arg instanceof Tensor) {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(((Tensor) arg).handle, TypeIndex.kTVMFFITensor);
|
||||
} else {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(arg.dltensorHandle, TypeIndex.kTVMFFIDLTensorPtr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg Module.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(Module arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(arg.handle, TypeIndex.kTVMFFIModule);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg Function.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(Function arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(arg.handle, TypeIndex.kTVMFFIFunction);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg bytes.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(byte[] arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgBytes(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push argument to the function.
|
||||
* @param arg Device.
|
||||
* @return this
|
||||
*/
|
||||
public Function pushArg(Device arg) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDevice(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke function with arguments.
|
||||
* @param args Can be Integer, Long, Float, Double, String, Tensor.
|
||||
* @return the result.
|
||||
*/
|
||||
public TVMValue call(Object... args) {
|
||||
for (Object arg : args) {
|
||||
pushArgToStack(arg);
|
||||
}
|
||||
return invoke();
|
||||
}
|
||||
|
||||
private static void pushArgToStack(Object arg) {
|
||||
if (arg instanceof TensorBase) {
|
||||
TensorBase nd = (TensorBase) arg;
|
||||
if (nd instanceof Tensor) {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(((Tensor) nd).handle, TypeIndex.kTVMFFITensor);
|
||||
} else {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(nd.dltensorHandle, TypeIndex.kTVMFFIDLTensorPtr);
|
||||
}
|
||||
} else if (arg instanceof TVMObject) {
|
||||
TVMObject obj = (TVMObject) arg;
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(obj.handle, obj.typeIndex);
|
||||
} else if (arg instanceof Integer) {
|
||||
Base._LIB.tvmFFIFunctionPushArgLong((Integer) arg);
|
||||
} else if (arg instanceof Long) {
|
||||
Base._LIB.tvmFFIFunctionPushArgLong((Long) arg);
|
||||
} else if (arg instanceof Float) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDouble((Float) arg);
|
||||
} else if (arg instanceof Double) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDouble((Double) arg);
|
||||
} else if (arg instanceof String) {
|
||||
Base._LIB.tvmFFIFunctionPushArgString((String) arg);
|
||||
} else if (arg instanceof byte[]) {
|
||||
Base._LIB.tvmFFIFunctionPushArgBytes((byte[]) arg);
|
||||
} else if (arg instanceof Device) {
|
||||
Base._LIB.tvmFFIFunctionPushArgDevice((Device) arg);
|
||||
} else if (arg instanceof TVMValueBytes) {
|
||||
byte[] bytes = ((TVMValueBytes) arg).value;
|
||||
Base._LIB.tvmFFIFunctionPushArgBytes(bytes);
|
||||
} else if (arg instanceof TVMValueString) {
|
||||
String str = ((TVMValueString) arg).value;
|
||||
Base._LIB.tvmFFIFunctionPushArgString(str);
|
||||
} else if (arg instanceof TVMValueDouble) {
|
||||
double value = ((TVMValueDouble) arg).value;
|
||||
Base._LIB.tvmFFIFunctionPushArgDouble(value);
|
||||
} else if (arg instanceof TVMValueLong) {
|
||||
long value = ((TVMValueLong) arg).value;
|
||||
Base._LIB.tvmFFIFunctionPushArgLong(value);
|
||||
} else if (arg instanceof TVMValueNull) {
|
||||
Base._LIB.tvmFFIFunctionPushArgHandle(0, TypeIndex.kTVMFFINone);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid argument: " + arg);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Callback {
|
||||
public Object invoke(TVMValue... args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register user-defined global function.
|
||||
* @param name The function name.
|
||||
* @param function The function to be registered.
|
||||
* @param override Whether override existing entry.
|
||||
*/
|
||||
public static void register(String name, Callback function, boolean override) {
|
||||
Base.RefLong createdFuncHandleRef = new Base.RefLong();
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionCreateFromCallback(function, createdFuncHandleRef));
|
||||
int ioverride = override ? 1 : 0;
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionSetGlobal(name, createdFuncHandleRef.value, ioverride));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register user-defined global function, do not override existing entry.
|
||||
* @param name The function name.
|
||||
* @param function The function to be registered.
|
||||
*/
|
||||
public static void register(String name, Callback function) {
|
||||
register(name, function, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java function to TVM function.
|
||||
* @param function Java function.
|
||||
* @return TVM function.
|
||||
*/
|
||||
public static Function convertFunc(Callback function) {
|
||||
Base.RefLong createdFuncHandleRef = new Base.RefLong();
|
||||
Base.checkCall(Base._LIB.tvmFFIFunctionCreateFromCallback(function, createdFuncHandleRef));
|
||||
return new Function(createdFuncHandleRef.value);
|
||||
}
|
||||
|
||||
private static Object invokeRegisteredCbFunc(Callback cb, TVMValue[] args) {
|
||||
if (cb == null) {
|
||||
System.err.println("[ERROR] Failed to get registered function");
|
||||
return null;
|
||||
}
|
||||
return cb.invoke(args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class LibInfo {
|
||||
native int nativeLibInit(String tvmLibFile);
|
||||
|
||||
native int shutdown();
|
||||
|
||||
native String tvmFFIGetLastError();
|
||||
|
||||
// Object
|
||||
native int tvmFFIObjectFree(long handle);
|
||||
|
||||
// Function
|
||||
native void tvmFFIFunctionPushArgLong(long arg);
|
||||
|
||||
native void tvmFFIFunctionPushArgDouble(double arg);
|
||||
|
||||
native void tvmFFIFunctionPushArgString(String arg);
|
||||
|
||||
native void tvmFFIFunctionPushArgBytes(byte[] arg);
|
||||
|
||||
native void tvmFFIFunctionPushArgHandle(long arg, int argTypeIndex);
|
||||
|
||||
native void tvmFFIFunctionPushArgDevice(Device device);
|
||||
|
||||
native int tvmFFIFunctionListGlobalNames(List<String> funcNames);
|
||||
|
||||
native int tvmFFIFunctionGetGlobal(String name, Base.RefLong handle);
|
||||
|
||||
native int tvmFFIFunctionSetGlobal(String name, long handle, int override);
|
||||
|
||||
native int tvmFFIFunctionCall(long handle, Base.RefTVMValue retVal);
|
||||
|
||||
native int tvmFFIFunctionCreateFromCallback(Function.Callback function, Base.RefLong handle);
|
||||
|
||||
// Tensor
|
||||
native int tvmFFIDLTensorGetShape(long handle, List<Long> shape);
|
||||
|
||||
native int tvmFFIDLTensorCopyFromTo(long from, long to);
|
||||
|
||||
native int tvmFFIDLTensorCopyFromJArray(byte[] fromRaw, long to);
|
||||
|
||||
native int tvmFFIDLTensorCopyToJArray(long from, byte[] to);
|
||||
|
||||
// the following functions are binded to keep things simpler
|
||||
// One possibility is to enhance FFI to support shape directly
|
||||
// so we do not need to run this binding through JNI
|
||||
// Device
|
||||
native int tvmSynchronize(int deviceType, int deviceId);
|
||||
|
||||
native int tvmTensorEmpty(long[] shape, int dtypeCode, int dtypeBits, int dtypeLanes,
|
||||
int deviceType, int deviceId, Base.RefLong handle);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Container of compiled functions of TVM.
|
||||
*/
|
||||
public class Module extends TVMObject {
|
||||
private static ThreadLocal<Map<String, Function>> apiFuncs =
|
||||
new ThreadLocal<Map<String, Function>>() {
|
||||
@Override
|
||||
protected Map<String, Function> initialValue() {
|
||||
return new HashMap<String, Function>();
|
||||
}
|
||||
};
|
||||
|
||||
private static Function getApi(String name) {
|
||||
Function func = apiFuncs.get().get(name);
|
||||
if (func == null) {
|
||||
func = Function.getFunction(name);
|
||||
apiFuncs.get().put(name, func);
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
Module(long handle) {
|
||||
super(handle, TypeIndex.kTVMFFIModule);
|
||||
}
|
||||
|
||||
private Function entry = null;
|
||||
private final String entryName = "main";
|
||||
|
||||
/**
|
||||
* Easy for user to get the instance from returned TVMValue.
|
||||
* @return this
|
||||
*/
|
||||
@Override
|
||||
public Module asModule() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry function.
|
||||
* @return The entry function if exist
|
||||
*/
|
||||
public Function entryFunc() {
|
||||
if (entry == null) {
|
||||
entry = getFunction(entryName);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get function from the module.
|
||||
* @param name The name of the function.
|
||||
* @param queryImports Whether also query modules imported by this module.
|
||||
* @return The result function.
|
||||
*/
|
||||
public Function getFunction(String name, boolean queryImports) {
|
||||
TVMValue ret = getApi("ffi.ModuleGetFunction")
|
||||
.pushArg(this)
|
||||
.pushArg(name)
|
||||
.pushArg(queryImports ? 1 : 0)
|
||||
.invoke();
|
||||
return ret.asFunction();
|
||||
}
|
||||
|
||||
public Function getFunction(String name) {
|
||||
return getFunction(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module to the import list of current one.
|
||||
* @param module The other module.
|
||||
*/
|
||||
public void importModule(Module module) {
|
||||
getApi("ffi.ModuleImportModule").pushArg(this).pushArg(module).invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type key of the module.
|
||||
* @return type key of the module.
|
||||
*/
|
||||
public String typeKey() {
|
||||
return getApi("ffi.ModuleGetTypeKind").pushArg(this).invoke().asString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load module from file.
|
||||
* @param path The path to the module file.
|
||||
* @param fmt The format of the file,
|
||||
* if not specified it will be inferred from suffix of the file.
|
||||
* @return The loaded module
|
||||
*/
|
||||
public static Module load(String path, String fmt) {
|
||||
TVMValue ret = getApi("ffi.ModuleLoadFromFile").pushArg(path).pushArg(fmt).invoke();
|
||||
return ret.asModule();
|
||||
}
|
||||
|
||||
public static Module load(String path) {
|
||||
return load(path, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether module runtime is enabled for target,
|
||||
* e.g., The following code checks if cuda is enabled.
|
||||
* Module.enabled("cuda")
|
||||
* @param target The target device type.
|
||||
* @return Whether runtime is enabled.
|
||||
*/
|
||||
public static boolean enabled(String target) {
|
||||
TVMValue ret = getApi("runtime.RuntimeEnabled").pushArg(target).invoke();
|
||||
return ret.asLong() != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class NativeLibraryLoader {
|
||||
private static final String libPathInJar = "/lib/native/";
|
||||
private static File tempDir;
|
||||
|
||||
static {
|
||||
try {
|
||||
tempDir = File.createTempFile("tvm4j", "");
|
||||
if (!tempDir.delete() || !tempDir.mkdir()) {
|
||||
throw new IOException("Couldn't create directory " + tempDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
/*
|
||||
* Different cleanup strategies for Windows and Linux.
|
||||
* TODO: shutdown hook won't work on Windows
|
||||
*/
|
||||
if (!"Windows".equals(getUnifiedOSName())) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (File f : tempDir.listFiles()) {
|
||||
System.err.println("Deleting " + f.getAbsolutePath());
|
||||
if (!f.delete()) {
|
||||
System.err.println("[WARN] Couldn't delete temporary file " + f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
System.err.println("Deleting " + tempDir.getAbsolutePath());
|
||||
if (!tempDir.delete()) {
|
||||
System.err.println(
|
||||
"[WARN] Couldn't delete temporary directory " + tempDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new RuntimeException("Windows not supported yet.");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.err.println("Couldn't create temporary directory: " + ex.getMessage());
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the library as a resource in jar, copy it to a tempfile
|
||||
* and load it using System.load(). The name of the library has to be the
|
||||
* base name, it is mapped to the corresponding system name using
|
||||
* System.mapLibraryName(). e.g., the library "foo" is called "libfoo.so"
|
||||
* under Linux and "foo.dll" under Windows, but you just have to pass "foo" to
|
||||
* the loadLibrary().
|
||||
*
|
||||
* @param libname basename of the library
|
||||
* @throws UnsatisfiedLinkError if library not found.
|
||||
* @throws IOException if file not found.
|
||||
*/
|
||||
public static void loadLibrary(String libname) throws UnsatisfiedLinkError, IOException {
|
||||
String mappedLibname = System.mapLibraryName(libname);
|
||||
String loadLibname = mappedLibname;
|
||||
if (mappedLibname.endsWith("dylib")) {
|
||||
System.err.println("Replaced .dylib with .jnilib");
|
||||
loadLibname = mappedLibname.replace(".dylib", ".jnilib");
|
||||
}
|
||||
System.err.println("Attempting to load " + loadLibname);
|
||||
extractResourceFileToTempDir(loadLibname, new Action() {
|
||||
@Override
|
||||
public void invoke(File target) {
|
||||
System.err.println("Loading library from " + target.getPath());
|
||||
System.load(target.getPath());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate all those Windows to "Windows". ("Windows XP", "Windows Vista", "Windows 7", etc.)
|
||||
*/
|
||||
private static String unifyOSName(String osname) {
|
||||
if (osname.startsWith("Windows")) {
|
||||
return "Windows";
|
||||
}
|
||||
return osname;
|
||||
}
|
||||
|
||||
private static String getUnifiedOSName() {
|
||||
return unifyOSName(System.getProperty("os.name"));
|
||||
}
|
||||
|
||||
private static File createTempFile(String name) throws IOException {
|
||||
return new File(tempDir + File.separator + name);
|
||||
}
|
||||
|
||||
static interface Action {
|
||||
public void invoke(File file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the resource file to a temp file and do an action.
|
||||
* @param filename source file name (in lib/native).
|
||||
* @param action callback function to deal with the copied file.
|
||||
*/
|
||||
public static void extractResourceFileToTempDir(String filename, Action action)
|
||||
throws IOException {
|
||||
final String libFileInJar = libPathInJar + filename;
|
||||
InputStream is = NativeLibraryLoader.class.getResourceAsStream(libFileInJar);
|
||||
if (is == null) {
|
||||
throw new UnsatisfiedLinkError("Couldn't find the resource " + filename);
|
||||
}
|
||||
System.err.println(String.format("Loading %s from %s", filename, libPathInJar));
|
||||
try {
|
||||
File tempfile = createTempFile(filename);
|
||||
OutputStream os = new FileOutputStream(tempfile);
|
||||
final long savedTime = System.currentTimeMillis();
|
||||
byte[] buf = new byte[8192];
|
||||
int len = is.read(buf);
|
||||
while (len > 0) {
|
||||
os.write(buf, 0, len);
|
||||
len = is.read(buf);
|
||||
}
|
||||
os.flush();
|
||||
final FileInputStream lock = new FileInputStream(tempfile);
|
||||
os.close();
|
||||
double seconds = (double) (System.currentTimeMillis() - savedTime) / 1e3;
|
||||
System.err.println(String.format("Copying took %.2f seconds.", seconds));
|
||||
action.invoke(tempfile);
|
||||
lock.close();
|
||||
} catch (IOException io) {
|
||||
System.err.println("[ERROR] Could not create the temp file: " + io.toString());
|
||||
throw io;
|
||||
} catch (UnsatisfiedLinkError ule) {
|
||||
System.err.println("Couldn't load copied link file: " + ule.toString());
|
||||
throw ule;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
/**
|
||||
* Base class of all TVM Objects.
|
||||
*/
|
||||
public class TVMObject extends TVMValue {
|
||||
protected long handle;
|
||||
public final int typeIndex;
|
||||
|
||||
public TVMObject(long handle, int typeIndex) {
|
||||
this.handle = handle;
|
||||
this.typeIndex = typeIndex;
|
||||
}
|
||||
|
||||
public void release() {
|
||||
Base.checkCall(Base._LIB.tvmFFIObjectFree(this.handle));
|
||||
this.handle = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
release();
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMType {
|
||||
public static final int INT = 0;
|
||||
public static final int UINT = 1;
|
||||
public static final int FLOAT = 2;
|
||||
public static final int HANDLE = 4;
|
||||
|
||||
public final int typeCode;
|
||||
public final int bits;
|
||||
public final int numOfBytes;
|
||||
public final int lanes;
|
||||
|
||||
/**
|
||||
* TVMType constructor.
|
||||
* @param typeStr type name, e.g., "float32", "float64", "uint8", etc.
|
||||
* @param lanes Tensor lanes.
|
||||
*/
|
||||
public TVMType(String typeStr, int lanes) {
|
||||
this.lanes = lanes;
|
||||
int bitsTemp = 0;
|
||||
if (typeStr.startsWith("int")) {
|
||||
typeCode = INT;
|
||||
bitsTemp = Integer.parseInt(typeStr.substring(3));
|
||||
} else if (typeStr.startsWith("uint")) {
|
||||
typeCode = UINT;
|
||||
bitsTemp = Integer.parseInt(typeStr.substring(4));
|
||||
} else if (typeStr.startsWith("float")) {
|
||||
typeCode = FLOAT;
|
||||
bitsTemp = Integer.parseInt(typeStr.substring(5));
|
||||
} else if (typeStr.startsWith("handle")) {
|
||||
typeCode = HANDLE;
|
||||
bitsTemp = 64;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Do not know how to handle type " + typeStr);
|
||||
}
|
||||
bits = (bitsTemp == 0) ? 32 : bitsTemp;
|
||||
if ((bits & (bits - 1)) != 0 || bits < 8) {
|
||||
throw new IllegalArgumentException("Do not know how to handle type " + typeStr);
|
||||
}
|
||||
numOfBytes = bits / 8;
|
||||
}
|
||||
|
||||
public TVMType(String typeStr) {
|
||||
this(typeStr, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (typeCode << 16) | (bits << 8) | lanes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other != null && other instanceof TVMType) {
|
||||
TVMType otherInst = (TVMType) other;
|
||||
return (bits == otherInst.bits) && (typeCode == otherInst.typeCode)
|
||||
&& (lanes == otherInst.lanes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String typeCodeStr;
|
||||
switch (typeCode) {
|
||||
case INT:
|
||||
typeCodeStr = "int";
|
||||
break;
|
||||
case UINT:
|
||||
typeCodeStr = "uint";
|
||||
break;
|
||||
case FLOAT:
|
||||
typeCodeStr = "float";
|
||||
break;
|
||||
case HANDLE:
|
||||
typeCodeStr = "handle";
|
||||
break;
|
||||
default:
|
||||
typeCodeStr = "Unknown";
|
||||
break;
|
||||
}
|
||||
String str = typeCodeStr + bits;
|
||||
if (lanes != 1) {
|
||||
str += lanes;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValue {
|
||||
protected TVMValue() {}
|
||||
|
||||
public void release() {}
|
||||
|
||||
public long asLong() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public double asDouble() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public byte[] asBytes() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Module asModule() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Function asFunction() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public TensorBase asTensor() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
// easy for JNI to use.
|
||||
long asHandle() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValueBytes extends TVMValue {
|
||||
public final byte[] value;
|
||||
|
||||
public TVMValueBytes(byte[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] asBytes() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValueDouble extends TVMValue {
|
||||
public final double value;
|
||||
|
||||
public TVMValueDouble(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double asDouble() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
/**
|
||||
* Java class related to TVM handles (ArgTypeCode.HANDLE)
|
||||
*/
|
||||
public class TVMValueHandle extends TVMValue {
|
||||
public final long value;
|
||||
|
||||
public TVMValueHandle(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long asHandle() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValueLong extends TVMValue {
|
||||
public final long value;
|
||||
|
||||
public TVMValueLong(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long asLong() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValueNull extends TVMValue {
|
||||
public TVMValueNull() {}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
public class TVMValueString extends TVMValue {
|
||||
public final String value;
|
||||
|
||||
public TVMValueString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Lightweight Tensor class of TVM runtime.
|
||||
*/
|
||||
public class Tensor extends TensorBase {
|
||||
private final TVMType dtype;
|
||||
private final Device device;
|
||||
|
||||
Tensor(long handle, boolean isView, TVMType dtype, Device dev) {
|
||||
super(handle, isView);
|
||||
this.dtype = dtype;
|
||||
this.device = dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by float64
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(double[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.FLOAT || dtype.bits != 64) {
|
||||
throw new IllegalArgumentException("Cannot set double[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putDouble(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by float32
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(float[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.FLOAT || dtype.bits != 32) {
|
||||
throw new IllegalArgumentException("Cannot set float[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putFloat(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by int64
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(long[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 64) {
|
||||
throw new IllegalArgumentException("Cannot set long[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putLong(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by float32
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(int[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 32) {
|
||||
throw new IllegalArgumentException("Cannot set int[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putInt(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by int16
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(short[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 16) {
|
||||
throw new IllegalArgumentException("Cannot set short[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putShort(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by int8
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(byte[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 8) {
|
||||
throw new IllegalArgumentException("Cannot set byte[] for " + dtype.toString() + " array");
|
||||
}
|
||||
copyFromRaw(sourceArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a native array.
|
||||
* The Tensor type must by uint16
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFrom(char[] sourceArray) {
|
||||
checkCopySize(sourceArray.length);
|
||||
if (dtype.typeCode != TVMType.UINT || dtype.bits != 16) {
|
||||
throw new IllegalArgumentException("Cannot set char[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[] nativeArr = new byte[sourceArray.length * dtype.numOfBytes];
|
||||
for (int i = 0; i < sourceArray.length; ++i) {
|
||||
wrapBytes(nativeArr, i * dtype.numOfBytes, dtype.numOfBytes).putChar(sourceArray[i]);
|
||||
}
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(nativeArr, this.dltensorHandle));
|
||||
}
|
||||
|
||||
private void checkCopySize(int sourceLength) {
|
||||
long arrSize = size();
|
||||
if (arrSize != sourceLength) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Array shape size not match: %d v.s. %d", sourceLength, size()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from a raw byte array.
|
||||
* @param sourceArray the source data
|
||||
*/
|
||||
public void copyFromRaw(byte[] sourceArray) {
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromJArray(sourceArray, this.dltensorHandle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shape of current Tensor.
|
||||
* @return an array representing shape of current tensor
|
||||
*/
|
||||
public long[] shape() {
|
||||
List<Long> data = new ArrayList<Long>();
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorGetShape(this.dltensorHandle, data));
|
||||
long[] shapeArr = new long[data.size()];
|
||||
for (int i = 0; i < shapeArr.length; ++i) {
|
||||
shapeArr[i] = data.get(i);
|
||||
}
|
||||
return shapeArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total size of current Tensor.
|
||||
* @return size of current Tensor.
|
||||
*/
|
||||
public long size() {
|
||||
long product = 1L;
|
||||
long[] shapeArr = shape();
|
||||
for (int i = 0; i < shapeArr.length; ++i) {
|
||||
product *= shapeArr[i];
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be float64
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public double[] asDoubleArray() {
|
||||
if (dtype.typeCode != TVMType.FLOAT || dtype.bits != 64) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to double[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
double[] array = new double[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getDouble();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be float32
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public float[] asFloatArray() {
|
||||
if (dtype.typeCode != TVMType.FLOAT || dtype.bits != 32) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to float[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
float[] array = new float[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getFloat();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be int64
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public long[] asLongArray() {
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 64) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to long[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
long[] array = new long[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getLong();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be int32
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public int[] asIntArray() {
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 32) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to int[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
int[] array = new int[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getInt();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be int16
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public short[] asShortArray() {
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 16) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to short[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
short[] array = new short[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getShort();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be uint16
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public char[] asCharArray() {
|
||||
if (dtype.typeCode != TVMType.UINT || dtype.bits != 16) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to char[] for " + dtype.toString() + " array");
|
||||
}
|
||||
byte[][] units = groupInternalBytes();
|
||||
char[] array = new char[units.length];
|
||||
for (int i = 0; i < units.length; ++i) {
|
||||
array[i] = wrapBytes(units[i]).getChar();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied flat java array of current array (row-major).
|
||||
* The Tensor dtype must be int8
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public byte[] asByteArray() {
|
||||
if (dtype.typeCode != TVMType.INT || dtype.bits != 8) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot set convert to byte[] for " + dtype.toString() + " array");
|
||||
}
|
||||
return internal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copied internal byte array of current array (row-major).
|
||||
* @return A copy of array content.
|
||||
*/
|
||||
public byte[] internal() {
|
||||
Tensor tmp = Tensor.empty(shape(), dtype);
|
||||
copyTo(tmp);
|
||||
|
||||
int arrLength = dtype.numOfBytes * (int) size();
|
||||
byte[] arr = new byte[arrLength];
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyToJArray(this.dltensorHandle, arr));
|
||||
return arr;
|
||||
}
|
||||
|
||||
private byte[][] groupInternalBytes() {
|
||||
byte[] raw = internal();
|
||||
int unitSize = dtype.numOfBytes;
|
||||
if (raw.length <= 0 || raw.length % unitSize != 0) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"%s size %d cannot divide byte array size %d", dtype.toString(), unitSize, raw.length));
|
||||
}
|
||||
|
||||
int numOfUnits = raw.length / unitSize;
|
||||
byte[][] units = new byte[numOfUnits][unitSize];
|
||||
for (int i = 0; i < numOfUnits; ++i) {
|
||||
System.arraycopy(raw, i * unitSize, units[i], 0, unitSize);
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device of current array.
|
||||
* @return the device.
|
||||
*/
|
||||
public Device device() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty array given shape, type and device.
|
||||
* @param shape The shape of the array.
|
||||
* @param dtype The data type of the array.
|
||||
* @param dev The device of the array.
|
||||
* @return The array tvm supported.
|
||||
*/
|
||||
public static Tensor empty(long[] shape, TVMType dtype, Device dev) {
|
||||
Base.RefLong refHandle = new Base.RefLong();
|
||||
Base.checkCall(Base._LIB.tvmTensorEmpty(
|
||||
shape, dtype.typeCode, dtype.bits, dtype.lanes, dev.deviceType, dev.deviceId, refHandle));
|
||||
return new Tensor(refHandle.value, false, dtype, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty array on cpu given shape and type.
|
||||
* @param shape The shape of the array.
|
||||
* @param dtype The data type of the array.
|
||||
* @return The array tvm supported.
|
||||
*/
|
||||
public static Tensor empty(long[] shape, TVMType dtype) {
|
||||
return empty(shape, dtype, Device.cpu(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty float32 array on cpu given shape.
|
||||
* @param shape The shape of the array.
|
||||
* @return The array tvm supported.
|
||||
*/
|
||||
public static Tensor empty(long[] shape) {
|
||||
return empty(shape, new TVMType("float32", 1), Device.cpu(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty float32 array given shape and device.
|
||||
* @param shape The shape of the array.
|
||||
* @param dev The device of the array.
|
||||
* @return The array tvm supported.
|
||||
*/
|
||||
public static Tensor empty(long[] shape, Device dev) {
|
||||
return empty(shape, new TVMType("float32", 1), dev);
|
||||
}
|
||||
|
||||
private static ByteBuffer wrapBytes(byte[] bytes) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return bb;
|
||||
}
|
||||
|
||||
private static ByteBuffer wrapBytes(byte[] bytes, int offset, int length) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return bb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
/**
|
||||
* Base class of Tensor. To handle callback array.
|
||||
* Only deep-copy supported.
|
||||
*/
|
||||
public class TensorBase extends TVMValue {
|
||||
protected long handle;
|
||||
public final boolean isView;
|
||||
protected final long dltensorHandle;
|
||||
|
||||
TensorBase(long handle, boolean isView) {
|
||||
this.dltensorHandle = isView ? handle : handle + 8 * 2;
|
||||
this.handle = isView ? 0 : handle;
|
||||
this.isView = isView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TensorBase asTensor() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the Tensor.
|
||||
*/
|
||||
public void release() {
|
||||
if (this.handle != 0) {
|
||||
Base.checkCall(Base._LIB.tvmFFIObjectFree(this.handle));
|
||||
this.handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
release();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy array to target.
|
||||
* @param target The target array to be copied, must have same shape as this array.
|
||||
* @return target
|
||||
*/
|
||||
public TensorBase copyTo(TensorBase target) {
|
||||
Base.checkCall(Base._LIB.tvmFFIDLTensorCopyFromTo(this.dltensorHandle, target.dltensorHandle));
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
// Type code used in API calls
|
||||
public class TypeIndex {
|
||||
public static final int kTVMFFINone = 0;
|
||||
public static final int kTVMFFIInt = 1;
|
||||
public static final int kTVMFFIBool = 2;
|
||||
public static final int kTVMFFIFloat = 3;
|
||||
public static final int kTVMFFIOpaquePtr = 4;
|
||||
public static final int kTVMFFIDataType = 5;
|
||||
public static final int kTVMFFIDevice = 6;
|
||||
public static final int kTVMFFIDLTensorPtr = 7;
|
||||
public static final int kTVMFFIRawStr = 8;
|
||||
public static final int kTVMFFIByteArrayPtr = 9;
|
||||
public static final int kTVMFFIObjectRValueRef = 10;
|
||||
public static final int kTVMFFIStaticObjectBegin = 64;
|
||||
public static final int kTVMFFIObject = 64;
|
||||
public static final int kTVMFFIStr = 65;
|
||||
public static final int kTVMFFIBytes = 66;
|
||||
public static final int kTVMFFIError = 67;
|
||||
public static final int kTVMFFIFunction = 68;
|
||||
public static final int kTVMFFIShape = 70;
|
||||
public static final int kTVMFFITensor = 71;
|
||||
public static final int kTVMFFIArray = 72;
|
||||
public static final int kTVMFFIMap = 73;
|
||||
public static final int kTVMFFIModule = 73;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import org.apache.tvm.Function;
|
||||
import org.apache.tvm.TVMValue;
|
||||
|
||||
/**
|
||||
* RPC Client.
|
||||
*/
|
||||
public class Client {
|
||||
/**
|
||||
* Connect to RPC Server.
|
||||
* @param url The url of the host.
|
||||
* @param port The port to connect to.
|
||||
* @param key Additional key to match server.
|
||||
* @return The connected session.
|
||||
*/
|
||||
public static RPCSession connect(String url, int port, String key) {
|
||||
Function doConnect = RPC.getApi("Connect");
|
||||
if (doConnect == null) {
|
||||
throw new RuntimeException("Please compile with USE_RPC=1");
|
||||
}
|
||||
TVMValue sess = doConnect.pushArg(url).pushArg(port).pushArg(key).invoke();
|
||||
return new RPCSession(sess.asModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to RPC Server.
|
||||
* @param url The url of the host.
|
||||
* @param port The port to connect to.
|
||||
* @return The connected session.
|
||||
*/
|
||||
public static RPCSession connect(String url, int port) {
|
||||
return connect(url, port, "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Server processor for proxy connection.
|
||||
*/
|
||||
public class ConnectProxyServerProcessor implements ServerProcessor {
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final String key;
|
||||
|
||||
private volatile Socket currSocket = new Socket();
|
||||
private Runnable callback;
|
||||
|
||||
/**
|
||||
* Construct proxy server processor.
|
||||
* @param host Proxy server host.
|
||||
* @param port Proxy server port.
|
||||
* @param key Proxy server key.
|
||||
*/
|
||||
public ConnectProxyServerProcessor(String host, int port, String key) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.key = "server:" + key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback when a connection is received e.g., to record the time for a
|
||||
* watchdog.
|
||||
* @param callback Runnable object.
|
||||
*/
|
||||
public void setStartTimeCallback(Runnable callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the socket.
|
||||
*/
|
||||
@Override
|
||||
public void terminate() {
|
||||
Utils.closeQuietly(currSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SocketAddress address = new InetSocketAddress(host, port);
|
||||
currSocket.connect(address, 6000);
|
||||
final InputStream in = currSocket.getInputStream();
|
||||
final OutputStream out = currSocket.getOutputStream();
|
||||
out.write(Utils.toBytes(RPC.RPC_MAGIC));
|
||||
out.write(Utils.toBytes(key.length()));
|
||||
out.write(Utils.toBytes(key));
|
||||
int magic = Utils.wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
if (magic == RPC.RPC_MAGIC + 1) {
|
||||
throw new RuntimeException(String.format("key: %s has already been used in proxy", key));
|
||||
} else if (magic == RPC.RPC_MAGIC + 2) {
|
||||
System.err.println("RPCProxy do not have matching client key " + key);
|
||||
} else if (magic != RPC.RPC_MAGIC) {
|
||||
throw new RuntimeException(address + " is not RPC Proxy");
|
||||
}
|
||||
// Get key from remote
|
||||
int keylen = Utils.wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
String remoteKey = Utils.decodeToStr(Utils.recvAll(in, keylen));
|
||||
System.err.println("RPCProxy connected to " + address);
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
|
||||
SocketChannel sockChannel = new SocketChannel(currSocket);
|
||||
new NativeServerLoop(sockChannel.getFsend(), sockChannel.getFrecv()).run();
|
||||
System.err.println("Finish serving " + address);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.BindException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
/**
|
||||
* Server processor with tracker connection (based on standalone).
|
||||
* This RPC Server registers itself with an RPC Tracker for a specific queue
|
||||
* (using its device key) and listens for incoming requests.
|
||||
*/
|
||||
public class ConnectTrackerServerProcessor implements ServerProcessor {
|
||||
private ServerSocket server;
|
||||
private final String trackerHost;
|
||||
private final int trackerPort;
|
||||
// device key
|
||||
private final String key;
|
||||
// device key plus randomly generated key (per-session)
|
||||
private final String matchKey;
|
||||
private int serverPort = 5001;
|
||||
public static final int MAX_SERVER_PORT = 5555;
|
||||
// time to wait before aborting tracker connection (ms)
|
||||
public static final int TRACKER_TIMEOUT = 6000;
|
||||
// time to wait before retrying tracker connection (ms)
|
||||
public static final int RETRY_PERIOD = TRACKER_TIMEOUT;
|
||||
// time to wait for a connection before refreshing tracker connection (ms)
|
||||
public static final int STALE_TRACKER_TIMEOUT = 300000;
|
||||
// time to wait if no timeout value is specified (seconds)
|
||||
public static final int HARD_TIMEOUT_DEFAULT = 300;
|
||||
private RPCWatchdog watchdog;
|
||||
private Socket trackerSocket;
|
||||
|
||||
/**
|
||||
* Construct tracker server processor.
|
||||
* @param trackerHost Tracker host.
|
||||
* @param trackerPort Tracker port.
|
||||
* @param key Device key.
|
||||
* @param watchdog watch for timeout, etc.
|
||||
* @throws java.io.IOException when socket fails to open.
|
||||
*/
|
||||
public ConnectTrackerServerProcessor(
|
||||
String trackerHost, int trackerPort, String key, RPCWatchdog watchdog) throws IOException {
|
||||
while (true) {
|
||||
try {
|
||||
this.server = new ServerSocket(serverPort);
|
||||
server.setSoTimeout(STALE_TRACKER_TIMEOUT);
|
||||
break;
|
||||
} catch (BindException e) {
|
||||
System.err.println(serverPort);
|
||||
System.err.println(e);
|
||||
serverPort++;
|
||||
if (serverPort > MAX_SERVER_PORT) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.err.println("using port: " + serverPort);
|
||||
this.trackerHost = trackerHost;
|
||||
this.trackerPort = trackerPort;
|
||||
this.key = key;
|
||||
this.matchKey = key + ":" + Math.random();
|
||||
this.watchdog = watchdog;
|
||||
}
|
||||
|
||||
public String getMatchKey() {
|
||||
return matchKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String recvKey = null;
|
||||
try {
|
||||
trackerSocket = connectToTracker();
|
||||
// open a socket and handshake with tracker
|
||||
register();
|
||||
Socket socket = null;
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
while (true) {
|
||||
try {
|
||||
System.err.println("waiting for requests...");
|
||||
// wait for client request
|
||||
socket = server.accept();
|
||||
in = socket.getInputStream();
|
||||
out = socket.getOutputStream();
|
||||
int magic = Utils.wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
if (magic != RPC.RPC_MAGIC) {
|
||||
out.write(Utils.toBytes(RPC.RPC_CODE_MISMATCH));
|
||||
System.err.println("incorrect RPC magic");
|
||||
Utils.closeQuietly(socket);
|
||||
continue;
|
||||
}
|
||||
recvKey = Utils.recvString(in);
|
||||
System.err.println("matchKey:" + matchKey);
|
||||
System.err.println("key: " + recvKey);
|
||||
// incorrect key
|
||||
if (recvKey.indexOf(matchKey) == -1) {
|
||||
out.write(Utils.toBytes(RPC.RPC_CODE_MISMATCH));
|
||||
System.err.println("key mismatch, expected: " + matchKey + " got: " + recvKey);
|
||||
Utils.closeQuietly(socket);
|
||||
continue;
|
||||
}
|
||||
// successfully got client request and completed handshake with client
|
||||
break;
|
||||
} catch (SocketTimeoutException e) {
|
||||
System.err.println("no incoming connections, refreshing...");
|
||||
// need to reregister, if the tracker died we should see a socked closed exception
|
||||
if (!needRefreshKey()) {
|
||||
System.err.println("reregistering...");
|
||||
register();
|
||||
}
|
||||
}
|
||||
}
|
||||
int timeout = HARD_TIMEOUT_DEFAULT;
|
||||
int timeoutArgIndex = recvKey.indexOf(RPC.TIMEOUT_ARG);
|
||||
if (timeoutArgIndex != -1) {
|
||||
timeout = Integer.parseInt(recvKey.substring(timeoutArgIndex + RPC.TIMEOUT_ARG.length()));
|
||||
}
|
||||
System.err.println("alloted timeout: " + timeout);
|
||||
if (!recvKey.startsWith("client:")) {
|
||||
System.err.println("recv key mismatch...");
|
||||
out.write(Utils.toBytes(RPC.RPC_CODE_MISMATCH));
|
||||
} else {
|
||||
out.write(Utils.toBytes(RPC.RPC_MAGIC));
|
||||
// send server key to the client
|
||||
Utils.sendString(out, recvKey);
|
||||
}
|
||||
|
||||
System.err.println("Connection from " + socket.getRemoteSocketAddress().toString());
|
||||
// received timeout in seconds
|
||||
watchdog.startTimeout(timeout * 1000);
|
||||
SocketChannel sockChannel = new SocketChannel(socket);
|
||||
new NativeServerLoop(sockChannel.getFsend(), sockChannel.getFrecv()).run();
|
||||
System.err.println("Finish serving " + socket.getRemoteSocketAddress().toString());
|
||||
Utils.closeQuietly(socket);
|
||||
} catch (ConnectException e) {
|
||||
// if the tracker connection failed, wait a bit before retrying
|
||||
try {
|
||||
Thread.sleep(RETRY_PERIOD);
|
||||
} catch (InterruptedException e_) {
|
||||
System.err.println("interrupted before retrying to connect to tracker...");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (trackerSocket != null) {
|
||||
trackerSocket.close();
|
||||
}
|
||||
server.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Socket connectToTracker() throws IOException {
|
||||
trackerSocket = new Socket();
|
||||
SocketAddress address = new InetSocketAddress(trackerHost, trackerPort);
|
||||
trackerSocket.connect(address, TRACKER_TIMEOUT);
|
||||
InputStream trackerIn = trackerSocket.getInputStream();
|
||||
OutputStream trackerOut = trackerSocket.getOutputStream();
|
||||
trackerOut.write(Utils.toBytes(RPC.RPC_TRACKER_MAGIC));
|
||||
int trackerMagic = Utils.wrapBytes(Utils.recvAll(trackerIn, 4)).getInt();
|
||||
if (trackerMagic != RPC.RPC_TRACKER_MAGIC) {
|
||||
throw new SocketException("failed to connect to tracker (WRONG MAGIC)");
|
||||
}
|
||||
String infoJSON = generateCinfo(key);
|
||||
Utils.sendString(trackerOut, infoJSON);
|
||||
int recvCode = Integer.parseInt(Utils.recvString(trackerIn));
|
||||
if (recvCode != RPC.TrackerCode.SUCCESS) {
|
||||
throw new SocketException("failed to connect to tracker (not SUCCESS)");
|
||||
}
|
||||
return trackerSocket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the RPC Server with the RPC Tracker.
|
||||
*/
|
||||
private void register() throws IOException {
|
||||
InputStream trackerIn = trackerSocket.getInputStream();
|
||||
OutputStream trackerOut = trackerSocket.getOutputStream();
|
||||
// send a JSON with PUT, device key, RPC server port, and the randomly
|
||||
// generated key
|
||||
String putJSON = generatePut(RPC.TrackerCode.PUT, key, serverPort, matchKey);
|
||||
Utils.sendString(trackerOut, putJSON);
|
||||
int recvCode = Integer.parseInt(Utils.recvString(trackerIn));
|
||||
if (recvCode != RPC.TrackerCode.SUCCESS) {
|
||||
throw new SocketException("failed to register with tracker (not SUCCESS)");
|
||||
}
|
||||
System.err.println("registered with tracker...");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the RPC Tracker has our key.
|
||||
*/
|
||||
private boolean needRefreshKey() throws IOException {
|
||||
InputStream trackerIn = trackerSocket.getInputStream();
|
||||
OutputStream trackerOut = trackerSocket.getOutputStream();
|
||||
String getJSON = generateGetPendingMatchKeys(RPC.TrackerCode.GET_PENDING_MATCHKEYS);
|
||||
Utils.sendString(trackerOut, getJSON);
|
||||
String recvJSON = Utils.recvString(trackerIn);
|
||||
System.err.println("pending matchkeys: " + recvJSON);
|
||||
// fairly expensive string operation...
|
||||
if (recvJSON.indexOf(matchKey) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// handcrafted JSON
|
||||
private String generateCinfo(String key) {
|
||||
String cinfo = "{\"key\" : "
|
||||
+ "\"server:" + key + "\", \"addr\": [null, \"" + serverPort + "\"]}";
|
||||
return "[" + RPC.TrackerCode.UPDATE_INFO + ", " + cinfo + "]";
|
||||
}
|
||||
|
||||
// handcrafted JSON
|
||||
private String generatePut(int code, String key, int port, String matchKey) {
|
||||
return "[" + code + ", "
|
||||
+ "\"" + key + "\""
|
||||
+ ", "
|
||||
+ "[" + port + ", "
|
||||
+ "\"" + matchKey + "\""
|
||||
+ "]"
|
||||
+ ", "
|
||||
+ "null"
|
||||
+ "]";
|
||||
}
|
||||
|
||||
// handcrafted JSON
|
||||
private String generateGetPendingMatchKeys(int code) {
|
||||
return "[" + code + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.apache.tvm.Function;
|
||||
import org.apache.tvm.Module;
|
||||
import org.apache.tvm.TVMValue;
|
||||
|
||||
/**
|
||||
* Call native ServerLoop on socket file descriptor.
|
||||
*/
|
||||
public class NativeServerLoop implements Runnable {
|
||||
private final Function fsend;
|
||||
private final Function frecv;
|
||||
|
||||
/**
|
||||
* Constructor for NativeServerLoop.
|
||||
* @param fsend socket.send function.
|
||||
* @param frecv socket.recv function.
|
||||
*/
|
||||
public NativeServerLoop(final Function fsend, final Function frecv) {
|
||||
this.fsend = fsend;
|
||||
this.frecv = frecv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
File tempDir = null;
|
||||
try {
|
||||
tempDir = serverEnv();
|
||||
System.err.println("starting server loop...");
|
||||
RPC.getApi("ServerLoop").pushArg(fsend).pushArg(frecv).invoke();
|
||||
System.err.println("done server loop...");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (tempDir != null) {
|
||||
String[] entries = tempDir.list();
|
||||
for (String s : entries) {
|
||||
File currentFile = new File(tempDir.getPath(), s);
|
||||
if (!currentFile.delete()) {
|
||||
System.err.println(
|
||||
"[WARN] Couldn't delete temporary file " + currentFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
if (!tempDir.delete()) {
|
||||
System.err.println(
|
||||
"[WARN] Couldn't delete temporary directory " + tempDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static File serverEnv() throws IOException {
|
||||
// Server environment function return temp dir.
|
||||
final File tempDir = File.createTempFile("tvm4j_rpc_", "");
|
||||
if (!tempDir.delete() || !tempDir.mkdir()) {
|
||||
throw new IOException("Couldn't create directory " + tempDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
Function.register("tvm.rpc.server.workpath", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
return tempDir + File.separator + args[0].asString();
|
||||
}
|
||||
}, true);
|
||||
|
||||
Function.register("tvm.rpc.server.load_module", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
String filename = args[0].asString();
|
||||
String path = tempDir + File.separator + filename;
|
||||
System.err.println("Load module from " + path);
|
||||
return Module.load(path);
|
||||
}
|
||||
}, true);
|
||||
|
||||
return tempDir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.tvm.Function;
|
||||
|
||||
public class RPC {
|
||||
public static final int RPC_TRACKER_MAGIC = 0x2f271;
|
||||
public static final int RPC_MAGIC = 0xff271;
|
||||
public static final int RPC_CODE_MISMATCH = RPC_MAGIC + 2;
|
||||
public static final int RPC_SESS_MASK = 128;
|
||||
|
||||
public static final String TIMEOUT_ARG = "-timeout=";
|
||||
|
||||
public class TrackerCode {
|
||||
public static final int PUT = 3;
|
||||
public static final int UPDATE_INFO = 5;
|
||||
public static final int GET_PENDING_MATCHKEYS = 7;
|
||||
public static final int SUCCESS = 0;
|
||||
}
|
||||
|
||||
private static ThreadLocal<Map<String, Function>> apiFuncs =
|
||||
new ThreadLocal<Map<String, Function>>() {
|
||||
@Override
|
||||
protected Map<String, Function> initialValue() {
|
||||
return new HashMap<String, Function>();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get internal function starts with namespace tvm.rpc.
|
||||
* @param name function name.
|
||||
* @return the function, null if not exists.
|
||||
*/
|
||||
static Function getApi(String name) {
|
||||
Function func = apiFuncs.get().get(name);
|
||||
if (func == null) {
|
||||
func = Function.getFunction("rpc." + name);
|
||||
if (func == null) {
|
||||
return null;
|
||||
}
|
||||
apiFuncs.get().put(name, func);
|
||||
}
|
||||
return func;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.tvm.Device;
|
||||
import org.apache.tvm.Function;
|
||||
import org.apache.tvm.Module;
|
||||
|
||||
/**
|
||||
* RPC Client session module.
|
||||
* Do not directly create the object, use Client.connect.
|
||||
*/
|
||||
public class RPCSession {
|
||||
private final Module session;
|
||||
private final int tblIndex;
|
||||
private final Map<String, Function> remoteFuncs = new HashMap<String, Function>();
|
||||
|
||||
RPCSession(Module sess) {
|
||||
session = sess;
|
||||
tblIndex = (int) RPC.getApi("SessTableIndex").pushArg(session).invoke().asLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get function from the session.
|
||||
* @param name The name of the function.
|
||||
* @return The result function.
|
||||
*/
|
||||
public Function getFunction(String name) {
|
||||
return session.getFunction(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a remote device.
|
||||
* @param devType device type.
|
||||
* @param devId device id.
|
||||
* @return The corresponding encoded remote device.
|
||||
*/
|
||||
public Device device(String devType, int devId) {
|
||||
Device dev = new Device(devType, devId);
|
||||
int encode = (tblIndex + 1) * RPC.RPC_SESS_MASK;
|
||||
return new TVMRemoteDevice(dev.deviceType + encode, devId, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a remote device.
|
||||
* @param devType device type.
|
||||
* @return The corresponding encoded remote device.
|
||||
*/
|
||||
public Device device(String devType) {
|
||||
return device(devType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a remote device.
|
||||
* @param devType device type.
|
||||
* @param devId device id.
|
||||
* @return The corresponding encoded remote device.
|
||||
*/
|
||||
public Device device(int devType, int devId) {
|
||||
int encode = (tblIndex + 1) * RPC.RPC_SESS_MASK;
|
||||
return new TVMRemoteDevice(devType + encode, devId, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a remote device.
|
||||
* @param devType device type.
|
||||
* @return The corresponding encoded remote device.
|
||||
*/
|
||||
public Device device(int devType) {
|
||||
return device(devType, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote CPU device.
|
||||
* @param devId device id.
|
||||
* @return Remote CPU device.
|
||||
*/
|
||||
public Device cpu(int devId) {
|
||||
return Device.cpu(devId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote CPU device.
|
||||
* @return Remote CPU device.
|
||||
*/
|
||||
public Device cpu() {
|
||||
return cpu(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote CUDA GPU device.
|
||||
* @param devId device id.
|
||||
* @return Remote CUDA GPU device.
|
||||
*/
|
||||
public Device cuda(int devId) {
|
||||
return Device.cuda(devId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote CUDA GPU device.
|
||||
* @return Remote CUDA GPU device.
|
||||
*/
|
||||
public Device cuda() {
|
||||
return cuda(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote OpenCL device.
|
||||
* @param devId device id.
|
||||
* @return Remote OpenCL device.
|
||||
*/
|
||||
public Device cl(int devId) {
|
||||
return Device.opencl(devId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote OpenCL device.
|
||||
* @return Remote OpenCL device.
|
||||
*/
|
||||
public Device cl() {
|
||||
return cl(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote OpenCL device.
|
||||
* @param devId device id.
|
||||
* @return Remote OpenCL device.
|
||||
*/
|
||||
public Device vulkan(int devId) {
|
||||
return Device.vulkan(devId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote OpenCL device.
|
||||
* @return Remote OpenCL device.
|
||||
*/
|
||||
public Device vulkan() {
|
||||
return vulkan(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote Metal device.
|
||||
* @param devId device id.
|
||||
* @return Remote metal device.
|
||||
*/
|
||||
public Device metal(int devId) {
|
||||
return Device.metal(devId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct remote Metal device.
|
||||
* @return Remote metal device.
|
||||
*/
|
||||
public Device metal() {
|
||||
return metal(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload binary to remote runtime temp folder.
|
||||
* @param data The binary in local to upload.
|
||||
* @param target The path in remote, cannot be null.
|
||||
*/
|
||||
public void upload(byte[] data, String target) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("Please specify the upload target");
|
||||
}
|
||||
final String funcName = "upload";
|
||||
Function remoteFunc = remoteFuncs.get(funcName);
|
||||
if (remoteFunc == null) {
|
||||
remoteFunc = getFunction("tvm.rpc.server.upload");
|
||||
remoteFuncs.put(funcName, remoteFunc);
|
||||
}
|
||||
remoteFunc.pushArg(target).pushArg(data).invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file to remote runtime temp folder.
|
||||
* @param data The file in local to upload.
|
||||
* @param target The path in remote.
|
||||
* @throws java.io.IOException for network failure.
|
||||
*/
|
||||
public void upload(File data, String target) throws IOException {
|
||||
byte[] blob = getBytesFromFile(data);
|
||||
upload(blob, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload file to remote runtime temp folder.
|
||||
* @param data The file in local to upload.
|
||||
* @throws java.io.IOException for network failure.
|
||||
*/
|
||||
public void upload(File data) throws IOException {
|
||||
upload(data, data.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Download file from remote temp folder.
|
||||
* @param path The relative location to remote temp folder.
|
||||
* @return The result blob from the file.
|
||||
*/
|
||||
public byte[] download(String path) {
|
||||
final String name = "download";
|
||||
Function func = remoteFuncs.get(name);
|
||||
if (func == null) {
|
||||
func = getFunction("tvm.rpc.server.download");
|
||||
remoteFuncs.put(name, func);
|
||||
}
|
||||
return func.pushArg(path).invoke().asBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a remote module, the file need to be uploaded first.
|
||||
* @param path The relative location to remote temp folder.
|
||||
* @return The remote module containing remote function.
|
||||
*/
|
||||
public Module loadModule(String path) {
|
||||
return RPC.getApi("LoadRemoteModule").pushArg(session).pushArg(path).invoke().asModule();
|
||||
}
|
||||
|
||||
private static byte[] getBytesFromFile(File file) throws IOException {
|
||||
// Get the size of the file
|
||||
long length = file.length();
|
||||
|
||||
if (length > Integer.MAX_VALUE) {
|
||||
throw new IOException("File " + file.getName() + " is too large!");
|
||||
}
|
||||
|
||||
// cannot create an array using a long type.
|
||||
byte[] bytes = new byte[(int) length];
|
||||
|
||||
// Read in the bytes
|
||||
int offset = 0;
|
||||
int numRead = 0;
|
||||
|
||||
InputStream is = new FileInputStream(file);
|
||||
try {
|
||||
while (
|
||||
offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
|
||||
offset += numRead;
|
||||
}
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
|
||||
// Ensure all the bytes have been read in
|
||||
if (offset < bytes.length) {
|
||||
throw new IOException("Could not completely read file " + file.getName());
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
/**
|
||||
* Watchdog for RPC.
|
||||
*/
|
||||
public class RPCWatchdog extends Thread {
|
||||
private int timeout = 0;
|
||||
private boolean started = false;
|
||||
|
||||
public RPCWatchdog() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a timeout with watchdog (must be called before finishTimeout).
|
||||
* @param timeout watchdog timeout in ms.
|
||||
*/
|
||||
public synchronized void startTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
started = true;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish a timeout with watchdog (must be called after startTimeout).
|
||||
*/
|
||||
public synchronized void finishTimeout() {
|
||||
started = false;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait and kill RPC if timeout is exceeded.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
// timeout not started
|
||||
synchronized (this) {
|
||||
while (!started) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("watchdog interrupted...");
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized (this) {
|
||||
while (started) {
|
||||
try {
|
||||
System.err.println("waiting for timeout: " + timeout);
|
||||
this.wait(timeout);
|
||||
if (!started) {
|
||||
System.err.println("watchdog woken up, ok...");
|
||||
} else {
|
||||
System.err.println("watchdog woke up!");
|
||||
System.err.println("terminating...");
|
||||
terminate();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("watchdog interrupted...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default method to terminate the running RPCActivity process.
|
||||
*/
|
||||
protected void terminate() {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* RPC Server.
|
||||
*/
|
||||
public class Server {
|
||||
private final WorkerThread worker;
|
||||
|
||||
private static class WorkerThread extends Thread {
|
||||
private volatile boolean running = true;
|
||||
private final ServerProcessor processor;
|
||||
|
||||
public WorkerThread(ServerProcessor processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (running) {
|
||||
processor.run();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
running = false;
|
||||
processor.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a standalone server.
|
||||
* @param serverPort Port.
|
||||
* @throws IOException if failed to bind localhost:port.
|
||||
*/
|
||||
public Server(int serverPort) throws IOException {
|
||||
worker = new WorkerThread(new StandaloneServerProcessor(serverPort));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a server connected to proxy.
|
||||
* Use sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess
|
||||
* to get file descriptor for the socket.
|
||||
* @param proxyHost The proxy server host.
|
||||
* @param proxyPort The proxy server port.
|
||||
* @param key The key to identify the server.
|
||||
*/
|
||||
public Server(String proxyHost, int proxyPort, String key) {
|
||||
worker = new WorkerThread(new ConnectProxyServerProcessor(proxyHost, proxyPort, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server.
|
||||
*/
|
||||
public void start() {
|
||||
worker.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the server.
|
||||
*/
|
||||
public void terminate() {
|
||||
worker.terminate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
/**
|
||||
* Abstract runnable class for RPC server process.
|
||||
*/
|
||||
public interface ServerProcessor extends Runnable {
|
||||
public void terminate();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import org.apache.tvm.Function;
|
||||
import org.apache.tvm.TVMValue;
|
||||
import org.apache.tvm.TVMValueBytes;
|
||||
|
||||
public class SocketChannel {
|
||||
private final Socket socket;
|
||||
|
||||
SocketChannel(Socket sock) {
|
||||
socket = sock;
|
||||
}
|
||||
|
||||
private Function fsend = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
byte[] data = args[0].asBytes();
|
||||
try {
|
||||
socket.getOutputStream().write(data);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
return data.length;
|
||||
}
|
||||
});
|
||||
|
||||
private Function frecv = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
long size = args[0].asLong();
|
||||
try {
|
||||
return new TVMValueBytes(Utils.recvAll(socket.getInputStream(), (int) size));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public Function getFsend() {
|
||||
return fsend;
|
||||
}
|
||||
|
||||
public Function getFrecv() {
|
||||
return frecv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Server processor for standalone.
|
||||
*/
|
||||
public class StandaloneServerProcessor implements ServerProcessor {
|
||||
private final ServerSocket server;
|
||||
|
||||
public StandaloneServerProcessor(int serverPort) throws IOException {
|
||||
this.server = new ServerSocket(serverPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final Socket socket = server.accept();
|
||||
final InputStream in = socket.getInputStream();
|
||||
final OutputStream out = socket.getOutputStream();
|
||||
int magic = Utils.wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
if (magic != RPC.RPC_MAGIC) {
|
||||
Utils.closeQuietly(socket);
|
||||
return;
|
||||
}
|
||||
int keyLen = Utils.wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
String key = Utils.decodeToStr(Utils.recvAll(in, keyLen));
|
||||
if (!key.startsWith("client:")) {
|
||||
out.write(Utils.toBytes(RPC.RPC_MAGIC + 2));
|
||||
} else {
|
||||
out.write(Utils.toBytes(RPC.RPC_MAGIC));
|
||||
// send server key to the client
|
||||
String serverKey = "server:java";
|
||||
out.write(Utils.toBytes(serverKey.length()));
|
||||
out.write(Utils.toBytes(serverKey));
|
||||
}
|
||||
|
||||
SocketChannel sockChannel = new SocketChannel(socket);
|
||||
System.err.println("Connection from " + socket.getRemoteSocketAddress().toString());
|
||||
new NativeServerLoop(sockChannel.getFsend(), sockChannel.getFrecv()).run();
|
||||
System.err.println("Finish serving " + socket.getRemoteSocketAddress().toString());
|
||||
Utils.closeQuietly(socket);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import org.apache.tvm.Device;
|
||||
|
||||
// always related to RPCSession. Cannot construct by users.
|
||||
public class TVMRemoteDevice extends Device {
|
||||
public final RPCSession rpcSession;
|
||||
|
||||
TVMRemoteDevice(int deviceType, int deviceId, RPCSession rpcSession) {
|
||||
super(deviceType, deviceId);
|
||||
this.rpcSession = rpcSession;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Utilities for RPC.
|
||||
*/
|
||||
class Utils {
|
||||
public static byte[] recvAll(final InputStream in, final int numBytes) throws IOException {
|
||||
byte[] res = new byte[numBytes];
|
||||
int numRead = 0;
|
||||
while (numRead < numBytes) {
|
||||
int chunk = in.read(res, numRead, Math.min(numBytes - numRead, 1024));
|
||||
numRead += chunk;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void closeQuietly(Socket socket) {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.shutdownInput();
|
||||
socket.shutdownOutput();
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
// close quietly, do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuffer wrapBytes(byte[] bytes) {
|
||||
ByteBuffer bb = ByteBuffer.wrap(bytes);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(int number) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(4);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
return bb.putInt(number).array();
|
||||
}
|
||||
|
||||
public static byte[] toBytes(String str) {
|
||||
byte[] bytes = new byte[str.length()];
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
bytes[i] = (byte) str.charAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String decodeToStr(byte[] bytes) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (byte bt : bytes) {
|
||||
builder.append((char) bt);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String recvString(InputStream in) throws IOException {
|
||||
String recvString = null;
|
||||
int len = wrapBytes(Utils.recvAll(in, 4)).getInt();
|
||||
recvString = decodeToStr(Utils.recvAll(in, len));
|
||||
return recvString;
|
||||
}
|
||||
|
||||
public static void sendString(OutputStream out, String string) throws IOException {
|
||||
out.write(toBytes(string.length()));
|
||||
out.write(toBytes(string));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class FunctionTest {
|
||||
@Test
|
||||
public void test_reg_sum_number() {
|
||||
Function.register("sum_number", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
long res = 0L;
|
||||
for (TVMValue arg : args) {
|
||||
res += arg.asLong();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
});
|
||||
Function func = Function.getFunction("sum_number");
|
||||
TVMValue res = func.pushArg(10).pushArg(20).invoke();
|
||||
assertEquals(30, res.asLong());
|
||||
res.release();
|
||||
func.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_add_string() {
|
||||
System.err.println("[TEST] test_add_string");
|
||||
|
||||
Function func = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
String res = "";
|
||||
for (TVMValue arg : args) {
|
||||
res += arg.asString();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
});
|
||||
TVMValue res = func.pushArg("Hello").pushArg(" ").pushArg("World!").invoke();
|
||||
assertEquals("Hello World!", res.asString());
|
||||
res.release();
|
||||
func.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_sum_first_byte() {
|
||||
Function func = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
byte[] bt = new byte[1];
|
||||
for (TVMValue arg : args) {
|
||||
bt[0] += arg.asBytes()[0];
|
||||
}
|
||||
return bt;
|
||||
}
|
||||
});
|
||||
TVMValue res = func.pushArg(new byte[] {1}).pushArg(new byte[] {2, 3}).invoke();
|
||||
assertArrayEquals(new byte[] {3}, res.asBytes());
|
||||
res.release();
|
||||
func.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_sum_tensor() {
|
||||
final long[] shape = new long[] {2, 1};
|
||||
Function func = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
double sum = 0.0;
|
||||
for (TVMValue arg : args) {
|
||||
Tensor arr = Tensor.empty(shape, new TVMType("float32"));
|
||||
arg.asTensor().copyTo(arr);
|
||||
float[] nativeArr = arr.asFloatArray();
|
||||
for (int i = 0; i < nativeArr.length; ++i) {
|
||||
sum += nativeArr[i];
|
||||
}
|
||||
arr.release();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
});
|
||||
Tensor arr = Tensor.empty(shape, new TVMType("float32"));
|
||||
arr.copyFrom(new float[] {2f, 3f});
|
||||
TVMValue res = func.pushArg(arr).pushArg(arr).invoke();
|
||||
assertEquals(10.0, res.asDouble(), 1e-3);
|
||||
res.release();
|
||||
func.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_return_function() {
|
||||
Function myFunc = Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
final long y = args[0].asLong();
|
||||
return Function.convertFunc(new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
final long x = args[0].asLong();
|
||||
return x + y;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Function func = myFunc.pushArg(10).invoke().asFunction();
|
||||
TVMValue res = func.pushArg(20).invoke();
|
||||
assertEquals(30, res.asLong());
|
||||
func.release();
|
||||
myFunc.release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Random;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ModuleTest {
|
||||
private final Logger logger = LoggerFactory.getLogger(ModuleTest.class);
|
||||
private static String loadingDir;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
loadingDir = System.getProperty("test.tempdir");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_load_add_func_cpu() {
|
||||
Module fadd = Module.load(loadingDir + File.separator + "add_cpu.so");
|
||||
|
||||
Device dev = new Device("cpu", 0);
|
||||
long[] shape = new long[] {2};
|
||||
Tensor arr = Tensor.empty(shape, dev);
|
||||
|
||||
arr.copyFrom(new float[] {3f, 4f});
|
||||
|
||||
Tensor res = Tensor.empty(shape, dev);
|
||||
|
||||
fadd.entryFunc().pushArg(arr).pushArg(arr).pushArg(res).invoke();
|
||||
assertArrayEquals(new float[] {6f, 8f}, res.asFloatArray(), 1e-3f);
|
||||
|
||||
// test call() api
|
||||
fadd.entryFunc().call(arr, arr, res);
|
||||
assertArrayEquals(new float[] {6f, 8f}, res.asFloatArray(), 1e-3f);
|
||||
|
||||
arr.release();
|
||||
res.release();
|
||||
fadd.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_load_add_func_cuda() {
|
||||
final Random RND = new Random(0);
|
||||
|
||||
Device dev = new Device("cuda", 0);
|
||||
if (!dev.exist()) {
|
||||
logger.warn("CUDA GPU does not exist. Skip the test.");
|
||||
return;
|
||||
}
|
||||
|
||||
Module fadd = Module.load(loadingDir + File.separator + "add_cuda.so");
|
||||
|
||||
final int dim = 100;
|
||||
long[] shape = new long[] {dim};
|
||||
Tensor arr = Tensor.empty(shape, dev);
|
||||
|
||||
float[] data = new float[dim];
|
||||
float[] dataX2 = new float[dim];
|
||||
for (int i = 0; i < dim; ++i) {
|
||||
data[i] = RND.nextFloat();
|
||||
dataX2[i] = data[i] * 2;
|
||||
}
|
||||
arr.copyFrom(data);
|
||||
|
||||
Tensor res = Tensor.empty(shape, dev);
|
||||
fadd.entryFunc().pushArg(arr).pushArg(arr).pushArg(res).invoke();
|
||||
|
||||
assertArrayEquals(dataX2, res.asFloatArray(), 1e-3f);
|
||||
|
||||
arr.release();
|
||||
res.release();
|
||||
fadd.release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.tvm;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TensorTest {
|
||||
@Test
|
||||
public void test_from_float32() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("float32"));
|
||||
tensor.copyFrom(new float[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new float[] {1f, 2f, 3f, 4f}, tensor.asFloatArray(), 1e-3f);
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_float64() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("float64"));
|
||||
tensor.copyFrom(new double[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new double[] {1.0, 2.0, 3.0, 4.0}, tensor.asDoubleArray(), 1e-3);
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_int8() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("int8"));
|
||||
tensor.copyFrom(new byte[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new byte[] {1, 2, 3, 4}, tensor.asByteArray());
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_int16() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("int16"));
|
||||
tensor.copyFrom(new short[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new short[] {1, 2, 3, 4}, tensor.asShortArray());
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_int32() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("int32"));
|
||||
tensor.copyFrom(new int[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new int[] {1, 2, 3, 4}, tensor.asIntArray());
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_int64() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("int64"));
|
||||
tensor.copyFrom(new long[] {1, 2, 3, 4});
|
||||
assertArrayEquals(new long[] {1, 2, 3, 4}, tensor.asLongArray());
|
||||
tensor.release();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_from_uint16() {
|
||||
Tensor tensor = Tensor.empty(new long[] {2, 2}, new TVMType("uint16"));
|
||||
tensor.copyFrom(new char[] {65535, 2, 3, 4});
|
||||
assertArrayEquals(new char[] {65535, 2, 3, 4}, tensor.asCharArray());
|
||||
tensor.release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.apache.tvm;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.tvm.rpc.Server;
|
||||
|
||||
public class TestUtils {
|
||||
public static class RefInt {
|
||||
public int value;
|
||||
}
|
||||
|
||||
public static Server startServer(RefInt portRef) {
|
||||
Server server = null;
|
||||
int port = 9981;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
try {
|
||||
server = new Server(port + i);
|
||||
server.start();
|
||||
portRef.value = port + i;
|
||||
return server;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Cannot find an available port.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.tvm.rpc;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.apache.tvm.Function;
|
||||
import org.apache.tvm.Module;
|
||||
import org.apache.tvm.TVMValue;
|
||||
import org.apache.tvm.TestUtils;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RPCTest {
|
||||
private final Logger logger = LoggerFactory.getLogger(RPCTest.class);
|
||||
|
||||
@Ignore("RPC test is not enabled")
|
||||
@Test
|
||||
public void test_addone() {
|
||||
if (!Module.enabled("rpc")) {
|
||||
logger.warn("RPC is not enabled. Skip.");
|
||||
return;
|
||||
}
|
||||
Function.register("test.rpc.addone", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
return args[0].asLong() + 1L;
|
||||
}
|
||||
});
|
||||
|
||||
TestUtils.RefInt port = new TestUtils.RefInt();
|
||||
Server server = null;
|
||||
try {
|
||||
server = TestUtils.startServer(port);
|
||||
RPCSession client = Client.connect("127.0.0.1", port.value);
|
||||
Function func = client.getFunction("test.rpc.addone");
|
||||
assertEquals(11L, func.call(10).asLong());
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("RPC test is not enabled")
|
||||
@Test
|
||||
public void test_strcat() {
|
||||
if (!Module.enabled("rpc")) {
|
||||
logger.warn("RPC is not enabled. Skip.");
|
||||
return;
|
||||
}
|
||||
Function.register("test.rpc.strcat", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... args) {
|
||||
return args[0].asString() + ":" + args[1].asLong();
|
||||
}
|
||||
});
|
||||
|
||||
TestUtils.RefInt port = new TestUtils.RefInt();
|
||||
Server server = null;
|
||||
try {
|
||||
server = TestUtils.startServer(port);
|
||||
RPCSession client = Client.connect("127.0.0.1", port.value);
|
||||
Function func = client.getFunction("test.rpc.strcat");
|
||||
assertEquals("abc:11", func.call("abc", 11L).asString());
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Proxy server may not have been ready when this test runs,"
|
||||
+ " will add retry when callback function can deal with Java exception."
|
||||
+ " After that we'll enable this test.")
|
||||
@Test
|
||||
public void
|
||||
test_connect_proxy_server() {
|
||||
String proxyHost = System.getProperty("test.rpc.proxy.host");
|
||||
int proxyPort = Integer.parseInt(System.getProperty("test.rpc.proxy.port"));
|
||||
|
||||
Function.register("test.rpc.proxy.addone", new Function.Callback() {
|
||||
@Override
|
||||
public Object invoke(TVMValue... tvmValues) {
|
||||
return tvmValues[0].asLong() + 1L;
|
||||
}
|
||||
});
|
||||
|
||||
Server server = null;
|
||||
try {
|
||||
server = new Server(proxyHost, proxyPort, "x1");
|
||||
server.start();
|
||||
|
||||
RPCSession client = Client.connect(proxyHost, proxyPort, "x1");
|
||||
Function f1 = client.getFunction("test.rpc.proxy.addone");
|
||||
assertEquals(11L, f1.call(10L).asLong());
|
||||
} finally {
|
||||
if (server != null) {
|
||||
server.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
# 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.
|
||||
# Prepare test library for standalone wasm runtime test.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import tvm
|
||||
from tvm import relax, te
|
||||
from tvm.script import relax as R
|
||||
|
||||
|
||||
def prepare_relax_lib(base_path):
|
||||
pipeline = relax.get_pipeline()
|
||||
|
||||
@tvm.script.ir_module
|
||||
class Mod:
|
||||
@R.function
|
||||
def main(x: R.Tensor(["n"], "float32"), y: R.Tensor(["n"], "float32")):
|
||||
lv0 = R.add(x, y)
|
||||
return lv0
|
||||
|
||||
target = tvm.target.Target("llvm")
|
||||
|
||||
mod = pipeline(Mod)
|
||||
ex = relax.build(mod, target)
|
||||
relax_path = os.path.join(base_path, "add_relax.so")
|
||||
ex.export_library(relax_path)
|
||||
|
||||
|
||||
def prepare_cpu_lib(base_path):
|
||||
target = "llvm"
|
||||
if not tvm.runtime.enabled(target):
|
||||
raise RuntimeError(f"Target {target} is not enbaled")
|
||||
n = te.var("n")
|
||||
A = te.placeholder((n,), name="A")
|
||||
B = te.placeholder((n,), name="B")
|
||||
C = te.compute(A.shape, lambda *i: A(*i) + B(*i), name="C")
|
||||
mod = tvm.IRModule.from_expr(te.create_prim_func([A, B, C]).with_attr("global_symbol", "myadd"))
|
||||
fadd = tvm.build(mod, target)
|
||||
lib_path = os.path.join(base_path, "add_cpu.so")
|
||||
fadd.export_library(lib_path)
|
||||
|
||||
|
||||
def prepare_gpu_lib(base_path):
|
||||
if not tvm.cuda().exist:
|
||||
print("CUDA is not enabled, skip the generation")
|
||||
return
|
||||
n = te.var("n")
|
||||
A = te.placeholder((n,), name="A")
|
||||
B = te.placeholder((n,), name="B")
|
||||
C = te.compute(A.shape, lambda *i: A(*i) + B(*i), name="C")
|
||||
mod = tvm.IRModule.from_expr(te.create_prim_func([A, B, C]).with_attr("global_symbol", "myadd"))
|
||||
sch = tvm.s_tir.Schedule(mod)
|
||||
sch.work_on("myadd")
|
||||
(i,) = sch.get_loops(block=sch.get_sblock("C"))
|
||||
i0, i1 = sch.split(i, [None, 32])
|
||||
sch.bind(i0, "blockIdx.x")
|
||||
sch.bind(i1, "threadIdx.x")
|
||||
fadd = tvm.build(sch.mod, "cuda")
|
||||
lib_path = os.path.join(base_path, "add_cuda.so")
|
||||
fadd.export_library(lib_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
base_path = sys.argv[1]
|
||||
prepare_cpu_lib(base_path)
|
||||
prepare_gpu_lib(base_path)
|
||||
prepare_relax_lib(base_path)
|
||||
@@ -0,0 +1,39 @@
|
||||
# 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.
|
||||
|
||||
from tvm.rpc import proxy
|
||||
|
||||
|
||||
def start_proxy_server(port, timeout):
|
||||
prox = proxy.Proxy("127.0.0.1", port=port, port_end=port + 1)
|
||||
if timeout > 0:
|
||||
import time
|
||||
|
||||
time.sleep(timeout)
|
||||
prox.terminate()
|
||||
else:
|
||||
prox.proc.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit(-1)
|
||||
port = int(sys.argv[1])
|
||||
timeout = 0 if len(sys.argv) == 2 else float(sys.argv[2])
|
||||
start_proxy_server(port, timeout)
|
||||
Reference in New Issue
Block a user