You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2019/12/12 07:40:46 UTC

[GitHub] [incubator-tvm] BenjaminTu commented on a change in pull request #4500: [VTA][Python] Instruction Level Metal Test Infrastructure

BenjaminTu commented on a change in pull request #4500: [VTA][Python] Instruction Level Metal Test Infrastructure
URL: https://github.com/apache/incubator-tvm/pull/4500#discussion_r356995278
 
 

 ##########
 File path: vta/tests/hardware/metal_test/device.py
 ##########
 @@ -0,0 +1,278 @@
+# 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 ctypes import *
+from _macros_h import *
+from insn_lib import *
+import numpy as np
+
+# dictionary that maps actions to their corresponding value
+ACTIONS = {"1DLOAD":VTA_OPCODE_LOAD, "2DLOAD":VTA_OPCODE_LOAD, "ALU":None, "GEMM":None, 
+ "1DSTORE":VTA_OPCODE_STORE, "2DSTORE":VTA_OPCODE_STORE, "FINISH":None}
+# dictionary that maps items to their corresponding ID
+ITEMS = {"UOP":VTA_MEM_ID_UOP, "INP":VTA_MEM_ID_INP, "WGT":VTA_MEM_ID_WGT, "ACC":VTA_MEM_ID_ACC, "OUT":VTA_MEM_ID_OUT,
+# alu opcodes to their corresponding value
+"MIN":VTA_ALU_OPCODE_MIN, "MAX":VTA_ALU_OPCODE_MAX, "ADD":VTA_ALU_OPCODE_ADD, "SHR":VTA_ALU_OPCODE_SHR, "EMPTY":None}
+
+class InsnStream:
+
+	def __init__(self):
+		self.insn_buf = []
+	
+	"""
+	Add a instruction to the instruction stream
+		Args:
+		action: Instruction type (ignores case)
+		item: Item or ALU opcode for ALU actions (ignores case)
+		others: micro-ops for different instructions
+
+		Raises:	
+		ValueError: If action or item is invalid
+	"""
+	def add(self, action, item="EMPTY", sram=0, dram=0, use_imm=False, imm_val=0, 
+	 y_size=1, x_size=0, x_stride=0, x_pad=0, y_pad=0, vec_len=0):
+		if (action.upper() not in ACTIONS) or (item.upper() not in ITEMS):
+			raise ValueError("Invalid opcode/item")
+		self.insn_buf.append((action.upper(), item.upper(), sram, dram, use_imm, imm_val, y_size, x_size, x_stride, x_pad, y_pad, vec_len))
+	
+	"""Clear the stream"""
+	def clear(self):
+		self.insn_buf = []
+
+class Device:
+
+	def __init__(self, batch, in_channels, out_channels, insn_stream, uop_compression=True):
+
+		self.insn_stream = insn_stream
+		# set up dimensions
+		self.batch, self.in_channels, self.out_channels = batch, in_channels, out_channels
+		
+		# set up flags
+		self.uop_compression = uop_compression
+
+		# gemm size
+		self.ins_size = len(insn_stream.insn_buf)
+		self.inp_size = (int)(batch / VTA_BATCH * in_channels / VTA_BLOCK_IN)
+		self.wgt_size = (int) (in_channels / VTA_BLOCK_IN * out_channels / VTA_BLOCK_OUT)
+		self.out_size = (int) (batch / VTA_BATCH * out_channels / VTA_BLOCK_OUT)
+
+		# get every computing stage and set uop_size buffer accordingly
+		self.uop_size_buf = []
+		self.action_buf = []
+		for i in range(self.ins_size):
+			insn = self.insn_stream.insn_buf[i]
+			if insn[0] == "GEMM" or insn[0] == "ALU":
+				if insn[0] == "GEMM":
+					uop_size = (int) (batch / VTA_BATCH) if uop_compression else \
+				(int) (batch / VTA_BATCH * in_channels / VTA_BLOCK_IN * out_channels / VTA_BLOCK_OUT)
+				elif insn[0] == "ALU":
+					uop_size = 1 if uop_compression else out_channels // VTA_BLOCK_OUT
+				self.uop_size_buf.append(uop_size)
+				self.action_buf.append(insn[0])
+		
+		# assert dimensions is divisible
+		assert batch % VTA_BATCH == 0
+		assert in_channels % VTA_BLOCK_IN == 0
+		assert out_channels % VTA_BLOCK_OUT == 0
+
+		# generate instructions
+		self.__generate_insn()
+
+		# uop setup
+		self.__uop_setup()
+
+	"""print the instructions for this device"""
+	def print_insn(self):
+		print_instruction(self.ins_size, self.insn_buf)
+	"""print the micro-ops for this device"""
+	def print_uop(self):
+		print_uop(np.sum(self.uop_size_buf), self.uop_buf)
+	"""print the parameters for this device"""
+	def print_params(self):
+		print_params()
+
+	def __generate_insn(self):
+		# previous state, present state and next state
+		prevs, ps, ns = "load", "load", "load"
+		self.insn_buf = (VTAGenericInsn * self.ins_size)()
+		index, cmp_ind = 0, 0
+		assert "LOAD" in self.insn_stream.insn_buf[0][0], "Instruction shold start with Load instruction"
+		SIZE = {"INP":self.inp_size, "WGT":self.wgt_size, "ACC":self.out_size, "OUT":self.out_size}
+
+		# generate instructions
+		for i in range(self.ins_size):
+			# check for order
+			if (i + 1) < self.ins_size: 
+				n_action, n_item = self.insn_stream.insn_buf[i+1][0], self.insn_stream.insn_buf[i+1][1]
+				# check for order
+				if "LOAD" in n_action:
+					ns = "load"
+				elif n_action == "GEMM" or n_action == "ALU":
+					ns = "compute"
+				elif "STORE" in n_action:
+					ns = "store"
+				elif n_action == "FINISH":
+					ns = "finish"
+
+				assert not(ps == "load" and ns == "store"), "Instruction Wrong order!"
+				assert not(ps == "compute" and ns == "load"), "Instruction Wrong order!"
+				assert not(ps == "store" and ns == "compute"), "Instruction Wrong order!"
+
+			# generate instructions for GEMM 
+			action, item, sram, dram, use_imm, imm_val, y_size, x_size, \
+			 x_stride, x_pad, y_pad, vec_len = self.insn_stream.insn_buf[i]
+			# size
+			size = SIZE.get(item) if (item != "UOP") else self.uop_size_buf[cmp_ind]
+
+			# dependencies
+			pop_next = 1 if (prevs == "store" and ps == "load") else 0
+			push_next = 1 if (ps == "load" and ns == "compute") else 0
+
+			# make sure dependancies, ACC don't need push_next dependencies
+			if action == "1DLOAD":
+				self.insn_buf[index] = get_1Dloadstore_insn(ACTIONS.get(action), ITEMS.get(item), sram, dram, size, 
+				 0, pop_next, 0, push_next)
+
+			elif action == "2DLOAD":
+				self.insn_buf[index] = get_2Dloadstore_insn(ACTIONS.get(action), ITEMS.get(item), sram, dram, 
+				 y_size, x_size, x_stride, y_pad, x_pad, 0, pop_next, 0, 0)
+
+			elif action == "GEMM":
+				self.insn_buf[index] = get_gemm_insn(0, (int) (self.batch / VTA_BATCH), (int) (self.in_channels / VTA_BLOCK_IN),
+				 (int) (self.out_channels / VTA_BLOCK_OUT), self.uop_compression, 1, 0, 0, 1)
 
 Review comment:
   I'm not sure here, I'm assuming all the instructions should be in the order of load/compute store, therefore, the place where GEMM and ALU could be is pretty much set (dependencies are pretty much set?). I've checked the order of instructions before hand to see if the user instruction follows the correct pattern to prevent unwanted things to happen. 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services