wfd-util.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/debugfs.h>
  14. #include <linux/hrtimer.h>
  15. #include <linux/limits.h>
  16. #include <linux/mm.h>
  17. #include <linux/slab.h>
  18. #include "wfd-util.h"
  19. static struct dentry *wfd_debugfs_root;
  20. int wfd_stats_setup()
  21. {
  22. wfd_debugfs_root = debugfs_create_dir("wfd", NULL);
  23. if (wfd_debugfs_root == ERR_PTR(-ENODEV))
  24. return -ENODEV;
  25. else if (!wfd_debugfs_root)
  26. return -ENOMEM;
  27. else
  28. return 0;
  29. }
  30. void wfd_stats_teardown()
  31. {
  32. if (wfd_debugfs_root)
  33. debugfs_remove_recursive(wfd_debugfs_root);
  34. }
  35. int wfd_stats_init(struct wfd_stats *stats, int device)
  36. {
  37. char device_str[NAME_MAX] = "";
  38. int rc = 0;
  39. if (!stats) {
  40. rc = -EINVAL;
  41. goto wfd_stats_init_fail;
  42. } else if (!wfd_debugfs_root || wfd_debugfs_root == ERR_PTR(-ENODEV)) {
  43. WFD_MSG_ERR("wfd debugfs root does not exist\n");
  44. rc = -ENOENT;
  45. goto wfd_stats_init_fail;
  46. }
  47. memset(stats, 0, sizeof(*stats));
  48. INIT_LIST_HEAD(&stats->enc_queue);
  49. mutex_init(&stats->mutex);
  50. snprintf(device_str, sizeof(device_str), "%d", device);
  51. stats->d_parent = debugfs_create_dir(device_str, wfd_debugfs_root);
  52. if (IS_ERR(stats->d_parent)) {
  53. rc = PTR_ERR(stats->d_parent);
  54. stats->d_parent = NULL;
  55. goto wfd_stats_init_fail;
  56. }
  57. stats->d_v4l2_buf_count = debugfs_create_u32("v4l2_buf_count", S_IRUGO,
  58. stats->d_parent, &stats->v4l2_buf_count);
  59. if (IS_ERR(stats->d_v4l2_buf_count)) {
  60. rc = PTR_ERR(stats->d_v4l2_buf_count);
  61. stats->d_v4l2_buf_count = NULL;
  62. goto wfd_stats_init_fail;
  63. }
  64. stats->d_mdp_buf_count = debugfs_create_u32("mdp_buf_count", S_IRUGO,
  65. stats->d_parent, &stats->mdp_buf_count);
  66. if (IS_ERR(stats->d_mdp_buf_count)) {
  67. rc = PTR_ERR(stats->d_mdp_buf_count);
  68. stats->d_mdp_buf_count = NULL;
  69. goto wfd_stats_init_fail;
  70. }
  71. stats->d_vsg_buf_count = debugfs_create_u32("vsg_buf_count", S_IRUGO,
  72. stats->d_parent, &stats->vsg_buf_count);
  73. if (IS_ERR(stats->d_vsg_buf_count)) {
  74. rc = PTR_ERR(stats->d_vsg_buf_count);
  75. stats->d_vsg_buf_count = NULL;
  76. goto wfd_stats_init_fail;
  77. }
  78. stats->d_enc_buf_count = debugfs_create_u32("enc_buf_count", S_IRUGO,
  79. stats->d_parent, &stats->enc_buf_count);
  80. if (IS_ERR(stats->d_enc_buf_count)) {
  81. rc = PTR_ERR(stats->d_enc_buf_count);
  82. stats->d_enc_buf_count = NULL;
  83. goto wfd_stats_init_fail;
  84. }
  85. stats->d_frames_encoded = debugfs_create_u32("frames_encoded", S_IRUGO,
  86. stats->d_parent, &stats->frames_encoded);
  87. if (IS_ERR(stats->d_frames_encoded)) {
  88. rc = PTR_ERR(stats->d_frames_encoded);
  89. stats->d_frames_encoded = NULL;
  90. goto wfd_stats_init_fail;
  91. }
  92. stats->d_mdp_updates = debugfs_create_u32("mdp_updates", S_IRUGO,
  93. stats->d_parent, &stats->mdp_updates);
  94. if (IS_ERR(stats->d_mdp_updates)) {
  95. rc = PTR_ERR(stats->d_mdp_updates);
  96. stats->d_mdp_updates = NULL;
  97. goto wfd_stats_init_fail;
  98. }
  99. stats->d_enc_avg_latency = debugfs_create_u32("enc_avg_latency",
  100. S_IRUGO, stats->d_parent, &stats->enc_avg_latency);
  101. if (IS_ERR(stats->d_enc_avg_latency)) {
  102. rc = PTR_ERR(stats->d_enc_avg_latency);
  103. stats->d_enc_avg_latency = NULL;
  104. goto wfd_stats_init_fail;
  105. }
  106. return rc;
  107. wfd_stats_init_fail:
  108. return rc;
  109. }
  110. int wfd_stats_update(struct wfd_stats *stats, enum wfd_stats_event event)
  111. {
  112. int rc = 0;
  113. mutex_lock(&stats->mutex);
  114. switch (event) {
  115. case WFD_STAT_EVENT_CLIENT_QUEUE:
  116. stats->v4l2_buf_count++;
  117. break;
  118. case WFD_STAT_EVENT_CLIENT_DEQUEUE: {
  119. struct wfd_stats_encode_sample *sample = NULL;
  120. stats->v4l2_buf_count--;
  121. if (!list_empty(&stats->enc_queue))
  122. sample = list_first_entry(&stats->enc_queue,
  123. struct wfd_stats_encode_sample,
  124. list);
  125. if (sample) {
  126. ktime_t kdiff = ktime_sub(ktime_get(),
  127. sample->encode_start_ts);
  128. uint32_t diff = ktime_to_ms(kdiff);
  129. stats->enc_cumulative_latency += diff;
  130. stats->enc_latency_samples++;
  131. stats->enc_avg_latency = stats->enc_cumulative_latency /
  132. stats->enc_latency_samples;
  133. list_del(&sample->list);
  134. kfree(sample);
  135. sample = NULL;
  136. }
  137. break;
  138. }
  139. case WFD_STAT_EVENT_MDP_QUEUE:
  140. stats->mdp_buf_count++;
  141. break;
  142. case WFD_STAT_EVENT_MDP_DEQUEUE:
  143. stats->mdp_buf_count--;
  144. stats->mdp_updates++;
  145. break;
  146. case WFD_STAT_EVENT_ENC_QUEUE: {
  147. struct wfd_stats_encode_sample *sample = NULL;
  148. stats->enc_buf_count++;
  149. stats->frames_encoded++;
  150. sample = kzalloc(sizeof(*sample), GFP_KERNEL);
  151. if (sample) {
  152. INIT_LIST_HEAD(&sample->list);
  153. sample->encode_start_ts = ktime_get();
  154. list_add_tail(&sample->list, &stats->enc_queue);
  155. } else {
  156. WFD_MSG_WARN("Unable to measure latency\n");
  157. }
  158. break;
  159. }
  160. case WFD_STAT_EVENT_ENC_DEQUEUE:
  161. stats->enc_buf_count--;
  162. break;
  163. case WFD_STAT_EVENT_VSG_QUEUE:
  164. stats->vsg_buf_count++;
  165. break;
  166. case WFD_STAT_EVENT_VSG_DEQUEUE:
  167. stats->vsg_buf_count--;
  168. break;
  169. default:
  170. rc = -ENOTSUPP;
  171. }
  172. mutex_unlock(&stats->mutex);
  173. return rc;
  174. }
  175. int wfd_stats_deinit(struct wfd_stats *stats)
  176. {
  177. WFD_MSG_DBG("Latencies: avg enc. latency %d",
  178. stats->enc_avg_latency);
  179. /* Delete all debugfs files in one shot :) */
  180. if (stats->d_parent)
  181. debugfs_remove_recursive(stats->d_parent);
  182. stats->d_parent =
  183. stats->d_v4l2_buf_count =
  184. stats->d_mdp_buf_count =
  185. stats->d_vsg_buf_count =
  186. stats->d_enc_buf_count =
  187. stats->d_frames_encoded =
  188. stats->d_mdp_updates =
  189. stats->d_enc_avg_latency = NULL;
  190. return 0;
  191. }