qdio_perf.c 4.4 KB
Newer Older
J
Jan Glauber 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
/*
 *  drivers/s390/cio/qdio_perf.c
 *
 *  Copyright IBM Corp. 2008
 *
 *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
 */
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/ccwdev.h>

#include "cio.h"
#include "css.h"
#include "device.h"
#include "ioasm.h"
#include "chsc.h"
#include "qdio_debug.h"
#include "qdio_perf.h"

int qdio_performance_stats;
struct qdio_perf_stats perf_stats;

#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *qdio_perf_pde;
#endif

inline void qdio_perf_stat_inc(atomic_long_t *count)
{
	if (qdio_performance_stats)
		atomic_long_inc(count);
}

inline void qdio_perf_stat_dec(atomic_long_t *count)
{
	if (qdio_performance_stats)
		atomic_long_dec(count);
}

/*
 * procfs functions
 */
static int qdio_perf_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, "Number of qdio interrupts\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.qdio_int));
	seq_printf(m, "Number of PCI interrupts\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.pci_int));
	seq_printf(m, "Number of adapter interrupts\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.thin_int));
	seq_printf(m, "\n");
	seq_printf(m, "Inbound tasklet runs\t\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.tasklet_inbound));
	seq_printf(m, "Outbound tasklet runs\t\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.tasklet_outbound));
	seq_printf(m, "Adapter interrupt tasklet runs/loops\t\t: %li/%li\n",
		   (long)atomic_long_read(&perf_stats.tasklet_thinint),
		   (long)atomic_long_read(&perf_stats.tasklet_thinint_loop));
	seq_printf(m, "Adapter interrupt inbound tasklet runs/loops\t: %li/%li\n",
		   (long)atomic_long_read(&perf_stats.thinint_inbound),
		   (long)atomic_long_read(&perf_stats.thinint_inbound_loop));
	seq_printf(m, "\n");
	seq_printf(m, "Number of SIGA In issued\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.siga_in));
	seq_printf(m, "Number of SIGA Out issued\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.siga_out));
	seq_printf(m, "Number of SIGA Sync issued\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.siga_sync));
	seq_printf(m, "\n");
	seq_printf(m, "Number of inbound transfers\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.inbound_handler));
	seq_printf(m, "Number of outbound transfers\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.outbound_handler));
	seq_printf(m, "\n");
	seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n",
		   (long)atomic_long_read(&perf_stats.fast_requeue));
	seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n",
		   (long)atomic_long_read(&perf_stats.debug_tl_out_timer));
	seq_printf(m, "Number of stop polling calls\t\t\t: %li\n",
		   (long)atomic_long_read(&perf_stats.debug_stop_polling));
	seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n",
		   (long)atomic_long_read(&perf_stats.thinint_inbound_loop2));
	seq_printf(m, "\n");
	return 0;
}
static int qdio_perf_seq_open(struct inode *inode, struct file *filp)
{
	return single_open(filp, qdio_perf_proc_show, NULL);
}

static struct file_operations qdio_perf_proc_fops = {
	.owner	 = THIS_MODULE,
	.open	 = qdio_perf_seq_open,
	.read	 = seq_read,
	.llseek  = seq_lseek,
	.release = single_release,
};

/*
 * sysfs functions
 */
static ssize_t qdio_perf_stats_show(struct bus_type *bus, char *buf)
{
	return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
}

static ssize_t qdio_perf_stats_store(struct bus_type *bus,
			      const char *buf, size_t count)
{
	unsigned long i;

	if (strict_strtoul(buf, 16, &i) != 0)
		return -EINVAL;
	if ((i != 0) && (i != 1))
		return -EINVAL;
	if (i == qdio_performance_stats)
		return count;

	qdio_performance_stats = i;
	/* reset performance statistics */
	if (i == 0)
		memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
	return count;
}

static BUS_ATTR(qdio_performance_stats, 0644, qdio_perf_stats_show,
		qdio_perf_stats_store);

int __init qdio_setup_perf_stats(void)
{
	int rc;

	rc = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
	if (rc)
		return rc;

#ifdef CONFIG_PROC_FS
	memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
	qdio_perf_pde = proc_create("qdio_perf", S_IFREG | S_IRUGO,
				    NULL, &qdio_perf_proc_fops);
#endif
	return 0;
}

145
void qdio_remove_perf_stats(void)
J
Jan Glauber 已提交
146 147 148 149 150 151
{
#ifdef CONFIG_PROC_FS
	remove_proc_entry("qdio_perf", NULL);
#endif
	bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
}