1
0

amdgpu_stress.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright 2021 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. */
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <fcntl.h>
  27. #include <stdarg.h>
  28. #include <string.h>
  29. #include <errno.h>
  30. #include <unistd.h>
  31. #include <stdlib.h>
  32. #include <inttypes.h>
  33. #include "drm.h"
  34. #include "xf86drmMode.h"
  35. #include "xf86drm.h"
  36. #include "amdgpu.h"
  37. #include "amdgpu_drm.h"
  38. #include "amdgpu_internal.h"
  39. #define MAX_CARDS_SUPPORTED 4
  40. #define NUM_BUFFER_OBJECTS 1024
  41. #define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \
  42. (((sub_op) & 0xFF) << 8) | \
  43. (((op) & 0xFF) << 0))
  44. #define SDMA_OPCODE_COPY 1
  45. # define SDMA_COPY_SUB_OPCODE_LINEAR 0
  46. #define SDMA_PACKET_SI(op, b, t, s, cnt) ((((op) & 0xF) << 28) | \
  47. (((b) & 0x1) << 26) | \
  48. (((t) & 0x1) << 23) | \
  49. (((s) & 0x1) << 22) | \
  50. (((cnt) & 0xFFFFF) << 0))
  51. #define SDMA_OPCODE_COPY_SI 3
  52. /** Help string for command line parameters */
  53. static const char usage[] =
  54. "Usage: %s [-?h] [-b v|g|vg size] "
  55. "[-c from to size count]\n"
  56. "where:\n"
  57. " b - Allocate a BO in VRAM, GTT or VRAM|GTT of size bytes.\n"
  58. " This flag can be used multiple times. The first bo will\n"
  59. " have id `1`, then second id `2`, ...\n"
  60. " c - Copy size bytes from BO (bo_id1) to BO (bo_id2), count times\n"
  61. " h - Display this help\n"
  62. "\n"
  63. "Sizes can be postfixes with k, m or g for kilo, mega and gigabyte scaling\n";
  64. /** Specified options strings for getopt */
  65. static const char options[] = "?hb:c:";
  66. /* Open AMD devices.
  67. * Returns the fd of the first device it could open.
  68. */
  69. static int amdgpu_open_device(void)
  70. {
  71. drmDevicePtr devices[MAX_CARDS_SUPPORTED];
  72. unsigned int i;
  73. int drm_count;
  74. drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED);
  75. if (drm_count < 0) {
  76. fprintf(stderr, "drmGetDevices2() returned an error %d\n",
  77. drm_count);
  78. return drm_count;
  79. }
  80. for (i = 0; i < drm_count; i++) {
  81. drmVersionPtr version;
  82. int fd;
  83. /* If this is not PCI device, skip*/
  84. if (devices[i]->bustype != DRM_BUS_PCI)
  85. continue;
  86. /* If this is not AMD GPU vender ID, skip*/
  87. if (devices[i]->deviceinfo.pci->vendor_id != 0x1002)
  88. continue;
  89. if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER))
  90. continue;
  91. fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
  92. /* This node is not available. */
  93. if (fd < 0) continue;
  94. version = drmGetVersion(fd);
  95. if (!version) {
  96. fprintf(stderr,
  97. "Warning: Cannot get version for %s."
  98. "Error is %s\n",
  99. devices[i]->nodes[DRM_NODE_RENDER],
  100. strerror(errno));
  101. close(fd);
  102. continue;
  103. }
  104. if (strcmp(version->name, "amdgpu")) {
  105. /* This is not AMDGPU driver, skip.*/
  106. drmFreeVersion(version);
  107. close(fd);
  108. continue;
  109. }
  110. drmFreeVersion(version);
  111. drmFreeDevices(devices, drm_count);
  112. return fd;
  113. }
  114. return -1;
  115. }
  116. amdgpu_device_handle device_handle;
  117. amdgpu_context_handle context_handle;
  118. amdgpu_bo_handle resources[NUM_BUFFER_OBJECTS];
  119. uint64_t virtual[NUM_BUFFER_OBJECTS];
  120. unsigned int num_buffers;
  121. uint32_t *pm4;
  122. int alloc_bo(uint32_t domain, uint64_t size)
  123. {
  124. struct amdgpu_bo_alloc_request request = {};
  125. amdgpu_bo_handle bo;
  126. amdgpu_va_handle va;
  127. uint64_t addr;
  128. int r;
  129. if (num_buffers >= NUM_BUFFER_OBJECTS)
  130. return -ENOSPC;
  131. request.alloc_size = size;
  132. request.phys_alignment = 0;
  133. request.preferred_heap = domain;
  134. request.flags = 0;
  135. r = amdgpu_bo_alloc(device_handle, &request, &bo);
  136. if (r)
  137. return r;
  138. r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general,
  139. size, 0, 0, &addr, &va, 0);
  140. if (r)
  141. return r;
  142. r = amdgpu_bo_va_op_raw(device_handle, bo, 0, size, addr,
  143. AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE |
  144. AMDGPU_VM_PAGE_EXECUTABLE, AMDGPU_VA_OP_MAP);
  145. if (r)
  146. return r;
  147. resources[num_buffers] = bo;
  148. virtual[num_buffers] = addr;
  149. fprintf(stdout, "Allocated BO number %u at 0x%" PRIx64 ", domain 0x%x, size %" PRIu64 "\n",
  150. num_buffers++, addr, domain, size);
  151. return 0;
  152. }
  153. int submit_ib(uint32_t from, uint32_t to, uint64_t size, uint32_t count)
  154. {
  155. struct amdgpu_cs_request ibs_request;
  156. struct amdgpu_cs_fence fence_status;
  157. struct amdgpu_cs_ib_info ib_info;
  158. uint64_t copied = size, delta;
  159. struct timespec start, stop;
  160. uint64_t src = virtual[from];
  161. uint64_t dst = virtual[to];
  162. uint32_t expired;
  163. int i, r;
  164. i = 0;
  165. while (size) {
  166. uint64_t bytes = size < 0x40000 ? size : 0x40000;
  167. if (device_handle->info.family_id == AMDGPU_FAMILY_SI) {
  168. pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0,
  169. bytes);
  170. pm4[i++] = 0xffffffff & dst;
  171. pm4[i++] = 0xffffffff & src;
  172. pm4[i++] = (0xffffffff00000000 & dst) >> 32;
  173. pm4[i++] = (0xffffffff00000000 & src) >> 32;
  174. } else {
  175. pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY,
  176. SDMA_COPY_SUB_OPCODE_LINEAR,
  177. 0);
  178. if ( device_handle->info.family_id >= AMDGPU_FAMILY_AI)
  179. pm4[i++] = bytes - 1;
  180. else
  181. pm4[i++] = bytes;
  182. pm4[i++] = 0;
  183. pm4[i++] = 0xffffffff & src;
  184. pm4[i++] = (0xffffffff00000000 & src) >> 32;
  185. pm4[i++] = 0xffffffff & dst;
  186. pm4[i++] = (0xffffffff00000000 & dst) >> 32;
  187. }
  188. size -= bytes;
  189. src += bytes;
  190. dst += bytes;
  191. }
  192. memset(&ib_info, 0, sizeof(ib_info));
  193. ib_info.ib_mc_address = virtual[0];
  194. ib_info.size = i;
  195. memset(&ibs_request, 0, sizeof(ibs_request));
  196. ibs_request.ip_type = AMDGPU_HW_IP_DMA;
  197. ibs_request.ring = 0;
  198. ibs_request.number_of_ibs = 1;
  199. ibs_request.ibs = &ib_info;
  200. ibs_request.fence_info.handle = NULL;
  201. r = clock_gettime(CLOCK_MONOTONIC, &start);
  202. if (r)
  203. return errno;
  204. r = amdgpu_bo_list_create(device_handle, num_buffers, resources, NULL,
  205. &ibs_request.resources);
  206. if (r)
  207. return r;
  208. for (i = 0; i < count; ++i) {
  209. r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1);
  210. if (r)
  211. return r;
  212. }
  213. r = amdgpu_bo_list_destroy(ibs_request.resources);
  214. if (r)
  215. return r;
  216. memset(&fence_status, 0, sizeof(fence_status));
  217. fence_status.ip_type = ibs_request.ip_type;
  218. fence_status.ip_instance = 0;
  219. fence_status.ring = ibs_request.ring;
  220. fence_status.context = context_handle;
  221. fence_status.fence = ibs_request.seq_no;
  222. r = amdgpu_cs_query_fence_status(&fence_status,
  223. AMDGPU_TIMEOUT_INFINITE,
  224. 0, &expired);
  225. if (r)
  226. return r;
  227. r = clock_gettime(CLOCK_MONOTONIC, &stop);
  228. if (r)
  229. return errno;
  230. delta = stop.tv_nsec + stop.tv_sec * 1000000000UL;
  231. delta -= start.tv_nsec + start.tv_sec * 1000000000UL;
  232. fprintf(stdout, "Submitted %u IBs to copy from %u(%" PRIx64 ") to %u(%" PRIx64 ") %" PRIu64 " bytes took %" PRIu64 " usec\n",
  233. count, from, virtual[from], to, virtual[to], copied, delta / 1000);
  234. return 0;
  235. }
  236. void next_arg(int argc, char **argv, const char *msg)
  237. {
  238. optarg = argv[optind++];
  239. if (optind > argc || optarg[0] == '-') {
  240. fprintf(stderr, "%s\n", msg);
  241. exit(EXIT_FAILURE);
  242. }
  243. }
  244. uint64_t parse_size(void)
  245. {
  246. uint64_t size;
  247. char ext[2];
  248. ext[0] = 0;
  249. if (sscanf(optarg, "%" PRIi64 "%1[kmgKMG]", &size, ext) < 1) {
  250. fprintf(stderr, "Can't parse size arg: %s\n", optarg);
  251. exit(EXIT_FAILURE);
  252. }
  253. switch (ext[0]) {
  254. case 'k':
  255. case 'K':
  256. size *= 1024;
  257. break;
  258. case 'm':
  259. case 'M':
  260. size *= 1024 * 1024;
  261. break;
  262. case 'g':
  263. case 'G':
  264. size *= 1024 * 1024 * 1024;
  265. break;
  266. default:
  267. break;
  268. }
  269. return size;
  270. }
  271. int main(int argc, char **argv)
  272. {
  273. uint32_t major_version, minor_version;
  274. uint32_t domain, from, to, count;
  275. uint64_t size;
  276. int fd, r, c;
  277. fd = amdgpu_open_device();
  278. if (fd < 0) {
  279. perror("Cannot open AMDGPU device");
  280. exit(EXIT_FAILURE);
  281. }
  282. r = amdgpu_device_initialize(fd, &major_version, &minor_version, &device_handle);
  283. if (r) {
  284. fprintf(stderr, "amdgpu_device_initialize returned %d\n", r);
  285. exit(EXIT_FAILURE);
  286. }
  287. r = amdgpu_cs_ctx_create(device_handle, &context_handle);
  288. if (r) {
  289. fprintf(stderr, "amdgpu_cs_ctx_create returned %d\n", r);
  290. exit(EXIT_FAILURE);
  291. }
  292. if (argc == 1) {
  293. fprintf(stderr, usage, argv[0]);
  294. exit(EXIT_FAILURE);
  295. }
  296. r = alloc_bo(AMDGPU_GEM_DOMAIN_GTT, 2ULL * 1024 * 1024);
  297. if (r) {
  298. fprintf(stderr, "Buffer allocation failed with %d\n", r);
  299. exit(EXIT_FAILURE);
  300. }
  301. r = amdgpu_bo_cpu_map(resources[0], (void **)&pm4);
  302. if (r) {
  303. fprintf(stderr, "Buffer mapping failed with %d\n", r);
  304. exit(EXIT_FAILURE);
  305. }
  306. opterr = 0;
  307. while ((c = getopt(argc, argv, options)) != -1) {
  308. switch (c) {
  309. case 'b':
  310. if (!strcmp(optarg, "v"))
  311. domain = AMDGPU_GEM_DOMAIN_VRAM;
  312. else if (!strcmp(optarg, "g"))
  313. domain = AMDGPU_GEM_DOMAIN_GTT;
  314. else if (!strcmp(optarg, "vg"))
  315. domain = AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT;
  316. else {
  317. fprintf(stderr, "Invalid domain: %s\n", optarg);
  318. exit(EXIT_FAILURE);
  319. }
  320. next_arg(argc, argv, "Missing buffer size");
  321. size = parse_size();
  322. if (size < getpagesize()) {
  323. fprintf(stderr, "Buffer size to small %" PRIu64 "\n", size);
  324. exit(EXIT_FAILURE);
  325. }
  326. r = alloc_bo(domain, size);
  327. if (r) {
  328. fprintf(stderr, "Buffer allocation failed with %d\n", r);
  329. exit(EXIT_FAILURE);
  330. }
  331. break;
  332. case 'c':
  333. if (sscanf(optarg, "%u", &from) != 1) {
  334. fprintf(stderr, "Can't parse from buffer: %s\n", optarg);
  335. exit(EXIT_FAILURE);
  336. }
  337. next_arg(argc, argv, "Missing to buffer");
  338. if (sscanf(optarg, "%u", &to) != 1) {
  339. fprintf(stderr, "Can't parse to buffer: %s\n", optarg);
  340. exit(EXIT_FAILURE);
  341. }
  342. next_arg(argc, argv, "Missing size");
  343. size = parse_size();
  344. next_arg(argc, argv, "Missing count");
  345. count = parse_size();
  346. r = submit_ib(from, to, size, count);
  347. if (r) {
  348. fprintf(stderr, "IB submission failed with %d\n", r);
  349. exit(EXIT_FAILURE);
  350. }
  351. break;
  352. case '?':
  353. case 'h':
  354. fprintf(stderr, usage, argv[0]);
  355. exit(EXIT_SUCCESS);
  356. default:
  357. fprintf(stderr, usage, argv[0]);
  358. exit(EXIT_FAILURE);
  359. }
  360. }
  361. return EXIT_SUCCESS;
  362. }