perf.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * perf.c - performance monitor
  4. *
  5. * Copyright (C) 2021 Intel Corporation
  6. *
  7. * Author: Lu Baolu <[email protected]>
  8. * Fenghua Yu <[email protected]>
  9. */
  10. #include <linux/spinlock.h>
  11. #include "iommu.h"
  12. #include "perf.h"
  13. static DEFINE_SPINLOCK(latency_lock);
  14. bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
  15. {
  16. struct latency_statistic *lstat = iommu->perf_statistic;
  17. return lstat && lstat[type].enabled;
  18. }
  19. int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
  20. {
  21. struct latency_statistic *lstat;
  22. unsigned long flags;
  23. int ret = -EBUSY;
  24. if (dmar_latency_enabled(iommu, type))
  25. return 0;
  26. spin_lock_irqsave(&latency_lock, flags);
  27. if (!iommu->perf_statistic) {
  28. iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
  29. GFP_ATOMIC);
  30. if (!iommu->perf_statistic) {
  31. ret = -ENOMEM;
  32. goto unlock_out;
  33. }
  34. }
  35. lstat = iommu->perf_statistic;
  36. if (!lstat[type].enabled) {
  37. lstat[type].enabled = true;
  38. lstat[type].counter[COUNTS_MIN] = UINT_MAX;
  39. ret = 0;
  40. }
  41. unlock_out:
  42. spin_unlock_irqrestore(&latency_lock, flags);
  43. return ret;
  44. }
  45. void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
  46. {
  47. struct latency_statistic *lstat = iommu->perf_statistic;
  48. unsigned long flags;
  49. if (!dmar_latency_enabled(iommu, type))
  50. return;
  51. spin_lock_irqsave(&latency_lock, flags);
  52. memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
  53. spin_unlock_irqrestore(&latency_lock, flags);
  54. }
  55. void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
  56. {
  57. struct latency_statistic *lstat = iommu->perf_statistic;
  58. unsigned long flags;
  59. u64 min, max;
  60. if (!dmar_latency_enabled(iommu, type))
  61. return;
  62. spin_lock_irqsave(&latency_lock, flags);
  63. if (latency < 100)
  64. lstat[type].counter[COUNTS_10e2]++;
  65. else if (latency < 1000)
  66. lstat[type].counter[COUNTS_10e3]++;
  67. else if (latency < 10000)
  68. lstat[type].counter[COUNTS_10e4]++;
  69. else if (latency < 100000)
  70. lstat[type].counter[COUNTS_10e5]++;
  71. else if (latency < 1000000)
  72. lstat[type].counter[COUNTS_10e6]++;
  73. else if (latency < 10000000)
  74. lstat[type].counter[COUNTS_10e7]++;
  75. else
  76. lstat[type].counter[COUNTS_10e8_plus]++;
  77. min = lstat[type].counter[COUNTS_MIN];
  78. max = lstat[type].counter[COUNTS_MAX];
  79. lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
  80. lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
  81. lstat[type].counter[COUNTS_SUM] += latency;
  82. lstat[type].samples++;
  83. spin_unlock_irqrestore(&latency_lock, flags);
  84. }
  85. static char *latency_counter_names[] = {
  86. " <0.1us",
  87. " 0.1us-1us", " 1us-10us", " 10us-100us",
  88. " 100us-1ms", " 1ms-10ms", " >=10ms",
  89. " min(us)", " max(us)", " average(us)"
  90. };
  91. static char *latency_type_names[] = {
  92. " inv_iotlb", " inv_devtlb", " inv_iec",
  93. " svm_prq"
  94. };
  95. int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
  96. {
  97. struct latency_statistic *lstat = iommu->perf_statistic;
  98. unsigned long flags;
  99. int bytes = 0, i, j;
  100. memset(str, 0, size);
  101. for (i = 0; i < COUNTS_NUM; i++)
  102. bytes += snprintf(str + bytes, size - bytes,
  103. "%s", latency_counter_names[i]);
  104. spin_lock_irqsave(&latency_lock, flags);
  105. for (i = 0; i < DMAR_LATENCY_NUM; i++) {
  106. if (!dmar_latency_enabled(iommu, i))
  107. continue;
  108. bytes += snprintf(str + bytes, size - bytes,
  109. "\n%s", latency_type_names[i]);
  110. for (j = 0; j < COUNTS_NUM; j++) {
  111. u64 val = lstat[i].counter[j];
  112. switch (j) {
  113. case COUNTS_MIN:
  114. if (val == UINT_MAX)
  115. val = 0;
  116. else
  117. val = div_u64(val, 1000);
  118. break;
  119. case COUNTS_MAX:
  120. val = div_u64(val, 1000);
  121. break;
  122. case COUNTS_SUM:
  123. if (lstat[i].samples)
  124. val = div_u64(val, (lstat[i].samples * 1000));
  125. else
  126. val = 0;
  127. break;
  128. default:
  129. break;
  130. }
  131. bytes += snprintf(str + bytes, size - bytes,
  132. "%12lld", val);
  133. }
  134. }
  135. spin_unlock_irqrestore(&latency_lock, flags);
  136. return bytes;
  137. }