cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

perf.c (4029B)


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