10inline const std::string ProfileBasedSearcherName =
"ProfileBasedSearcher";
11inline const std::string ProfileBasedSearcherFile =
"ProfileBasedSearcher.py";
12inline const std::string ProfileBasedSearcherModule =
14"#!/usr/bin/env python -W ignore::DeprecationWarning\n" +
17"Searcher which explores configurations according to observed bottlenecks\n" +
18"and ML model created on historical data (on the same tuning space, but\n" +
19"possibly different HW and input size). For more information, see\n" +
20"J. Filipovic et al. Using hardware performance counters to speed up\n" +
21"autotuning convergence on GPUs. JPDC, vol. 160, 2021.\n" +
27"import numpy as np\n" +
33"import pyktt as ktt\n" +
35"np.printoptions(precision=5, suppress=True)\n" +
37"# verbosity level (0, 1, 2, 3)\n" +
43"# all constant used by the searcher\n" +
44"# CORR_SHIFT: value added to correlation (positive forces to search parameters with weak correlation but strong variation)\n" +
45"# EXP: exponent used to prioritize configurations with high score (probab = score ^ EXP, where score is in <0, 1> )\n" +
46"# REACT_TO_INST_BOTTLENECKS: minimal instructions bottlenecks, which affects scoring of tuning configurations\n" +
47"# CUTOFF: maximal score of configurations, which are discarded from tuning space\n" +
48"# BATCH: number of configuration from which the fastest one is profiled, set in KTT\n" +
49"# NEIGHBOR_SIZE: number of neighboring configurations that are used for batch selection, set in KTT\n" +
50"# RANDOM_SIZE: number of random configurations that are used for batch selection, set in KTT\n" +
51"# NEIGHBOR_DISTANCE: distance between configurations (how many TP have different values) that are still considered neighbors\n" +
54"REACT_TO_INST_BOTTLENECKS = 0.7\n" +
56"NEIGHBOR_DISTANCE = 2\n" +
58"########################### loading models functions ################################\n" +
60"def loadMLModel(trainedKnowledgeBase):\n" +
61" return pickle.load(open(trainedKnowledgeBase, 'rb'))\n" +
63"def loadMLModelMetadata(filename) :\n" +
65" with open(filename, 'r') as metadataFile:\n" +
66" metadata = json.load(metadataFile)\n" +
69"def loadCompleteMappingCounters(tuningSpace, rangeC) :\n" +
70" words = tuningSpace.readline().split(',')\n" +
72" #for i in range(tuningInt[1]+1, len(words)) :\n" +
73" for i in rangeC :\n" +
74" if i < len(words) :\n" +
75" counters.append(words[i].rstrip())\n" +
76" for j in range(i+1, len(words)) :\n" +
77" counters.append(words[j].rstrip())\n" +
82"def loadCompleteMapping(tuningSpace, rangeT, rangeC) :\n" +
83" tuningSpace.seek(0)\n" +
84" wordsHead = tuningSpace.readline().split(',')\n" +
85" #pcInt = [tuningInt[1]+1, len(wordsHead)-1]\n" +
87" for i in rangeC :\n" +
88" if i < len(wordsHead) :\n" +
89" myRange.append(i)\n" +
90" restPCs = list(range(rangeC[-1]+1, len(wordsHead)))\n" +
91" pcInt = myRange + restPCs\n" +
94" for line in tuningSpace.readlines() :\n" +
95" words = line.split(',')\n" +
96" if len(words) <= 1: break\n" +
99" #for i in range(tuningInt[0], tuningInt[1]+1) :\n" +
100" for i in rangeT :\n" +
101" tunRow.append(float(words[i]))\n" +
103" #for i in range(pcInt[0], pcInt[1]+1) :\n" +
104" # pcRow[wordsHead[i].rstrip()] = float(words[i])\n" +
106" #for i in range(pcInt[0], pcInt[1]+1) :\n" +
107" for i in pcInt :\n" +
108" pcRow.append(float(words[i]))\n" +
110" spaceRow = [tunRow, pcRow]\n" +
111" space.append(spaceRow)\n" +
116"####################### GPU arch. dependent functions ##########################\n" +
118"# analyzeBottlenecks\n" +
119"# analysis of bottlenecks, observes profiling counters and scores bottlenecks\n" +
120"# in interval <0, 1>\n" +
121"# GPU dependent, implemented for CUDA compute capabilities 3.0 - 7.5\n" +
123"def analyzeBottlenecks (countersNames, countersData, cc, multiprocessors, cores, verbose):\n" +
124" bottlenecks = {}\n" +
125" # analyze global memory\n" +
127" DRAMutil = countersData[countersNames.index(\"dram_utilization\")]\n" +
128" DRAMldTrans = countersData[countersNames.index(\"dram_read_transactions\")]\n" +
129" DRAMstTrans = countersData[countersNames.index(\"dram_write_transactions\")]\n" +
131" DRAMutil = countersData[countersNames.index(\"dram__throughput.avg.pct_of_peak_sustained_elapsed\")]/10.0\n" +
132" DRAMldTrans = countersData[countersNames.index(\"dram__sectors_read.sum\")]\n" +
133" DRAMstTrans = countersData[countersNames.index(\"dram__sectors_write.sum\")]\n" +
134" if DRAMldTrans + DRAMstTrans > 0 and DRAMutil > 0 :\n" +
135" bnDRAMRead = (DRAMldTrans / (DRAMldTrans + DRAMstTrans)) * (DRAMutil / 10.0)\n" +
136" bnDRAMWrite = (DRAMstTrans / (DRAMldTrans + DRAMstTrans)) * (DRAMutil / 10.0)\n" +
139" bnDRAMWrite = 0\n" +
140" bottlenecks['bnDRAMRead'] = bnDRAMRead\n" +
141" bottlenecks['bnDRAMWrite'] = bnDRAMWrite\n" +
143" # analyze cache system\n" +
145" L2util = countersData[countersNames.index(\"l2_utilization\")]\n" +
146" L2ldTrans = countersData[countersNames.index(\"l2_read_transactions\")]\n" +
147" L2stTrans = countersData[countersNames.index(\"l2_write_transactions\")]\n" +
148" texUtil = countersData[countersNames.index(\"tex_utilization\")]\n" +
149" #texFuUtil = countersData[countersNames.index(\"tex_fu_utilization\")]\n" +
150" texTrans = countersData[countersNames.index(\"tex_cache_transactions\")]\n" +
152" L2util = countersData[countersNames.index(\"lts__t_sectors.avg.pct_of_peak_sustained_elapsed\")]/10.0\n" +
153" L2ldTrans = countersData[countersNames.index(\"lts__t_sectors_op_read.sum\")]\n" +
154" L2stTrans = countersData[countersNames.index(\"lts__t_sectors_op_write.sum\")]\n" +
155" texUtil = countersData[countersNames.index(\"l1tex__t_requests_pipe_lsu_mem_global_op_ld.avg.pct_of_peak_sustained_active\")]/10.0\n" +
156" #texFuUtil = countersData[countersNames.index(\"tex_fu_utilization\")]\n" +
157" texTrans = countersData[countersNames.index(\"l1tex__t_requests_pipe_lsu_mem_global_op_ld.sum\")]\n" +
158" bnL2Read = (L2ldTrans / (L2ldTrans + L2stTrans)) * (L2util / 10.0)\n" +
159" bnL2Write = (L2stTrans / (L2ldTrans + L2stTrans)) * (L2util / 10.0)\n" +
160" #bnTex = max(texUtil / 10.0, texFuUtil / 10.0)\n" +
161" bnTex = texUtil / 10.0\n" +
162" bottlenecks['bnL2Read'] = bnL2Read\n" +
163" bottlenecks['bnL2Write'] = bnL2Write\n" +
164" bottlenecks['bnTex'] = bnTex\n" +
166" # analyze local (non-registers private in OpenCL) memory\n" +
168" locOverhead = countersData[countersNames.index(\"local_memory_overhead\")]\n" +
170" #XXX this is highly experimental computation\n" +
171" locOverhead = 100.0 * countersNames.index(\"l1tex__t_sectors_pipe_lsu_mem_local_op_st.sum\") / L2stTrans\n" +
172" bottlenecks['bnLocal'] = (locOverhead/100.0) * max(DRAMutil/10.0, L2util/10.0, texUtil/10.0)#, texFuUtil/10.0)\n" +
174" # analyze shared memory\n" +
177" SMutil = countersData[countersNames.index(\"shared_efficiency\")]\n" +
179" SMutil = countersData[countersNames.index(\"shared_utilization\")]\n" +
180" SMldTrans = countersData[countersNames.index(\"shared_load_transactions\")]\n" +
181" SMstTrans = countersData[countersNames.index(\"shared_store_transactions\")]\n" +
183" SMutil = countersData[countersNames.index(\"l1tex__data_pipe_lsu_wavefronts_mem_shared.avg.pct_of_peak_sustained_elapsed\")]/10.0\n" +
184" SMldTrans = countersData[countersNames.index(\"l1tex__data_pipe_lsu_wavefronts_mem_shared_op_ld.sum\")]\n" +
185" SMstTrans = countersData[countersNames.index(\"l1tex__data_pipe_lsu_wavefronts_mem_shared_op_st.sum\")]\n" +
187" if (SMldTrans + SMstTrans > 0):\n" +
188" bnSMRead = (SMldTrans / (SMldTrans + SMstTrans)) * (SMutil / 10.0)\n" +
189" bnSMWrite = (SMstTrans / (SMldTrans + SMstTrans)) * (SMutil / 10.0)\n" +
193" bottlenecks['bnSMRead'] = bnSMRead\n" +
194" bottlenecks['bnSMWrite'] = bnSMWrite\n" +
196" # analyze multiprocessor parallelism\n" +
198" occupancy = countersData[countersNames.index(\"achieved_occupancy\")]\n" +
200" occupancy = countersData[countersNames.index(\"sm__warps_active.avg.pct_of_peak_sustained_active\")]/100.0\n" +
201" bnMPparal = 1.0 - occupancy\n" +
202" bottlenecks['bnMPparal'] = bnMPparal\n" +
204" # analyze global parallelism\n" +
206" smEfficiency = 100.0 #countersData[countersNames.index(\"sm_efficiency\")] #commented-out as with driver 515.65.01 and CUDA 11.7, sm_efficiency shows weird behaviour\n" +
208" smEfficiency = countersData[countersNames.index(\"smsp__cycles_active.avg.pct_of_peak_sustained_elapsed\")]\n" +
209" bnGparal = (100.0 - smEfficiency) / 100.0\n" +
210" bottlenecks['bnGparal'] = bnGparal\n" +
212" threadBlocks = countersData[countersNames.index(\"Global size\")] / countersData[countersNames.index(\"Local size\")]\n" +
213" bnTailEffect = 1 - (threadBlocks / (((threadBlocks + multiprocessors-1) / multiprocessors) * multiprocessors))\n" +
214" bottlenecks['bnTailEffect'] = bnTailEffect\n" +
215" #print(bnTailEffect, threadBlocks, countersData[countersNames.index(\"Global size\")], countersData[countersNames.index(\"Local size\")])\n" +
217" bnThreads = max(0, (cores * 5 - countersData[countersNames.index(\"Global size\")]) / (cores * 5))\n" +
218" bottlenecks['bnThreads'] = bnThreads\n" +
220" # analyze instructions\n" +
221" # insctruction counts\n" +
223" spInstr = countersData[countersNames.index(\"inst_fp_32\")]\n" +
224" dpInstr = countersData[countersNames.index(\"inst_fp_64\")]\n" +
225" intInstr = countersData[countersNames.index(\"inst_integer\")]\n" +
226" #commInstr = countersData[countersNames.index(\"inst_inter_thread_communication\")]\n" +
227" miscInstr = countersData[countersNames.index(\"inst_misc\")]\n" +
228" ldstInstr = countersData[countersNames.index(\"inst_compute_ld_st\")]\n" +
229" ctrlInst = countersData[countersNames.index(\"inst_control\")]\n" +
230" bconvInstr = countersData[countersNames.index(\"inst_bit_convert\")]\n" +
231" execInstr = countersData[countersNames.index(\"inst_executed\")]\n" +
233" spInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_fp32_pred_on.sum\")]\n" +
234" dpInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_fp64_pred_on.sum\")]\n" +
235" intInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_integer_pred_on.sum\")]\n" +
236" #commInstr = countersData[countersNames.index(\"inst_inter_thread_communication\")]\n" +
237" miscInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_misc_pred_on.sum\")]\n" +
238" ldstInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_memory_pred_on.sum\")]\n" +
239" ctrlInst = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_control_pred_on.sum\")]\n" +
240" bconvInstr = countersData[countersNames.index(\"smsp__sass_thread_inst_executed_op_conversion_pred_on.sum\")]\n" +
241" execInstr = countersData[countersNames.index(\"smsp__inst_executed.sum\")]\n" +
243" #instruction utilization\n" +
246" spUtil = countersData[countersNames.index(\"flop_sp_efficiency\")]\n" +
247" dpUtil = countersData[countersNames.index(\"flop_dp_efficiency\")]\n" +
248" sfuUtil = 0 #XXX we don't have this counter\n" +
250" spUtil = countersData[countersNames.index(\"single_precision_fu_utilization\")]\n" +
251" dpUtil = countersData[countersNames.index(\"double_precision_fu_utilization\")]\n" +
252" sfuUtil = countersData[countersNames.index(\"special_fu_utilization\")]\n" +
253" cfUtil = countersData[countersNames.index(\"cf_fu_utilization\")]\n" +
254" ldstUtil = countersData[countersNames.index(\"ldst_fu_utilization\")]\n" +
255" texFuUtil = countersData[countersNames.index(\"tex_fu_utilization\")]\n" +
256" instrSlotUtil = countersData[countersNames.index(\"issue_slot_utilization\")]\n" +
258" instrEffExec = countersData[countersNames.index(\"warp_execution_efficiency\")]\n" +
259" instrEffPred = countersData[countersNames.index(\"warp_nonpred_execution_efficiency\")]\n" +
261" instrEffExec = 100\n" +
262" instrEffPred = 100\n" +
264" spUtil = countersData[countersNames.index(\"smsp__pipe_fma_cycles_active.avg.pct_of_peak_sustained_active\")]/10.0\n" +
265" dpUtil = countersData[countersNames.index(\"smsp__inst_executed_pipe_fp64.avg.pct_of_peak_sustained_active\")]/10.0\n" +
266" sfuUtil = countersData[countersNames.index(\"smsp__inst_executed_pipe_xu.avg.pct_of_peak_sustained_active\")]/10.0\n" +
267" cfUtil = 0.0 #XXX we don't have this counter\n" +
268" ldstUtil = countersData[countersNames.index(\"smsp__inst_executed_pipe_lsu.avg.pct_of_peak_sustained_active\")]/10.0\n" +
269" texFuUtil = countersData[countersNames.index(\"smsp__inst_executed_pipe_tex.avg.pct_of_peak_sustained_active\")]/10.0\n" +
270" instrSlotUtil = countersData[countersNames.index(\"smsp__issue_active.avg.pct_of_peak_sustained_active\")]\n" +
271" instrEffExec = countersData[countersNames.index(\"smsp__thread_inst_executed_per_inst_executed.ratio\")]*100.0/32.0\n" +
272" instrEffPred = countersData[countersNames.index(\"smsp__thread_inst_executed_per_inst_executed.pct\")]\n" +
274" instrExecFitted = execInstr*32.0 * (100.0/instrEffExec) * (100.0/instrEffPred) #XXX this should be equal to spInstr+dpInstr+intInstr+miscInstr+ldstInstr+ctrlInst+bconvInstr\n" +
276" instrUtilFitted = instrSlotUtil/100.0\n" +
278" instrUtilFitted = min(1.0, instrSlotUtil/50.0) # dual-issue causes max 50% utilization of instruction of single type\n" +
280" spUtilApprox = (spInstr/instrExecFitted) * instrUtilFitted\n" +
281" dpUtilApprox = (dpInstr/instrExecFitted) * instrUtilFitted\n" +
282" ldstUtilApprox = (ldstInstr/instrExecFitted) * instrUtilFitted\n" +
283" cfUtilApprox = (ctrlInst/instrExecFitted) * instrUtilFitted\n" +
284" intUtilApprox = (intInstr/instrExecFitted) * instrUtilFitted\n" +
285" miscUtilApprox = (miscInstr/instrExecFitted) * instrUtilFitted\n" +
286" bconvUtilApprox = (bconvInstr/instrExecFitted) * instrUtilFitted\n" +
288" #print(\"single_precision_fu_utilization reported/computed: \", spUtil, (spInstr/instrExecFitted) * instrUtilFitted)\n" +
289"# #workaround is to bottleneck instructions only if utilization is significant\n" +
290"# maxUtil = max(spUtil, dpUtil, cfUtil)\n" +
291"# maxUtilInst = max(spInstr, dpInstr, ctrlInst) #XXX should select the same category as the line above\n" +
292"# if maxUtil > 6:\n" +
293"# intUtilApprox = intInstr/maxUtilInst * maxUtil\n" +
294"# miscUtilApprox = miscInstr/maxUtilInst * maxUtil\n" +
295"# bconvUtilApprox = bconvInstr/maxUtilInst * maxUtil\n" +
297"# intUtilApprox = 0.0\n" +
298"# miscUtilApprox = 0.0\n" +
299"# bconvUtilApprox = 0.0\n" +
301"# bnSP = spUtil/10.0\n" +
302" bnSP = spUtilApprox\n" +
303"# bnDP = dpUtil/10.0\n" +
304" bnDP = dpUtilApprox\n" +
305" bnSFU = sfuUtil/10.0\n" +
306"# bnCF = cfUtil/10.0\n" +
307" bnCF = cfUtilApprox\n" +
308"# bnLDST = ldstUtil/10.0\n" +
309" bnLDST = ldstUtilApprox\n" +
310" bnTexFu = texFuUtil/10.0\n" +
311" bnInt = intUtilApprox\n" +
312" bnMisc = miscUtilApprox\n" +
313" bnBconv = bconvUtilApprox\n" +
315" bottlenecks['bnSP'] = bnSP\n" +
316" bottlenecks['bnDP'] = bnDP\n" +
317" bottlenecks['bnSFU'] = bnSFU\n" +
318" bottlenecks['bnCF'] = bnCF\n" +
319" bottlenecks['bnLDST'] = bnLDST\n" +
320" bottlenecks['bnTexFu'] = bnTexFu\n" +
321" bottlenecks['bnInt'] = bnInt\n" +
322" bottlenecks['bnMisc'] = bnMisc\n" +
323" bottlenecks['bnBconv'] = bnBconv\n" +
325" issueWeight = 0.0\n" +
326" maxInstrUtil = max(spUtilApprox/instrUtilFitted, dpUtilApprox/instrUtilFitted, sfuUtil/10.0, cfUtilApprox/instrUtilFitted, ldstUtilApprox/instrUtilFitted, intUtilApprox/instrUtilFitted, miscUtilApprox/instrUtilFitted, bconvUtilApprox/instrUtilFitted)\n" +
327" if maxInstrUtil > REACT_TO_INST_BOTTLENECKS :\n" +
328" issueWeight = (maxInstrUtil - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
329" bnInstIssue = (100.0 - instrSlotUtil) / 100 * issueWeight\n" +
330" #bnInstIssue = (100.0 - instrSlotUtil) / 100 * max(spUtilApprox/instrUtilFitted, dpUtilApprox/instrUtilFitted, sfuUtil/instrUtilFitted/10.0, cfUtilApprox/instrUtilFitted, ldstUtilApprox/instrUtilFitted, texFuUtil/instrUtilFitted/10.0, intUtilApprox/instrUtilFitted, miscUtilApprox/instrUtilFitted, bconvUtilApprox/instrUtilFitted)\n" +
331" bottlenecks['bnInstIssue'] = bnInstIssue\n" +
333" if verbose > 1 :\n" +
334" print(\"[Profile-based searcher details] bottlenecks:\", bottlenecks)\n" +
336" return bottlenecks\n" +
338"# computeChanges\n" +
339"# computes how to change profiling counters according to bottlenecks\n" +
340"# absolute value of computed changes means its importance, the sign means\n" +
341"# required direction (increase/decrease the counter)\n" +
342"# GPU dependent, implemented for CUDA compute capabilities 3.0 - 7.5\n" +
343"# Note: this function is separated from analyzeBottlenecks in order to manage\n" +
344"# portability across arch. easily (computed bottlenecks are arch. independent)\n" +
346"def computeChanges(bottlenecks, countersNames, cc, verbose):\n" +
347" # set how important is to change particular profiling counters\n" +
348" changeImportance = [0.0]*len(countersNames)\n" +
350" # memory-subsystem related counters\n" +
352" changeImportance[countersNames.index('dram_read_transactions')] = - bottlenecks['bnDRAMRead']\n" +
353" changeImportance[countersNames.index('dram_write_transactions')] = - bottlenecks['bnDRAMWrite']\n" +
354" changeImportance[countersNames.index('l2_read_transactions')] = - bottlenecks['bnL2Read']\n" +
355" changeImportance[countersNames.index('l2_write_transactions')] = - bottlenecks['bnL2Write']\n" +
356" changeImportance[countersNames.index('tex_cache_transactions')] = - bottlenecks['bnTex']\n" +
357" changeImportance[countersNames.index('local_memory_overhead')] = - bottlenecks['bnLocal']\n" +
358" changeImportance[countersNames.index('shared_load_transactions')] = - bottlenecks['bnSMRead']\n" +
359" changeImportance[countersNames.index('shared_store_transactions')] = - bottlenecks['bnSMWrite']\n" +
361" changeImportance[countersNames.index('dram__sectors_read.sum')] = - bottlenecks['bnDRAMRead']\n" +
362" changeImportance[countersNames.index('dram__sectors_write.sum')] = - bottlenecks['bnDRAMWrite']\n" +
363" changeImportance[countersNames.index('lts__t_sectors_op_read.sum')] = - bottlenecks['bnL2Read']\n" +
364" changeImportance[countersNames.index('lts__t_sectors_op_write.sum')] = - bottlenecks['bnL2Write']\n" +
365" #TODO solve additive counters more elegantly?\n" +
366" changeImportance[countersNames.index('l1tex__t_requests_pipe_lsu_mem_global_op_ld.sum')] = - bottlenecks['bnTex']\n" +
367" changeImportance[countersNames.index('l1tex__t_sectors_pipe_lsu_mem_local_op_ld.sum')] = - bottlenecks['bnLocal']\n" +
368" changeImportance[countersNames.index('l1tex__t_sectors_pipe_lsu_mem_local_op_st.sum')] = - bottlenecks['bnLocal']\n" +
369" changeImportance[countersNames.index('l1tex__data_pipe_lsu_wavefronts_mem_shared_op_ld.sum')] = - bottlenecks['bnSMRead']\n" +
370" changeImportance[countersNames.index('l1tex__data_pipe_lsu_wavefronts_mem_shared_op_st.sum')] = - bottlenecks['bnSMWrite']\n" +
372" # instructions related counters\n" +
374" if bottlenecks['bnSP'] > REACT_TO_INST_BOTTLENECKS :\n" +
375" changeImportance[countersNames.index('inst_fp_32')] = - (bottlenecks['bnSP'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
376" changeImportance[countersNames.index('flop_sp_efficiency')] = (bottlenecks['bnSP'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
377" if bottlenecks['bnDP'] > REACT_TO_INST_BOTTLENECKS :\n" +
378" changeImportance[countersNames.index('inst_fp_64')] = - (bottlenecks['bnDP']- REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
379" #changeImportance[countersNames.index('special_fu_utilization')] = + bottlenecks['bnSFU'] #TODO how to count SFU instructions?\n" +
380" if bottlenecks['bnCF'] > REACT_TO_INST_BOTTLENECKS :\n" +
381" changeImportance[countersNames.index('inst_control')] = - (bottlenecks['bnCF'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
382" if bottlenecks['bnLDST'] > REACT_TO_INST_BOTTLENECKS :\n" +
383" changeImportance[countersNames.index('inst_compute_ld_st')] = - (bottlenecks['bnLDST'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
384" #changeImportance[countersNames.index('tex_fu_utilization')] = + bottlenecks['bnTexFu']\n" +
385" if bottlenecks['bnInt'] > REACT_TO_INST_BOTTLENECKS :\n" +
386" changeImportance[countersNames.index('inst_integer')] = - (bottlenecks['bnInt'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
387" if bottlenecks['bnMisc'] > REACT_TO_INST_BOTTLENECKS :\n" +
388" changeImportance[countersNames.index('inst_misc')] = - (bottlenecks['bnMisc'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
389" if bottlenecks['bnBconv'] > REACT_TO_INST_BOTTLENECKS :\n" +
390" changeImportance[countersNames.index('inst_bit_convert')] = - (bottlenecks['bnBconv'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
391" #if bottlenecks['bnInstIssue'] > REACT_TO_INST_BOTTLENECKS :\n" +
392" changeImportance[countersNames.index('issue_slot_utilization')] = bottlenecks['bnInstIssue'] #(bottlenecks['bnInstIssue'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
394" if bottlenecks['bnSP'] > REACT_TO_INST_BOTTLENECKS :\n" +
395" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_fp32_pred_on.sum')] = - bottlenecks['bnSP']\n" +
396" if bottlenecks['bnDP'] > REACT_TO_INST_BOTTLENECKS :\n" +
397" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_fp64_pred_on.sum')] = - bottlenecks['bnDP']\n" +
398" #changeImportance[countersNames.index('special_fu_utilization')] = + bottlenecks['bnSFU'] #TODO how to count SFU instructions?\n" +
399" if bottlenecks['bnCF'] > REACT_TO_INST_BOTTLENECKS :\n" +
400" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_control_pred_on.sum')] = - (bottlenecks['bnCF'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
401" if bottlenecks['bnLDST'] > REACT_TO_INST_BOTTLENECKS :\n" +
402" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_memory_pred_on.sum')] = - (bottlenecks['bnLDST'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
403" #changeImportance[countersNames.index('tex_fu_utilization')] = + bottlenecks['bnTexFu']\n" +
404" if bottlenecks['bnInt'] > REACT_TO_INST_BOTTLENECKS :\n" +
405" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_integer_pred_on.sum')] = - (bottlenecks['bnInt'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
406" if bottlenecks['bnMisc'] > REACT_TO_INST_BOTTLENECKS :\n" +
407" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_misc_pred_on.sum')] = - (bottlenecks['bnMisc'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
408" if bottlenecks['bnBconv'] > REACT_TO_INST_BOTTLENECKS :\n" +
409" changeImportance[countersNames.index('smsp__sass_thread_inst_executed_op_conversion_pred_on.sum')] = - (bottlenecks['bnBconv'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
410" #if bottlenecks['bnInstIssue'] > REACT_TO_INST_BOTTLENECKS :\n" +
411" changeImportance[countersNames.index('smsp__issue_active.avg.pct_of_peak_sustained_active')] = bottlenecks['bnInstIssue'] #(bottlenecks['bnInstIssue'] - REACT_TO_INST_BOTTLENECKS) / (1.0 - REACT_TO_INST_BOTTLENECKS)\n" +
413" #parallelism related counters\n" +
415" changeImportance[countersNames.index('sm_efficiency')] = bottlenecks['bnGparal']\n" +
417" changeImportance[countersNames.index('smsp__cycles_active.avg.pct_of_peak_sustained_elapsed')] = bottlenecks['bnGparal']\n" +
419" changeImportance[countersNames.index('Global size')] = bottlenecks['bnThreads']#bottlenecks['bnTailEffect'] + bottlenecks['bnThreads']\n" +
420" #changeImportance[countersNames.index('Local size')] = - bottlenecks['bnTailEffect'] / 2\n" +
422" if verbose > 1 :\n" +
423" print(\"[Profile-based searcher details] changeImportance:\", changeImportance)\n" +
425" return changeImportance\n" +
427"###################### GPU arch. independent functions #########################\n" +
429"# scoreTuningConfigurationsExact\n" +
430"# scores all tuning configurations according to required changes of profiling\n" +
431"# counters and expected effect of the tuning parameters to profiling counters\n" +
432"# GPU independent\n" +
433"# This version uses completely computed offline space\n" +
435"def scoreTuningConfigurationsExact(changeImportance, tuningparamsNames, actualConf, tuningSpace, completeMapping, scoreDistrib, verbose):\n" +
436" newScoreDistrib = [0.0] * len(tuningSpace)\n" +
437" #search index of actualConf in completeMapping (some conf. can be missing, therefore, we need to check tuning parameters)\n" +
439" for conf in completeMapping :\n" +
440" if actualConf == conf[0] :\n" +
441" actualPC = conf[1]\n" +
442" if len(actualPC) == 0 :\n" +
443" # the configuration is not known in the completeMapping, return uniform distrib\n" +
444" for i in range(0, len(tuningSpace)) :\n" +
445" uniformScoreDistrib = [1.0] * len(tuningSpace)\n" +
446" if scoreDistrib[i] == 0.0 :\n" +
447" uniformScoreDistrib[i] = 0.0\n" +
448" return uniformScoreDistrib\n" +
451" # for each tuning configuration\n" +
452" for i in range(0, len(tuningSpace)) :\n" +
453" #seek for equivalent tuning configuration in the completeMapping\n" +
454" #TODO this implementation assumes the same order of tuning configurations, create mapping between indexes instead\n" +
456" for j in range(cmIdx, len(completeMapping)) :\n" +
457" if (tuningSpace[i] == completeMapping[j][0]) :\n" +
458" myPC = completeMapping[j][1]\n" +
461" if (len(myPC) == 0) :\n" +
462" newScoreDistrib[i] = 0.0\n" +
464" #score configuration\n" +
465" for j in range(0, len(changeImportance)) :\n" +
467" newScoreDistrib[i] = newScoreDistrib[i] + changeImportance[j] * (myPC[j] - actualPC[j]) / (myPC[j]+actualPC[j])\n" +
468" except ZeroDivisionError :\n" +
469" newScoreDistrib[i] = newScoreDistrib[i] + 0.0\n" +
471" minScore = min(newScoreDistrib)\n" +
472" maxScore = max(newScoreDistrib)\n" +
473" if verbose > 1 :\n" +
474" print(\"[Profile-based searcher details] scoreDistrib interval: \", minScore, maxScore)\n" +
475" for i in range(0, len(tuningSpace)) :\n" +
476" if newScoreDistrib[i] < CUTOFF :\n" +
477" newScoreDistrib[i] = 0.0\n" +
479" if newScoreDistrib[i] < 0.0 :\n" +
480" newScoreDistrib[i] = 1.0 - (newScoreDistrib[i] / minScore)\n" +
482" if newScoreDistrib[i] > 0.0 :\n" +
483" newScoreDistrib[i] = 1.0 + (newScoreDistrib[i] / maxScore)\n" +
484" newScoreDistrib[i] = newScoreDistrib[i]**EXP\n" +
485" if newScoreDistrib[i] < 0.0001 :\n" +
486" newScoreDistrib[i] = 0.0001\n" +
488" # if was 0, set to 0 (explored)\n" +
489" if scoreDistrib[i] == 0.0 :\n" +
490" newScoreDistrib[i] = 0.0\n" +
492" if verbose > 2 :\n" +
493" print(\"[Profile-based searcher debug] newScoreDistrib\", newScoreDistrib)\n" +
495" return newScoreDistrib\n" +
498"# scoreTuningConfigurationsPredictor\n" +
499"# scores all tuning configurations according to required changes of profiling\n" +
500"# counters and expected effect of the tuning parameters to profiling counters\n" +
501"# GPU independent\n" +
502"# This version uses predictor based on ML model\n" +
503"def scoreTuningConfigurationsPredictor(changeImportance, tuningParametersReorderingFromSearchSpaceToModel, actualConf, tuningSpace, scoreDistrib, loaded_model, verbose):\n" +
504" def mulfunc(a, b, c):\n" +
505" if (a * (b - c)) > 0.0:\n" +
507" if (a * (b - c)) < 0.0:\n" +
512" newScoreDistrib = [0.0] * len(tuningSpace)\n" +
515" # Using ML predictor\n" +
516" reorderedActualConf = reorderList(actualConf, tuningParametersReorderingFromSearchSpaceToModel)\n" +
517" predictedPC = loaded_model.predict([reorderedActualConf])\n" +
518" actualPC = list(predictedPC.flatten())\n" +
520" if len(actualPC) == 0 :\n" +
521" for i in range(0, len(tuningSpace)) :\n" +
522" uniformScoreDistrib = [1.0] * len(tuningSpace)\n" +
523" if scoreDistrib[i] == 0.0 :\n" +
524" uniformScoreDistrib[i] = 0.0\n" +
525" return uniformScoreDistrib\n" +
528" #################################################### Using ML predictor\n" +
529" #reorder the tuning space data so that they are in the correct order\n" +
530" # TP from tuning space and T from model might be in different order, thus reordering is necessary\n" +
531" reorderedTuningSpace = reorderTuningSpace(tuningSpace, tuningParametersReorderingFromSearchSpaceToModel)\n" +
532" predictedMyPC = loaded_model.predict(reorderedTuningSpace)\n" +
533" predictedMyPC1 = np.array(predictedMyPC)\n" +
534" actualPC1 = np.array(actualPC)\n" +
535" n = len(changeImportance) - len(actualPC1)\n" +
536" changeImportance = changeImportance[:len(changeImportance)-n]\n" +
537" changeImportance1 = np.array(changeImportance)\n" +
539" vfunc = np.vectorize(mulfunc)\n" +
540" if verbose < 3:\n" +
541" # supressing the warning about dividing with zero\n" +
542" # nan that results from that is converted to number just below\n" +
543" with warnings.catch_warnings():\n" +
544" warnings.simplefilter(\"ignore\")\n" +
545" mul = vfunc(changeImportance1, predictedMyPC1, actualPC1)\n" +
546" res = np.array(mul * abs(changeImportance1 * 2.0 * (predictedMyPC1 - actualPC1) / (predictedMyPC1+actualPC1)))\n" +
548" mul = vfunc(changeImportance1, predictedMyPC1, actualPC1)\n" +
549" res = np.array(mul * abs(changeImportance1 * 2.0 * (predictedMyPC1 - actualPC1) / (predictedMyPC1+actualPC1)))\n" +
550" res = np.nan_to_num(res)\n" +
551" newScoreDistrib = res.sum(axis=1)\n" +
553" minScore = min(newScoreDistrib)\n" +
554" maxScore = max(newScoreDistrib)\n" +
555" if verbose > 1 :\n" +
556" print(\"[Profile-based searcher details] scoreDistrib interval: \", minScore, maxScore)\n" +
557" for i in range(0, len(tuningSpace)) :\n" +
558" if newScoreDistrib[i] < CUTOFF :\n" +
559" newScoreDistrib[i] = 0.0001\n" +
561" if newScoreDistrib[i] < 0.0 :\n" +
562" newScoreDistrib[i] = 1.0 - (newScoreDistrib[i] / minScore)\n" +
564" if newScoreDistrib[i] > 0.0 :\n" +
565" newScoreDistrib[i] = 1.0 + (newScoreDistrib[i] / maxScore)\n" +
566" newScoreDistrib[i] = newScoreDistrib[i]**EXP\n" +
567" if newScoreDistrib[i] < 0.0001 :\n" +
568" newScoreDistrib[i] = 0.0001\n" +
570" # if was 0, set to 0 (explored)\n" +
571" if scoreDistrib[i] == 0.0 :\n" +
572" newScoreDistrib[i] = 0.0\n" +
574" if verbose > 2 :\n" +
575" print(\"[Profile-based searcher debug] Predictor newScoreDistrib:\", newScoreDistrib)\n" +
577" return newScoreDistrib\n" +
579"# randomSearchStep\n" +
580"# perform one step of random search (without memory)\n" +
581"def randomSearchStep(tuningSpaceSize) :\n" +
582" return int(random.random() * tuningSpaceSize)\n" +
584"# weightedRandomSearchStep\n" +
585"# perform one step of random search using weighted probability based on\n" +
586"# profiling counters\n" +
587"def weightedRandomSearchStep(scoreDistrib, tuningSpaceSize) :\n" +
588" if (sum(scoreDistrib) == 0.0) :\n" +
589" print(\"Weighted search error: no more tuning configurations.\")\n" +
590" return randomSearchStep(tuningSpaceSize)\n" +
592" rnd = random.random() * sum(scoreDistrib)\n" +
595" for j in range (0, tuningSpaceSize):\n" +
596" tmp = tmp + scoreDistrib[j]\n" +
597" if rnd < tmp : break\n" +
601"####################### auxiliary functions ##########################\n" +
603"def setComputeBound():\n" +
604" global REACT_TO_INST_BOTTLENECKS\n" +
605" REACT_TO_INST_BOTTLENECKS = 0.5\n" +
607"def setMemoryBound():\n" +
608" global REACT_TO_INST_BOTTLENECKS\n" +
609" REACT_TO_INST_BOTTLENECKS = 0.7\n" +
611"def reorderList(data, reorderingIndices) :\n" +
612" return [x for _, x in sorted(zip(reorderingIndices, data))]\n" +
614"def reorderTuningSpace(data, reorderingIndices) :\n" +
615" reorderedData = []\n" +
616" for row in data:\n" +
617" reorderedData.append(reorderList(row, reorderingIndices))\n" +
618" return reorderedData\n" +
620"def getConfigurationIndices(self, configurations) :\n" +
622" for c in configurations :\n" +
623" ind.append(self.GetIndex(c))\n" +
627"####################### searcher class ##########################\n" +
629"class PyProfilingSearcher(ktt.Searcher):\n" +
633" multiprocessors = 0\n" +
634" modelMetadata = 0\n" +
635" bestDuration = -1\n" +
636" bestConf = None\n" +
637" preselectedBatch = []\n" +
638" tuningParamsNames = []\n" +
639" currentConfiguration = ktt.KernelConfiguration()\n" +
643" neighborSize = -1\n" +
644" randomSize = -1\n" +
646" # sometimes, the order of tuning parameters in the search space (as generated by KTT) differs from the order of tuning parameters in the saved ML model\n" +
647" #therefore, we need to reorder them to align, so that the model works with the correctly ordered data\n" +
648" tuningParametersReorderingFromSearchSpaceToModel = 0\n" +
650" def __init__(self):\n" +
651" ktt.Searcher.__init__(self)\n" +
653" def OnInitialize(self):\n" +
655" # initialize the batch, make sure it includes unique, i.e. non-repeating configurations\n" +
657" while count < self.batchSize:\n" +
658" for i in range (count, self.batchSize) :\n" +
659" self.preselectedBatch.append(self.GetRandomConfiguration())\n" +
660" self.preselectedBatch = self.GetUniqueConfigurations(self.preselectedBatch)\n" +
661" count = len(self.preselectedBatch)\n" +
662" if self.verbose > 0:\n" +
663" print(\"[Profile-based searcher info] Batch initialized with configurations \", getConfigurationIndices(self, self.preselectedBatch))\n" +
665" # select configuration and remove it from he batch\n" +
666" self.currentConfiguration = self.preselectedBatch.pop(0)\n" +
667" if self.verbose > 0:\n" +
668" print(\"[Profile-based searcher info] Selected configuration \" + str(self.GetIndex(self.currentConfiguration)), flush = True)\n" +
670" # determine the difference in the order of TP from search space and from the model\n" +
671" tp = self.currentConfiguration.GetPairs()\n" +
673" self.tuningParamsNames.append(p.GetName())\n" +
674" self.tuningParametersReorderingFromSearchSpaceToModel = []\n" +
675" for tp in self.tuningParamsNames:\n" +
676" self.tuningParametersReorderingFromSearchSpaceToModel.append(self.modelMetadata['tp'].index(tp))\n" +
677" if self.verbose > 2:\n" +
678" print(\"[Profile-based searcher debug] Tuning parameters in the search space:\", self.tuningParamsNames)\n" +
679" print(\"[Profile-based searcher debug] Tuning parameters in the model:\", self.modelMetadata['tp'])\n" +
680" print(\"[Profile-based searcher debug] Tuning parameters reordering list\", self.tuningParametersReorderingFromSearchSpaceToModel)\n" +
682" def Configure(self, tuner, modelFile, batchSize, neighborSize, randomSize, logLevel):\n" +
683" self.tuner = tuner\n" +
684" self.ccMajor = tuner.GetCurrentDeviceInfo().GetCudaComputeCapabilityMajor()\n" +
685" self.ccMinor = tuner.GetCurrentDeviceInfo().GetCudaComputeCapabilityMinor()\n" +
686" self.cc = self.ccMajor + round(0.1 * self.ccMinor, 1)\n" +
687" self.multiprocessors = tuner.GetCurrentDeviceInfo().GetMaxComputeUnits()\n" +
689" self.modelMetadata = loadMLModelMetadata(modelFile + \".metadata.json\")\n" +
690" self.model = loadMLModel(modelFile)\n" +
691" self.batchSize = batchSize\n" +
692" self.neighborSize = neighborSize\n" +
693" self.randomSize = randomSize\n" +
695" if (str(logLevel) == \"LoggingLevel.Off\"):\n" +
696" self.verbose = 0\n" +
697" if (str(logLevel) == \"LoggingLevel.Info\"):\n" +
698" self.verbose = 1\n" +
699" if (str(logLevel) == \"LoggingLevel.Warning\" or str(logLevel) == \"LoggingLevel.Error\"):\n" +
700" self.verbose = 2\n" +
701" if (str(logLevel) == \"LoggingLevel.Debug\"):\n" +
702" self.verbose = 3\n" +
704" if self.verbose > 0:\n" +
705" print(\"[Profile-based searcher info] Loaded model file\", modelFile)\n" +
706" print(\"[Profile-based searcher info] Batch size set to\", batchSize)\n" +
707" print(\"[Profile-based searcher info] Neighbor size set to\", neighborSize)\n" +
708" print(\"[Profile-based searcher info] Random size set to\", randomSize)\n" +
709" print(\"[Profile-based searcher info] Log level set to\", logLevel)\n" +
712"# GetUniqueConfigurations\n" +
713"# takes a list and returns a list that does not contain repeating configurations\n" +
714" def GetUniqueConfigurations(self, configurations):\n" +
715" uniqueConfigurations = []\n" +
716" indicesConfigurations = []\n" +
717" uniqueIndicesConfigurations = []\n" +
718" for c in configurations:\n" +
719" indicesConfigurations.append(self.GetIndex(c))\n" +
720" uniqueIndicesConfigurations = list(set(indicesConfigurations))\n" +
722" for i in uniqueIndicesConfigurations:\n" +
723" uniqueConfigurations.append(self.GetConfiguration(i))\n" +
724" return uniqueConfigurations\n" +
726"# CalculateNextConfiguration\n" +
727"# determines the next configuration that KTT subsequently runs or profiles\n" +
728" def CalculateNextConfiguration(self, previousResult):\n" +
729" if (previousResult.IsValid()) and ((self.bestConf == None) or (previousResult.GetKernelDuration() < self.bestDuration)) :\n" +
730" self.bestDuration = previousResult.GetKernelDuration()\n" +
731" self.bestConf = self.currentConfiguration\n" +
732" if self.verbose > 1:\n" +
733" print(\"[Profile-based searcher details] Found new best configuration\", self.GetIndex(self.bestConf), \"with kernel time\", self.bestDuration/1000, \"us\", flush = True)\n" +
735" # if we still have configurations in the batch\n" +
736" if len(self.preselectedBatch) > 0:\n" +
737" if self.verbose > 1:\n" +
738" print(\"[Profile-based searcher details] PreselectedBatch has\", len(self.preselectedBatch), \"remaining items:\", getConfigurationIndices(self, self.preselectedBatch), flush = True)\n" +
739" # just take one from the top and run that\n" +
740" self.currentConfiguration = self.preselectedBatch.pop(0)\n" +
741" # if we have an empty batch and we don't have any best configuration from it (invalid configurations, failed compilation, runtime, or validation)\n" +
742" elif self.bestConf == None:\n" +
743" if self.verbose > 1:\n" +
744" print(\"[Profile-based searcher details] Preselected batch contained invalid configurations only, generating random one.\")\n" +
745" # initialize the batch, make sure it includes unique, i.e. non-repeating configurations\n" +
747" maxBatchSize = min(self.batchSize, self.GetUnexploredConfigurationsCount())\n" +
748" while count < maxBatchSize:\n" +
749" for i in range (count, maxBatchSize) :\n" +
750" self.preselectedBatch.append(self.GetRandomConfiguration())\n" +
751" self.preselectedBatch = self.GetUniqueConfigurations(self.preselectedBatch)\n" +
752" count = len(self.preselectedBatch)\n" +
753" if self.verbose > 0:\n" +
754" print(\"[Profile-based searcher info] Batch generated with configurations \", getConfigurationIndices(self, self.preselectedBatch))\n" +
755" # select configuration and remove it from batch\n" +
756" self.currentConfiguration = self.preselectedBatch.pop(0)\n" +
757" # if we have an empty batch and we have the fastest configuration from it\n" +
759" if self.verbose > 1:\n" +
760" print(\"[Profile-based searcher details] Preselected batch empty\", flush = True)\n" +
761" if self.bestDuration != -1 :\n" +
762" # we run the fastest one once again, but with profiling\n" +
763" self.currentConfiguration = self.bestConf\n" +
764" self.bestDuration = -1\n" +
765" self.tuner.SetProfiling(True)\n" +
766" if self.verbose > 0 :\n" +
767" print(\"[Profile-based searcher info] Running profiling for the best configuration from the batch, configuration\", str(self.GetIndex(self.currentConfiguration)), flush = True)\n" +
768" # this happens when the fastest configuration is the last one, e.g. with batchSize == 1, then we just take profiling info from the last run\n" +
770" # get PCs from the last tuning run\n" +
771" if len(previousResult.GetResults()) > 1:\n" +
772" print(\"Profile-based searcher warning: this version of profile-based searcher does not support searching kernels collections. Using counters from kernels 0 only.\")\n" +
773" globalSize = previousResult.GetResults()[0].GetGlobalSize()\n" +
774" localSize = previousResult.GetResults()[0].GetLocalSize()\n" +
775" profilingCountersRun = previousResult.GetResults()[0].GetProfilingData().GetCounters() #FIXME this supposes there is no composition profiled\n" +
776" pcNames = [\"Global size\", \"Local size\"]\n" +
777" pcVals = [globalSize.GetTotalSize()*localSize.GetTotalSize(), localSize.GetTotalSize()]\n" +
778" for pd in profilingCountersRun :\n" +
779" pcNames.append(pd.GetName())\n" +
780" if (pd.GetType() == ktt.ProfilingCounterType.Int) :\n" +
781" pcVals.append(pd.GetValueInt())\n" +
782" elif (pd.GetType() == ktt.ProfilingCounterType.UnsignedInt) or (pd.GetType() == ktt.ProfilingCounterType.Throughput) or (pd.GetType() == ktt.ProfilingCounterType.UtilizationLevel):\n" +
783" pcVals.append(pd.GetValueUint())\n" +
784" elif (pd.GetType() == ktt.ProfilingCounterType.Double) or (pd.GetType() == ktt.ProfilingCounterType.Percent) :\n" +
785" pcVals.append(pd.GetValueDouble())\n" +
787" print(\"Fatal error, unsupported PC value passed to profile-based searcher!\")\n" +
790" # candidates pool generation\n" +
791" # select candidate configurations according to position of the best one plus some random sample\n" +
792" candidates = self.GetNeighbourConfigurations(self.bestConf, NEIGHBOR_DISTANCE, self.neighborSize)\n" +
793" # make sure we don't have repeating configurations in the candidates list\n" +
794" candidates = self.GetUniqueConfigurations(candidates)\n" +
795" # number of candidates needs to decrease at the end of the search, as we don't have enough unexplored configurations\n" +
796" maxPossibleCandidatesSize = min(len(candidates) + self.randomSize, self.GetUnexploredConfigurationsCount())\n" +
797" # add random configurations to fill up the candidates pool\n" +
798" count = len(candidates)\n" +
799" while count < maxPossibleCandidatesSize:\n" +
800" for i in range (count, maxPossibleCandidatesSize) :\n" +
801" candidates.append(self.GetRandomConfiguration())\n" +
802" candidates = self.GetUniqueConfigurations(candidates)\n" +
803" count = len(candidates)\n" +
806" if self.verbose > 1:\n" +
807" print(\"[Profile-based searcher details] Evaluating model for\", str(len(candidates)), \"candidates...\", flush = True)\n" +
809" # create a small tuning space from candidates\n" +
810" candidatesTuningSpace = []\n" +
811" for c in candidates :\n" +
812" tp = c.GetPairs()\n" +
813" candidateParams = []\n" +
815" candidateParams.append(p.GetValue())\n" +
816" candidatesTuningSpace.append(candidateParams)\n" +
817" myTuningSpace = []\n" +
818" tp = self.bestConf.GetPairs()\n" +
820" myTuningSpace.append(p.GetValue())\n" +
823" # score the configurations\n" +
824" scoreDistrib = [1.0]*len(candidates)\n" +
825" bottlenecks = analyzeBottlenecks(pcNames, pcVals, self.cc, self.multiprocessors, self.convertSM2Cores() * self.multiprocessors, self.verbose)\n" +
826" changes = computeChanges(bottlenecks, self.modelMetadata['pc'], self.modelMetadata['cc'], self.verbose)\n" +
827" scoreDistrib = scoreTuningConfigurationsPredictor(changes, self.tuningParametersReorderingFromSearchSpaceToModel, myTuningSpace, candidatesTuningSpace, scoreDistrib, self.model, self.verbose)\n" +
829" if self.verbose > 2:\n" +
830" print(\"[Profile-based searcher debug] Scoring of the candidates done.\", flush = True)\n" +
832" # select next batch\n" +
833" selectedIndices = []\n" +
834" # if we have more candidates than batchSize, use weightedRandom to choose from them, biasing with score\n" +
835" if len(candidates) > self.batchSize :\n" +
837" while numInBatch < self.batchSize :\n" +
838" idx = weightedRandomSearchStep(scoreDistrib, len(candidates))\n" +
839" #check if we have not chosen the same configuration in previous iterations\n" +
840" if selectedIndices == [] or idx not in selectedIndices:\n" +
841" self.preselectedBatch.append(candidates[idx])\n" +
842" selectedIndices.append(idx)\n" +
843" numInBatch = numInBatch + 1\n" +
844" scoreDistrib[idx] = 0.0\n" +
845" # if we have less candidates than batchSize, just put them all in batch\n" +
847" for i in range(0, len(candidates)):\n" +
848" self.preselectedBatch.append(candidates[i])\n" +
850" if self.verbose > 0:\n" +
851" print(\"[Profile-based searcher info] Turning off profiling, new batch selected with length\", len(self.preselectedBatch), \"containing configurations:\", getConfigurationIndices(self, self.preselectedBatch), flush = True)\n" +
853" # select configuration and remove it from batch\n" +
854" self.currentConfiguration = self.preselectedBatch.pop(0)\n" +
855" self.bestConf = None\n" +
856" self.tuner.SetProfiling(False)\n" +
860" def GetCurrentConfiguration(self):\n" +
861" return self.currentConfiguration\n" +
863" def convertSM2Cores(self):\n" +
864" smToCoresDict = {\n" +
883" compact = (self.ccMajor << 4) + self.ccMinor\n" +
884" if compact in smToCoresDict:\n" +
885" return smToCoresDict[compact]\n" +
887" print(\"Warning: unknown number of cores for SM \" + str(self.ccMajor) + \".\" + str(self.ccMinor) + \", using default value of \" + str(defaultSM))\n" +
888" return defaultSM\n" +
890"def executeSearcher(tuner, kernel, model, batchSize, neighborSize, randomSize, logLevel):\n" +
891" searcher = PyProfilingSearcher()\n" +
892" tuner.SetSearcher(kernel, searcher)\n" +
893" searcher.Configure(tuner, model, batchSize, neighborSize, randomSize, logLevel)\n" +
Definition KttPlatform.h:41