khab_test.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #include "hab.h"
  7. #include <linux/rtc.h>
  8. #if !defined CONFIG_GHS_VMM && defined(CONFIG_QTI_QUIN_GVM)
  9. #include <linux/cacheflush.h>
  10. #include <linux/list.h>
  11. #include "hab_pipe.h"
  12. #include "hab_qvm.h"
  13. #include "khab_test.h"
  14. static char g_perf_test_result[256];
  15. enum hab_perf_test_type {
  16. HAB_SHMM_THGPUT = 0x0,
  17. };
  18. #define HAB_PERF_TEST_MMID 802
  19. #define PERF_TEST_ITERATION 50
  20. #define MEM_READ_ITERATION 30
  21. static int hab_shmm_throughput_test(void)
  22. {
  23. struct hab_device *habDev;
  24. struct qvm_channel *dev;
  25. struct hab_shared_buf *sh_buf;
  26. struct physical_channel *pchan;
  27. ktime_t start_time = 0, end_time = 0;
  28. int i, counter;
  29. void *test_data;
  30. unsigned char *source_data, *shmm_adr;
  31. register int sum;
  32. register int *pp, *lastone;
  33. int throughput[3][2] = { {0} };
  34. int latency[6][PERF_TEST_ITERATION];
  35. int ret = 0, tmp, size;
  36. habDev = find_hab_device(HAB_PERF_TEST_MMID);
  37. if (!habDev || list_empty(&(habDev->pchannels))) {
  38. ret = -ENOMEM;
  39. return ret;
  40. }
  41. pchan = list_first_entry(&(habDev->pchannels),
  42. struct physical_channel, node);
  43. dev = pchan->hyp_data;
  44. if (!dev) {
  45. ret = -EPERM;
  46. return ret;
  47. }
  48. sh_buf = dev->tx_buf;
  49. /* pChannel is of 128k, we use 64k to test */
  50. size = 0x10000;
  51. if (!sh_buf) {
  52. pr_err("Share buffer address is empty, exit the perf test\n");
  53. ret = -ENOMEM;
  54. return ret;
  55. }
  56. shmm_adr = (unsigned char *)sh_buf->data;
  57. test_data = kzalloc(size, GFP_ATOMIC);
  58. if (!test_data) {
  59. ret = -ENOMEM;
  60. return ret;
  61. }
  62. source_data = kzalloc(size, GFP_ATOMIC);
  63. if (!source_data) {
  64. ret = -ENOMEM;
  65. kfree(test_data);
  66. return ret;
  67. }
  68. for (i = 0; i < PERF_TEST_ITERATION; i++) {
  69. /* Normal memory copy latency */
  70. flush_cache_all();
  71. start_time = ktime_get();
  72. memcpy(test_data, source_data, size);
  73. end_time = ktime_get();
  74. latency[0][i] = ktime_us_delta(end_time, start_time);
  75. /* Share memory copy latency */
  76. flush_cache_all();
  77. start_time = ktime_get();
  78. memcpy(shmm_adr, source_data, size);
  79. end_time = ktime_get();
  80. latency[1][i] = ktime_us_delta(end_time, start_time);
  81. /* Normal memory read latency */
  82. counter = MEM_READ_ITERATION;
  83. sum = 0;
  84. latency[2][i] = 0;
  85. flush_cache_all();
  86. while (counter-- > 0) {
  87. pp = test_data;
  88. lastone = (int *)((char *)test_data + size - 512);
  89. start_time = ktime_get();
  90. while (pp <= lastone) {
  91. sum +=
  92. pp[0] + pp[4] + pp[8] + pp[12]
  93. + pp[16] + pp[20] + pp[24] + pp[28]
  94. + pp[32] + pp[36] + pp[40] + pp[44]
  95. + pp[48] + pp[52] + pp[56] + pp[60]
  96. + pp[64] + pp[68] + pp[72] + pp[76]
  97. + pp[80] + pp[84] + pp[88] + pp[92]
  98. + pp[96] + pp[100] + pp[104]
  99. + pp[108] + pp[112]
  100. + pp[116] + pp[120]
  101. + pp[124];
  102. pp += 128;
  103. }
  104. end_time = ktime_get();
  105. latency[2][i] += ktime_us_delta(end_time, start_time);
  106. flush_cache_all();
  107. }
  108. /* Share memory read latency*/
  109. counter = MEM_READ_ITERATION;
  110. sum = 0;
  111. latency[3][i] = 0;
  112. while (counter-- > 0) {
  113. pp = (int *)shmm_adr;
  114. lastone = (int *)(shmm_adr + size - 512);
  115. start_time = ktime_get();
  116. while (pp <= lastone) {
  117. sum +=
  118. pp[0] + pp[4] + pp[8] + pp[12]
  119. + pp[16] + pp[20] + pp[24] + pp[28]
  120. + pp[32] + pp[36] + pp[40] + pp[44]
  121. + pp[48] + pp[52] + pp[56] + pp[60]
  122. + pp[64] + pp[68] + pp[72] + pp[76]
  123. + pp[80] + pp[84] + pp[88] + pp[92]
  124. + pp[96] + pp[100] + pp[104]
  125. + pp[108] + pp[112]
  126. + pp[116] + pp[120]
  127. + pp[124];
  128. pp += 128;
  129. }
  130. end_time = ktime_get();
  131. latency[3][i] += ktime_us_delta(end_time, start_time);
  132. flush_cache_all();
  133. }
  134. /* Normal memory write latency */
  135. flush_cache_all();
  136. start_time = ktime_get();
  137. memset(test_data, 'c', size);
  138. end_time = ktime_get();
  139. latency[4][i] = ktime_us_delta(end_time, start_time);
  140. /* Share memory write latency */
  141. flush_cache_all();
  142. start_time = ktime_get();
  143. memset(shmm_adr, 'c', size);
  144. end_time = ktime_get();
  145. latency[5][i] = ktime_us_delta(end_time, start_time);
  146. }
  147. /* Calculate normal memory copy throughput by average */
  148. tmp = 0;
  149. for (i = 0; i < PERF_TEST_ITERATION; i++)
  150. tmp += latency[0][i];
  151. throughput[0][0] = (tmp != 0) ? size*PERF_TEST_ITERATION/tmp : 0;
  152. /* Calculate share memory copy throughput by average */
  153. tmp = 0;
  154. for (i = 0; i < PERF_TEST_ITERATION; i++)
  155. tmp += latency[1][i];
  156. throughput[0][1] = (tmp != 0) ? size*PERF_TEST_ITERATION/tmp : 0;
  157. /* Calculate normal memory read throughput by average */
  158. tmp = 0;
  159. for (i = 0; i < PERF_TEST_ITERATION; i++)
  160. tmp += latency[2][i];
  161. throughput[1][0] = (tmp != 0) ?
  162. size*PERF_TEST_ITERATION*MEM_READ_ITERATION/tmp : 0;
  163. /* Calculate share memory read throughput by average */
  164. tmp = 0;
  165. for (i = 0; i < PERF_TEST_ITERATION; i++)
  166. tmp += latency[3][i];
  167. throughput[1][1] = (tmp != 0) ?
  168. size*PERF_TEST_ITERATION*MEM_READ_ITERATION/tmp : 0;
  169. /* Calculate normal memory write throughput by average */
  170. tmp = 0;
  171. for (i = 0; i < PERF_TEST_ITERATION; i++)
  172. tmp += latency[4][i];
  173. throughput[2][0] = (tmp != 0) ?
  174. size*PERF_TEST_ITERATION/tmp : 0;
  175. /* Calculate share memory write throughput by average */
  176. tmp = 0;
  177. for (i = 0; i < PERF_TEST_ITERATION; i++)
  178. tmp += latency[5][i];
  179. throughput[2][1] = (tmp != 0) ?
  180. size*PERF_TEST_ITERATION/tmp : 0;
  181. kfree(test_data);
  182. kfree(source_data);
  183. snprintf(g_perf_test_result, sizeof(g_perf_test_result),
  184. "cpy(%d,%d)/read(%d,%d)/write(%d,%d)",
  185. throughput[0][0], throughput[0][1], throughput[1][0],
  186. throughput[1][1], throughput[2][0], throughput[2][1]);
  187. return ret;
  188. }
  189. int hab_perf_test(long testId)
  190. {
  191. int ret;
  192. switch (testId) {
  193. case HAB_SHMM_THGPUT:
  194. ret = hab_shmm_throughput_test();
  195. break;
  196. default:
  197. pr_err("Invalid performance test ID %ld\n", testId);
  198. ret = -EINVAL;
  199. }
  200. return ret;
  201. }
  202. static int kick_hab_perf_test(const char *val, const struct kernel_param *kp);
  203. static int get_hab_perf_result(char *buffer, const struct kernel_param *kp);
  204. module_param_call(perf_test, kick_hab_perf_test, get_hab_perf_result,
  205. NULL, 0600);
  206. static int kick_hab_perf_test(const char *val, const struct kernel_param *kp)
  207. {
  208. long testId;
  209. int err = kstrtol(val, 10, &testId);
  210. if (err)
  211. return err;
  212. memset(g_perf_test_result, 0, sizeof(g_perf_test_result));
  213. return hab_perf_test(testId);
  214. }
  215. static int get_hab_perf_result(char *buffer, const struct kernel_param *kp)
  216. {
  217. return strscpy(buffer, g_perf_test_result,
  218. strlen(g_perf_test_result)+1);
  219. }
  220. #endif
  221. static struct kobject *hab_kobject;
  222. static int vchan_stat;
  223. static int context_stat;
  224. static int pid_stat;
  225. static ssize_t vchan_show(struct kobject *kobj, struct kobj_attribute *attr,
  226. char *buf)
  227. {
  228. return hab_stat_show_vchan(&hab_driver, buf, PAGE_SIZE);
  229. }
  230. static ssize_t vchan_store(struct kobject *kobj, struct kobj_attribute *attr,
  231. const char *buf, size_t count)
  232. {
  233. int ret;
  234. ret = sscanf(buf, "%du", &vchan_stat);
  235. if (ret < 1) {
  236. pr_err("failed to read anything from input %d\n", ret);
  237. return 0;
  238. } else
  239. return count;
  240. }
  241. static ssize_t ctx_show(struct kobject *kobj, struct kobj_attribute *attr,
  242. char *buf)
  243. {
  244. return hab_stat_show_ctx(&hab_driver, buf, PAGE_SIZE);
  245. }
  246. static ssize_t ctx_store(struct kobject *kobj, struct kobj_attribute *attr,
  247. const char *buf, size_t count)
  248. {
  249. int ret;
  250. ret = sscanf(buf, "%du", &context_stat);
  251. if (ret < 1) {
  252. pr_err("failed to read anything from input %d\n", ret);
  253. return 0;
  254. } else
  255. return count;
  256. }
  257. static ssize_t expimp_show(struct kobject *kobj, struct kobj_attribute *attr,
  258. char *buf)
  259. {
  260. return hab_stat_show_expimp(&hab_driver, pid_stat, buf, PAGE_SIZE);
  261. }
  262. static ssize_t expimp_store(struct kobject *kobj, struct kobj_attribute *attr,
  263. const char *buf, size_t count)
  264. {
  265. int ret = -1;
  266. char str[36] = {0};
  267. struct uhab_context *ctx = NULL;
  268. struct virtual_channel *vchan = NULL;
  269. if (buf) {
  270. ret = sscanf(buf, "%35s", str);
  271. if (ret < 1) {
  272. pr_err("failed to read anything from input %d\n", ret);
  273. return -EINVAL;
  274. }
  275. } else
  276. return -EINVAL;
  277. if (strnlen(str, strlen("dump_pipe")) == strlen("dump_pipe") &&
  278. strcmp(str, "dump_pipe") == 0) {
  279. /* string terminator is ignored */
  280. list_for_each_entry(ctx, &hab_driver.uctx_list, node) {
  281. if (ctx->owner == pid_stat) {
  282. vchan = list_first_entry(&ctx->vchannels,
  283. struct virtual_channel, node);
  284. if (vchan) {
  285. dump_hab_wq(vchan->pchan); /* user context */
  286. }
  287. }
  288. }
  289. return count;
  290. }
  291. ret = sscanf(buf, "%du", &pid_stat);
  292. if (ret < 1)
  293. pr_err("failed to read anything from input %d\n", ret);
  294. else
  295. return count; /* good result stored */
  296. return -EEXIST;
  297. }
  298. static ssize_t reclaim_show(struct kobject *kobj, struct kobj_attribute *attr,
  299. char *buf)
  300. {
  301. return hab_stat_show_reclaim(&hab_driver, buf, PAGE_SIZE);
  302. }
  303. static ssize_t reclaim_store(struct kobject *kobj, struct kobj_attribute *attr,
  304. const char *buf, size_t count)
  305. {
  306. return 0;
  307. }
  308. static struct kobj_attribute vchan_attribute = __ATTR(vchan_stat, 0660,
  309. vchan_show,
  310. vchan_store);
  311. static struct kobj_attribute ctx_attribute = __ATTR(context_stat, 0660,
  312. ctx_show,
  313. ctx_store);
  314. static struct kobj_attribute expimp_attribute = __ATTR(pid_stat, 0660,
  315. expimp_show,
  316. expimp_store);
  317. static struct kobj_attribute reclaim_attribute = __ATTR(reclaim_stat, 0660,
  318. reclaim_show,
  319. reclaim_store);
  320. int hab_stat_init_sub(struct hab_driver *driver)
  321. {
  322. int result;
  323. hab_kobject = kobject_create_and_add("hab", kernel_kobj);
  324. if (!hab_kobject)
  325. return -ENOMEM;
  326. result = sysfs_create_file(hab_kobject, &vchan_attribute.attr);
  327. if (result)
  328. pr_debug("cannot add vchan in /sys/kernel/hab %d\n", result);
  329. result = sysfs_create_file(hab_kobject, &ctx_attribute.attr);
  330. if (result)
  331. pr_debug("cannot add ctx in /sys/kernel/hab %d\n", result);
  332. result = sysfs_create_file(hab_kobject, &expimp_attribute.attr);
  333. if (result)
  334. pr_debug("cannot add expimp in /sys/kernel/hab %d\n", result);
  335. result = sysfs_create_file(hab_kobject, &reclaim_attribute.attr);
  336. if (result)
  337. pr_debug("cannot add reclaim in /sys/kernel/hab %d\n", result);
  338. return result;
  339. }
  340. int hab_stat_deinit_sub(struct hab_driver *driver)
  341. {
  342. sysfs_remove_file(hab_kobject, &vchan_attribute.attr);
  343. sysfs_remove_file(hab_kobject, &ctx_attribute.attr);
  344. sysfs_remove_file(hab_kobject, &expimp_attribute.attr);
  345. kobject_put(hab_kobject);
  346. return 0;
  347. }
  348. int dump_hab_get_file_name(char *file_time, int ft_size)
  349. {
  350. struct timespec64 time = {0};
  351. unsigned long local_time;
  352. struct rtc_time tm;
  353. ktime_get_real_ts64(&time);
  354. local_time = (unsigned long)(time.tv_sec - sys_tz.tz_minuteswest * 60);
  355. rtc_time64_to_tm(local_time, &tm);
  356. snprintf(file_time, ft_size, "%04d_%02d_%02d-%02d_%02d_%02d",
  357. tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
  358. tm.tm_min, tm.tm_sec);
  359. return 0;
  360. }