Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * perf.c - performance monitor
0004  *
0005  * Copyright (C) 2021 Intel Corporation
0006  *
0007  * Author: Lu Baolu <baolu.lu@linux.intel.com>
0008  *         Fenghua Yu <fenghua.yu@intel.com>
0009  */
0010 
0011 #include <linux/spinlock.h>
0012 
0013 #include "iommu.h"
0014 #include "perf.h"
0015 
0016 static DEFINE_SPINLOCK(latency_lock);
0017 
0018 bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
0019 {
0020     struct latency_statistic *lstat = iommu->perf_statistic;
0021 
0022     return lstat && lstat[type].enabled;
0023 }
0024 
0025 int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
0026 {
0027     struct latency_statistic *lstat;
0028     unsigned long flags;
0029     int ret = -EBUSY;
0030 
0031     if (dmar_latency_enabled(iommu, type))
0032         return 0;
0033 
0034     spin_lock_irqsave(&latency_lock, flags);
0035     if (!iommu->perf_statistic) {
0036         iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
0037                         GFP_ATOMIC);
0038         if (!iommu->perf_statistic) {
0039             ret = -ENOMEM;
0040             goto unlock_out;
0041         }
0042     }
0043 
0044     lstat = iommu->perf_statistic;
0045 
0046     if (!lstat[type].enabled) {
0047         lstat[type].enabled = true;
0048         lstat[type].counter[COUNTS_MIN] = UINT_MAX;
0049         ret = 0;
0050     }
0051 unlock_out:
0052     spin_unlock_irqrestore(&latency_lock, flags);
0053 
0054     return ret;
0055 }
0056 
0057 void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
0058 {
0059     struct latency_statistic *lstat = iommu->perf_statistic;
0060     unsigned long flags;
0061 
0062     if (!dmar_latency_enabled(iommu, type))
0063         return;
0064 
0065     spin_lock_irqsave(&latency_lock, flags);
0066     memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
0067     spin_unlock_irqrestore(&latency_lock, flags);
0068 }
0069 
0070 void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
0071 {
0072     struct latency_statistic *lstat = iommu->perf_statistic;
0073     unsigned long flags;
0074     u64 min, max;
0075 
0076     if (!dmar_latency_enabled(iommu, type))
0077         return;
0078 
0079     spin_lock_irqsave(&latency_lock, flags);
0080     if (latency < 100)
0081         lstat[type].counter[COUNTS_10e2]++;
0082     else if (latency < 1000)
0083         lstat[type].counter[COUNTS_10e3]++;
0084     else if (latency < 10000)
0085         lstat[type].counter[COUNTS_10e4]++;
0086     else if (latency < 100000)
0087         lstat[type].counter[COUNTS_10e5]++;
0088     else if (latency < 1000000)
0089         lstat[type].counter[COUNTS_10e6]++;
0090     else if (latency < 10000000)
0091         lstat[type].counter[COUNTS_10e7]++;
0092     else
0093         lstat[type].counter[COUNTS_10e8_plus]++;
0094 
0095     min = lstat[type].counter[COUNTS_MIN];
0096     max = lstat[type].counter[COUNTS_MAX];
0097     lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
0098     lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
0099     lstat[type].counter[COUNTS_SUM] += latency;
0100     lstat[type].samples++;
0101     spin_unlock_irqrestore(&latency_lock, flags);
0102 }
0103 
0104 static char *latency_counter_names[] = {
0105     "                  <0.1us",
0106     "   0.1us-1us", "    1us-10us", "  10us-100us",
0107     "   100us-1ms", "    1ms-10ms", "      >=10ms",
0108     "     min(us)", "     max(us)", " average(us)"
0109 };
0110 
0111 static char *latency_type_names[] = {
0112     "   inv_iotlb", "  inv_devtlb", "     inv_iec",
0113     "     svm_prq"
0114 };
0115 
0116 int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
0117 {
0118     struct latency_statistic *lstat = iommu->perf_statistic;
0119     unsigned long flags;
0120     int bytes = 0, i, j;
0121 
0122     memset(str, 0, size);
0123 
0124     for (i = 0; i < COUNTS_NUM; i++)
0125         bytes += snprintf(str + bytes, size - bytes,
0126                   "%s", latency_counter_names[i]);
0127 
0128     spin_lock_irqsave(&latency_lock, flags);
0129     for (i = 0; i < DMAR_LATENCY_NUM; i++) {
0130         if (!dmar_latency_enabled(iommu, i))
0131             continue;
0132 
0133         bytes += snprintf(str + bytes, size - bytes,
0134                   "\n%s", latency_type_names[i]);
0135 
0136         for (j = 0; j < COUNTS_NUM; j++) {
0137             u64 val = lstat[i].counter[j];
0138 
0139             switch (j) {
0140             case COUNTS_MIN:
0141                 if (val == UINT_MAX)
0142                     val = 0;
0143                 else
0144                     val = div_u64(val, 1000);
0145                 break;
0146             case COUNTS_MAX:
0147                 val = div_u64(val, 1000);
0148                 break;
0149             case COUNTS_SUM:
0150                 if (lstat[i].samples)
0151                     val = div_u64(val, (lstat[i].samples * 1000));
0152                 else
0153                     val = 0;
0154                 break;
0155             default:
0156                 break;
0157             }
0158 
0159             bytes += snprintf(str + bytes, size - bytes,
0160                       "%12lld", val);
0161         }
0162     }
0163     spin_unlock_irqrestore(&latency_lock, flags);
0164 
0165     return bytes;
0166 }