/** * Show the counters to the user * * @param m * @param v * @return */ static int proc_perf_show(struct seq_file *m, void *v) { int cpu; int i; proc_perf_update(); seq_printf(m, " %16s %16s\n", proc_perf_label[proc_perf_counter_control[0]], proc_perf_label[proc_perf_counter_control[1]]); for (cpu = 0; cpu < NR_CPUS; cpu++) { if (cpu_online(cpu)) seq_printf(m, "CPU%2d: %16lu %16lu\n", cpu, proc_perf_counter_data[cpu][0], proc_perf_counter_data[cpu][1]); } seq_printf(m, "\n"); for (i = 0; i < 4; i++) seq_printf(m, "%s: %lu\n", proc_perf_l2label[proc_perf_l2counter_control[i]], proc_perf_l2counter_data[i]); seq_printf(m, "\n" "Configuration of the performance counters is controller by writing\n" "one of the following values to:\n" " /sys/module/perf_counters/parameters/counter{0,1}\n" " /sys/module/perf_counters/parameters/l2counter{0-3}\n" "\n" "Possible CPU counters:"); for (i = 0; i < PROC_PERF_CORE_MAX; i++) { if ((i & 7) == 0) seq_printf(m, "\n "); if (proc_perf_label[i]) seq_printf(m, "%s ", proc_perf_label[i]); } seq_printf(m, "\n\nPossible L2 counters:"); for (i = 0; i < PROC_PERF_L2_MAX; i++) { if ((i & 3) == 0) seq_printf(m, "\n "); if (proc_perf_l2label[i]) seq_printf(m, "%s ", proc_perf_l2label[i]); } seq_printf(m, "\nWarning: Counter configuration doesn't update till you access /proc/octeon_perf.\n"); proc_perf_setup(); return 0; }
/** * Module initialization * * @return */ static int __init proc_perf_init(void) { printk("/proc/octeon_perf: Octeon performace counter interface loaded\n"); memset(proc_perf_label, 0, sizeof(proc_perf_label)); memset(proc_perf_l2label, 0, sizeof(proc_perf_l2label)); proc_perf_label[PROC_PERF_CORE_NONE] = "none"; proc_perf_label[PROC_PERF_CORE_CLK] = "clk"; proc_perf_label[PROC_PERF_CORE_ISSUE] = "issue"; proc_perf_label[PROC_PERF_CORE_RET] = "ret"; proc_perf_label[PROC_PERF_CORE_NISSUE] = "nissue"; proc_perf_label[PROC_PERF_CORE_SISSUE] = "sissue"; proc_perf_label[PROC_PERF_CORE_DISSUE] = "dissue"; proc_perf_label[PROC_PERF_CORE_IFI] = "ifi"; proc_perf_label[PROC_PERF_CORE_BR] = "br"; proc_perf_label[PROC_PERF_CORE_BRMIS] = "brmis"; proc_perf_label[PROC_PERF_CORE_J] = "j"; proc_perf_label[PROC_PERF_CORE_JMIS] = "jmis"; proc_perf_label[PROC_PERF_CORE_REPLAY] = "replay"; proc_perf_label[PROC_PERF_CORE_IUNA] = "iuna"; proc_perf_label[PROC_PERF_CORE_TRAP] = "trap"; proc_perf_label[PROC_PERF_CORE_UULOAD] = "uuload"; proc_perf_label[PROC_PERF_CORE_UUSTORE] = "uustore"; proc_perf_label[PROC_PERF_CORE_ULOAD] = "uload"; proc_perf_label[PROC_PERF_CORE_USTORE] = "ustore"; proc_perf_label[PROC_PERF_CORE_EC] = "ec"; proc_perf_label[PROC_PERF_CORE_MC] = "mc"; proc_perf_label[PROC_PERF_CORE_CC] = "cc"; proc_perf_label[PROC_PERF_CORE_CSRC] = "csrc"; proc_perf_label[PROC_PERF_CORE_CFETCH] = "cfetch"; proc_perf_label[PROC_PERF_CORE_CPREF] = "cpref"; proc_perf_label[PROC_PERF_CORE_ICA] = "ica"; proc_perf_label[PROC_PERF_CORE_II] = "ii"; proc_perf_label[PROC_PERF_CORE_IP] = "ip"; proc_perf_label[PROC_PERF_CORE_CIMISS] = "cimiss"; proc_perf_label[PROC_PERF_CORE_WBUF] = "wbuf"; proc_perf_label[PROC_PERF_CORE_WDAT] = "wdat"; proc_perf_label[PROC_PERF_CORE_WBUFLD] = "wbufld"; proc_perf_label[PROC_PERF_CORE_WBUFFL] = "wbuffl"; proc_perf_label[PROC_PERF_CORE_WBUFTR] = "wbuftr"; proc_perf_label[PROC_PERF_CORE_BADD] = "badd"; proc_perf_label[PROC_PERF_CORE_BADDL2] = "baddl2"; proc_perf_label[PROC_PERF_CORE_BFILL] = "bfill"; proc_perf_label[PROC_PERF_CORE_DDIDS] = "ddids"; proc_perf_label[PROC_PERF_CORE_IDIDS] = "idids"; proc_perf_label[PROC_PERF_CORE_DIDNA] = "didna"; proc_perf_label[PROC_PERF_CORE_LDS] = "lds"; proc_perf_label[PROC_PERF_CORE_LMLDS] = "lmlds"; proc_perf_label[PROC_PERF_CORE_IOLDS] = "iolds"; proc_perf_label[PROC_PERF_CORE_DMLDS] = "dmlds"; proc_perf_label[PROC_PERF_CORE_STS] = "sts"; proc_perf_label[PROC_PERF_CORE_LMSTS] = "lmsts"; proc_perf_label[PROC_PERF_CORE_IOSTS] = "iosts"; proc_perf_label[PROC_PERF_CORE_IOBDMA] = "iobdma"; proc_perf_label[PROC_PERF_CORE_DTLB] = "dtlb"; proc_perf_label[PROC_PERF_CORE_DTLBAD] = "dtlbad"; proc_perf_label[PROC_PERF_CORE_ITLB] = "itlb"; proc_perf_label[PROC_PERF_CORE_SYNC] = "sync"; proc_perf_label[PROC_PERF_CORE_SYNCIOB] = "synciob"; proc_perf_label[PROC_PERF_CORE_SYNCW] = "syncw"; proc_perf_l2label[PROC_PERF_L2_CYCLES] = "cycles"; proc_perf_l2label[PROC_PERF_L2_IMISS] = "imiss"; proc_perf_l2label[PROC_PERF_L2_IHIT] = "ihit"; proc_perf_l2label[PROC_PERF_L2_DMISS] = "dmiss"; proc_perf_l2label[PROC_PERF_L2_DHIT] = "dhit"; proc_perf_l2label[PROC_PERF_L2_MISS] = "miss"; proc_perf_l2label[PROC_PERF_L2_HIT] = "hit"; proc_perf_l2label[PROC_PERF_L2_VICTIM_BUFFER_HIT] = "victim-buffer-hit"; proc_perf_l2label[PROC_PERF_L2_LFB_NQ_INDEX_CONFLICT] = "lfb-nq-index-conflict"; proc_perf_l2label[PROC_PERF_L2_TAG_PROBE] = "tag-probe"; proc_perf_l2label[PROC_PERF_L2_TAG_UPDATE] = "tag-update"; proc_perf_l2label[PROC_PERF_L2_TAG_PROBE_COMPLETED] = "tag-probe-completed"; proc_perf_l2label[PROC_PERF_L2_TAG_DIRTY_VICTIM] = "tag-dirty-victim"; proc_perf_l2label[PROC_PERF_L2_DATA_STORE_NOP] = "data-store-nop"; proc_perf_l2label[PROC_PERF_L2_DATA_STORE_READ] = "data-store-read"; proc_perf_l2label[PROC_PERF_L2_DATA_STORE_WRITE] = "data-store-write"; proc_perf_l2label[PROC_PERF_L2_MEMORY_FILL_DATA_VALID] = "memory-fill-data-valid"; proc_perf_l2label[PROC_PERF_L2_MEMORY_WRITE_REQUEST] = "memory-write-request"; proc_perf_l2label[PROC_PERF_L2_MEMORY_READ_REQUEST] = "memory-read-request"; proc_perf_l2label[PROC_PERF_L2_MEMORY_WRITE_DATA_VALID] = "memory-write-data-valid"; proc_perf_l2label[PROC_PERF_L2_XMC_NOP] = "xmc-nop"; proc_perf_l2label[PROC_PERF_L2_XMC_LDT] = "xmc-ldt"; proc_perf_l2label[PROC_PERF_L2_XMC_LDI] = "xmc-ldi"; proc_perf_l2label[PROC_PERF_L2_XMC_LDD] = "xmc-ldd"; proc_perf_l2label[PROC_PERF_L2_XMC_STF] = "xmc-stf"; proc_perf_l2label[PROC_PERF_L2_XMC_STT] = "xmc-stt"; proc_perf_l2label[PROC_PERF_L2_XMC_STP] = "xmc-stp"; proc_perf_l2label[PROC_PERF_L2_XMC_STC] = "xmc-stc"; proc_perf_l2label[PROC_PERF_L2_XMC_DWB] = "xmc-dwb"; proc_perf_l2label[PROC_PERF_L2_XMC_PL2] = "xmc-pl2"; proc_perf_l2label[PROC_PERF_L2_XMC_PSL1] = "xmc-psl1"; proc_perf_l2label[PROC_PERF_L2_XMC_IOBLD] = "xmc-iobld"; proc_perf_l2label[PROC_PERF_L2_XMC_IOBST] = "xmc-iobst"; proc_perf_l2label[PROC_PERF_L2_XMC_IOBDMA] = "xmc-iobdma"; proc_perf_l2label[PROC_PERF_L2_XMC_IOBRSP] = "xmc-iobrsp"; proc_perf_l2label[PROC_PERF_L2_XMD_BUS_VALID] = "xmd-bus-valid"; proc_perf_l2label[PROC_PERF_L2_XMD_BUS_VALID_DST_L2C] = "xmd-bus-valid-dst-l2c"; proc_perf_l2label[PROC_PERF_L2_XMD_BUS_VALID_DST_IOB] = "xmd-bus-valid-dst-iob"; proc_perf_l2label[PROC_PERF_L2_XMD_BUS_VALID_DST_PP] = "xmd-bus-valid-dst-pp"; proc_perf_l2label[PROC_PERF_L2_RSC_NOP] = "rsc-nop"; proc_perf_l2label[PROC_PERF_L2_RSC_STDN] = "rsc-stdn"; proc_perf_l2label[PROC_PERF_L2_RSC_FILL] = "rsc-fill"; proc_perf_l2label[PROC_PERF_L2_RSC_REFL] = "rsc-refl"; proc_perf_l2label[PROC_PERF_L2_RSC_STIN] = "rsc-stin"; proc_perf_l2label[PROC_PERF_L2_RSC_SCIN] = "rsc-scin"; proc_perf_l2label[PROC_PERF_L2_RSC_SCFL] = "rsc-scfl"; proc_perf_l2label[PROC_PERF_L2_RSC_SCDN] = "rsc-scdn"; proc_perf_l2label[PROC_PERF_L2_RSD_DATA_VALID] = "rsd-data-valid"; proc_perf_l2label[PROC_PERF_L2_RSD_DATA_VALID_FILL] = "rsd-data-valid-fill"; proc_perf_l2label[PROC_PERF_L2_RSD_DATA_VALID_STRSP] = "rsd-data-valid-strsp"; proc_perf_l2label[PROC_PERF_L2_RSD_DATA_VALID_REFL] = "rsd-data-valid-refl"; proc_perf_l2label[PROC_PERF_L2_LRF_REQ] = "lrf-req"; proc_perf_l2label[PROC_PERF_L2_DT_RD_ALLOC] = "dt-rd-alloc"; proc_perf_l2label[PROC_PERF_L2_DT_WR_INVA] = "dt-wr-inva"; proc_perf_entry = create_proc_entry("octeon_perf", 0, NULL); if (proc_perf_entry) proc_perf_entry->proc_fops = &proc_perf_operations; proc_perf_setup(); return 0; }
/** * IOCTL on /proc/octeon_perf * * @param inode * @param file * @param cmd * @param arg * @return */ static int proc_perf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { //printk("proc_perf_ioctl(cmd=0x%x(%u), arg=0x%lx)\n", cmd, cmd, arg); switch (cmd) { case PROC_PERF_IOCTL_SETUP_COUNTER0: if ((arg<=PROC_PERF_CORE_MAX) && proc_perf_label[arg]) { strcpy(counter0, proc_perf_label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_SETUP_COUNTER1: if ((arg<=PROC_PERF_CORE_MAX) && proc_perf_label[arg]) { strcpy(counter1, proc_perf_label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_SETUP_L2COUNTER0: if ((arg<=PROC_PERF_L2_MAX) && proc_perf_l2label[arg]) { strcpy(l2counter0, proc_perf_l2label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_SETUP_L2COUNTER1: if ((arg<=PROC_PERF_L2_MAX) && proc_perf_l2label[arg]) { strcpy(l2counter1, proc_perf_l2label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_SETUP_L2COUNTER2: if ((arg<=PROC_PERF_L2_MAX) && proc_perf_l2label[arg]) { strcpy(l2counter2, proc_perf_l2label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_SETUP_L2COUNTER3: if ((arg<=PROC_PERF_L2_MAX) && proc_perf_l2label[arg]) { strcpy(l2counter3, proc_perf_l2label[arg]); proc_perf_setup(); return 0; } return -EINVAL; case PROC_PERF_IOCTL_READ_COUNTER0: proc_perf_update(); copy_to_user((void*)arg, proc_perf_counter_data[smp_processor_id()] + 0, sizeof(long long)); return 0; case PROC_PERF_IOCTL_READ_COUNTER1: proc_perf_update(); copy_to_user((void*)arg, proc_perf_counter_data[smp_processor_id()] + 1, sizeof(long long)); return 0; case PROC_PERF_IOCTL_READ_L2COUNTER0: proc_perf_update(); copy_to_user((void*)arg, proc_perf_l2counter_data + 0, sizeof(long long)); return 0; case PROC_PERF_IOCTL_READ_L2COUNTER1: proc_perf_update(); copy_to_user((void*)arg, proc_perf_l2counter_data + 1, sizeof(long long)); return 0; case PROC_PERF_IOCTL_READ_L2COUNTER2: proc_perf_update(); copy_to_user((void*)arg, proc_perf_l2counter_data + 2, sizeof(long long)); return 0; case PROC_PERF_IOCTL_READ_L2COUNTER3: proc_perf_update(); copy_to_user((void*)arg, proc_perf_l2counter_data + 3, sizeof(long long)); return 0; default: return -EINVAL; } }
/** * Show the counters to the user * * @param m * @param v * @return */ static int proc_perf_show(struct seq_file *m, void *v) { int cpu; int i; uint64_t dram_clocks; uint64_t dram_operations; proc_perf_update(); seq_printf(m, " %16s %16s\n", proc_perf_label[proc_perf_counter_control[0]], proc_perf_label[proc_perf_counter_control[1]]); for (cpu=0; cpu<NR_CPUS; cpu++) { if (cpu_online(cpu)) seq_printf(m, "CPU%2d: %16lu %16lu\n", cpu, proc_perf_counter_data[cpu][0], proc_perf_counter_data[cpu][1]); } seq_printf(m, "\n"); for (i=0; i<4; i++) seq_printf(m, "%s: %lu\n", proc_perf_l2label[proc_perf_l2counter_control[i]], proc_perf_l2counter_data[i]); /* Compute DRAM utilization */ dram_operations = (octeon_read_csr(OCTEON_LMC_OPS_CNT_HI) << 32) | octeon_read_csr(OCTEON_LMC_OPS_CNT_LO); dram_clocks = (octeon_read_csr(OCTEON_LMC_DCLK_CNT_HI) << 32) | octeon_read_csr(OCTEON_LMC_DCLK_CNT_LO); if (dram_clocks > proc_perf_dram_clocks) { uint64_t delta_clocks = dram_clocks - proc_perf_dram_clocks; uint64_t delta_operations = dram_operations - proc_perf_dram_operations; uint64_t percent_x100 = 10000 * delta_operations / delta_clocks; seq_printf(m, "\nDRAM ops count: %lu, dclk count: %lu, utilization: %lu.%02lu%%\n", delta_operations, delta_clocks, percent_x100 / 100, percent_x100 % 100); } proc_perf_dram_operations = dram_operations; proc_perf_dram_clocks = dram_clocks; seq_printf(m, "\n" "Configuration of the performance counters is controller by writing\n" "one of the following values to:\n" " /sys/module/perf_counters/parameters/counter{0,1}\n" " /sys/module/perf_counters/parameters/l2counter{0-3}\n" "\n" "Possible CPU counters:"); for (i=0; i<PROC_PERF_CORE_MAX; i++) { if ((i & 7) == 0) seq_printf(m, "\n "); if (proc_perf_label[i]) seq_printf(m, "%s ", proc_perf_label[i]); } seq_printf(m, "\n\nPossible L2 counters:"); for (i=0; i<PROC_PERF_L2_MAX; i++) { if ((i & 3) == 0) seq_printf(m, "\n "); if (proc_perf_l2label[i]) seq_printf(m, "%s ", proc_perf_l2label[i]); } seq_printf(m, "\nWarning: Counter configuration doesn't update till you access /proc/octeon_perf.\n"); proc_perf_setup(); return 0; }