You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

manifest.py 11 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #
  2. # \file generator.py
  3. #
  4. # \brief Generates the CUTLASS Library's instances
  5. #
  6. import enum
  7. import os.path
  8. import shutil
  9. from lazy_file import LazyFile
  10. from library import *
  11. from gemm_operation import *
  12. from conv2d_operation import *
  13. ###################################################################################################
  14. class EmitOperationKindLibrary:
  15. def __init__(self, generated_path, kind, args):
  16. self.generated_path = generated_path
  17. self.kind = kind
  18. self.args = args
  19. self.emitters = {
  20. OperationKind.Gemm: EmitGemmConfigurationLibrary
  21. , OperationKind.Conv2d: EmitConv2dConfigurationLibrary
  22. }
  23. self.configurations = [];
  24. self.header_template ="""
  25. /*
  26. Generated by manifest.py - Do not edit.
  27. */
  28. #include "cutlass/cutlass.h"
  29. #include "cutlass/library/library.h"
  30. #include "cutlass/library/manifest.h"
  31. namespace cutlass {
  32. namespace library {
  33. ///////////////////////////////////////////////////////////////////////////////////////////////////
  34. """
  35. self.entry_template = """
  36. //
  37. // Entry point to construct operations
  38. //
  39. void initialize_all_${operation_name}_operations(Manifest &manifest) {
  40. """
  41. self.configuration_prototype_template = "void initialize_${configuration_name}(Manifest &manifest);\n"
  42. self.configuration_template =" initialize_${configuration_name}(manifest);\n"
  43. self.epilogue_template ="""
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////////////////////////
  46. } // namespace library
  47. } // namespace cutlass
  48. """
  49. #
  50. def __enter__(self):
  51. self.operation_path = os.path.join(self.generated_path, OperationKindNames[self.kind])
  52. os.mkdir(self.operation_path)
  53. self.top_level_path = os.path.join(self.operation_path, "all_%s_operations.cu" % OperationKindNames[self.kind])
  54. self.top_level_file = open(self.top_level_path, "w")
  55. self.top_level_file.write(self.header_template)
  56. self.source_files = [self.top_level_path,]
  57. return self
  58. #
  59. def emit(self, configuration_name, operations):
  60. with self.emitters[self.kind](self.operation_path, configuration_name) as configuration_emitter:
  61. for operation in operations:
  62. configuration_emitter.emit(operation)
  63. self.source_files.append(configuration_emitter.configuration_path)
  64. self.configurations.append(configuration_name)
  65. self.top_level_file.write(SubstituteTemplate(self.configuration_prototype_template, {'configuration_name': configuration_name} ))
  66. #
  67. def __exit__(self, exception_type, exception_value, traceback):
  68. self.top_level_file.write(SubstituteTemplate(self.entry_template, {'operation_name': OperationKindNames[self.kind]}))
  69. for configuration_name in self.configurations:
  70. self.top_level_file.write(SubstituteTemplate(self.configuration_template, {'configuration_name': configuration_name}))
  71. self.top_level_file.write(self.epilogue_template)
  72. self.top_level_file.close()
  73. ###################################################################################################
  74. ###################################################################################################
  75. class Options:
  76. def __init__(self):
  77. pass
  78. ###################################################################################################
  79. #
  80. class Manifest:
  81. #
  82. def __init__(self, args):
  83. self.operations = {}
  84. self.args = args
  85. architectures = args.architectures.split(';') if len(args.architectures) else ['50',]
  86. self.compute_capabilities = [int(x) for x in architectures]
  87. self.selected_kernels = []
  88. if args.operations == 'all':
  89. self.operations_enabled = []
  90. else:
  91. operations_list = [
  92. OperationKind.Gemm
  93. , OperationKind.Conv2d
  94. ]
  95. self.operations_enabled = [x for x in operations_list if OperationKindNames[x] in args.operations.split(',')]
  96. if args.kernels == 'all':
  97. self.kernel_names = []
  98. else:
  99. self.kernel_names = [x for x in args.kernels.split(',') if x != '']
  100. self.ignore_kernel_names = [x for x in args.ignore_kernels.split(',') if x != '']
  101. if args.kernel_filter_file is None:
  102. self.kernel_filter_list = []
  103. else:
  104. self.kernel_filter_list = self.get_kernel_filters(args.kernel_filter_file)
  105. self.operation_count = 0
  106. self.operations_by_name = {}
  107. self.top_level_prologue = '''
  108. #include "cutlass/library/library.h"
  109. #include "cutlass/library/manifest.h"
  110. namespace cutlass {
  111. namespace library {
  112. ${prototypes}
  113. void initialize_all(Manifest &manifest) {
  114. '''
  115. self.top_level_reserve = ' manifest.reserve(${operation_count});\n\n'
  116. self.top_level_epilogue = '''
  117. }
  118. } // namespace library
  119. } // namespace cutlass
  120. '''
  121. def get_kernel_filters (self, kernelListFile):
  122. if os.path.isfile(kernelListFile):
  123. with open(kernelListFile, 'r') as fileReader:
  124. lines = [line.rstrip() for line in fileReader if not line.startswith("#")]
  125. lines = [re.compile(line) for line in lines if line]
  126. return lines
  127. else:
  128. return []
  129. def filter_out_kernels(self, kernel_name, kernel_filter_list):
  130. for kernel_filter_re in kernel_filter_list:
  131. if kernel_filter_re.search(kernel_name) is not None:
  132. return True
  133. return False
  134. #
  135. def _filter_string_matches(self, filter_string, haystack):
  136. ''' Returns true if all substrings appear in the haystack in order'''
  137. substrings = filter_string.split('*')
  138. for sub in substrings:
  139. idx = haystack.find(sub)
  140. if idx < 0:
  141. return False
  142. haystack = haystack[idx + len(sub):]
  143. return True
  144. #
  145. def filter(self, operation):
  146. ''' Filtering operations based on various criteria'''
  147. # filter based on compute capability
  148. enabled = False
  149. for cc in self.compute_capabilities:
  150. if cc >= operation.tile_description.minimum_compute_capability and \
  151. cc <= operation.tile_description.maximum_compute_capability:
  152. enabled = True
  153. break
  154. if not enabled:
  155. return False
  156. if len(self.operations_enabled) and not operation.operation_kind in self.operations_enabled:
  157. return False
  158. # eliminate duplicates
  159. if operation.procedural_name() in self.operations_by_name.keys():
  160. return False
  161. # Filter based on list of valid substrings
  162. if len(self.kernel_names):
  163. name = operation.procedural_name()
  164. enabled = False
  165. # compare against the include list
  166. for name_substr in self.kernel_names:
  167. if self._filter_string_matches(name_substr, name):
  168. enabled = True
  169. break
  170. # compare against the exclude list
  171. for name_substr in self.ignore_kernel_names:
  172. if self._filter_string_matches(name_substr, name):
  173. enabled = False
  174. break
  175. if len(self.kernel_filter_list) > 0:
  176. enabled = False
  177. if self.filter_out_kernels(operation.procedural_name(), self.kernel_filter_list):
  178. enabled = True
  179. # todo: filter based on compute data type
  180. return enabled
  181. #
  182. #
  183. def append(self, operation):
  184. '''
  185. Inserts the operation.
  186. operation_kind -> configuration_name -> []
  187. '''
  188. if self.filter(operation):
  189. self.selected_kernels.append(operation.procedural_name())
  190. self.operations_by_name[operation.procedural_name()] = operation
  191. # add the configuration
  192. configuration_name = operation.configuration_name()
  193. if operation.operation_kind not in self.operations.keys():
  194. self.operations[operation.operation_kind] = {}
  195. if configuration_name not in self.operations[operation.operation_kind].keys():
  196. self.operations[operation.operation_kind][configuration_name] = []
  197. self.operations[operation.operation_kind][configuration_name].append(operation)
  198. self.operation_count += 1
  199. #
  200. #
  201. def emit(self, target = GeneratorTarget.Library):
  202. operation_emitters = {
  203. GeneratorTarget.Library: EmitOperationKindLibrary
  204. }
  205. generated_path = os.path.join(self.args.curr_build_dir, 'generated')
  206. # create generated/
  207. if os.path.exists(generated_path):
  208. shutil.rmtree(generated_path)
  209. os.mkdir(generated_path)
  210. source_files = []
  211. top_level_path = os.path.join(generated_path, 'initialize_all.cpp')
  212. with open(top_level_path, 'w') as top_level_file:
  213. if target == GeneratorTarget.Library:
  214. source_files.append(top_level_path)
  215. prototypes = []
  216. for operation_kind, configurations in self.operations.items():
  217. prototypes.append(SubstituteTemplate(
  218. "void initialize_all_${operation_kind}_operations(Manifest &manifest);",
  219. {'operation_kind': OperationKindNames[operation_kind]}))
  220. top_level_file.write(SubstituteTemplate(self.top_level_prologue,
  221. {'prototypes': "\n".join(prototypes)}))
  222. top_level_file.write(SubstituteTemplate(
  223. self.top_level_reserve, {'operation_count': str(self.operation_count)}))
  224. # for each operation kind, emit initializer for all configurations
  225. for operation_kind, configurations in self.operations.items():
  226. with operation_emitters[target](generated_path, operation_kind, self.args) as operation_kind_emitter:
  227. for configuration_name, operations in configurations.items():
  228. operation_kind_emitter.emit(configuration_name, operations)
  229. source_files += operation_kind_emitter.source_files
  230. top_level_file.write(SubstituteTemplate(
  231. " initialize_all_${operation_kind}_operations(manifest);\n",
  232. {'operation_kind': OperationKindNames[operation_kind]}))
  233. top_level_file.write(self.top_level_epilogue)
  234. # write the manifest.cmake file containing paths from all targets
  235. manifest_path = os.path.join(generated_path, "manifest.cmake")
  236. with open(manifest_path, "w") as manifest_file:
  237. target_name = 'cutlass_library_objs'
  238. target_text = SubstituteTemplate("""cutlass_target_sources(
  239. ${target_name}
  240. BATCH_SOURCES ON
  241. PRIVATE
  242. """, { 'target_name': target_name})
  243. manifest_file.write(target_text)
  244. for source_file in source_files:
  245. manifest_file.write(" %s\n" % str(source_file.replace('\\', '/')))
  246. manifest_file.write(")")
  247. #
  248. ###################################################################################################
  249. def GenerateManifest(args, operations, output_dir):
  250. manifest_path = os.path.join(output_dir, "all_%s_%s_operations.cu" % (args.operations, args.type))
  251. f = LazyFile(manifest_path)
  252. f.write("""
  253. /*
  254. Generated by generator.py - Do not edit.
  255. */
  256. #if __CUDACC_VER_MAJOR__ > 9 || (__CUDACC_VER_MAJOR__ == 9 && __CUDACC_VER_MINOR__ >= 2)
  257. #include "cutlass/cutlass.h"
  258. #include "src/cuda/cutlass/library.h"
  259. #include "src/cuda/cutlass/manifest.h"
  260. namespace cutlass {
  261. namespace library {
  262. """)
  263. for op in operations:
  264. f.write("void initialize_%s(Manifest &manifest);\n" % op.procedural_name())
  265. f.write("""
  266. void initialize_all_%s_%s_operations(Manifest &manifest) {
  267. """ % (args.operations, args.type))
  268. for op in operations:
  269. f.write(" initialize_%s(manifest);\n" % op.procedural_name())
  270. f.write("""
  271. }
  272. } // namespace library
  273. } // namespace cutlass
  274. #endif
  275. """)
  276. f.close()

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台