123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * perf.c - performance monitor
- *
- * Copyright (C) 2021 Intel Corporation
- *
- * Author: Lu Baolu <[email protected]>
- * Fenghua Yu <[email protected]>
- */
- #include <linux/spinlock.h>
- #include "iommu.h"
- #include "perf.h"
- static DEFINE_SPINLOCK(latency_lock);
- bool dmar_latency_enabled(struct intel_iommu *iommu, enum latency_type type)
- {
- struct latency_statistic *lstat = iommu->perf_statistic;
- return lstat && lstat[type].enabled;
- }
- int dmar_latency_enable(struct intel_iommu *iommu, enum latency_type type)
- {
- struct latency_statistic *lstat;
- unsigned long flags;
- int ret = -EBUSY;
- if (dmar_latency_enabled(iommu, type))
- return 0;
- spin_lock_irqsave(&latency_lock, flags);
- if (!iommu->perf_statistic) {
- iommu->perf_statistic = kzalloc(sizeof(*lstat) * DMAR_LATENCY_NUM,
- GFP_ATOMIC);
- if (!iommu->perf_statistic) {
- ret = -ENOMEM;
- goto unlock_out;
- }
- }
- lstat = iommu->perf_statistic;
- if (!lstat[type].enabled) {
- lstat[type].enabled = true;
- lstat[type].counter[COUNTS_MIN] = UINT_MAX;
- ret = 0;
- }
- unlock_out:
- spin_unlock_irqrestore(&latency_lock, flags);
- return ret;
- }
- void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
- {
- struct latency_statistic *lstat = iommu->perf_statistic;
- unsigned long flags;
- if (!dmar_latency_enabled(iommu, type))
- return;
- spin_lock_irqsave(&latency_lock, flags);
- memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
- spin_unlock_irqrestore(&latency_lock, flags);
- }
- void dmar_latency_update(struct intel_iommu *iommu, enum latency_type type, u64 latency)
- {
- struct latency_statistic *lstat = iommu->perf_statistic;
- unsigned long flags;
- u64 min, max;
- if (!dmar_latency_enabled(iommu, type))
- return;
- spin_lock_irqsave(&latency_lock, flags);
- if (latency < 100)
- lstat[type].counter[COUNTS_10e2]++;
- else if (latency < 1000)
- lstat[type].counter[COUNTS_10e3]++;
- else if (latency < 10000)
- lstat[type].counter[COUNTS_10e4]++;
- else if (latency < 100000)
- lstat[type].counter[COUNTS_10e5]++;
- else if (latency < 1000000)
- lstat[type].counter[COUNTS_10e6]++;
- else if (latency < 10000000)
- lstat[type].counter[COUNTS_10e7]++;
- else
- lstat[type].counter[COUNTS_10e8_plus]++;
- min = lstat[type].counter[COUNTS_MIN];
- max = lstat[type].counter[COUNTS_MAX];
- lstat[type].counter[COUNTS_MIN] = min_t(u64, min, latency);
- lstat[type].counter[COUNTS_MAX] = max_t(u64, max, latency);
- lstat[type].counter[COUNTS_SUM] += latency;
- lstat[type].samples++;
- spin_unlock_irqrestore(&latency_lock, flags);
- }
- static char *latency_counter_names[] = {
- " <0.1us",
- " 0.1us-1us", " 1us-10us", " 10us-100us",
- " 100us-1ms", " 1ms-10ms", " >=10ms",
- " min(us)", " max(us)", " average(us)"
- };
- static char *latency_type_names[] = {
- " inv_iotlb", " inv_devtlb", " inv_iec",
- " svm_prq"
- };
- int dmar_latency_snapshot(struct intel_iommu *iommu, char *str, size_t size)
- {
- struct latency_statistic *lstat = iommu->perf_statistic;
- unsigned long flags;
- int bytes = 0, i, j;
- memset(str, 0, size);
- for (i = 0; i < COUNTS_NUM; i++)
- bytes += snprintf(str + bytes, size - bytes,
- "%s", latency_counter_names[i]);
- spin_lock_irqsave(&latency_lock, flags);
- for (i = 0; i < DMAR_LATENCY_NUM; i++) {
- if (!dmar_latency_enabled(iommu, i))
- continue;
- bytes += snprintf(str + bytes, size - bytes,
- "\n%s", latency_type_names[i]);
- for (j = 0; j < COUNTS_NUM; j++) {
- u64 val = lstat[i].counter[j];
- switch (j) {
- case COUNTS_MIN:
- if (val == UINT_MAX)
- val = 0;
- else
- val = div_u64(val, 1000);
- break;
- case COUNTS_MAX:
- val = div_u64(val, 1000);
- break;
- case COUNTS_SUM:
- if (lstat[i].samples)
- val = div_u64(val, (lstat[i].samples * 1000));
- else
- val = 0;
- break;
- default:
- break;
- }
- bytes += snprintf(str + bytes, size - bytes,
- "%12lld", val);
- }
- }
- spin_unlock_irqrestore(&latency_lock, flags);
- return bytes;
- }
|