def consumePrintToFile(self, ctxt, numOutVar): # print results to file codeout = ctxt.codegen.finish outFile = Variable.val(ptr(CType.FILE), "outFile", codeout) emit(assign(outFile, fopen("queryresult.csv", "w")), codeout) for id, att in self.algExpr.outRelation.items(): emit(fprintf(outFile, att.name + ", "), codeout) emit(fprintf(outFile, "\\n", []), codeout) loopVar = Variable.val(CType.INT, "pv") with ForLoop(assign(declare(loopVar), intConst(0)), smaller(loopVar, numOutVar), assignAdd(loopVar, intConst(1)), codeout): for id, att in self.algExpr.outRelation.items(): ovar = ctxt.attFile.ocolFile[id] if att.dataType == Type.STRING: offs = ovar.arrayAccess(loopVar) charCol = ctxt.attFile.incolFile[att.id][1] emit(call("stringPrint", [charCol, offs, outFile]), codeout) else: emit( fprintf(outFile, CType.printFormat[ovar.dataType] + " ", [ovar.arrayAccess(loopVar)]), codeout) emit(fprintf(outFile, "\\n", []), codeout)
def htInsertFilter(self, ctxt): with IfClause(ctxt.vars.activeVar, ctxt.codegen): # compute a non-unique hash over join attributes hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen) Hash.attributes(self.algExpr.buildKeyAttributes, hashVar, ctxt) # find bucket bucketVar = Variable.val(CType.INT, "bucket", ctxt.codegen, intConst(0)) payl = self.payload.materialize("payl" + str(self.algExpr.opId), ctxt.codegen, ctxt) bucketFound = Variable.val(CType.INT, "bucketFound", ctxt.codegen, intConst(0)) numLookups = Variable.val(CType.INT, "numLookups", ctxt.codegen, intConst(0)) with WhileLoop(notLogic(bucketFound), ctxt.codegen) as loop: # allocate empty bucket or get tid from bucket emit( assign( bucketVar, call(qlib.Fct.HASH_AGG_BUCKET, [ self.htmem.ht, self.htmem.numEntries, hashVar, numLookups, addressof(payl) ])), ctxt.codegen) # verify grouping attributes from bucket probepayl = Variable.val( self.payload.getType(), "probepayl", ctxt.codegen, member(self.htmem.ht.arrayAccess(bucketVar), "payload")) self.payload.checkEquality(bucketFound, payl, probepayl, ctxt)
def columns(self, a, identifier, size, charSize=0): if (a.dataType == Type.STRING): var1 = Variable(CType.STR_OFFS, identifier + "_offset", size) var2 = Variable(CType.CHAR, identifier + "_char", charSize) return [var1, var2] else: return Variable(self.codegen.langType(a.dataType), identifier, size)
def inputColumns(self, a, identifier, size, charSize=0): if (a.dataType == Type.STRING): var1 = Variable(CType.SIZE, identifier + "_offset", add(size, intConst(1))) var2 = Variable(CType.CHAR, identifier + "_char", charSize) return [var1, var2] else: return Variable(self.codegen.langType(a.dataType), identifier, size)
def __init__(self, tid, scanType, isTempScan, table, scanRelation, algExpr, ctxt): vars = ctxt.vars self.scanType = scanType codegen = ctxt.codegen self.ctxt = ctxt if scanType == scanType.KERNEL: scanKernel = ctxt.codegen.openKernel( Kernel(ident.scanKernel(algExpr) + str(algExpr.opId))) tid.declareAssign(intConst(0), ctxt.codegen) vars.loopVar = Variable.val(CType.UINT, "loopVar") vars.loopVar.declareAssign( add(mul(blockIdx_x(), blockDim_x()), threadIdx_x()), codegen) vars.stepVar = Variable.val(CType.UINT, "step") vars.stepVar.declareAssign(mul(blockDim_x(), gridDim_x()), codegen) vars.flushVar = Variable.val(CType.UINT, "flushPipeline", codegen, intConst(0)) vars.activeVar = Variable.val(CType.INT, "active", codegen, intConst(0)) commentOperator("scan", ctxt.codegen) self.kernelLoop = WhileLoop(notLogic(vars.flushVar), codegen) emit(assign(vars.scanTid, vars.loopVar), codegen) emit(assign(vars.activeVar, smaller(vars.loopVar, table["size"])), codegen) comment("flush pipeline if no new elements", codegen) emit( assign( vars.flushVar, notLogic(ballotIntr(qlib.Const.ALL_LANES, vars.activeVar))), codegen) # inner scan loop elif scanType == scanType.INNER: self.outerActive = Variable.val(CType.INT, "outerActive" + str(algExpr.opId)) self.outerActive.declareAssign(ctxt.vars.activeVar, ctxt.codegen) self.innerLoop = ForLoop(assign(declare(tid), intConst(0)), smaller(tid, table["size"]), increment(tid), ctxt.codegen) emit(assign(ctxt.vars.activeVar, self.outerActive), ctxt.codegen) # map data columns for (id, a) in scanRelation.items(): if not isTempScan: ctxt.attFile.mapInputAttribute(a, table) else: ctxt.attFile.mapTemptableInputAttribute(a, table) # dematerialize with IfClause(ctxt.vars.activeVar, ctxt.codegen): for id, a in scanRelation.items(): ctxt.attFile.dematerializeAttribute(a, tid)
def produce(self, ctxt): algExpr = self.algExpr ctxt.vars.scanTid = Variable.tidLit(algExpr.table, algExpr.scanTableId) with ScanLoop(ctxt.vars.scanTid, ScanType.KERNEL, algExpr.isTempScan, self.algExpr.table, algExpr.outRelation, algExpr, ctxt): if self.algExpr.isTempScan: numOutVar = Variable.val(CType.INT, "nout_" + algExpr.table["name"]) ctxt.codegen.currentKernel.addVar(numOutVar) # call parent operator self.parent.consume(ctxt)
def consume(self, ctxt): ctxt.codegen.currentKernel.annotate("P" + str(self.algExpr.opId)) counters = list() emit(printf("<p" + str(self.algExpr.opId) + ">\\n"), ctxt.codegen.finish) for i in range(0, 33): counters.append( ctxt.codegen.newStatisticsCounter( "its" + str(i) + "active_" + "p" + str(self.algExpr.opId), str(i) + ", ")) emit(printf("</p" + str(self.algExpr.opId) + ">\\n\\n"), ctxt.codegen.finish) numActiveProfile = Variable.val( CType.INT, "numActiveProfile" + "_p" + str(self.algExpr.opId), ctxt.codegen) emit( assign( numActiveProfile, popcount(ballotIntr(qlib.Const.ALL_LANES, ctxt.vars.activeVar))), ctxt.codegen) with IfClause(equals(ctxt.codegen.warplane(), intConst(0)), ctxt.codegen): for i in range(0, 33): with IfClause(equals(numActiveProfile, intConst(i)), ctxt.codegen): emit(atomicAdd(counters[i], intConst(1)), ctxt.codegen) self.parent.consume(ctxt)
def consumePrintResultSample(self, ctxt, numOutVar): # print sample of results codegen = ctxt.codegen codeout = codegen.finish loopVar = Variable.val(CType.INT, "pv") printLimit = intConst(10) with ForLoop( assign(declare(loopVar), intConst(0)), andLogic(smaller(loopVar, printLimit), smaller(loopVar, numOutVar)), assignAdd(loopVar, intConst(1)), codeout): for id, att in self.algExpr.outRelation.items(): emit(printf(att.name + ": "), codeout) ovar = ctxt.attFile.ocolFile[id] if att.dataType == Type.STRING: offs = ovar.arrayAccess(loopVar) charCol = ctxt.attFile.incolFile[att.id][1] emit(call("stringPrint", [charCol, offs]), codeout) else: emit( printf(CType.printFormat[ovar.dataType], [ovar.arrayAccess(loopVar)]), codeout) emit(printf(" "), codeout) emit(printf("\\n", []), codeout) with IfClause(larger(numOutVar, printLimit), codeout): emit(printf("[...]\\n"), codeout) emit(printf("\\n"), codeout)
def bufDeclareSmem(self, bufferVars): ctxt = self.ctxt codegen = ctxt.codegen self.buf_ix = Variable.val(CType.INT, "bufIdx") self.buf_ix.declare(ctxt.codegen) comment("shared memory variables for divergence buffers", codegen.init()) # initialize shared memory buffers and store in dict by variable name self.buffers = dict() for v in self.bufferVars: buf = Variable.val(v.dataType, ident.divergenceBuffer(v)) buf.declareSharedArray(intConst(KernelCall.defaultBlockSize), ctxt.codegen.init()) self.buffers[v.get()] = buf
def consume(self, ctxt): self.consumeCall += 1 if (self.consumeCall % 2 == 1): commentOperator("nested join: materialize inner ", ctxt.codegen) self.tableName = "inner" + str(self.algExpr.opId) self.denseWrite = DenseWrite(self.algExpr.leftChild.outRelation, self.tableName, MaterializationType.TEMPTABLE, self.algExpr.leftChild.tupleNum, ctxt) elif (self.consumeCall % 2 == 0): commentOperator("nested join: loop inner ", ctxt.codegen) ctxt.codegen.currentKernel.addVar(self.denseWrite.numOut) self.innerTid = Variable.tidLit(self.denseWrite.getTable(), 0) ctxt.innerLoopCount += 1 with ScanLoop(self.innerTid, ScanType.INNER, True, self.denseWrite.getTable(), self.algExpr.leftChild.outRelation, self.algExpr, ctxt): with IfClause(ctxt.vars.activeVar, ctxt.codegen): emit( assign(ctxt.vars.activeVar, self.algExpr.condition.translate(ctxt)), ctxt.codegen) # call parent operator self.parent.consume(ctxt) ctxt.innerLoopCount -= 1
def __init__(self, relation, tableName, matType, sizeEstimate, ctxt): vars = ctxt.vars codegen = ctxt.codegen self.relation = relation self.tableName = tableName self.numOut = Variable.val(CType.INT, "nout_" + tableName, codegen.declare) codegen.gpumem.mapForWrite(self.numOut) codegen.gpumem.initVar(self.numOut, intConst(0)) codegen.currentKernel.addVar(self.numOut) wp = Variable.val(CType.INT, "wp", codegen) self.useWarpScan = True if not self.useWarpScan: with IfClause(ctxt.activeVar, codegen): emit(assign(wp, atomicAdd(self.numOut, intConst(1))), codegen) codegen.add(codewrite) else: mask = Variable.val(CType.INT, "writeMask", codegen) numactive = Variable.val(CType.INT, "numProj", codegen) emit( assign( mask, ballotIntr(qlib.Const.ALL_LANES, intConst(vars.activeVar))), codegen) emit(assign(numactive, popcount(mask)), codegen) with IfClause(equals(codegen.warplane(), intConst(0)), codegen): emit(assign(wp, atomicAdd(self.numOut, numactive)), codegen) emit( assign(wp, shuffleIntr(qlib.Const.ALL_LANES, wp, intConst(0))), codegen) emit( assign( wp, add(wp, popcount(andBitwise(mask, codegen.prefixlanes())))), codegen) with IfClause(vars.activeVar, codegen): for id, att in relation.items(): if matType == MaterializationType.RESULT: ctxt.attFile.mapOutputAttribute(att, sizeEstimate) elif matType == MaterializationType.TEMPTABLE: ctxt.attFile.mapTemptableOutputAttribute( att, self.getTable(), sizeEstimate) ctxt.attFile.materializeAttribute(att, wp, matType)
def newStatisticsCounter(self, varname, text): counter = Variable.val(CType.UINT, varname) counter.declareAssign(intConst(0), self.declare) self.gpumem.mapForWrite(counter) self.gpumem.initVar(counter, "0u") self.currentKernel.addVar(counter) emit(printf(text + "%i\\n", [counter]), self.finish) return counter
def mapTemptableOutputAttribute(self, a, table, sizeEstimate): tempIdent = "itm_" + table["name"] + "_" + a.name itmCol = self.columns(a, tempIdent, sizeEstimate) if a.dataType == Type.STRING: itmCol = Variable(CType.STR_TYPE, tempIdent, sizeEstimate) self.codegen.gpumem.declareAllocate(itmCol) self.codegen.currentKernel.addVar(itmCol) self.itmFile[a.id] = itmCol
def stringConstant(self, token): self.constCounter += 1 c = Variable.val(CType.STR_TYPE, "c" + str(self.constCounter)) emit( assign(declare(c), call("stringConstant", ["\"" + token + "\"", len(token)])), self.init()) return c
def consumeHashTable(self, ctxt): htmem = self.htmem ctxt.vars.scanTid = Variable.tidLit(htmem.getTable(self.algExpr.opId), self.algExpr.opId) self.algExpr.table = htmem.getTable(self.algExpr.opId) self.algExpr.scanTableId = 1 with ScanLoop(ctxt.vars.scanTid, ScanType.KERNEL, False, htmem.getTable(self.algExpr.opId), dict(), self.algExpr, ctxt): commentOperator("scan aggregation ht", self.algExpr.opId, ctxt.codegen) htmem.addToKernel(ctxt.codegen.currentKernel) if self.algExpr.doGroup: with IfClause(ctxt.vars.activeVar, ctxt.codegen): emit( assignAnd( ctxt.vars.activeVar, equals( member(htmem.ht.arrayAccess(ctxt.vars.scanTid), "lock.lock"), "OnceLock::LOCK_DONE")), ctxt.codegen) with IfClause(ctxt.vars.activeVar, ctxt.codegen): payl = Variable.val(self.payload.getType(), "payl") payl.declareAssign( member(htmem.ht.arrayAccess(ctxt.vars.scanTid), "payload"), ctxt.codegen) self.payload.dematerialize(payl, ctxt) with IfClause(ctxt.vars.activeVar, ctxt.codegen): htmem.dematerializeAggregationAttributes( ctxt.vars.scanTid, ctxt) for (id, att) in self.algExpr.avgAggregates.items(): count = self.algExpr.countAttr type = ctxt.codegen.langType(att.dataType) emit( assign( ctxt.attFile.access(att), div(ctxt.attFile.access(att), cast(type, ctxt.attFile.access(count)))), ctxt.codegen) # call parent operator self.parent.consume(ctxt)
def warpid(self): try: return self.currentKernel.warpid except AttributeError: self.currentKernel.warpid = Variable.val(CType.UINT, "warpid") emit( assign(declare(self.currentKernel.warpid), div(threadIdx_x(), intConst(32))), self.init()) return self.currentKernel.warpid
def warplane(self): try: return self.currentKernel.warplane except AttributeError: self.currentKernel.warplane = Variable.val(CType.UINT, "warplane") emit( assign(declare(self.currentKernel.warplane), modulo(threadIdx_x(), intConst(32))), self.init()) return self.currentKernel.warplane
def close(self): ctxt = self.ctxt endVar = Variable.val(CType.INT, "matchEnd") offsetVar = Variable.val(CType.INT, "matchOffset") matchStepVar = Variable.val(CType.INT, "matchStep") emit( assign( self.mask, ballotIntr(qlib.Const.ALL_LANES, intConst(ctxt.vars.activeVar))), ctxt.codegen) emit(assign(self.numactive, popcount(self.mask)), ctxt.codegen) # closes main buffer loop self.whileLoop.close() # write remaining active tuples to buffer self.bufferHelper.consumeFlushToBuffer(self.numactive, self.mask)
def open(self): ctxt = self.ctxt commentOperator("divergence buffer", self.opId, ctxt.codegen) comment( "ensures that the thread activity in each warp (32 threads) lies above a given threshold", ctxt.codegen) comment( "depending on the buffer count inactive lanes are either refilled or flushed to the buffer", ctxt.codegen) self.mask = Variable.val(CType.INT, "activemask" + str(self.opId) + "_") self.numactive = Variable.val(CType.INT, "numactive" + str(self.opId) + "_") self.bailout = Variable.val(CType.INT, "minTuplesInFlight" + str(self.opId) + "_") self.mask.declareAssign( ballotIntr(qlib.Const.ALL_LANES, ctxt.vars.activeVar), ctxt.codegen) self.numactive.declareAssign(popcount(self.mask), ctxt.codegen) # declare buffer variables ( shuffle registers or shared memory ) self.bufferHelper.consumeDeclareBuffer(self.bufferVars) emit( assign( declare(self.bailout), inlineIf(ctxt.vars.flushVar, intConst(0), intConst(self.threshold))), ctxt.codegen) # starts main buffer loop self.whileLoop = WhileLoop( larger(add(ctxt.vars.buffercount, self.numactive), self.bailout), ctxt.codegen) # refill active lanes if activity below threshold self.bufferHelper.consumeRefillFromBuffer(self.numactive, self.mask, self.threshold) return self
def htProbeMultiMatchSemiAnti(self, ctxt): self.endVar = Variable.val(CType.INT, "matchEnd" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) self.offsetVar = Variable.val(CType.INT, "matchOffset" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) self.matchStepVar = Variable.val(CType.INT, "matchStep" + str(self.algExpr.opId), ctxt.codegen, intConst(1)) filterMatch = Variable.val(CType.INT, "filterMatch" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) probeActive = Variable.val(CType.INT, "probeActive" + str(self.algExpr.opId), ctxt.codegen, ctxt.vars.activeVar) hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) with IfClause(probeActive, ctxt.codegen): Hash.attributes(self.algExpr.probeKeyAttributes, hashVar, ctxt) emit( assign( probeActive, call(qlib.Fct.HASH_PROBE_MULTI, [ self.htmem.ht, self.htmem.numEntries, hashVar, self.offsetVar, self.endVar ])), ctxt.codegen) with WhileLoop(probeActive, ctxt.codegen): payl = Variable.val(self.htmem.payload.dataType, "payl", ctxt.codegen) emit(assign(payl, self.htmem.payload.arrayAccess(self.offsetVar)), ctxt.codegen) self.payload.dematerialize(payl, ctxt) emit(assign(filterMatch, intConst(1)), ctxt.codegen) Hash.checkEquality(filterMatch, self.algExpr.buildKeyAttributes, self.algExpr.probeKeyAttributes, ctxt) if self.algExpr.conditions is not None: emit( assignAnd(filterMatch, self.algExpr.conditions.translate(ctxt)), ctxt.codegen) emit(assignAdd(self.offsetVar, self.matchStepVar), ctxt.codegen) emit(assignAnd(probeActive, notLogic(filterMatch)), ctxt.codegen) emit(assignAnd(probeActive, smaller(self.offsetVar, self.endVar)), ctxt.codegen) if self.algExpr.joinType == Join.SEMI: emit(assignAnd(ctxt.vars.activeVar, filterMatch), ctxt.codegen) if self.algExpr.joinType == Join.ANTI: emit(assignAnd(ctxt.vars.activeVar, notLogic(filterMatch)), ctxt.codegen) self.parent.consume(ctxt)
def consumeDeclareBuffer(self, bufferVars): ctxt = self.ctxt codegen = ctxt.codegen self.bufferbase = Variable.val(CType.INT, "bufferBase") emit( assign(declare(self.bufferbase), mul(codegen.warpid(), intConst(32))), ctxt.codegen.init()) self.scan = Variable.val(CType.INT, "scan") self.scan.declare(codegen) self.numRemaining = Variable.val(CType.INT, "remaining") self.numRemaining.declare(ctxt.codegen) # remember variables that need to be buffered at this pipeline stage self.bufferVars = bufferVars.copy() if self.buftype is BufferType.SMEM: self.bufDeclareSmem(bufferVars) if self.buftype is BufferType.REG: self.bufDeclareReg(bufferVars)
def bufDeclareReg(self, bufferVars): ctxt = self.ctxt comment("register variables for divergence buffers", ctxt.codegen) self.shuffleSourceLane = Variable.val(CType.INT, "shuffleSourceLane") self.shuffleSourceLane.declareSharedArray( intConst(KernelCall.defaultBlockSize), ctxt.codegen.init()) self.sourceLane = Variable.val(CType.INT, "sourceLane" + str(self.opId) + "_") self.sourceLane.declare(ctxt.codegen.init()) self.activeDest = Variable.val(CType.INT, "activeDest" + str(self.opId) + "_") self.activeDest.declare(ctxt.codegen.init()) self.activeSource = Variable.val(CType.INT, "activeSource" + str(self.opId) + "_") self.activeSource.declare(ctxt.codegen.init()) self.buffers = dict() self.shuffleBuffers = dict() for v in self.bufferVars: buf = Variable.val(v.dataType, ident.registerBuffer(v)) sbuf = Variable.val(v.dataType, ident.registerShuffleBuffer(v)) buf.declare(ctxt.codegen.init()) sbuf.declare(ctxt.codegen.init()) self.buffers[v.get()] = buf self.shuffleBuffers[v.get()] = sbuf
def htInsertMultiMatch(self, ctxt): # execute only when current thread has active elements with IfClause(ctxt.vars.activeVar, ctxt.codegen): # compute a (possibly) non-unique hash over all join attributes hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) with IfClause(ctxt.vars.activeVar, ctxt.codegen): Hash.attributes(self.algExpr.buildKeyAttributes, hashVar, ctxt) htRangeOffset = Variable.val(CType.INT, "offs" + str(self.algExpr.opId)) ctxt.codegen.gpumem.local(htRangeOffset, intConst(0)) scanCall = KernelCall.library("scanMultiHT", [ self.htmem.ht.getGPU(), self.htmem.numEntries, htRangeOffset.getGPU() ]) ctxt.codegen.kernelCalls.append(scanCall) ctxt.codegen.openMirrorKernel("_ins") emit( call(qlib.Fct.HASH_COUNT_MULTI, [self.htmem.ht, self.htmem.numEntries, hashVar]), ctxt.codegen.currentKernel) ctxt.codegen.mirrorKernel.addVar(htRangeOffset) payl = self.payload.materialize("payl", ctxt.codegen.mirrorKernel, ctxt) emit( call(qlib.Fct.HASH_INSERT_MULTI, [ self.htmem.ht, self.htmem.payload, htRangeOffset, self.htmem.numEntries, hashVar, addressof(payl) ]), ctxt.codegen.mirrorKernel)
def prefixlanes(self): try: return self.currentKernel.prefixlanes except AttributeError: self.currentKernel.prefixlanes = Variable.val( CType.UINT, "prefixlanes") emit( assign( declare(self.currentKernel.prefixlanes), shiftRight(bitmask32f(), sub(intConst(32), self.warplane()))), self.init()) return self.currentKernel.prefixlanes
def __init__(self, ctxt, bufferVars, threshold=0.8): self.ctxt = ctxt self.threshold = int(32 * threshold) self.hasBalancingCode = False self.bufferVars = bufferVars buffercount = Variable.val(CType.INT, "buffercount") buffercount.declareAssign(intConst(0), ctxt.codegen.init()) ctxt.vars.buffercount = buffercount self.bufferHelper = BufferHelperSharedMemory(ctxt, BufferType.SMEM) self.open()
def translate ( self, ctxt ): code = Code() var = Variable.val ( ctxt.codegen.langType ( self.type ), "casevar" + str(self.exprId) ) var.declare ( ctxt.codegen ) #declare variable w0,t0 = self.exprListWhenThen[0] with lang.IfClause ( w0.translate ( ctxt ), ctxt.codegen ): lang.emit ( lang.assign ( var, t0.translate ( ctxt ) ), ctxt.codegen ) for w,t in self.exprListWhenThen[1:]: with lang.ElseIfClause ( w.translate ( ctxt ), ctxt.codegen ): lang.emit ( lang.assign ( var, t.translate ( ctxt ) ), ctxt.codegen ) if self.exprElse != None: with lang.ElseClause ( ctxt.codegen ): lang.emit ( lang.assign ( var, self.exprElse.translate ( ctxt ) ), ctxt.codegen ) return var.get()
def htProbeFilter(self, ctxt): with IfClause(ctxt.vars.activeVar, ctxt.codegen): hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) Hash.attributes(self.algExpr.probeKeyAttributes, hashVar, ctxt) numLookups = Variable.val(CType.INT, "numLookups" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) location = Variable.val(CType.INT, "location" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) filterMatch = Variable.val(CType.INT, "filterMatch" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) probeCall = call(qlib.Fct.HASH_AGG_CHECK, [ self.htmem.ht, self.htmem.numEntries, hashVar, numLookups, location ]) activeProbe = Variable.val(CType.INT, "activeProbe" + str(self.algExpr.opId), ctxt.codegen, intConst(1)) with WhileLoop(andLogic(notLogic(filterMatch), activeProbe), ctxt.codegen) as loop: emit(assign(activeProbe, probeCall), ctxt.codegen) # verify grouping attributes from bucket with IfClause(activeProbe, ctxt.codegen): probepayl = Variable.val( self.payload.getType(), "probepayl", ctxt.codegen, member(self.htmem.ht.arrayAccess(location), "payload")) self.payload.dematerialize(probepayl, ctxt) emit(assign(filterMatch, intConst(1)), ctxt.codegen) Hash.checkEquality(filterMatch, self.algExpr.buildKeyAttributes, self.algExpr.probeKeyAttributes, ctxt) if self.algExpr.conditions is not None: emit( assignAnd(filterMatch, self.algExpr.conditions.translate(ctxt)), ctxt.codegen) if self.algExpr.joinType == Join.SEMI: emit(assignAnd(ctxt.vars.activeVar, filterMatch), ctxt.codegen) if self.algExpr.joinType == Join.ANTI: emit(assignAnd(ctxt.vars.activeVar, notLogic(filterMatch)), ctxt.codegen) self.parent.consume(ctxt)
def htInsertSingleMatch(self, ctxt): # execute only when current thread has active elements with IfClause(ctxt.vars.activeVar, ctxt.codegen): # prepare payload payl = self.payload.materialize("payl" + str(self.algExpr.opId), ctxt.codegen, ctxt) # compute a non-unique hash over join attributes hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen) Hash.attributes(self.algExpr.buildKeyAttributes, hashVar, ctxt) # do hash insert call emit( call(qlib.Fct.HASH_BUILD_UNIQUE, [ self.htmem.ht, self.htmem.numEntries, hashVar, addressof(payl) ]), ctxt.codegen)
def variable(self, a, identifier, size=0): return Variable(self.codegen.langType(a.dataType), identifier, size)
def consume(self, ctxt): commentOperator("aggregation", ctxt.codegen) # create aggregation hash table with grouping payload if self.algExpr.doGroup: self.payload = Payload("apayl" + str(self.algExpr.opId), self.algExpr.groupAttributes, ctxt) htmem = HashTableMemory.createAgg("aht" + str(self.algExpr.opId), self.algExpr.tupleNum * 2.0, self.payload, ctxt.codegen) else: htmem = HashTableMemory(1, ctxt.codegen) # create and initialize aggregation buckets htmem.addAggregationAttributes(self.algExpr.aggregateAttributes, self.algExpr.aggregateTuples, ctxt) htmem.addToKernel(ctxt.codegen.currentKernel) # find bucket bucketVar = Variable.val(CType.INT, "bucket", ctxt.codegen, intConst(0)) if self.algExpr.doGroup: with IfClause(ctxt.vars.activeVar, ctxt.codegen): #payload hashVar = Variable.val(CType.UINT64, "hash" + str(self.algExpr.opId), ctxt.codegen, intConst(0)) Hash.attributes(self.algExpr.groupAttributes, hashVar, ctxt) payl = self.payload.materialize("payl", ctxt.codegen, ctxt) bucketFound = Variable.val(CType.INT, "bucketFound", ctxt.codegen, intConst(0)) numLookups = Variable.val(CType.INT, "numLookups", ctxt.codegen, intConst(0)) with WhileLoop(notLogic(bucketFound), ctxt.codegen) as loop: # allocate empty bucket or get tid from bucket emit( assign( bucketVar, call(qlib.Fct.HASH_AGG_BUCKET, [ htmem.ht, htmem.numEntries, hashVar, numLookups, addressof(payl) ])), ctxt.codegen) # verify grouping attributes from bucket probepayl = Variable.val( self.payload.getType(), "probepayl", ctxt.codegen, member(htmem.ht.arrayAccess(bucketVar), "payload")) self.payload.checkEquality(bucketFound, payl, probepayl, ctxt) # atomic summation of aggregates with IfClause(ctxt.vars.activeVar, ctxt.codegen): for id, (inId, reduction) in self.algExpr.aggregateTuples.items(): typ = ctxt.codegen.langType( self.algExpr.aggregateAttributes[id].dataType) agg = addressof(htmem.accessAggregationAttribute( id, bucketVar)) # count if reduction == Reduction.COUNT: sys.stdout.flush() atomAdd = atomicAdd(agg, cast(typ, intConst(1))) if inId in ctxt.attFile.isNullFile: with IfClause(notLogic(ctxt.attFile.isNullFile[inId]), ctxt.codegen): emit(atomAdd, ctxt.codegen) else: emit(atomAdd, ctxt.codegen) continue val = cast( typ, ctxt.attFile.access( self.algExpr.aggregateInAttributes[inId])) # min if reduction == Reduction.MIN: emit(atomicMin(agg, val), ctxt.codegen) # max elif reduction == Reduction.MAX: emit(atomicMax(agg, val), ctxt.codegen) # sum elif reduction == Reduction.SUM: emit(atomicAdd(agg, val), ctxt.codegen) # avg elif reduction == Reduction.AVG: emit(atomicAdd(agg, val), ctxt.codegen) self.htmem = htmem