diff options
Diffstat (limited to 'sys/contrib/octeon-sdk/cvmx-profiler.c')
-rw-r--r-- | sys/contrib/octeon-sdk/cvmx-profiler.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/sys/contrib/octeon-sdk/cvmx-profiler.c b/sys/contrib/octeon-sdk/cvmx-profiler.c new file mode 100644 index 0000000..88ee3e1 --- /dev/null +++ b/sys/contrib/octeon-sdk/cvmx-profiler.c @@ -0,0 +1,239 @@ +/***********************license start*************** + * Copyright (c) 2011 Cavium Inc. (support@cavium.com). All rights + * reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * * Neither the name of Cavium Inc. nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * This Software, including technical data, may be subject to U.S. export control + * laws, including the U.S. Export Administration Act and its associated + * regulations, and may be subject to export or import regulations in other + * countries. + * + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO + * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR + * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. + ************************license end**************************************/ + +/** + * @file + * + * Interface to event profiler. + * + */ + +#include "cvmx-config.h" +#include "cvmx.h" +#include "cvmx-interrupt.h" +#include "cvmx-sysinfo.h" +#include "cvmx-coremask.h" +#include "cvmx-spinlock.h" +#include "cvmx-atomic.h" +#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) +#include "cvmx-error.h" +#endif +#include "cvmx-asm.h" +#include "cvmx-bootmem.h" +#include "cvmx-profiler.h" + +#ifdef PROFILER_DEBUG +#define PRINTF(fmt, args...) cvmx_safe_printf(fmt, ##args) +#else +#define PRINTF(fmt, args...) +#endif + +CVMX_SHARED static event_counter_control_block_t eccb; +cvmx_config_block_t *pcpu_cfg_blk; + +int read_percpu_block = 1; + +/** + * Set Interrupt IRQ line for Performance Counter + * + */ +void cvmx_update_perfcnt_irq(void) +{ + uint64_t cvmctl; + + /* Clear CvmCtl[IPPCI] bit and move the Performance Counter + * interrupt to IRQ 6 + */ + CVMX_MF_COP0(cvmctl, COP0_CVMCTL); + cvmctl &= ~(7 << 7); + cvmctl |= 6 << 7; + CVMX_MT_COP0(cvmctl, COP0_CVMCTL); +} + +/** + * @INTERNAL + * Return the baseaddress of the namedblock + * @param buf_name Name of Namedblock + * + * @return baseaddress of block on Success, NULL on failure. + */ +static +void *cvmx_get_memory_addr(const char* buf_name) +{ + void *buffer_ptr = NULL; + const struct cvmx_bootmem_named_block_desc *block_desc = cvmx_bootmem_find_named_block(buf_name); + if (block_desc) + buffer_ptr = cvmx_phys_to_ptr(block_desc->base_addr); + assert (buffer_ptr != NULL); + + return buffer_ptr; +} + +/** + * @INTERNAL + * Initialize the cpu block metadata. + * + * @param cpu core no + * @param size size of per cpu memory in named block + * + */ +static +void cvmx_init_pcpu_block(int cpu, int size) +{ + eccb.cfg_blk.pcpu_base_addr[cpu] = (char *)cvmx_get_memory_addr(EVENT_BUFFER_BLOCK) + (size * cpu); + assert (eccb.cfg_blk.pcpu_base_addr[cpu] != NULL); + + cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; + + cpu_buf->pcpu_blk_info.size = size; + cpu_buf->pcpu_blk_info.max_samples = ((size - sizeof(cvmx_cpu_event_block_t)) / sizeof(cvmx_sample_entry_t)); + cpu_buf->pcpu_blk_info.sample_count = 0; + cpu_buf->pcpu_blk_info.sample_read = 0; + cpu_buf->pcpu_blk_info.data = eccb.cfg_blk.pcpu_base_addr[cpu] + sizeof(cvmx_cpu_event_block_t) + PADBYTES; + cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.tail = \ + cpu_buf->pcpu_data = cpu_buf->pcpu_blk_info.data; + cpu_buf->pcpu_blk_info.end = eccb.cfg_blk.pcpu_base_addr[cpu] + size; + + cvmx_atomic_set32(&read_percpu_block, 0); + + /* + * Write per cpu mem base address info in to 'event config' named block, + * This info is needed by oct-remote-profile to get Per cpu memory + * base address of each core of the named block. + */ + pcpu_cfg_blk = (cvmx_config_block_t *) eccb.config_blk_base_addr; + pcpu_cfg_blk->pcpu_base_addr[cpu] = eccb.cfg_blk.pcpu_base_addr[cpu]; +} + +/** + * @INTERNAL + * Retrieve the info from the 'event_config' named block. + * + * Here events value is read(as passed to oct-remote-profile) to reset perf + * counters on every Perf counter overflow. + * + */ +static +void cvmx_read_config_blk(void) +{ + eccb.config_blk_base_addr = (char *)cvmx_get_memory_addr(EVENT_BUFFER_CONFIG_BLOCK); + memcpy(&(eccb.cfg_blk.events), eccb.config_blk_base_addr + \ + offsetof(cvmx_config_block_t, events), sizeof(int64_t)); + + cvmx_atomic_set32(&eccb.read_cfg_blk,1); + PRINTF("cfg_blk.events=%lu, sample_count=%ld\n", eccb.cfg_blk.events, eccb.cfg_blk.sample_count); +} + +/** + * @INTERNAL + * Add new sample to the buffer and increment the head pointer and + * global sample count(i.e sum total of samples collected on all cores) + * + */ +static +void cvmx_add_sample_to_buffer(void) +{ + uint32_t epc; + int cpu = cvmx_get_core_num(); + CVMX_MF_COP0(epc, COP0_EPC); + + cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; + + /* + * head/tail pointer can be NULL, and this case arises when oct-remote-profile is + * invoked afresh. To keep memory sane for current instance, we clear namedblock off + * previous data and this is accomplished by octeon_remote_write_mem from host. + */ + if (cvmx_unlikely(!cpu_buf->pcpu_blk_info.head && !cpu_buf->pcpu_blk_info.end)) { + /* Reread the event count as a different threshold val could be + * passed with profiler alongside --events flag */ + cvmx_read_config_blk(); + cvmx_init_pcpu_block(cpu, EVENT_PERCPU_BUFFER_SIZE); + } + + /* In case of hitting end of buffer, reset head,data ptr to start */ + if (cpu_buf->pcpu_blk_info.head == cpu_buf->pcpu_blk_info.end) + cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data = cpu_buf->pcpu_data; + + /* Store the pc, respective core no.*/ + cvmx_sample_entry_t *sample = (cvmx_sample_entry_t *) cpu_buf->pcpu_blk_info.data; + sample->pc = epc; + sample->core = cpu; + + /* Update Per CPU stats */ + cpu_buf->pcpu_blk_info.sample_count++; + cpu_buf->pcpu_blk_info.data += sizeof(cvmx_sample_entry_t); + cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data; + + /* Increment the global sample count i.e sum total of samples on all cores*/ + cvmx_atomic_add64(&(pcpu_cfg_blk->sample_count), 1); + + PRINTF("the core%d:pc 0x%016lx, sample_count=%ld\n", cpu, sample->pc, cpu_buf->pcpu_blk_info.sample_count); +} + +/** + * @INTERNAL + * Reset performance counters + * + * @param pf The performance counter Number (0, 1) + * @param events The threshold value for which interrupt has to be asserted + */ +static +void cvmx_reset_perf_counter(int pf, uint64_t events) +{ + uint64_t pfc; + pfc = (1ull << 63) - events; + + if (!pf) { + CVMX_MT_COP0(pfc, COP0_PERFVALUE0); + } else + CVMX_MT_COP0(pfc, COP0_PERFVALUE1); +} + +void cvmx_collect_sample(void) +{ + if (!eccb.read_cfg_blk) + cvmx_read_config_blk(); + + if (read_percpu_block) + cvmx_init_pcpu_block(cvmx_get_core_num(), EVENT_PERCPU_BUFFER_SIZE); + + cvmx_add_sample_to_buffer(); + cvmx_reset_perf_counter(0, eccb.cfg_blk.events); +} |