causal_conv1d.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. # SPDX-License-Identifier: Apache-2.0
  2. # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
  3. # Copyright (c) 2024, Tri Dao.
  4. # Adapted from https://github.com/Dao-AILab/causal-conv1d/blob/main/causal_conv1d/causal_conv1d_interface.py
  5. import numpy as np
  6. import torch
  7. from vllm.platforms import current_platform
  8. from vllm.triton_utils import tl, triton
  9. from vllm.v1.attention.backends.utils import NULL_BLOCK_ID, PAD_SLOT_ID
  10. @triton.jit(do_not_specialize_on_alignment=["num_cache_lines"])
  11. def _causal_conv1d_fwd_kernel( # continuous batching
  12. # Pointers to matrices
  13. x_ptr, # (dim, cu_seqlen) holding `batch` of actual sequences + padded sequences
  14. w_ptr, # (dim, width)
  15. bias_ptr,
  16. initial_states_ptr, # conv_states_ptr
  17. cache_indices_ptr, # (batch, n_blocks + padding) The second dimension contains
  18. # the block indices relevant for each sequence
  19. # plus potential 0-padding at the beginning and at the end
  20. has_initial_states_ptr,
  21. query_start_loc_ptr,
  22. batch_ptr,
  23. token_chunk_offset_ptr,
  24. block_idx_first_scheduled_token, # (batch,)
  25. block_idx_last_scheduled_token, # (batch,)
  26. initial_state_idx, # (batch,)
  27. num_computed_tokens, # (batch,)
  28. o_ptr, # (dim, seqlen) - actually pointing to x_ptr
  29. # Matrix dimensions
  30. dim: tl.constexpr,
  31. num_cache_lines, # added to support vLLM larger cache lines
  32. # Strides
  33. stride_x_dim: tl.constexpr, # stride to get to next feature-value,
  34. stride_x_token: tl.int64, # stride to get to next token (same feature-index, same sequence-index)
  35. stride_w_dim: tl.constexpr, # stride to get to next dim-axis value
  36. stride_w_width: tl.constexpr, # stride to get to next width-axis value
  37. stride_istate_seq: tl.constexpr,
  38. stride_istate_dim: tl.constexpr,
  39. stride_istate_token: tl.constexpr,
  40. stride_cache_indices: tl.constexpr,
  41. stride_o_dim: tl.constexpr,
  42. stride_o_token: tl.int64,
  43. stride_o_group: tl.int64, # with OUT_GROUP: stride between groups of OUT_GROUP features
  44. stride_block_m: tl.constexpr, # Stride block to align divided by BLOCK_M
  45. # others
  46. pad_slot_id: tl.constexpr,
  47. null_block_id: tl.constexpr,
  48. # Meta-parameters
  49. HAS_BIAS: tl.constexpr,
  50. KERNEL_WIDTH: tl.constexpr,
  51. SILU_ACTIVATION: tl.constexpr,
  52. IS_APC_ENABLED: tl.constexpr,
  53. HAS_NULL_BLOCK: tl.constexpr,
  54. NP2_STATELEN: tl.constexpr,
  55. OUT_GROUP: tl.constexpr,
  56. BLOCK_M: tl.constexpr,
  57. BLOCK_N: tl.constexpr,
  58. launch_pdl: tl.constexpr,
  59. ):
  60. conv_states_ptr = initial_states_ptr
  61. conv_state_indices_ptr = cache_indices_ptr
  62. stride_conv_state_seq = stride_istate_seq
  63. stride_conv_state_dim = stride_istate_dim
  64. stride_conv_state_tok = stride_istate_token
  65. state_len = (
  66. KERNEL_WIDTH - 1
  67. ) # can be passed via argument if it's not the same as this value
  68. if launch_pdl:
  69. tl.extra.cuda.gdc_wait()
  70. # one program handles one chunk in a single sequence
  71. # rather than mixing sequences - to make updating initial_states across sequences efficiently
  72. # single-sequence id
  73. idx_seq = tl.load(batch_ptr + tl.program_id(0)).to(tl.int64)
  74. chunk_offset = tl.load(token_chunk_offset_ptr + tl.program_id(0))
  75. # BLOCK_N elements along the feature-dimension (channel)
  76. idx_feats = tl.program_id(1) * BLOCK_N + tl.arange(0, BLOCK_N)
  77. if idx_seq == pad_slot_id:
  78. if launch_pdl:
  79. tl.extra.cuda.gdc_launch_dependents()
  80. return
  81. sequence_start_index = tl.load(query_start_loc_ptr + idx_seq)
  82. sequence_end_index = tl.load(query_start_loc_ptr + idx_seq + 1)
  83. # find the actual sequence length
  84. seqlen = sequence_end_index - sequence_start_index
  85. B_size: tl.constexpr = stride_block_m * BLOCK_M
  86. if IS_APC_ENABLED:
  87. # Handle the case if prefix caching is enabled.
  88. # In particular, if prefix caching is enabled, the program write additional cache states to "cache_indices_ptr"
  89. # Get the length of the completed sequence so far and compute the offset.
  90. current_first_index = tl.load(block_idx_first_scheduled_token + idx_seq)
  91. current_last_index = tl.load(block_idx_last_scheduled_token + idx_seq)
  92. sequence_completed_index = tl.load(num_computed_tokens + idx_seq)
  93. # Compute the offset where the first stride_block_m-aligned first full block is
  94. # Value in "token-space"
  95. sequence_completed_offset_token = sequence_completed_index % B_size
  96. seq_completed_offset = B_size - sequence_completed_offset_token
  97. seq_end_offset = (seqlen - seq_completed_offset) % B_size
  98. last_full_block_token_index = sequence_end_index - seq_end_offset
  99. # If the sequence without the sequence_offset_index is stride_cache_chunk-aligned, then the last full chunk is the second-to-last one
  100. if seq_end_offset == 0:
  101. last_full_block_token_index = last_full_block_token_index - B_size
  102. # Get the number of blocks to be filled for the current sequence
  103. # If n_block_to_fill = 0, then only the state at the sequence end is stored
  104. n_block_to_fill = current_last_index - current_first_index
  105. # Get the index of the init block
  106. conv_state_init_index = tl.load(initial_state_idx + idx_seq)
  107. else:
  108. n_block_to_fill = 0
  109. current_last_index = 0
  110. conv_state_init_index = 0
  111. current_first_index = 0
  112. last_full_block_token_index = 0
  113. token_offset = BLOCK_M * chunk_offset
  114. segment_len = min(BLOCK_M, seqlen - token_offset)
  115. # base of the sequence
  116. x_base = (
  117. x_ptr + sequence_start_index * stride_x_token + idx_feats * stride_x_dim
  118. ) # [BLOCK_N,]
  119. # cache_idx
  120. conv_states_input_coord = tl.load(
  121. conv_state_indices_ptr + idx_seq * stride_cache_indices + conv_state_init_index
  122. ).to(tl.int64)
  123. if HAS_NULL_BLOCK: # noqa
  124. if conv_states_input_coord == null_block_id:
  125. # not processing as this is a null block (padding)
  126. if launch_pdl:
  127. tl.extra.cuda.gdc_launch_dependents()
  128. return
  129. conv_states_base = (
  130. conv_states_ptr
  131. + (conv_states_input_coord * stride_conv_state_seq)
  132. + (idx_feats * stride_conv_state_dim)
  133. ) # [BLOCK_N,]
  134. w_base = w_ptr + (idx_feats * stride_w_dim) # [BLOCK_N,]
  135. # Does 2 things:
  136. # 1. READ prior-block init-state data - [done by every Triton programs]
  137. # 2. update conv_state with new data [only by the Triton program handles chunk_offset=0]
  138. if chunk_offset == 0:
  139. # read from conv_states
  140. load_init_state = tl.load(has_initial_states_ptr + idx_seq).to(tl.int1)
  141. if load_init_state:
  142. # load from conv_states
  143. prior_tokens = conv_states_base + (state_len - 1) * stride_conv_state_tok
  144. mask_w = idx_feats < dim
  145. if KERNEL_WIDTH == 2:
  146. conv_states_ptrs = prior_tokens # [BLOCK_N]
  147. col0 = tl.load(conv_states_ptrs, mask_w, 0.0)
  148. if KERNEL_WIDTH == 3:
  149. conv_states_ptrs = prior_tokens # [BLOCK_N]
  150. col1 = tl.load(conv_states_ptrs, mask_w, 0.0)
  151. conv_states_ptrs = prior_tokens - 1 * stride_conv_state_tok # [BLOCK_N]
  152. col0 = tl.load(conv_states_ptrs, mask_w, 0.0)
  153. if KERNEL_WIDTH == 4:
  154. conv_states_ptrs = prior_tokens # [BLOCK_N]
  155. col2 = tl.load(conv_states_ptrs, mask_w, 0.0)
  156. conv_states_ptrs = prior_tokens - 1 * stride_conv_state_tok # [BLOCK_N]
  157. col1 = tl.load(conv_states_ptrs, mask_w, 0.0)
  158. conv_states_ptrs = prior_tokens - 2 * stride_conv_state_tok # [BLOCK_N]
  159. col0 = tl.load(conv_states_ptrs, mask_w, 0.0)
  160. if KERNEL_WIDTH == 5:
  161. conv_states_ptrs = prior_tokens # [BLOCK_N]
  162. col3 = tl.load(conv_states_ptrs, mask_w, 0.0)
  163. conv_states_ptrs = prior_tokens - 1 * stride_conv_state_tok # [BLOCK_N]
  164. col2 = tl.load(conv_states_ptrs, mask_w, 0.0)
  165. conv_states_ptrs = prior_tokens - 2 * stride_conv_state_tok # [BLOCK_N]
  166. col1 = tl.load(conv_states_ptrs, mask_w, 0.0)
  167. conv_states_ptrs = prior_tokens - 3 * stride_conv_state_tok # [BLOCK_N]
  168. col0 = tl.load(conv_states_ptrs, mask_w, 0.0)
  169. else:
  170. # prior-tokens are zeros
  171. if KERNEL_WIDTH >= 2: # STRATEGY1
  172. # first chunk and does not have prior-token, so just set to 0
  173. col0 = tl.zeros((BLOCK_N,), dtype=x_ptr.dtype.element_ty)
  174. if KERNEL_WIDTH >= 3: # STRATEGY1
  175. col1 = tl.zeros((BLOCK_N,), dtype=x_ptr.dtype.element_ty)
  176. if KERNEL_WIDTH >= 4: # STRATEGY1
  177. col2 = tl.zeros((BLOCK_N,), dtype=x_ptr.dtype.element_ty)
  178. if KERNEL_WIDTH >= 5: # STRATEGY1
  179. col3 = tl.zeros((BLOCK_N,), dtype=x_ptr.dtype.element_ty)
  180. # STEP 2:
  181. # here prepare data for updating conv_state
  182. if (
  183. state_len <= seqlen
  184. ): # SMALL_CACHE=True (only move part of 'x' into conv_state cache)
  185. # just read from 'x'
  186. # copy 'x' data to conv_state
  187. # load only 'x' data (and set 0 before 'x' if seqlen < state_len)
  188. idx_tokens_last = (seqlen - state_len) + tl.arange(
  189. 0, NP2_STATELEN
  190. ) # [BLOCK_M]
  191. x_ptrs = (
  192. x_ptr
  193. + ((sequence_start_index + idx_tokens_last) * stride_x_token)[:, None]
  194. + (idx_feats * stride_x_dim)[None, :]
  195. ) # [BLOCK_M,BLOCK_N,]
  196. mask_x = (
  197. (idx_tokens_last >= 0)[:, None]
  198. & (idx_tokens_last < seqlen)[:, None]
  199. & (idx_feats < dim)[None, :]
  200. ) # token-index # token-index # feature-index
  201. loaded_x = tl.load(x_ptrs, mask_x, 0.0)
  202. idx_tokens_conv = tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  203. # Compute the offset where the last block should be written in the conv_states
  204. conv_states_output_coord = tl.load(
  205. conv_state_indices_ptr
  206. + idx_seq * stride_cache_indices
  207. + current_last_index
  208. ).to(tl.int64)
  209. conv_states_ptrs_target = (
  210. conv_states_ptr
  211. + (conv_states_output_coord * stride_conv_state_seq) # Offset from seq
  212. + (idx_feats * stride_conv_state_dim)
  213. )[None, :] + ( # [BLOCK_N,]
  214. idx_tokens_conv * stride_conv_state_tok
  215. )[:, None]
  216. mask = (idx_tokens_conv < state_len)[:, None] & (idx_feats < dim)[None, :]
  217. tl.debug_barrier() # NOTE: use this due to bug in Triton compiler
  218. tl.store(conv_states_ptrs_target, loaded_x, mask)
  219. else:
  220. if load_init_state:
  221. # update conv_state by shifting left, i.e. take last few cols from conv_state + cols from 'x'
  222. idx_tokens_conv = tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  223. conv_states_ptrs_source = (
  224. conv_states_ptr
  225. + (conv_states_input_coord * stride_conv_state_seq)
  226. + (idx_feats * stride_conv_state_dim)[None, :]
  227. + ((idx_tokens_conv + seqlen) * stride_conv_state_tok)[:, None]
  228. ) # [BLOCK_M, BLOCK_N]
  229. mask = (
  230. (conv_states_input_coord < num_cache_lines)
  231. & ((idx_tokens_conv + seqlen) < state_len)[:, None]
  232. & (idx_feats < dim)[None, :]
  233. )
  234. conv_state = tl.load(conv_states_ptrs_source, mask, other=0.0)
  235. VAL = state_len - seqlen
  236. x_ptrs = (
  237. x_base[None, :]
  238. + ((idx_tokens_conv - VAL) * stride_x_token)[:, None]
  239. ) # [BLOCK_M, BLOCK_N]
  240. mask_x = (
  241. (idx_tokens_conv - VAL >= 0)[:, None]
  242. & (idx_tokens_conv - VAL < seqlen)[:, None]
  243. & (idx_feats < dim)[None, :]
  244. ) # token-index # token-index # feature-index
  245. loaded_x = tl.load(x_ptrs, mask_x, 0.0)
  246. tl.debug_barrier() # need this due to the bug in tl.where not enforcing this when data is the result of another tl.load
  247. new_conv_state = tl.where(
  248. mask, conv_state, loaded_x
  249. ) # BUG in 'tl.where' which requires a barrier before this
  250. conv_states_ptrs_target = (
  251. conv_states_base
  252. + (idx_tokens_conv * stride_conv_state_tok)[:, None]
  253. ) # [BLOCK_M, BLOCK_N]
  254. mask = (idx_tokens_conv < state_len)[:, None] & (idx_feats < dim)[
  255. None, :
  256. ]
  257. tl.store(conv_states_ptrs_target, new_conv_state, mask)
  258. else: # load_init_state == False
  259. # update conv_state by shifting left, BUT
  260. # set cols prior to 'x' as zeros + cols from 'x'
  261. idx_tokens_conv = tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  262. VAL = state_len - seqlen
  263. x_ptrs = (
  264. x_base[None, :]
  265. + ((idx_tokens_conv - VAL) * stride_x_token)[:, None]
  266. ) # [BLOCK_M, BLOCK_N]
  267. mask_x = (
  268. (idx_tokens_conv - VAL >= 0)[:, None]
  269. & (idx_tokens_conv - VAL < seqlen)[:, None]
  270. & (idx_feats < dim)[None, :]
  271. ) # token-index # token-index # feature-index
  272. new_conv_state = tl.load(x_ptrs, mask_x, 0.0)
  273. conv_states_ptrs_target = (
  274. conv_states_base
  275. + (idx_tokens_conv * stride_conv_state_tok)[:, None]
  276. ) # [BLOCK_M, BLOCK_N]
  277. mask = (idx_tokens_conv < state_len)[:, None] & (idx_feats < dim)[
  278. None, :
  279. ]
  280. tl.store(conv_states_ptrs_target, new_conv_state, mask)
  281. else: # chunk_offset > 0
  282. # read prior-token data from `x`
  283. load_init_state = True
  284. prior_tokens = x_base + (token_offset - 1) * stride_x_token
  285. mask_w = idx_feats < dim
  286. if KERNEL_WIDTH == 2:
  287. conv_states_ptrs = prior_tokens # [BLOCK_N]
  288. col0 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  289. if KERNEL_WIDTH == 3:
  290. conv_states_ptrs = prior_tokens # [BLOCK_N]
  291. col1 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  292. conv_states_ptrs = prior_tokens - 1 * stride_x_token # [BLOCK_N]
  293. col0 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  294. if KERNEL_WIDTH == 4:
  295. conv_states_ptrs = prior_tokens # [BLOCK_N]
  296. col2 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  297. conv_states_ptrs = prior_tokens - 1 * stride_x_token # [BLOCK_N]
  298. col1 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  299. conv_states_ptrs = prior_tokens - 2 * stride_x_token # [BLOCK_N]
  300. col0 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  301. if KERNEL_WIDTH == 5:
  302. # ruff: noqa: F841
  303. conv_states_ptrs = prior_tokens # [BLOCK_N]
  304. col3 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  305. conv_states_ptrs = prior_tokens - 1 * stride_x_token # [BLOCK_N]
  306. col2 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  307. conv_states_ptrs = prior_tokens - 2 * stride_x_token # [BLOCK_N]
  308. col1 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  309. conv_states_ptrs = prior_tokens - 3 * stride_x_token # [BLOCK_N]
  310. col0 = tl.load(conv_states_ptrs, mask_w, 0.0, cache_modifier=".ca")
  311. # Store intermediate states aligned with stride_block_m
  312. # The additional states are cached starting from the last stride_block_m.
  313. # For example:
  314. # If n_block_to_fill = 0, then only the state at the sequence end is cached and the process below is not involved.
  315. # If n_block_to_fill > 0, then the states at the sequence end and at the n_block_to_fill-last
  316. # stride_block_m are cached.
  317. # For example chunk_offset = n_block_to_fill stores the state at last_full_block
  318. if (chunk_offset - 1) < n_block_to_fill:
  319. # Store the states at the chunk boundaries from the start of the sequence
  320. idx_tokens_last = (
  321. last_full_block_token_index
  322. - (n_block_to_fill - chunk_offset) * B_size
  323. - state_len
  324. ) + tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  325. x_ptrs = (
  326. x_ptr
  327. + (idx_tokens_last * stride_x_token)[:, None]
  328. + (idx_feats * stride_x_dim)[None, :]
  329. ) # [BLOCK_M,BLOCK_N,]
  330. mask_x = (idx_tokens_last >= 0)[:, None] & (idx_feats < dim)[
  331. None, :
  332. ] # token-index # token-index # feature-index
  333. loaded_x = tl.load(x_ptrs, mask_x, 0.0)
  334. idx_tokens_conv = tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  335. # cache_idx
  336. conv_states_output_coord = tl.load(
  337. conv_state_indices_ptr
  338. + idx_seq * stride_cache_indices
  339. + current_first_index
  340. + (chunk_offset - 1)
  341. ).to(tl.int64)
  342. conv_states_ptrs_target = (
  343. conv_states_ptr
  344. + (conv_states_output_coord * stride_conv_state_seq) # Offset from seq
  345. + (idx_feats * stride_conv_state_dim)
  346. )[None, :] + ( # [BLOCK_N,]
  347. idx_tokens_conv * stride_conv_state_tok
  348. )[:, None]
  349. mask = (idx_tokens_conv < state_len)[:, None] & (idx_feats < dim)[None, :]
  350. tl.debug_barrier() # NOTE: use this due to bug in Triton compiler
  351. tl.store(conv_states_ptrs_target, loaded_x, mask)
  352. if HAS_BIAS:
  353. bias = bias_ptr + idx_feats
  354. mask_bias = idx_feats < dim
  355. acc_preload = tl.load(bias, mask=mask_bias, other=0.0).to(
  356. tl.float32
  357. ) # [BLOCK_N]
  358. else:
  359. acc_preload = tl.zeros((BLOCK_N,), dtype=tl.float32)
  360. x_base_1d = x_base + token_offset * stride_x_token # starting of chunk
  361. # PRE-LOAD WEIGHTS
  362. mask_w = idx_feats < dim
  363. if KERNEL_WIDTH >= 2:
  364. w_ptrs = w_base + (0 * stride_w_width) # [BLOCK_N] tensor
  365. w_col0 = tl.load(w_ptrs, mask_w, other=0.0)
  366. w_ptrs = w_base + (1 * stride_w_width) # [BLOCK_N] tensor
  367. w_col1 = tl.load(w_ptrs, mask_w, other=0.0)
  368. if KERNEL_WIDTH >= 3:
  369. w_ptrs = w_base + (2 * stride_w_width) # [BLOCK_N] tensor
  370. w_col2 = tl.load(w_ptrs, mask_w, other=0.0)
  371. if KERNEL_WIDTH >= 4:
  372. w_ptrs = w_base + (3 * stride_w_width) # [BLOCK_N] tensor
  373. w_col3 = tl.load(w_ptrs, mask_w, other=0.0)
  374. mask_x_1d = idx_feats < dim
  375. if launch_pdl:
  376. tl.extra.cuda.gdc_launch_dependents()
  377. for idx_token in range(segment_len):
  378. acc = acc_preload
  379. matrix_w = w_col0
  380. matrix_x = col0
  381. for j in tl.static_range(KERNEL_WIDTH):
  382. if KERNEL_WIDTH == 2:
  383. if j == 1: # KERNEL_WIDTH-1:
  384. matrix_w = w_col1
  385. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  386. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  387. elif KERNEL_WIDTH == 3:
  388. if j == 1:
  389. matrix_w = w_col1
  390. matrix_x = col1
  391. elif j == 2:
  392. matrix_w = w_col2
  393. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  394. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  395. elif KERNEL_WIDTH == 4:
  396. if j == 1:
  397. matrix_w = w_col1
  398. matrix_x = col1
  399. elif j == 2:
  400. matrix_w = w_col2
  401. matrix_x = col2
  402. elif j == 3:
  403. matrix_w = w_col3
  404. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  405. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  406. acc += matrix_x * matrix_w # [BLOCK_N]
  407. if KERNEL_WIDTH == 2:
  408. col0 = matrix_x
  409. elif KERNEL_WIDTH == 3:
  410. col0 = col1
  411. col1 = matrix_x
  412. elif KERNEL_WIDTH == 4:
  413. col0 = col1
  414. col1 = col2
  415. col2 = matrix_x
  416. if SILU_ACTIVATION:
  417. acc = acc / (1 + tl.exp(-acc))
  418. mask_1d = (idx_token < segment_len) & (
  419. idx_feats < dim
  420. ) # token-index # feature-index
  421. if OUT_GROUP > 0:
  422. o_feats = (idx_feats // OUT_GROUP) * stride_o_group + (idx_feats % OUT_GROUP) * stride_o_dim
  423. else:
  424. o_feats = idx_feats * stride_o_dim
  425. o_ptrs = (
  426. o_ptr
  427. + (sequence_start_index + token_offset + idx_token) * stride_o_token
  428. + o_feats
  429. )
  430. tl.store(o_ptrs, acc, mask=mask_1d)
  431. def causal_conv1d_fn(
  432. x: torch.Tensor,
  433. weight: torch.Tensor,
  434. bias: torch.Tensor | None,
  435. conv_states: torch.Tensor,
  436. query_start_loc: torch.Tensor,
  437. cache_indices: torch.Tensor | None = None,
  438. has_initial_state: torch.Tensor | None = None,
  439. activation: str | None = "silu",
  440. pad_slot_id: int = PAD_SLOT_ID,
  441. null_block_id: int = NULL_BLOCK_ID,
  442. block_idx_first_scheduled_token: torch.Tensor | None = None,
  443. block_idx_last_scheduled_token: torch.Tensor | None = None,
  444. initial_state_idx: torch.Tensor | None = None,
  445. num_computed_tokens: torch.Tensor | None = None,
  446. block_size_to_align=0,
  447. metadata=None,
  448. validate_data=False,
  449. out_group: int = 0,
  450. ):
  451. """Support varlen + continuous batching when x is 2D tensor.
  452. x: (dim,cu_seq_len)
  453. cu_seq_len = total tokens of all seqs in that batch
  454. sequences are concatenated from left to right for varlen
  455. weight: (dim, width)
  456. conv_states: (...,dim,width - 1) itype
  457. updated inplace if cache_indices are not provided
  458. [it use `cache_indices` to get the index to the cache of conv_state for that sequence
  459. conv_state[cache_indices[i]] for seq-i - to be used as initial_state when has_initial_state[i] = True
  460. and after that conv_state[cache_indices[i]] need to be shift-left and updated with values from 'x'
  461. ]
  462. query_start_loc: (batch + 1) int32
  463. The cumulative sequence lengths of the sequences in
  464. the batch, used to index into sequence. prepended by 0.
  465. if
  466. x = [5, 1, 1, 1] <- continuous batching (batch=4)
  467. then
  468. query_start_loc = [0, 5, 6, 7, 8] <- the starting index of the next sequence; while the last value is
  469. the ending index of the last sequence
  470. [length(query_start_loc)-1 == batch]
  471. for example: query_start_loc = torch.Tensor([0,10,16,17]),
  472. x.shape=(dim,17)
  473. cache_indices: (batch) int32
  474. indicates the corresponding state index,
  475. like so: conv_state = conv_states[cache_indices[batch_id]]
  476. has_initial_state: (batch) bool
  477. indicates whether should the kernel take the current state as initial
  478. state for the calculations
  479. [single boolean for each sequence in the batch: True or False]
  480. bias: (dim,)
  481. activation: either None or "silu" or "swish" or True
  482. pad_slot_id: int
  483. if cache_indices is passed, lets the kernel identify padded
  484. entries that will not be processed,
  485. for example: cache_indices = [pad_slot_id, 1, 20, pad_slot_id]
  486. in this case, the kernel will not process entries at
  487. indices 0 and 3
  488. block_idx_first_scheduled_token: (batch,), dtype int32
  489. The pointer into cache_indices, where the first cache block to be filled is located.
  490. block_idx_last_scheduled_token: (batch,), dtype int32
  491. The pointer into cache_indices, where the last cache block to be filled is located.
  492. initial_state_idx: (batch,), dtype int32
  493. The pointer into cache_indices, where the cache block containing the initial state is located.
  494. num_computed_tokens: (batch,), dtype int32
  495. The number of tokens already completed for each sequence
  496. block_size_to_align: int
  497. The block size to align the cached states to
  498. out: same shape as `x`
  499. """
  500. if isinstance(activation, bool) and activation:
  501. activation = "silu"
  502. args = None
  503. # Store original dtype to cast back at the end
  504. original_x_dtype = x.dtype
  505. x = x.to(conv_states.dtype)
  506. if out_group:
  507. # Output [dim // out_group, seqlen, out_group]: each group of features
  508. # (q, k, v of a merged conv) comes out as its own dense tensor.
  509. assert x.dim() == 2 and x.shape[0] % out_group == 0
  510. out = torch.empty(x.shape[0] // out_group, x.shape[1], out_group, dtype=x.dtype, device=x.device)
  511. else:
  512. out = torch.empty_like(x)
  513. if metadata is not None:
  514. nums_dict = metadata.nums_dict
  515. args = nums_dict
  516. batch_ptr = metadata.batch_ptr
  517. token_chunk_offset_ptr = metadata.token_chunk_offset_ptr
  518. else:
  519. seqlens = query_start_loc.diff().to("cpu")
  520. args = seqlens
  521. MAX_NUM_PROGRAMS = 1024
  522. batch_ptr = torch.full(
  523. (MAX_NUM_PROGRAMS,), PAD_SLOT_ID, dtype=torch.int32, device=x.device
  524. ) # tracking which seq-idx the Triton program is handling
  525. token_chunk_offset_ptr = torch.full(
  526. (MAX_NUM_PROGRAMS,), PAD_SLOT_ID, dtype=torch.int32, device=x.device
  527. ) # tracking BLOCK_M-based index in the sequence the Triton program is handling
  528. is_channel_last = (x.stride(0) == 1) & (x.stride(1) > 1)
  529. dim, cu_seqlen = x.shape
  530. _, width = weight.shape
  531. state_len = width - 1
  532. np2_statelen = triton.next_power_of_2(state_len)
  533. padded_batch = query_start_loc.size(0) - 1
  534. stride_x_dim = x.stride(0)
  535. stride_x_token = x.stride(1)
  536. stride_w_dim = weight.stride(0)
  537. stride_w_width = weight.stride(1)
  538. stride_istate_seq = 0
  539. stride_istate_dim = 0
  540. stride_istate_token = 0
  541. num_cache_lines = 0
  542. BLOCK_M = 8
  543. if conv_states is not None:
  544. # extensions to support vLLM:
  545. # 1. conv_states is used to replaced initial_states
  546. # 2. conv_states serve as a cache with num cache lines can be larger than batch size
  547. # 3. mapping from sequence x[idx] to a cache line at index as specified via cache_indices[idx]
  548. # 4. computation can be skipped if cache_indices[idx] == pad_slot_id
  549. num_cache_lines = conv_states.size(0)
  550. assert (
  551. num_cache_lines == conv_states.shape[0]
  552. and dim == conv_states.shape[1]
  553. and width - 1 <= conv_states.shape[2]
  554. )
  555. stride_istate_seq = conv_states.stride(0)
  556. stride_istate_dim = conv_states.stride(1)
  557. stride_istate_token = conv_states.stride(2)
  558. stride_o_group = 0
  559. if out_group:
  560. stride_o_group, stride_o_token, stride_o_dim = out.stride()
  561. elif out.dim() == 2:
  562. stride_o_dim = out.stride(0)
  563. stride_o_token = out.stride(1)
  564. else:
  565. stride_o_dim = out.stride(1)
  566. stride_o_token = out.stride(2)
  567. stride_cache_indices = cache_indices.stride(0) if cache_indices is not None else 0
  568. if validate_data:
  569. assert x.dim() == 2
  570. assert query_start_loc is not None
  571. assert query_start_loc.dim() == 1
  572. assert x.stride(0) == 1 or x.stride(1) == 1
  573. if bias is not None:
  574. assert bias.dim() == 1
  575. assert dim == bias.size(0)
  576. if cache_indices is not None:
  577. assert cache_indices.dim() == 1
  578. assert padded_batch == cache_indices.size(0)
  579. if has_initial_state is not None:
  580. assert has_initial_state.size() == (padded_batch,)
  581. assert conv_states is not None, (
  582. "ERROR: `has_initial_state` is used, which needs also `conv_states`"
  583. )
  584. assert weight.stride(1) == 1
  585. assert (dim, width) == weight.shape
  586. assert is_channel_last, "Need to run in channel-last layout"
  587. if block_size_to_align is not None and block_size_to_align > 0:
  588. assert (block_size_to_align % BLOCK_M) == 0, (
  589. "The mamba block size needs to be divisible by the BLOCK_M"
  590. )
  591. else:
  592. block_size_to_align = BLOCK_M
  593. if metadata is None:
  594. def num_program(META, seqlens):
  595. tot = 0
  596. mlist = []
  597. offsetlist = [] # type: ignore
  598. nums = -(-seqlens // META["BLOCK_M"])
  599. tot = nums.sum().item()
  600. mlist = np.repeat(np.arange(len(nums)), nums)
  601. for idx, num in enumerate(nums):
  602. offsetlist.extend(
  603. range(num)
  604. ) # chunk-idx if a sequence is split into multiple chunks
  605. if META["batch_ptr"].nelement() < len(mlist):
  606. newlen = len(mlist) + 1
  607. META["batch_ptr"].resize_(newlen).fill_(PAD_SLOT_ID)
  608. META["token_chunk_offset_ptr"].resize_(newlen).fill_(PAD_SLOT_ID)
  609. if META["batch_ptr"].nelement() >= len(mlist):
  610. META["batch_ptr"][0 : len(mlist)].copy_(
  611. torch.from_numpy(np.array(mlist))
  612. )
  613. META["token_chunk_offset_ptr"][0 : len(mlist)].copy_(
  614. torch.from_numpy(np.array(offsetlist))
  615. )
  616. META["batch_ptr"] = META["batch_ptr"].to(META["x_ptr"].device)
  617. META["token_chunk_offset_ptr"] = META["token_chunk_offset_ptr"].to(
  618. META["x_ptr"].device
  619. )
  620. return tot
  621. else:
  622. def num_program(META, nums_dict):
  623. tot = nums_dict[META["BLOCK_M"]]["tot"]
  624. mlist = nums_dict[META["BLOCK_M"]]["mlist"]
  625. mlist_len = nums_dict[META["BLOCK_M"]]["mlist_len"]
  626. offsetlist = nums_dict[META["BLOCK_M"]]["offsetlist"]
  627. if nums_dict[META["BLOCK_M"]]["batch_ptr"] is not None:
  628. META["batch_ptr"] = nums_dict[META["BLOCK_M"]]["batch_ptr"]
  629. META["token_chunk_offset_ptr"] = nums_dict[META["BLOCK_M"]][
  630. "token_chunk_offset_ptr"
  631. ]
  632. else:
  633. if META["batch_ptr"].nelement() < mlist_len:
  634. newlen = mlist_len + 1
  635. META["batch_ptr"].resize_(newlen).fill_(PAD_SLOT_ID)
  636. META["token_chunk_offset_ptr"].resize_(newlen).fill_(PAD_SLOT_ID)
  637. if META["batch_ptr"].nelement() >= mlist_len:
  638. META["batch_ptr"][0:mlist_len].copy_(mlist)
  639. META["token_chunk_offset_ptr"][0:mlist_len].copy_(offsetlist)
  640. return tot
  641. def grid(META):
  642. return (
  643. num_program(META, args),
  644. triton.cdiv(dim, META["BLOCK_N"]),
  645. )
  646. if batch_ptr.device != x.device:
  647. batch_ptr = batch_ptr.to(x.device)
  648. token_chunk_offset_ptr = token_chunk_offset_ptr.to(x.device)
  649. _causal_conv1d_fwd_kernel[grid](
  650. # Pointers to matrices
  651. x,
  652. weight,
  653. bias,
  654. conv_states,
  655. cache_indices,
  656. has_initial_state,
  657. query_start_loc,
  658. batch_ptr,
  659. token_chunk_offset_ptr,
  660. block_idx_first_scheduled_token,
  661. block_idx_last_scheduled_token,
  662. initial_state_idx,
  663. num_computed_tokens,
  664. out,
  665. # Matrix dimensions
  666. dim,
  667. num_cache_lines,
  668. # stride
  669. stride_x_dim,
  670. stride_x_token,
  671. stride_w_dim,
  672. stride_w_width,
  673. stride_istate_seq,
  674. stride_istate_dim,
  675. stride_istate_token,
  676. stride_cache_indices,
  677. stride_o_dim,
  678. stride_o_token,
  679. stride_o_group,
  680. block_size_to_align // BLOCK_M,
  681. # others
  682. pad_slot_id,
  683. null_block_id,
  684. # META
  685. HAS_BIAS=bias is not None,
  686. KERNEL_WIDTH=width,
  687. SILU_ACTIVATION=activation in ["silu", "swish"],
  688. IS_APC_ENABLED=block_idx_last_scheduled_token is not None,
  689. HAS_NULL_BLOCK=null_block_id is not None,
  690. NP2_STATELEN=np2_statelen,
  691. OUT_GROUP=out_group,
  692. # launch_cooperative_grid=True
  693. BLOCK_M=BLOCK_M,
  694. BLOCK_N=256,
  695. num_stages=2,
  696. launch_pdl=current_platform.is_arch_support_pdl(),
  697. )
  698. return out.to(original_x_dtype)
  699. @triton.jit(do_not_specialize_on_alignment=["num_cache_lines"])
  700. def _causal_conv1d_update_kernel(
  701. # Pointers to matrices
  702. x_ptr, # (batch, dim, seqlen)
  703. w_ptr, # (dim, width)
  704. bias_ptr,
  705. conv_state_ptr,
  706. conv_state_indices_ptr,
  707. num_accepted_tokens_ptr,
  708. query_start_loc_ptr, # (batch + 1)
  709. block_idx_last_scheduled_token, # (batch,)
  710. initial_state_idx, # (batch,)
  711. o_ptr, # (batch, dim, seqlen)
  712. # Matrix dimensions
  713. batch: int,
  714. dim: tl.constexpr,
  715. seqlen: tl.constexpr,
  716. state_len: tl.constexpr,
  717. num_cache_lines, # added to support vLLM larger cache lines
  718. # Strides
  719. stride_x_seq: tl.constexpr,
  720. stride_x_dim: tl.constexpr,
  721. stride_x_token: tl.int64,
  722. stride_w_dim: tl.constexpr,
  723. stride_w_width: tl.constexpr,
  724. stride_conv_state_seq: tl.constexpr,
  725. stride_conv_state_dim: tl.constexpr,
  726. stride_conv_state_tok: tl.constexpr,
  727. stride_state_indices: tl.constexpr,
  728. stride_o_seq: tl.constexpr,
  729. stride_o_dim: tl.constexpr,
  730. stride_o_token: tl.int64,
  731. # others
  732. null_block_id: tl.constexpr,
  733. # Meta-parameters
  734. HAS_BIAS: tl.constexpr,
  735. KERNEL_WIDTH: tl.constexpr,
  736. SILU_ACTIVATION: tl.constexpr,
  737. IS_VARLEN: tl.constexpr,
  738. IS_APC_ENABLED: tl.constexpr,
  739. IS_SPEC_DECODING: tl.constexpr,
  740. NP2_STATELEN: tl.constexpr,
  741. HAS_NULL_BLOCK: tl.constexpr,
  742. BLOCK_N: tl.constexpr,
  743. launch_pdl: tl.constexpr,
  744. ):
  745. if launch_pdl:
  746. tl.extra.cuda.gdc_wait()
  747. # ruff: noqa: E501
  748. idx_seq = tl.program_id(0)
  749. if idx_seq >= batch:
  750. if launch_pdl:
  751. tl.extra.cuda.gdc_launch_dependents()
  752. return
  753. # [BLOCK_N,] elements along the feature-dimension (channel)
  754. idx_feats = tl.program_id(1) * BLOCK_N + tl.arange(0, BLOCK_N)
  755. if IS_APC_ENABLED:
  756. # Get the state from the initial_state_idx
  757. conv_state_init = tl.load(initial_state_idx + idx_seq)
  758. current_last_index = tl.load(block_idx_last_scheduled_token + idx_seq)
  759. else:
  760. conv_state_init = 0
  761. current_last_index = 0
  762. # cache_idx
  763. conv_states_input_coord = tl.load(
  764. conv_state_indices_ptr + idx_seq * stride_state_indices + conv_state_init
  765. ).to(tl.int64)
  766. if HAS_NULL_BLOCK: # noqa
  767. if conv_states_input_coord == null_block_id:
  768. # not processing as this is not the actual sequence
  769. if launch_pdl:
  770. tl.extra.cuda.gdc_launch_dependents()
  771. return
  772. if IS_VARLEN:
  773. query_start_index = tl.load(query_start_loc_ptr + idx_seq).to(tl.int64)
  774. query_end_index = tl.load(query_start_loc_ptr + (idx_seq + 1)).to(tl.int64)
  775. # revise state_len and seqlen
  776. state_len = state_len - (seqlen - (query_end_index - query_start_index))
  777. seqlen = query_end_index - query_start_index
  778. x_offset = query_start_index * stride_x_token
  779. o_offset = query_start_index * stride_o_token
  780. else:
  781. query_start_index = idx_seq * seqlen
  782. query_end_index = query_start_index + seqlen
  783. x_offset = idx_seq * stride_x_seq
  784. o_offset = idx_seq * stride_o_seq
  785. if query_start_index == query_end_index:
  786. if launch_pdl:
  787. tl.extra.cuda.gdc_launch_dependents()
  788. return
  789. if IS_SPEC_DECODING:
  790. # The rolling of conv state:
  791. #
  792. # Before forward, the conv_state is:
  793. # [history1, history2, ..., historyM].
  794. #
  795. # After forward, the conv_state becomes:
  796. # [history2, ..., historyM, draft1, draft2, ..., draftN].
  797. #
  798. # After acceptance, it becomes:
  799. #
  800. # - accept 1 tokens: [history2, ..., historyM, draft1]
  801. # - accept 2 tokens: [history3, ..., historyM, draft1, draft2]
  802. # - and so on.
  803. conv_state_token_offset = (
  804. tl.load(num_accepted_tokens_ptr + idx_seq).to(tl.int64) - 1
  805. )
  806. else:
  807. conv_state_token_offset = 0
  808. # STEP 1: READ init_state data
  809. conv_states_base = (
  810. conv_state_ptr
  811. + (conv_states_input_coord * stride_conv_state_seq)
  812. + (idx_feats * stride_conv_state_dim)
  813. )
  814. mask_w = idx_feats < dim
  815. prior_tokens = conv_states_base + conv_state_token_offset * stride_conv_state_tok
  816. if KERNEL_WIDTH >= 2:
  817. conv_states_ptrs = prior_tokens # [BLOCK_N]
  818. col0 = tl.load(conv_states_ptrs, mask_w, 0.0)
  819. if KERNEL_WIDTH >= 3:
  820. conv_states_ptrs = prior_tokens + 1 * stride_conv_state_tok # [BLOCK_N]
  821. col1 = tl.load(conv_states_ptrs, mask_w, 0.0)
  822. if KERNEL_WIDTH >= 4:
  823. conv_states_ptrs = prior_tokens + 2 * stride_conv_state_tok # [BLOCK_N]
  824. col2 = tl.load(conv_states_ptrs, mask_w, 0.0)
  825. if KERNEL_WIDTH >= 5:
  826. conv_states_ptrs = prior_tokens + 3 * stride_conv_state_tok # [BLOCK_N]
  827. col3 = tl.load(conv_states_ptrs, mask_w, 0.0)
  828. if KERNEL_WIDTH >= 6:
  829. conv_states_ptrs = prior_tokens + 4 * stride_conv_state_tok # [BLOCK_N]
  830. col4 = tl.load(conv_states_ptrs, mask_w, 0.0)
  831. # STEP 2: assume state_len > seqlen
  832. idx_tokens = tl.arange(0, NP2_STATELEN) # [BLOCK_M]
  833. # With speculative decoding, the conv_state updates works in a sliding
  834. # window manner, at each forward pass, the tokens are shift by 1, so we
  835. # load since idx_tokens + 1.
  836. conv_state_ptrs_source = (
  837. conv_state_ptr
  838. + (conv_states_input_coord * stride_conv_state_seq)
  839. + conv_state_token_offset * stride_conv_state_tok
  840. + (idx_feats * stride_conv_state_dim)[None, :]
  841. + ((idx_tokens + (1 if IS_SPEC_DECODING else seqlen)) * stride_conv_state_tok)[
  842. :, None
  843. ]
  844. ) # [BLOCK_M, BLOCK_N]
  845. mask = (
  846. (conv_states_input_coord < num_cache_lines)
  847. & ((idx_tokens + seqlen) < state_len)[:, None]
  848. & (idx_feats < dim)[None, :]
  849. )
  850. conv_state = tl.load(conv_state_ptrs_source, mask, other=0.0)
  851. VAL = state_len - seqlen
  852. x_base = x_ptr + x_offset + (idx_feats * stride_x_dim) # [BLOCK_N]
  853. x_ptrs = (
  854. x_base[None, :] + ((idx_tokens - VAL) * stride_x_token)[:, None]
  855. ) # [BLOCK_M, BLOCK_N]
  856. mask_x = (
  857. (idx_tokens - VAL >= 0)[:, None]
  858. & (idx_tokens - VAL < seqlen)[:, None]
  859. & (idx_feats < dim)[None, :]
  860. ) # token-index # token-index # feature-index
  861. loaded_x = tl.load(x_ptrs, mask_x, 0.0)
  862. tl.debug_barrier()
  863. new_conv_state = tl.where(mask, conv_state, loaded_x)
  864. # Get the state from the initial_state_idx
  865. # cache_idx
  866. conv_states_offset = tl.load(
  867. conv_state_indices_ptr + idx_seq * stride_state_indices + current_last_index
  868. ).to(tl.int64)
  869. conv_state_ptrs_target = (
  870. conv_state_ptr
  871. + (conv_states_offset * stride_conv_state_seq) # Offset from seq
  872. + (idx_feats * stride_conv_state_dim)
  873. )[None, :] + ( # [BLOCK_N,]
  874. idx_tokens * stride_conv_state_tok
  875. )[:, None]
  876. mask = (idx_tokens < state_len)[:, None] & (idx_feats < dim)[None, :]
  877. tl.store(conv_state_ptrs_target, new_conv_state, mask)
  878. # STEP 3: init accumulator
  879. if HAS_BIAS:
  880. bias = bias_ptr + idx_feats
  881. mask_bias = idx_feats < dim
  882. acc_preload = tl.load(bias, mask=mask_bias, other=0.0).to(
  883. tl.float32
  884. ) # [BLOCK_N]
  885. else:
  886. acc_preload = tl.zeros((BLOCK_N,), dtype=tl.float32)
  887. # STEP 4:
  888. # PRE-LOAD WEIGHTS
  889. # first kernel column, configured for weights to handle BLOCK_N features in range
  890. w_base = w_ptr + (idx_feats * stride_w_dim) # [BLOCK_N,]
  891. mask_w = idx_feats < dim
  892. if KERNEL_WIDTH >= 2:
  893. w_ptrs = w_base + (0 * stride_w_width) # [BLOCK_N] tensor
  894. w_col0 = tl.load(w_ptrs, mask_w, other=0.0)
  895. w_ptrs = w_base + (1 * stride_w_width) # [BLOCK_N] tensor
  896. w_col1 = tl.load(w_ptrs, mask_w, other=0.0)
  897. if KERNEL_WIDTH >= 3:
  898. w_ptrs = w_base + (2 * stride_w_width) # [BLOCK_N] tensor
  899. w_col2 = tl.load(w_ptrs, mask_w, other=0.0)
  900. if KERNEL_WIDTH >= 4:
  901. w_ptrs = w_base + (3 * stride_w_width) # [BLOCK_N] tensor
  902. w_col3 = tl.load(w_ptrs, mask_w, other=0.0)
  903. if KERNEL_WIDTH >= 5:
  904. w_ptrs = w_base + (4 * stride_w_width) # [BLOCK_N] tensor
  905. w_col4 = tl.load(w_ptrs, mask_w, other=0.0)
  906. if KERNEL_WIDTH >= 6:
  907. w_ptrs = w_base + (5 * stride_w_width) # [BLOCK_N] tensor
  908. w_col5 = tl.load(w_ptrs, mask_w, other=0.0)
  909. x_base_1d = x_base # starting of chunk [BLOCK_N]
  910. mask_x_1d = idx_feats < dim
  911. # STEP 5: compute each token
  912. if launch_pdl:
  913. tl.extra.cuda.gdc_launch_dependents()
  914. for idx_token in tl.range(seqlen):
  915. acc = acc_preload
  916. matrix_w = w_col0
  917. matrix_x = col0
  918. for j in tl.static_range(KERNEL_WIDTH):
  919. if KERNEL_WIDTH == 2:
  920. if j == 1: # KERNEL_WIDTH-1:
  921. matrix_w = w_col1
  922. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  923. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  924. elif KERNEL_WIDTH == 3:
  925. if j == 1:
  926. matrix_w = w_col1
  927. matrix_x = col1
  928. elif j == 2:
  929. matrix_w = w_col2
  930. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  931. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  932. elif KERNEL_WIDTH == 4:
  933. if j == 1:
  934. matrix_w = w_col1
  935. matrix_x = col1
  936. elif j == 2:
  937. matrix_w = w_col2
  938. matrix_x = col2
  939. elif j == 3:
  940. matrix_w = w_col3
  941. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  942. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  943. elif KERNEL_WIDTH == 5:
  944. if j == 1:
  945. matrix_w = w_col1
  946. matrix_x = col1
  947. elif j == 2:
  948. matrix_w = w_col2
  949. matrix_x = col2
  950. elif j == 3:
  951. matrix_w = w_col3
  952. matrix_x = col3
  953. elif j == 4:
  954. matrix_w = w_col4
  955. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  956. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  957. elif KERNEL_WIDTH == 6:
  958. if j == 1:
  959. matrix_w = w_col1
  960. matrix_x = col1
  961. elif j == 2:
  962. matrix_w = w_col2
  963. matrix_x = col2
  964. elif j == 3:
  965. matrix_w = w_col3
  966. matrix_x = col3
  967. elif j == 4:
  968. matrix_w = w_col4
  969. matrix_x = col4
  970. elif j == 5:
  971. matrix_w = w_col5
  972. x_ptrs_1d = x_base_1d + idx_token * stride_x_token # [BLOCK_N]
  973. matrix_x = tl.load(x_ptrs_1d, mask=mask_x_1d)
  974. acc += matrix_x * matrix_w # [BLOCK_N]
  975. if KERNEL_WIDTH == 2:
  976. col0 = matrix_x
  977. elif KERNEL_WIDTH == 3:
  978. col0 = col1
  979. col1 = matrix_x
  980. elif KERNEL_WIDTH == 4:
  981. col0 = col1
  982. col1 = col2
  983. col2 = matrix_x
  984. elif KERNEL_WIDTH == 5:
  985. col0 = col1
  986. col1 = col2
  987. col2 = col3
  988. col3 = matrix_x
  989. elif KERNEL_WIDTH == 6:
  990. col0 = col1
  991. col1 = col2
  992. col2 = col3
  993. col3 = col4
  994. col4 = matrix_x
  995. if SILU_ACTIVATION:
  996. acc = acc / (1 + tl.exp(-acc))
  997. mask_1d = (idx_token < seqlen) & (
  998. idx_feats < dim
  999. ) # token-index # feature-index
  1000. o_ptrs = (
  1001. o_ptr + o_offset + idx_token * stride_o_token + (idx_feats * stride_o_dim)
  1002. )
  1003. tl.store(o_ptrs, acc, mask=mask_1d)
  1004. def causal_conv1d_update(
  1005. x: torch.Tensor,
  1006. conv_state: torch.Tensor,
  1007. weight: torch.Tensor,
  1008. bias: torch.Tensor | None = None,
  1009. activation: bool | str | None = None,
  1010. conv_state_indices: torch.Tensor | None = None,
  1011. num_accepted_tokens: torch.Tensor | None = None,
  1012. query_start_loc: torch.Tensor | None = None,
  1013. max_query_len: int = -1,
  1014. null_block_id: int = NULL_BLOCK_ID,
  1015. block_idx_last_scheduled_token: torch.Tensor | None = None,
  1016. initial_state_idx: torch.Tensor | None = None,
  1017. validate_data=False,
  1018. out: torch.Tensor | None = None,
  1019. ):
  1020. """x: Input tensor which can take the following shapes:
  1021. - `[batch, dim]` - single token prediction
  1022. - `[batch, dim, seqlen]` - single or multiple tokens prediction
  1023. - `[num_tokens, dim]` - continuous batching, where num_tokens is
  1024. the total tokens of all sequences in that batch
  1025. conv_state: (..., dim, state_len), where state_len >= width - 1
  1026. weight: (dim, width)
  1027. bias: (dim,)
  1028. conv_state_indices: (batch,), dtype int32
  1029. If not None, the conv_state is a larger tensor along the batch dim,
  1030. and we are selecting the batch coords specified by conv_state_indices.
  1031. Useful for a continuous batching scenario.
  1032. block_idx_last_scheduled_token: (batch,), dtype int32
  1033. The pointer into conv_state_indices, where the last cache block to be filled is located.
  1034. initial_state_idx: (batch,), dtype int32
  1035. The pointer into conv_state_indices, where the cache block containing the initial state is located.
  1036. num_accepted_tokens: (batch,), dtype int32
  1037. If not None, it indicates the number of accepted tokens for each
  1038. sequence in the batch.
  1039. This is used in speculative decoding, where the conv_state is updated
  1040. in a sliding window manner.
  1041. query_start_loc: (batch + 1,) int32
  1042. If not None, the inputs is given in a varlen fashion and this indicates
  1043. the starting index of each sequence in the batch.
  1044. max_query_len: int
  1045. If query_start_loc is not None, this indicates the maximum query
  1046. length in the batch.
  1047. null_block_id: int
  1048. Block ID used to identify padded entries in
  1049. conv_state_indices. Block 0 is the null block.
  1050. for example: conv_state_indices = [null_block_id, 1, 20, null_block_id]
  1051. in this case, the kernel will not process entries at
  1052. indices 0 and 3
  1053. out: optional output tensor with the same shape as `x`. When omitted,
  1054. the input is overwritten.
  1055. """
  1056. if validate_data:
  1057. assert null_block_id is not None
  1058. assert x.stride(1) == 1
  1059. if isinstance(activation, bool):
  1060. activation = "silu" if activation is True else None
  1061. elif activation is not None:
  1062. assert activation in ["silu", "swish"]
  1063. original_x_dtype = x.dtype
  1064. x = x.to(conv_state.dtype)
  1065. if out is None:
  1066. out = x
  1067. else:
  1068. if out.shape != x.shape:
  1069. raise ValueError(
  1070. f"`out` shape {tuple(out.shape)} must match `x` shape {tuple(x.shape)}."
  1071. )
  1072. if out.dtype != original_x_dtype or out.device != x.device:
  1073. raise ValueError(
  1074. "`out` must have the same dtype and device as the input `x`."
  1075. )
  1076. unsqueeze = query_start_loc is None and x.dim() == 2
  1077. if unsqueeze:
  1078. # make it (batch, dim, seqlen) with seqlen == 1
  1079. x = x.unsqueeze(-1)
  1080. out = out.unsqueeze(-1)
  1081. if query_start_loc is None:
  1082. batch, dim, seqlen = x.shape
  1083. else:
  1084. assert conv_state_indices is not None
  1085. batch = conv_state_indices.size(0)
  1086. dim = x.size(1)
  1087. seqlen = max_query_len
  1088. _, width = weight.shape
  1089. # conv_state: (..., dim, state_len), where state_len >= width - 1
  1090. num_cache_lines, _, state_len = conv_state.size()
  1091. if validate_data:
  1092. assert dim == weight.size(0)
  1093. assert state_len >= width - 1
  1094. # when above happens, we don't shift-left to keep any records in conv_state
  1095. assert dim == conv_state.size(1)
  1096. if conv_state_indices is None:
  1097. assert conv_state.size(0) >= batch
  1098. else:
  1099. assert batch == conv_state_indices.shape[0], (
  1100. f"ERROR: conv_state_indices should have shape ({batch},*) but got {conv_state_indices.shape}"
  1101. )
  1102. assert num_cache_lines >= batch
  1103. assert weight.stride(1) == 1 # Need this
  1104. stride_w_dim, stride_w_width = weight.stride()
  1105. if query_start_loc is None:
  1106. # X (batch, dim, seqlen)
  1107. stride_x_seq, stride_x_dim, stride_x_token = x.stride()
  1108. stride_o_seq, stride_o_dim, stride_o_token = out.stride()
  1109. else:
  1110. # X (dim, cu_seqlen)
  1111. stride_x_token, stride_x_dim = x.stride()
  1112. stride_x_seq = 0
  1113. stride_o_token, stride_o_dim = out.stride()
  1114. stride_o_seq = 0
  1115. stride_istate_seq, stride_istate_dim, stride_istate_token = conv_state.stride()
  1116. stride_state_indices = (
  1117. conv_state_indices.stride(0) if conv_state_indices is not None else 0
  1118. )
  1119. if num_accepted_tokens is not None:
  1120. state_len = width - 1 + (seqlen - 1) # effective state_len needed
  1121. else:
  1122. state_len = width - 1
  1123. np2_statelen = triton.next_power_of_2(state_len)
  1124. def grid(META):
  1125. return (
  1126. batch,
  1127. triton.cdiv(dim, META["BLOCK_N"]),
  1128. )
  1129. _causal_conv1d_update_kernel[grid](
  1130. # Pointers to matrices
  1131. x,
  1132. weight,
  1133. bias,
  1134. conv_state,
  1135. conv_state_indices,
  1136. num_accepted_tokens,
  1137. query_start_loc,
  1138. block_idx_last_scheduled_token,
  1139. initial_state_idx,
  1140. out,
  1141. # Matrix dimensions
  1142. batch,
  1143. dim,
  1144. seqlen,
  1145. state_len,
  1146. num_cache_lines,
  1147. # stride
  1148. stride_x_seq,
  1149. stride_x_dim,
  1150. stride_x_token,
  1151. stride_w_dim,
  1152. stride_w_width,
  1153. stride_istate_seq,
  1154. stride_istate_dim,
  1155. stride_istate_token,
  1156. stride_state_indices,
  1157. stride_o_seq,
  1158. stride_o_dim,
  1159. stride_o_token,
  1160. # others
  1161. null_block_id,
  1162. # META
  1163. HAS_BIAS=bias is not None,
  1164. KERNEL_WIDTH=width,
  1165. SILU_ACTIVATION=activation in ["silu", "swish"],
  1166. IS_VARLEN=query_start_loc is not None,
  1167. IS_APC_ENABLED=block_idx_last_scheduled_token is not None,
  1168. IS_SPEC_DECODING=num_accepted_tokens is not None,
  1169. NP2_STATELEN=np2_statelen,
  1170. HAS_NULL_BLOCK=null_block_id is not None,
  1171. BLOCK_N=256,
  1172. launch_pdl=current_platform.is_arch_support_pdl(),
  1173. )
  1174. if unsqueeze:
  1175. out = out.squeeze(-1)
  1176. return out.to(original_x_dtype)
  1177. if current_platform.is_cpu():
  1178. from vllm.model_executor.layers.mamba.ops.cpu.causal_conv1d import (
  1179. causal_conv1d_fn_cpu,
  1180. causal_conv1d_update_cpu,
  1181. )
  1182. causal_conv1d_fn = causal_conv1d_fn_cpu # type: ignore
  1183. causal_conv1d_update = causal_conv1d_update_cpu # type: ignore