-
Notifications
You must be signed in to change notification settings - Fork 147
Expand file tree
/
Copy pathCommon.py
More file actions
1967 lines (1720 loc) · 99.8 KB
/
Copy pathCommon.py
File metadata and controls
1967 lines (1720 loc) · 99.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
################################################################################
#
# Copyright (C) 2022-2024 Advanced Micro Devices, Inc. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
################################################################################
from . import __version__
from . import Parallel
from .TensileInstructions import getGfxName, TensileInstructions
from .Utilities.Toolchain import supportedCxxCompiler as supportedCompiler
from collections import OrderedDict
from copy import deepcopy
import math
import os.path
import subprocess
import sys
import time
import re
startTime = time.time()
ParallelMap = Parallel.ParallelMap
ParallelMap2 = Parallel.ParallelMap2
# print level
# 0 - user wants no printing
# 1 - user wants limited prints
# 2 - user wants full prints
################################################################################
# Global Parameters
################################################################################
globalParameters = OrderedDict()
workingDirectoryStack = []
########################################
# common
########################################
globalParameters["MinimumRequiredVersion"] = "0.0.0" # which version of tensile is required to handle all the features required by this configuration file
globalParameters["DeviceList"] = [] # list of GPU devices to use for tuning, empty=use default, [-1]=use all available
globalParameters["PerformanceMetric"] = "DeviceEfficiency" # performance metric for benchmarking; one of {DeviceEfficiency, CUEfficiency}
globalParameters["PrintLevel"] = 1 # how much info to print in generator. 0=none, 1=standard, 2=verbose
globalParameters["PrintTiming"] = False # print duration for each stage in generator.
globalParameters["ClientLogLevel"] = 3 # the log level of client. 0=Error, 1=Terse, 2=Verbose, 3=Debug (Aligned with ResultReporter.hpp)
# benchmarking
globalParameters["KernelTime"] = False # T=use device timers, F=use host timers
globalParameters["PreciseKernelTime"] = True # T=On hip, use the timestamps for kernel start and stop rather than separate events. Can provide more accurate kernel timing. For GlobalSplitU kernels, recommend disabling this to provide consistent
# timing between GSU / non-GSU kernels
globalParameters["CodeFromFiles"] = True # if False byte arrays will be generated during Benchmarking phase as before
globalParameters["SortProblems"] = False # sort problems by size; else use order in YAML file
globalParameters["PinClocks"] = False # T=pin gpu clocks and fan, F=don't
globalParameters["HardwareMonitor"] = True # False: disable benchmarking client monitoring clocks using rocm-smi.
globalParameters["MinFlopsPerSync"] = 1 # Minimum number of flops per sync to increase stability for small problems
globalParameters["NumBenchmarks"] = 1 # how many benchmark data points to collect per problem/solution
globalParameters["SyncsPerBenchmark"] = 1 # how iterations of the stream synchronization for-loop to do per benchmark data point
globalParameters["EnqueuesPerSync"] = 1 # how many solution enqueues to perform per synchronization
globalParameters["MaxEnqueuesPerSync"] = -1 # max solution enqueues to perform per synchronization
globalParameters["SleepPercent"] = 300 # how long to sleep after every data point: 25 means 25% of solution time. Sleeping lets gpu cool down more.
globalParameters["SkipSlowSolutionRatio"] = 0.0 # Skip slow solution during warm-up stage.
# The valid range of this ratio is (0.0 ~ 1.0), and 0.0 means no skipping.
# Skip condition: warm-up time * ratio > current best sol's warm-up time
# Suggestion:
# Small size : 0.5
# Medium size: 0.75
# Large size : 0.9
# cProfile
globalParameters["Profiler"] = 0 # Enable profiler. 0=off, 1=cProfile. This will set CpuThreads to 1.
# validation
globalParameters["NumElementsToValidate"] = 128 # number of elements to validate, 128 will be evenly spaced out (with prime number stride) across C tensor
globalParameters["NumElementsToValidateWinner"] = 0 # number of elements to validate in LibraryClient stage, the exact number to be validated is max(NumElementsToValidate,NumElementsToValidateWinner)
globalParameters["BoundsCheck"] = 0 # Bounds check
#1: Perform bounds check to find out of bounds reads/writes. NumElementsToValidate must be -1.
#2: Perform bounds check by front side guard page
#3: Perform bounds check by back side guard page
#4: Perform bounds check by both back and front side guard page
globalParameters["ValidationMaxToPrint"] = 4 # maximum number of mismatches to print
globalParameters["ValidationPrintValids"] = False # print matches too
# steps
globalParameters["ForceRedoBenchmarkProblems"] = True # if False and benchmarking already complete, then benchmarking will be skipped when tensile is re-run
globalParameters["ForceRedoLibraryLogic"] = True # if False and library logic already analyzed, then library logic will be skipped when tensile is re-run
globalParameters["ForceRedoLibraryClient"] = True # if False and library client already built, then building library client will be skipped when tensile is re-run
globalParameters["ShowProgressBar"] = True # if False and library client already built, then building library client will be skipped when tensile is re-run
globalParameters["SolutionSelectionAlg"] = 1 # algorithm to determine which solutions to keep. 0=removeLeastImportantSolutions, 1=keepWinnerSolutions (faster)
globalParameters["ExpandRanges"] = True # expand ranges into exact configs before writing logic file. False ignores ranges.
globalParameters["ExitAfterKernelGen"] = False # Exit after generating kernels
globalParameters["GenerateSourcesAndExit"] = False # Exit after kernel source generation.
globalParameters["WavefrontWidth"] = 64 # if False and library client already built, then building library client will be skipped when tensile is re-run
globalParameters["ExitOnFails"] = 1 # 1: Exit after benchmark run if failures detected. 2: Exit during benchmark run.
globalParameters["CpuThreads"] = -1 # How many CPU threads to use for kernel generation. 0=no threading, -1 == nproc, N=min(nproc,N). TODO - 0 sometimes fails with a kernel name error? 0 does not check error codes correctly
globalParameters["NumWarmups"] = 0
# FROM MERGE
#globalParameters["CpuThreads"] = -4 # How many CPU threads to use for kernel generation. 0=no threading, <0 == nproc*abs(CpuThreads), N=min(nproc,N)
# even if error occurs in kernel generation (ie due to resource overflow),
# generate the kernel source anyway. Tensile will also attempt to run
# the kernel. Useful to examine and debug overflow errors.
globalParameters["ForceGenerateKernel"] = 0
########################################
# optimization knob controls
########################################
globalParameters["UnrollLoopEfficiencyEnable"] = False # if True split(S) MAC&LDS in each unroll iteration into n smaller groups..
########################################
# less common
########################################
globalParameters["CMakeBuildType"] = "Release" # whether benchmark clients and library client should be release or debug
globalParameters["PrintSolutionRejectionReason"] = False # when a solution is marked as invalid, print why
globalParameters["LogicFormat"] = "yaml" # set library backend (yaml, or json)
globalParameters["LibraryFormat"] = "yaml" # set library backend (yaml, or msgpack)
# True/False: CSV will/won't export WinnerGFlops, WinnerTimeUS, WinnerIdx, WinnerName.
# TODO - if no side-effect, we can set default to True. This can make analyzing "LibraryLogic" (AddFromCSV) faster
globalParameters["CSVExportWinner"] = False
# (When NumBenchmarks > 1). True: CSV will merge the rows of same Problem-ID. False: Each problem will write out "NumBenchmarks" rows
# In old client - No effect, since in old client, CSV file only exports the last benchmark, somehow is not correct because the previous benchmarks are discarded
# In new client - csv file exports "NumBenchmarks" rows for every problem. This also make the later analyzing slower
# Set this to "True" can merge the rows for same problem, hence can reduce the csv file size and speed up the later analyzing
# TODO - if side-effect, we can set default to True. This can make "getResults()" / "AddFromCSV()" faster
globalParameters["CSVMergeSameProblemID"] = False
# how to initialize tensor data
# serial-in-u will use a sequence that increments in the K dimension
# This is a predictable patterns that can be checked as the kernel runs to detect
# when the wrong data is being used.
# trig_float initializes with the sin function to have non-zero values in the mantissa
# and exponent. It cannot be used for int8 or int32. Need to use tensileAlmostEqual
# not tensileEqual for checking the result.
# See ClientWriter.py, the DataInitName(Enum) for a list of initialization patterns
# - Problem-Independent: 0=0, 1=1, 2=2, 3=rand, 4=Nan, 5=Infinity, 6=BadInput(Nan), 7=BadOutput(Inf), 16=RandomNarrow,
# 21=RandomNegPosLimited(-128~128 or -1~1), 23~26=Ind Cos/Sin Abs or Not
# - Problem-dependent: 8=SerialID, 9=SerialDim0, 10=SerialDim1, 11=Identity, 12~15= Cos/Sin, Abs or Not
# For A, B, C, D: All the InitMode (0~16) can be used
# For Alpha/Beta: Only problem-independent init (0~7, 16, 23~26) can be used,
# problem-dependent init (8~15) would cause a exception (Invalid InitMode) in New Client
globalParameters["DataInitTypeAB"] = 3
globalParameters["DataInitTypeA"] = -1
globalParameters["DataInitTypeB"] = -1
globalParameters["DataInitTypeC"] = 3
globalParameters["DataInitTypeD"] = 0
globalParameters["DataInitTypeE"] = 0
globalParameters["DataInitTypeAlpha"] = 2
globalParameters["DataInitTypeBeta"] = 2
globalParameters["DataInitTypeBias"] = 3
globalParameters["DataInitTypeScaleA"] = 2
globalParameters["DataInitTypeScaleB"] = 2
globalParameters["DataInitTypeScaleC"] = 2
globalParameters["DataInitTypeScaleD"] = 2
globalParameters["DataInitTypeScaleAlphaVec"] = 3
globalParameters["DataInitValueActivationArgs"] = [2.0, 2.0]
globalParameters["CEqualD"] = False # Set to true if testing for the case where the pointer to C is the same as D.
# When this parameter is set to 0, the Tensile client will use srand(time(NULL)).
# If not 0 the Tensile client will use srand(seed).
globalParameters["DataInitSeed"] = 0
globalParameters["PruneSparseMode"] = 0 # Prune mode for Sparse Matrix: 0=random, 1=XX00, 2=X0X0, 3=0XX0, 4=X00X, 5=0X0X, 6=00XX
# build parameters
globalParameters["CMakeCXXFlags"] = "" # pass flags to cmake
globalParameters["CMakeCFlags"] = "" # pass flags to cmake
globalParameters["DebugKernel"] = False # assembly only, kernel gets buffer for debug "printing"; kernel writes data to memory, gets coppied to host and printed
globalParameters["LibraryPrintDebug"] = False # solutions will print enqueue info when enqueueing a kernel
globalParameters["AsanBuild"] = False # build with asan
globalParameters["SaveTemps"] = False # Generate intermediate results of hip kernels
globalParameters["KeepBuildTmp"] = False # If true, do not remove artifacts in build_tmp
# debug for assembly
globalParameters["EnableAsserts"] = False # Enable assembly debug assert
globalParameters["EnableDebugA"] = False # Enable / Disable CheckValue1A
globalParameters["EnableDebugB"] = False # Enable / Disable CheckValue1B
globalParameters["EnableDebugC"] = False # Enable / Disable CheckValueC
globalParameters["ExpectedValueC"] = 16.0 # Expected C Value when CheckValueC, debug for Alpha*A*B
globalParameters["ForceCExpectedValue"] = False # Force C to "DebugExpectedValueC", debug for global write
globalParameters["SplitGSU"] = False # Split GSU kernel into GSU1 and GSUM
# Tensor printing controls:
globalParameters["PrintTensorA"] = 0 # Print TensorA after initialization
globalParameters["PrintTensorB"] = 0 # Print TensorB after initialization
globalParameters["PrintTensorC"] = 0 # Print TensorC. 0x1=after init; 0x2=after copy-back; 0x3=both
globalParameters["PrintTensorD"] = 0 # Print TensorD. 0x1=after init; 0x2=after copy-back; 0x3=both
globalParameters["PrintTensorRef"] = 0 # Print reference tensor. 0x1=after init; 0x2=after copy-back; 0x3=both
globalParameters["PrintTensorBias"] = 0 # Print TensorBias after initialization
globalParameters["PrintTensorAmaxD"] = 0 # Print AmaxD after validation
globalParameters["PrintIndexAssignments"] = 0 # Print the tensor index assignment info
globalParameters["PrintWinnersOnly"] = False # Only print the solutions which become the fastest
globalParameters["PrintCodeCommands"] = False # print the commands used to generate the code objects (asm,link,hip-clang, etc)
globalParameters["DumpTensors"] = False # If True, dump tensors to binary files instead of printing them.
# If PrintMax* is greater than the dimension, the middle elements will be replaced with "..."
# device selection
globalParameters["Platform"] = 0 # select opencl platform
globalParameters["Device"] = 0 # select hip device or opencl device within platform
# shouldn't need to change
globalParameters["DeviceLDS"] = 65536 # LDS bytes per CU, for computing occupancy
globalParameters["MaxLDS"] = 65536 # max LDS a kernel should attempt to use
globalParameters["ShortNames"] = False # on windows kernel names can get too long; =True will convert solution/kernel names to serial ids
globalParameters["MergeFiles"] = True # F=store every solution and kernel in separate file; T=store all solutions in single file
globalParameters["NumMergedFiles"] = 1 # The number of files that kernels should be split between when merging
globalParameters["MaxFileName"] = 64 # If a file name would be longer than this, shorten it with a hash.
globalParameters["SupportedISA"] = [(8,0,3), (9,0,0), (9,0,6), (9,0,8), (9,0,10), (9,4,0), (9,4,1), (9,4,2), (10,1,0), (10,1,1), (10,1,2), (10,3,0), (11,0,0), (11,0,1), (11,0,2), (12,0,0), (12,0,1)] # assembly kernels writer supports these architectures
globalParameters["NewClient"] = 2 # Old client deprecated: NewClient must be set to 2.
globalParameters["ClientBuildPath"] = "0_Build" # subdirectory for host code build directory
globalParameters["BenchmarkProblemsPath"] = "1_BenchmarkProblems" # subdirectory for benchmarking phases
globalParameters["BenchmarkDataPath"] = "2_BenchmarkData" # subdirectory for storing final benchmarking data
globalParameters["LibraryLogicPath"] = "3_LibraryLogic" # subdirectory for library logic produced by analysis
globalParameters["LibraryClientPath"] = "4_LibraryClient" # subdirectory for building example library client
globalParameters["ClientExecutionLockPath"] = None # Path for a file lock to ensure only one client is executed at once. filelock module is required if this is enabled.
globalParameters["LibraryUpdateFile"] = "" # File name for writing indices and speeds suitable for updating an existing library logic file
globalParameters["LibraryUpdateComment"] = False # Include solution name as a comment in the library update file
# internal, i.e., gets set during startup
globalParameters["CurrentISA"] = (0,0,0)
globalParameters["AMDGPUArchPath"] = None # /opt/rocm/llvm/bin/amdgpu-arch
globalParameters["ROCmAgentEnumeratorPath"] = None # /opt/rocm/bin/rocm_agent_enumerator
globalParameters["ROCmSMIPath"] = None # /opt/rocm/bin/rocm-smi
globalParameters["WorkingPath"] = os.getcwd() # path where tensile called from
globalParameters["IndexChars"] = "IJKLMNOPQRSTUVWXYZ" # which characters to use for C[ij]=Sum[k] A[ik]*B[jk]
globalParameters["ScriptPath"] = os.path.dirname(os.path.realpath(__file__)) # path to Tensile/Tensile.py
globalParameters["SourcePath"] = os.path.join(globalParameters["ScriptPath"], "Source") # path to Tensile/Source/
globalParameters["HipClangVersion"] = "0.0.0"
globalParameters["AMDClangVersion"] = "0.0.0"
# default runtime is selected based on operating system, user can override
if os.name == "nt":
globalParameters["RuntimeLanguage"] = "HIP" #"OCL"
else:
globalParameters["RuntimeLanguage"] = "HIP"
globalParameters["CodeObjectVersion"] = "default"
globalParameters["Architecture"] = "all"
# might be deprecated
globalParameters["EnableHalf"] = False
globalParameters["ClientArgs"] = ""
# perf model
globalParameters["PerfModelL2ReadHits"] = 0.0
globalParameters["PerfModelL2WriteHits"] = 0.15
globalParameters["PerfModelL2ReadBwMul"] = 2
globalParameters["PerfModelReadEfficiency"] = 0.85
# limitation for training
globalParameters["MaxWorkspaceSize"] = 128 * 1024 * 1024 # max workspace for training (128MB)
globalParameters["MinKForGSU"] = 32 # min K size to use GlobalSplitU algorithm (only for HPA now)
# control if a solution is run for a given problem
globalParameters["GranularityThreshold"] = 0.0
# directory where custom kernels are located
globalParameters["CustomKernelDirectory"] = os.path.join(os.path.dirname(os.path.realpath(__file__)), "CustomKernels")
globalParameters["PristineOnGPU"] = True # use Pristine memory on Tensile trainning verification or not
globalParameters["SeparateArchitectures"] = False # write Tensile library metadata to separate files for each architecture
globalParameters["LazyLibraryLoading"] = False # Load library and code object files when needed instead of at startup
globalParameters["EnableMarker"] = False # Enable Tensile markers
globalParameters["UseUserArgs"] = False
globalParameters["RotatingBufferSize"] = 0 # Size in MB
globalParameters["RotatingMode"] = 0 # Default is 0, allocated in order A0B0C0D0..ANBNCNDN. 1 is in order A0 pad B0 pad .... AN pad BN pad.
# Mode 0 requires memcpy everytime when the problem changes to reset the data, but mode 1 doesn't.
globalParameters["BuildIdKind"] = "sha1"
globalParameters["ValidateLibrary"] = False
globalParameters["AsmDebug"] = False # Set to True to keep debug information for compiled code objects
globalParameters["UseEffLike"] = True # Set to False to use winnerGFlops as the performance metric
# Save a copy - since pytest doesn't re-run this initialization code and YAML files can override global settings - odd things can happen
defaultGlobalParameters = deepcopy(globalParameters)
# Translate GPU targets to filter filenames in Tensile_LOGIC directory
architectureMap = {
'all':'_','gfx000':'none', 'gfx803':'r9nano', 'gfx900':'vega10',
'gfx906':'vega20', 'gfx906:xnack+':'vega20', 'gfx906:xnack-':'vega20',
'gfx908':'arcturus','gfx908:xnack+':'arcturus', 'gfx908:xnack-':'arcturus',
'gfx90a':'aldebaran', 'gfx90a:xnack+':'aldebaran', 'gfx90a:xnack-':'aldebaran',
'gfx940':'aquavanjaram', 'gfx940:xnack+':'aquavanjaram', 'gfx940:xnack-':'aquavanjaram',
'gfx941':'aquavanjaram', 'gfx941:xnack+':'aquavanjaram', 'gfx941:xnack-':'aquavanjaram',
'gfx942':'aquavanjaram', 'gfx942:xnack+':'aquavanjaram', 'gfx942:xnack-':'aquavanjaram',
'gfx1010':'navi10', 'gfx1011':'navi12', 'gfx1012':'navi14', 'gfx1030':'navi21',
'gfx1100':'navi31', 'gfx1101':'navi32', 'gfx1102':'navi33',
'gfx1200':'gfx1200', 'gfx1201':'gfx1201',
}
def getArchitectureName(gfxName):
if gfxName in architectureMap:
return architectureMap[gfxName]
else:
for archKey in architectureMap:
if gfxName in archKey:
return architectureMap[archKey]
return None
################################################################################
# Tensile internal parameters
################################################################################
# These parameters are not adjustable by the config yamls. They change with the
# generator versions
internalParameters = {
# Each universal kernel will generate one PostGSU(GlobalSplitUPGR) kernel
"GlobalSplitUPGR": 16
}
# These parameters are used in ContractionSolutions for user arguments support.
defaultInternalSupportParams = {
"KernArgsVersion": 2,
# Information about user input internal kernel argument support
# Change this to False if the CustomKernel does not support.
"SupportUserGSU": True,
# This is a little different from GSU because GSU is already a parameter,
# but WGM is not.
"SupportCustomWGM": True,
"SupportCustomStaggerU": True,
# Use GG as G's backend
"UseUniversalArgs": True
}
################################################################################
# Enumerate Valid Solution Parameters
################################################################################
validWorkGroups = []
for numThreads in range(32, 1025, 32):
for nsg in [ 1, 2, 4, 8, 16, 32, 64, 96, 128, 256 ]:
for sg0 in range(1, numThreads//nsg+1):
sg1 = numThreads//nsg//sg0
if sg0*sg1*nsg == numThreads:
workGroup = [sg0, sg1, nsg]
validWorkGroups.append(workGroup)
validThreadTileSides = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + list(range(20, 256, 4))
validThreadTiles = []
for i in validThreadTileSides:
for j in validThreadTileSides:
validThreadTiles.append([i, j])
validActivationFormats = ('NCHW', 'NHWC', 'CNHW', 'NCDHW', 'NDHWC', 'CNDHW')
validWeightFormats = ('KCYX', "KYXC", "CKYX", "CYXK", 'KCZYX', 'CKZYX', 'CZYXK')
validMacroTileSides = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 6, 12, 24, 48, 96, 192, 384, 768 ]
validMacroTiles = []
validISA = [(0,0,0)]
validISA.extend(globalParameters["SupportedISA"])
depthUs = list(range(2,1024+1,1))
for i in validMacroTileSides:
for j in validMacroTileSides:
validMacroTiles.append([i, j])
validMFMA = {}
validMFMA["H"] = [[32,32,4,2], [32,32,8,1], [16,16,4,4], [16,16,16,1], [4,4,4,16]]
validMFMA["S"] = [[32,32,1,2], [32,32,2,1], [16,16,1,4], [16,16,4,1], [4,4,1,16]]
validMFMA["B"] = [[32,32,2,2], [32,32,4,1], [16,16,2,4], [16,16,8,1], [4,4,2,16]]
validMFMA["4xi8"] = [[32,32,4,2], [32,32,8,1], [16,16,4,4], [16,16,16,1], [4,4,4,16], [32,32,16,1], [16,16,32,1]]
validMFMA["D"] = [[16,16,4,1], [4,4,4,4]]
validMFMA["B1k"] = [[32,32,4,2], [32,32,8,1], [16,16,4,4], [16,16,16,1], [4,4,4,16]]
validMFMA["C"] = validMFMA["S"]
validMFMA["Z"] = validMFMA["D"]
validMFMA["I8"] = [[32,32,4,2], [32,32,8,1], [16,16,4,4], [16,16,16,1], [4,4,4,16]] + [[32,32,16,1], [16,16,32,1]]
validMFMA["X"] = [[32,32,4,1], [16,16,8,1]]
validMFMA["F8"] = [[32,32,16,1], [16,16,32,1]]
validMFMA["B8"] = validMFMA["F8"]
validMFMA["F8B8"] = validMFMA["F8"]
validMFMA["B8F8"] = validMFMA["F8"]
validWMMA = [[16,16,16,1], ]
validTT = 32
validMFMA["_format9"] = []
for MFMA in [validMFMA["H"], validMFMA["S"], validMFMA["B"], validMFMA["D"], validMFMA["X"], validMFMA["F8"], validWMMA]:
for MI in MFMA:
for bm in range(int(math.log(MI[3],2))+1):
for tt0 in range(1,validTT+1):
for tt1 in range(1,validTT+1):
for wave_m in range (3):
for wave_n in range(3):
validMFMA["_format9"].append([MI[0],MI[1],MI[2],MI[3],2**bm,tt0,tt1,2**wave_m, 2**wave_n])
validMatrixInstructions = [[], [-1]] + validMFMA["H"] + validMFMA["S"] + validMFMA["B"] + validMFMA["D"] + validMFMA["B1k"] + validMFMA["X"]
validMatrixInstructions = validMatrixInstructions + validMFMA["_format9"]
validSMFMA = {}
validSMFMA["H"] = [[32,32,16,1], [16,16,32,1]]
validSMFMA["B"] = [[32,32,16,1], [16,16,32,1]]
validSMFMA["4xi8"] = [[32,32,32,1], [16,16,64,1]]
validSMFMA["I8"] = validSMFMA["4xi8"]
validSMFMA["F8"] = [[32,32,32,1], [16,16,64,1]]
validSMFMA["B8"] = validSMFMA["F8"]
validSMFMA["F8B8"] = validSMFMA["F8"]
validSMFMA["B8F8"] = validSMFMA["F8"]
validSMFMA["_format9"] = []
for SMFMA in [validSMFMA["H"], validSMFMA["B"], validSMFMA["4xi8"], validSMFMA["F8"]]:
for MI in SMFMA:
for bm in range(int(math.log(MI[3],2))+1):
for tt0 in range(1,validTT+1):
for tt1 in range(1,validTT+1):
for wave_m in range (3):
for wave_n in range(3):
validSMFMA["_format9"].append([MI[0],MI[1],MI[2],MI[3],2**bm,tt0,tt1,2**wave_m, 2**wave_n])
validSparseMatrixInstructions = validSMFMA["H"] + validSMFMA["B"] + validSMFMA["4xi8"]
validMatrixInstructions = validMatrixInstructions + validSparseMatrixInstructions + validSMFMA["_format9"]
# The supported typed GEMM, each entry is (Ti, To, Tc).
# DataType (Ti) = The data-type of the input matrices: A/B
# DestDataType (To) = The data-type of the output matrices: C/D
# ComputeDataType (Tc) = The data-type of computation: alpha/beta:
# Cinternal: basically should == ComputeDataType
# This is used in SolutionStruct.py::checkIfSupportedGEMMType()
validGEMMTypes = [ ('H','H','H'), ('S','S','S'), ('D','D','D'), ('C','C','C'), ('Z','Z','Z'), \
('H','H','S'), ('H','S','S'), \
('B','B','S'), ('B','S','S'), ('B','H','S'), \
('I8','I','I'), ('4xi8','I','I'), ('I8','I8','I'), \
('I8','I','S'), ('I8','I8','S'), ('I8', 'H', 'S'), ('I8', 'B', 'S'), \
('F8','S','S'), ('B8','S','S'), \
('F8B8','S','S'), ('B8F8', 'S', 'S'), \
('F8','H','S'), ('B8','H','S'), \
('F8B8','H','S'), ('B8F8','H','S'), ('B8','B','S'), \
('H','F8','S'), ('F8','B','S'), ('F8B8','B','S'), ('B8F8','B','S'), \
# in/out are both R8
('F8','F8','S'), ('B8','B8','S'), \
('F8B8','B8','S'), ('B8F8', 'B8', 'S'), \
('F8','B8','S'), ('B8','F8','S'), \
('F8B8','F8','S'), ('B8F8', 'F8', 'S') ]
# All HPA types are listed here (HPA=T). The name of the library logic files for these types is:
# *_TiToTc_BH*.yaml where Ti, To, and Tc are the data types of A/B, C/D, and computation, respectively.
# The name of the library logic files for non-HPA (HPA=F) types is: *_TiB*.yaml.
HPATypes = [ ('H','S','S'), ('H','H','S'), ('B','B','S'), ('B','S','S'), ('B','H','S'), ('I8','I','I'), \
('4xi8','I','I'), ('I8','I','S'), ('I8','I8','S'), ('I8', 'H', 'S'), ('I8', 'B', 'S'),\
('F8','S','S'), ('B8','S','S'), ('F8B8','S','S'), ('B8F8', 'S', 'S'), \
('F8','H','S'), ('B8','H','S'), ('F8B8','H','S'), ('B8F8','H','S'), \
('H','F8','S'), ('F8','B','S'), ('F8B8','B','S'), \
# in/out are both R8
('F8','F8','S'), ('B8','B8','S'), ('F8B8','B8','S'), ('B8F8', 'B8', 'S'), \
('F8','B8','S'), ('B8','F8','S'), ('F8B8','F8','S'), ('B8F8', 'F8', 'S') ]
validParameters = {
# 0: Global read is along parallel direction in thread level,
# each load instruction stride whole threads.
# ----> perp
# | [w0, w0, w1,w1,w2,w2,w3,w3, w0, w0, w1,w1,w2,w2,w3,w3]
# | [ t0,t32] [ ] [ t0,t32] [ ]
# para | [ t1,t33] [ wave 1,2,3 ] [ t1,t33] [ wave 1,2,3 ]
# | [ .., ..] [ ] [ .., ..] [ ]
# | [t31,t63] [ ] [t31,t63] [ ]
# V [-load_1] [-load_2]
#
# 1: Each wave load a block of memory,
# each load instruction stride 64 threads.
# ----> perp
# [ w0, w0, w0, w0, w1,w1,w1,w1, w2,w2,w2,w2, w3,w3,w3,w3]
# | [ t0,t32][ t0,t32]
# para | [ t1,t33][ t1,t33]
# | [ .., ..][ .., ..]
# | [t31,t63][t31,t63]
# V [-load_1][-load_2]
#
#
# 2: Each load instruction spread threads evenly in the perp direction
# ----> perp
# | [w0, w1, w2, w3, w0, w1, w2, w3, w0, w1, w2, w3, w0, w1, w2, w3]
# | [t0 ] [t0 ] [t32] [t32]
# para | [t1 ] [t1 ] [t33] [t33]
# | [.. ] [.. ] [.. ] [.. ]
# | [t31] [t31] [t63] [t63]
# V [load_1] [load_2] [load_1] [load_2]
#
"WaveSeparateGlobalReadA": [ 0, 1, 2 ],
"WaveSeparateGlobalReadB": [ 0, 1, 2 ],
# Add an unrolled loop and NGLL loop with swapped GRA and GRB order.
# which may change the tlb thrashing behavior.
"UnrollLoopSwapGlobalReadOrder": [0, 1],
# PrefetchGlobalRead = 1:
# Requires 2X LDS space, and VGPRs for buffering data on way into LDS
# prefetch / double-buffer reads from global memory -> vgprs -> lds.
#
# PrefetchGlobalRead = 2:
# Do another prefetch while writing data from vgpr to lds.
# prefetch / double-buffer reads from global memory -> vgprs --> lds.
# |-> prefetch reads
"PrefetchGlobalRead": [ 0, 1, 2 ],
# number of iteration prefetch local reads from lds to VGPRs buffer = PLR
"PrefetchLocalRead": list(range(128+1)),
# MatrixInstruction Only
# If set ClusterLocalRead, each iteration dedicated vgprBuffer for localRead
# So we can schedule these localReads to the front of the loop
"ClusterLocalRead": [0,1],
# We use double LDS buffer when PrefetchGlobalRead.
# While it reads data from LDS[0]/[1], it prefetch global data and writes to LDS[1]/[0]
# If we can make sure all data are read from LDS to register before writing data to LDS, we can use 1 LDS buffer to save LDS memory.
# this can help to generate Kernel that LDS usage originally exceed MaxLDS if using double LDS buffer,
# or help to increase Occupancy.
# 1 means: Force to use 1 LDS Buffer even with PrefetchGlobalRead
# -1 means: generator will use 1 LDS buffer only when LDS exceed MaxLDS
# Use case:
# SIA2: 1LDSBuffer is set to 1 natively
# SIA3: 1LDSBuffer works only when PGR=True
# TODO: optimize scheduling to support more cases.
"1LDSBuffer": [-1 ,0, 1],
# Split the unroll summation into multiple sections and combine the sections
# GSU applies only to the unroll summation dimension
# Set to 0 to disable GSU, kernel code will be generated without GSU support
"GlobalSplitU": list(range(0, 1024+1)),
# choose how to do GlobalSplitU
# 1: use atomic operation to accumulate on one buffer
# 2: each GSU group write to each own buffer and accumulate by another kernel
# 3: each GSU group write to each own buffer and accumulate by same kernel
"GlobalSplitUAlgorithm": ["SingleBuffer", "MultipleBuffer", "MultipleBufferSingleKernel"],
# don't create a whole copy of the Unroll loop with loads removed - instead
# use buffer limits to suppress global loads and ignore unnecessary ds_reads
"SuppressNoLoadLoop": [False, True],
# For PrefetchGlobalRead=1, create a second copy of the unroll loop with
# the LDS pointer swaps expanded into inline constants for LDS read and write instructions
# This eliminates 4 vector XOR instructions used for pointer swap
"ExpandPointerSwap": [False, True],
# Schedule global reads and global read increments into LocalRead iterations
# Can reduce pressure on local read instruction dispatch queue
# 0=perform global reads at start of instruction loop
# 1=schedule into the local read instruction iterations
"ScheduleGlobalRead": [0, 1],
# Schedule local writes into LocalRead iterations.
# Can reduce pressure on local read instruction dispatch queue
"ScheduleLocalWrite": [0, 1],
# Scheduling algorithm to use for each iteration:
# 0 = minimal/no scheduling. Global Read and increments, followed by local reads,
# followed by local writes, followed by MACs
"ScheduleIterAlg": [0, 1, 2, 3],
# For MatrixInstruction and SIA3, number of GlobalReadInstruction between mfma
# the purpose of this parameter is to control density of global read instruction scheduling
# Scheduling global read back to back can have better memory efficiency
# However, when full of vmem FIFO, it will block other instruction to be issued
# Range from 0.01 to 32
# 0.1 means 1 GR per 10 mfma
# 5 means 5 GR per 1 mfma
"GlobalReadPerMfma": [ i/100 for i in range(1,3200)],
#
# For MatrixInstruction and SIA3, number of LocalWriteInstruction between mfma
# the purpose of this parameter is to control density of local write instruction scheduling
# In PGR1, we want to schedule local write more denser, so we can have more
# latency to hide global read
# In PGR2, since LW is followed by GR, every LW has same whole loop latency
# to hide global read. We want to schedule LW less denser, can
# avoid full of vmem FIFO.
# Range from 0.01 to 32
# 0.1 means 1 LW per 10 mfma
# 5 means 5 LW per 1 mfma
# -1 will derived an optimized value internally
# -2 will derived an optimized value and override LWPM silently (debug only, not recommended)
"LocalWritePerMfma": [ i/100 for i in range(1,3200)] + [ -1 ],
# Interleave alpha scale calculation with beta loads and address calcs - rather
# than as a separate block of instructions
"InterleaveAlpha": [0, 1],
# Create a copy of NoLoadLoop which interleaves the stores with the final mac
# calculation and may perform other optimizations
# 0 = no interleave
# 1 = interleave one stores after required macs have completed execution
# 2 = interleave two stores after required macs have completed execution
"OptNoLoadLoop": [0, 1, 2],
"BufferLoad": [ False, True ],
"BufferStore": [ False, True ],
# Attempt to load directly from global memory into Vgpr.
# Assembly only
"DirectToVgprA": [ False, True ],
"DirectToVgprB": [ False, True ],
"DirectToVgprSparseMetadata": [ False, True ],
# Attempt to load directly from global memory into LDS.
# Assembly only
# Requires BufferLoad, assembler support for lds modifier on buffer
# loads (checked automatically), GlobalVectorWidth=1 (this is hw
# requirement) and A/B must not require any transpose.
# DirectToLds reduces load latency and eliminates the
# G2L registers used to stage data. Also replaces the
# local write offset with an SGPR.
# For an 8x8 TT with PrefetchGlobalRead=1 this can save 33 VGPRs.
# - Requirements for DirectToLds=1:
# GlobalReadVectorWidth = 1/2/4 (GRVW * bpe must be 4 for now)
# TransposeLDS = 1 for TLU=0 case
# DirectToLds support for x1 only for now
"DirectToLds": [ False, True ],
# Load options:
# (GRO = Global Read Offset)
# BufferLoad=0:
# = Use flat instructions with 64 bit GRO for each load
# + supports sizes up to 2^64
# - uses many VGPR for addressing
# - uses execmask+compares for edge detection
# - generates extra LDS traffic (could convert flat->global load)
# BufferLoad=1:
# = Use buffer load instructions with 32-bit offset
# + Less VGPRS (32b offset vs 64-bit) needed for addressing
# + Uses hardware buffer limit for edge detection
# - Limited range - the bot-right corner of macro-tile (plus padding=GRVW
# for shift-pointer, if ShiftPtr is required) must be within 2^32.
# ShiftPtrPad = MayShift ? GRWV*BPE : 0
# For TLU=1: Unroll*StrideA1 + ShiftPtrPad <= 2^32
# For TLU=0: MT*StrideA1 + ShiftPtrPad <= 2^32
# These conditions should be checked using Assert - TODO
# = UseSgprForGRO=1:
# + Attempt to use SGPR for Global Read Offsets.
# + Use one VGPR base GRO + many SGPR GRO rather than many VGPR GRO.
# + Each SGPR stores an offset from base GlobalReadOffset+0.
# - Requirements for UseSgprForGRO=1:
# - BufferLoad=1
# - Use appropriate Assert*ElementMultiple or GRVW=1 to eliminate need for ShifPtr
# (UseSgprForGRO does not support ShiftPtr since ShiftPtr needs to potentially shift GRO)
# = KernelWriterAssembly also supports 64-bit 2D buffer size (see use64bPbcLimit)
# - Requires 4 instructions to move scalar limit and a couple SGPR
# - Enabled by default. If the overhead matters we can add asserts/YAML parm to specialize
# = UseInstOffsetForGRO=1:
# + Attempt to use Instruction offset for Global Read Offsets.
# + This feature avoid updating m0 for subsequent GRO(s) for directToLds feature
# - Requirements for UseInstOffsetForGRO=1:
# - BufferLoad=1
# - DirectToLds=1
# converting m0 update from LocalWriteAddrSGpr using is usually win
# -1 attempt to use a heuristic to determine when the tile size will use too many SGPR and fall back to VGPR
"UseInstOffsetForGRO": [ -1, 0, 1],
# Converting VGPR GRO into SGPR GRO is usually a win
# However, the mode may exhaust all available SGPR, in particular for large unroll
# -1 attempt to use a heuristic to determine when the tile size will use too many SGPR and fall back to VGPR
"UseSgprForGRO": [ -1, 0, 1],
# Use a 64-bit shadow limit register to allow buffers larger than 2^32 bytes
"Use64bShadowLimit": [ True, False],
# Assertion properties
# These provide information or assertions that the problem size meets certain requirements
# for sizes or alignments. The kernel generator can use this information to produce
# a kernel which uses those assertions to produce a faster kernel.
#
# If modifying or adding Assertions also change ProblemProperties class in TensileTypes.h
# Kernel generator will assume that the summation size is some multiple of the element size
# and uses this to optimize the kernel.
# This can result in more efficient kernels, but requires runtime checking to ensure the specified
# summation value meets the requirements.
# (Recommended AF1EM value is 8 for half, 4 for single, 2 for double)
#
# Optimizations enabled by AssertSummationElementMultiple>1:
# - If >=2 for half:
# - Tail loop loads can be vectorized 2X to use dword
# - Enables asm kernels on V20
# - Can use DirectToLds for both unroll and tail loops
# - Tail loop can be unrolled up to InnerUnroll amount if AssertSummationElementMultiple%InnerUnroll==0
#
# 1 indicates no assertion (since all sizes are multiples of 1)
"AssertSummationElementMultiple": [1,2,4,8,16,32,64,128],
# Kernel generator will assume that the FreeIndex[0] size is some multiple of the element size
# and uses this to optimize the kernel.
# FreeIndex[0] is usually letter "I"
# (Recommended AF0EM value is 8 for half, 4 for single, 2 for double)
#
# Optimizations enabled by AssertFree0ElementMultiple>1:
# Load optimizations:
# - For TLU=1 matrix, if AF1WM>=GLVW then can enable UseSgprForGRO
# - Reduces registers used for address calculations
# - Removes address shift/unshift code
# - UseSgprForGRO will only be enabled if all matrices meet assertion requirements.
#
# Store Optimizations:
# - Can vectorize stores in edge tiles. Vector width can be up to AF0EM.
# (since C matrix is always coalesced in Free0 index direction and this assertion guarantees the index element multiple)
#
# 1 indicates no assertion (since all sizes are multiples of 1)
"AssertFree0ElementMultiple" : [1,2,4,8,16],
# Kernel generator will assume that the FreeIndex[1] size is some multiple of the element size
# and uses this to optimize the kernel.
# FreeIndex[1] is usually letter "J"
# (Recommended AF1EM value is 8 for half, 4 for single, 2 for double)
# Optimizations enabled by AssertFree1ElementMultiple>1:
# - See above AssertFree0ElementMultiple "Load optimizations"
# 1 indicates no assertion (since all sizes are multiples of 1)
"AssertFree1ElementMultiple" : [1,2,4,8,16],
# Assertions that require arithmetic intensity to be specified value.
# Arithmetic intensity measures the ratio of computation to memory bandwidth required for a problem.
# These predicates can be used to adjust solution selection compute-bound or memory-bound problems.
"AssertAIGreaterThanEqual": -1,
"AssertAILessThanEqual": -1,
# Stagger the start summation position of the tiles.
# Elements from the summation dimension are loaded at offsets rather than all starting at 0.
# StaggerU is the max 'clicks' of StaggerUStride bytes where each wg starts ; see StaggerUMapping
# for how the specific stagger for a given wg is determined.
#
# The tile assignment C are same as with StaggerOffset=0 ; the difference is the
# order that the summation elements are added.
# GRO will wrap back to the row start when the edge is reached.
#
# This can be effective for TLU=0 style matrices where the K dimension is a large power-of-2.
# In this case the start of each row of the tile is separated by an exact power-of-2
# which causes poor dram, cache, and tlb behavior. V20 has 16 channels each 256 bytes wide.
# StaggerU adjusts the start position in the summation (aka 'U') dimension
# to avoid these conflicts. Both A and B matrix start at the adjusted position.
# If >0 specifies the offset in multiples of the macro-tile "unroll" dim
# - Higher values will spread traffic to more channels but provide less L2 re-use.
# - StaggerU and WorkGroupMapping interact and should be tuned together -
# The WGM controls how tiles are assigned in C matrix, while StaggerU controls where those
# tiles start reading their summation dim parms.
# - StaggerU requires BufferLoad==1 and is silently ignored if BufferLoad==0
"StaggerU": [0,2,4,8,16,32,64],
# Stride in bytes for each staggeru 'click'.
# 256 is recommended since this is the width of memory channel (on gfx803,gfx900,gf906) - so
# each click will start in a new memory channel and spread traffic among the 16 available channels.
# For example StaggerUStride=256 and StaggerU=8 will use 8 unique starting points
# in summation dimension, each offset by 256-bytes - provided the tensor dims are large
# enough to support this.
# StaggerUStride will be internally increased so it is an integer multiple of DepthU*BpeAB.
# (the implementation requires this - the unroll iteration accesses data in steps of
# DepthU*BPE
"StaggerUStride": [-1,16,32,64,128,256,512,1024,2048],
# How the tile assignment (wg0, wg1, wg2) controls the initial StaggerU offset:
# 0: Use wg0
# 1: Use wg1
# 2: Use wg2
# 3: Use wgSerial, wgSerial = wg0 + wg1 * nwg0 + wg2 * (nwg0 * nwg1)
# 4: Debug mode, offset each tile max allowed StaggerU. This just moves hotspot
# to a different bank since all workgroups still start at same point.
"StaggerUMapping": [0,1,2,3,4],
# GSU Workgroup Coalesced Ordering
# False: {(wg0,wg1,wg2,wgn)|(wg0,wg1,wg2,wgn)|...|(wg0,wg1,wg2,wgn)}
# True: {(wg0,wg0,wg0)|(wg1,wg1,wg1)|(wg2,wg2,wg2)|...|(wgn,wgn,wgn)}
"GlobalSplitUCoalesced": [False, True],
# GSU Workgroup Mapping
# False: wg issued order = {(wg0,wg1,wg2,wgn),(wg0,wg1,wg2,wgn)|...|(wg0,wg1,wg2,wgn)}
# -> workgroups do the summation by tile -> slower GR but faster GW
# True: wg issused oder = {(wg0,wg0,wg0)|(wg1,wg1,wg1)|(wg2,wg2,wg2)|...|(wgn,wgn,wgn)}
# -> workgroups split up the summation -> faster GR but slower GW
"GlobalSplitUWorkGroupMappingRoundRobin": [False, True],
# 0=don't use magic div (source only)
# 1=magic div alg #1. Slightly faster but limited range (if magic number is 2^32)
# 2=magic div alg#2. Slightly slower but handles all unsigned ints up to 2^32
"MagicDivAlg": [0,1,2],
# For Block Mapping type:
# 0 : Use hardware-assigned wg number with no remapping.
# N : WG block width. "Wrap" to a new wg1 "row" assignment after N WGs assigned in that row.
# Tensor C always mapped with first free coord as fastest moving
# (Elements in this dimension are sequential in memory.
#
# For 2D nonbatched Matrix this means index order is I, then J
# For 2D batched Matrix this means index order is I, then J, then K.
#
# Then for 2D case:
# - If drawn in row-major format, I is the width and J is the height.
# - WGM determines dimensions of the box used to assign tiles from C
# - WGM is the height of the box (in the J dimension)
# - Given WGM, the box width (in I dim) is determined by number of CUs
# - The box always moves across matrixC in the fastest-moving "I" dim, then
# wraps to next J. TODO - might be useful to change this?
#
# Examples for 2D matrix:
# WGM=8: on CU64 machine this is a square box
# WGM=1: Short/Fat - this will cover maximum width in I dimension of C. This matches hardware assigned mapping.
# WGM=64: Tall/Skinny - this will cover maximum width in J dimension of C.
#
# Formula for wgSerial:
# wgSerial = wg0 + (wg1 % WorkGroupMapping) * nwg0
"WorkGroupMapping": list(range(-1024, 1024+1)), # change a workgroup's id so that the all the workgroups on the gpu at a time are hitting L2 cache the best
"WorkGroupMappingXCC": [1,2,4,8,16,32], # change a workgroup's id so that contiguous workgroup can map on same XCC
# -1 : WorkGroupMappingXCCGroup will be set to CU_count at runtime. Please ensure that (CU_count % WGMXCC == 0).
"WorkGroupMappingXCCGroup": list(range(-1, 1024)), # change a workgroup's id so that contiguous workgroup can map on same XCC, remap workgroup in a group of WGMXCCG.
"MaxOccupancy": list(range(1, 40+1)), # wg / CU; if cache thrashing is hurting performance, this allocates extra lds to artificially limit occupancy
"WorkGroup": validWorkGroups, # ( wg0 x wg1 x LocalSplitU ) dimensions of the workgroup which will operate on a tile and share lds
#ThreadTile: ( tt0 x tt1 ) dimensions of the C tile that each thread works on,
# TT=4 and VW=4 means a thread will work on a tight 4x4 tile of C, where VW=1 means the tile will work on 16 spread out values
# Generally, the VW determines the consecutive a WI will work on, then it will skip ahead SG0*VW elements to get to the next row of VGPR inputs
"ThreadTile": validThreadTiles,
"MacroTile": validMacroTiles, # MT0 = wg0*tt0, MT1 = wg1*tt1
"WavefrontSize": [32, 64],
# MatrixInstruction: (M x N x K x B)
# XDLOPS tile definition, only valid for gfx908, gfx90a
# MxNxKxB specifies matrix instruction variants
# MxNxB determines the shape of the C tile each instruction worked on
# K determines the unroll depth
# If empty, do not use these instructions
#
# Alternative format: (M x N x K x B x MIBlockM x WaveTileM x WaveTileN x WaveM x WaveN)
# (Note: MxN means M-by-N in the following comments)
# MIBlockM determines how many blocks along M dimension for multi-block MI variants. Concrete examples:
# - MI 16x16x1x4 (4-block variant) with MIBlockM=4 -> (16x16)*(4x1)=64x16 tile per instruction executed
# - MI 32x32x1x2 (2-block variant) with MIBlockM=1 -> (32x32)*(1x2)=32x64 tile per instruction executed
# WaveTileM/N are dimensions of the C tile each wave works on, and is close to the concept of ThreadTile in classic VALU kernels
# - WT 4x1 -> each wave executes 4x1 matrix instructions on the C tile of total area (4*MITileM)x(1*MITileN)
# WaveM/N are dimensions of waves spawned for one workgroup where each wave consists of 64 threads
# - Wave2x2 -> a total of 4 waves in one workgroup of shape 2x2
# Putting it all together:
# - [32, 32, 1, 2, 1, 4, 1, 2, 2]
# ^^^^^^^^^^^^ ^ ^^^^ ^^^^
# MatrixInst BlkM WT Wave
# - means (32x64) per MI * (4x1) per wave * (2x2) per workgroup = (32*4*2)x(64*1*2) = 256x128 macro tile
# Tensile will ignore the parameters ThreadTile and WorkGroup when the alternative format is used
"MatrixInstruction": validMatrixInstructions,
# StoreRemap: Optimize MatrixInstruction store patterns to enhance performance.
# MI output data between each threads are along N dims.
# But global memory is along M dim continuous.
# That mean global write between each threads are not continuous.
# Therefore, store performance for MI instruction is poor.
# How StoreRemap works in final store stage:
# 1. Put all thread output data into LDS.
# 2. All thread read data from LDS along M dims.
# (match global Memory continuous direction)
# 3. All thread write out data into global memory.
# 0: Disable StoreRemap (default)
# 1~8: Enable StoreRemap and set the global write vector width
# Suggest optimum value: fp32 = [2,4], fp16 or bf16 = [4,8] (dwordx2 and dowrdx4)
# -1: Use dwordx2 if support SRVW, or set SRVW to 0
"StoreRemapVectorWidth": [-1,0,1,2,4,8],
# SourceSwap: Optimizes MatrixInstruction store pattern by swapping mfma input order.
"SourceSwap": [False, True],
# Following parameters are designed for store scheduling.
# (store stands for load from C (with beta) and store to C/D)
#
# we want to hide store behind unroll loop
# 1. if we can launch 2 WorkGroups per CU (occupancy >= 2, large M/N)
# 2. if there are remaining global memory bandwidth in unroll loop (compute bound kernel)
#
# we can hide store behind the other WG's loop by lowering priority of store
# priority of loop is the same as priority of store
# WG0: ???????????????\__
# |<-- loop --->|<-- store -->|end
#
# WG1: ___________________________/????????????\__
# |<--------- loop ------------------->|<-- store -->|end
#
# priority of loop is higher than priority of store
# WG0: ???????\____________________
# |<-- loop --->|<------ store ----->|end
#
# WG1: _____________/?????\__________________
# |<------- loop -------->|<----- store ---->|end
"StorePriorityOpt": [False, True],
#
# If we issue store in short period of time, kernel will become from compute bound to memory bound
# 0 means issue instructions as many as possible if VGPR available
"NumElementsPerBatchStore": list(range(-1, 256)),
#
# add sync after per batch store in order to store contiguous elements
# add sleep after per batch store in order to distribute store over whole loops
# NOTE: this parameter is highly depends on size_k
# 0 means no sync and sleep
"StoreSyncOpt": list(range(0, 256)),
#
# There are index or address calculation between global instructions.
# issue global instruction b2b has better performance
"GroupLoadStore": [False, True],
# In order to remove the copying from Acc vgpr to Arch vgpr, only use Arch vgprs for v_mfma_xxx.
# Only support for kernel whose totalVgpr counts less than 256 and gcn that has control bit ACC_CD.
"MIArchVgpr": [False, True],
# StreamK (SK) kernels divide work evenly among CUs by splitting along MT and K dimensions.
# Total work units are calculated as (#MTs x #LoopIters) and divided among workgroups.
# In most cases each workgroup will calculate a partial tile that are accumulated in a fixup step in the same kernel
# 0 : Standard data-parallel kernel
# 1 : Basic StreamK
# 2 : Two-Tile StreamK (each WG completes an even number of sk iterations, followed by an even number of dp tiles)
# 3 : Two-Tile StreamK with DP before SK tiles
# StreamK kernels can adjust the number of CUs being used.
# Using fewer sometimes increases overall throughput by allowing other kernels to run in parallel.
# StreamK grid is controlled by setting these enviornment variables:
# TENSILE_STREAMK_FIXED_GRID lets you override the default grid size with a specific number
# 0 = override disabled (default)
# TENSILE_STREAMK_FULL_TILES sets the number of full tiles to be included in stream-k work
# -1 = use prediction model for best performance (not yet implemented)
# 0 = only remainder tiles run in stream-k
# 1+ = remainder + 1 (or more) full grids of tiles run in stream-k (default=1)
# TENSILE_STREAMK_DYNAMIC_GRID selects dynamic grid mode, which automatically limits the number of CUs used:
# 0 = Off, always use all CUs.
# 1 = Only reduce CUs for small problems to number of output tiles when num_tiles < CU count.
# 2 = Also reduce CUs used for large sizes to improve data-parallel portion and reduce power.
# 3 = Analytically predict the best grid-size by weighing the cost of the fix-up step and the cost of processing MACs (default).
# Note: dynamic grid coefficients currently apply to gfx942 variants
# TENSILE_STREAMK_MAX_CUS allows the user to manually set maximum number of CUs used, which could free up some CUs for
# other operations to run in parallel with gemm.
# TENSILE_STREAMK_GRID_MULTIPLIER lets you set how many workgroups are created per CU being used.
# 1 = 1 WG per CU (default), for example. 2 will launch WGs = 2 x CU count.
# The priority of these environment variables is defined as follows:
# TENSILE_STREAMK_FIXED_GRID > TENSILE_STREAMK_DYNAMIC_GRID > TENSILE_STREAMK_MAX_CUS > TENSILE_STREAMK_GRID_MULTIPLIER
"StreamK": [0, 1, 2, 3],
# Determines if StreamK kernel uses atomics
# 0: uses workspace to store partial tiles, accumulate in deterministic fix-up step
# 1: uses atomics to accumulate partial tiles
"StreamKAtomic": [0, 1],
# Enables XCC-based remapping of workgroups, set the value to the number of XCCs
# for the device/configuration being used
# 0: uses default workgroup assignment
# 2+: remaps workgroups to be contiguous within an XCC for a given number of XCCs
"StreamKXCCMapping": [0] + list(range(2, 9)),
# Debug settings for stream-k kernels to disable parts of the kernel
# Bit 0: Don't generate fixup code
# Bit 1: Don't generate write to partials code
# Both parts can be disabled together
# 0 = Debug mode off, generate full kernel
# 1 = No fixup
# 2 = No partials
# 3 = Nofixup and no partials
"DebugStreamK": [0, 1, 2, 3],
# Controls desired width (#elements) for loads from global memory -> LDS.
# and eliminates the pointer unshift logic
# -1 : Set GlobalReadVectorWidth = VectorWidth
# NOTE: for input bpe=32, max GRVW is 4 (to fit dwordx4) (FP32), min GRVW is 1 (dword)
# bpe=16, max GRVW is 8 (to fit dwordx4) (FP16), min GRVW is 2 (dword)
# bpe=8, max GRVW is 16 (to fit dwordx4) (INT8), min GRVW is 4 (dword)
"GlobalReadVectorWidthA": [ -2, -1, 1, 2, 3, 4, 6, 8, 16 ],
"GlobalReadVectorWidthB": [ -2, -1, 1, 2, 3, 4, 6, 8, 16 ],
# Controls desired width (#elements) for loads from LDS -> VGPR.
# -1 : Set LocalReadVectorWidth = VectorWidth
# 1 cannot be used for half type.
# used in combination with TransposeLDS=True
# in TransposeLDS=1 case, use wider load to fetch elements in summation dimension from LDS
# helps optimizing instruction scheduling between MFMA and nonMFMA instructions
# NOTE: for input bpe=32, max LRVW is 4 (to fit ds_read_b128) (FP32)
# bpe=16, max LRVW is 8 (to fit ds_read_b128) (FP16)
# bpe=8, max LRVW is 16 (to fit ds_read_b128) (INT8)
"LocalReadVectorWidth": [ -1, 1, 2, 4, 8, 16 ],
# threads should read/write/operate on this many contiguous elements from the C matrix.
# If VW=4 then thread0 will process 4 consec C elements, then thread1 next 4, etc.
# If the ThreadTile is > VectorWidth then thread0 will next operate on the 4 elements in C at (4*NumThreads)
# Typically the load vector width and store vector width are directly related to the VW.
# The global load width is closely related to the width of local stores so
# GlobalReadVectorWidth also controls local write width.
# Local read width also matches since VectorWidth consec elements must be read
# Typically matching 16 bytes is good choice since the stores will be optimally coalesced with 16 bytes/WI.
# Using a VW too large which results in >16bytes/thread isn't supported