cvmx-profiler.c revision 259065
1/***********************license start*************** 2 * Copyright (c) 2011 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 * 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 * 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ************************license end**************************************/ 39 40/** 41 * @file 42 * 43 * Interface to event profiler. 44 * 45 */ 46 47#include "cvmx-config.h" 48#include "cvmx.h" 49#include "cvmx-interrupt.h" 50#include "cvmx-sysinfo.h" 51#include "cvmx-coremask.h" 52#include "cvmx-spinlock.h" 53#include "cvmx-atomic.h" 54#if !defined(CVMX_BUILD_FOR_FREEBSD_KERNEL) 55#include "cvmx-error.h" 56#endif 57#include "cvmx-asm.h" 58#include "cvmx-bootmem.h" 59#include "cvmx-profiler.h" 60 61#ifdef PROFILER_DEBUG 62#define PRINTF(fmt, args...) cvmx_safe_printf(fmt, ##args) 63#else 64#define PRINTF(fmt, args...) 65#endif 66 67CVMX_SHARED static event_counter_control_block_t eccb; 68cvmx_config_block_t *pcpu_cfg_blk; 69 70int read_percpu_block = 1; 71 72/** 73 * Set Interrupt IRQ line for Performance Counter 74 * 75 */ 76void cvmx_update_perfcnt_irq(void) 77{ 78 uint64_t cvmctl; 79 80 /* Clear CvmCtl[IPPCI] bit and move the Performance Counter 81 * interrupt to IRQ 6 82 */ 83 CVMX_MF_COP0(cvmctl, COP0_CVMCTL); 84 cvmctl &= ~(7 << 7); 85 cvmctl |= 6 << 7; 86 CVMX_MT_COP0(cvmctl, COP0_CVMCTL); 87} 88 89/** 90 * @INTERNAL 91 * Return the baseaddress of the namedblock 92 * @param buf_name Name of Namedblock 93 * 94 * @return baseaddress of block on Success, NULL on failure. 95 */ 96static 97void *cvmx_get_memory_addr(const char* buf_name) 98{ 99 void *buffer_ptr = NULL; 100 const struct cvmx_bootmem_named_block_desc *block_desc = cvmx_bootmem_find_named_block(buf_name); 101 if (block_desc) 102 buffer_ptr = cvmx_phys_to_ptr(block_desc->base_addr); 103 assert (buffer_ptr != NULL); 104 105 return buffer_ptr; 106} 107 108/** 109 * @INTERNAL 110 * Initialize the cpu block metadata. 111 * 112 * @param cpu core no 113 * @param size size of per cpu memory in named block 114 * 115 */ 116static 117void cvmx_init_pcpu_block(int cpu, int size) 118{ 119 eccb.cfg_blk.pcpu_base_addr[cpu] = (char *)cvmx_get_memory_addr(EVENT_BUFFER_BLOCK) + (size * cpu); 120 assert (eccb.cfg_blk.pcpu_base_addr[cpu] != NULL); 121 122 cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; 123 124 cpu_buf->pcpu_blk_info.size = size; 125 cpu_buf->pcpu_blk_info.max_samples = ((size - sizeof(cvmx_cpu_event_block_t)) / sizeof(cvmx_sample_entry_t)); 126 cpu_buf->pcpu_blk_info.sample_count = 0; 127 cpu_buf->pcpu_blk_info.sample_read = 0; 128 cpu_buf->pcpu_blk_info.data = eccb.cfg_blk.pcpu_base_addr[cpu] + sizeof(cvmx_cpu_event_block_t) + PADBYTES; 129 cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.tail = \ 130 cpu_buf->pcpu_data = cpu_buf->pcpu_blk_info.data; 131 cpu_buf->pcpu_blk_info.end = eccb.cfg_blk.pcpu_base_addr[cpu] + size; 132 133 cvmx_atomic_set32(&read_percpu_block, 0); 134 135 /* 136 * Write per cpu mem base address info in to 'event config' named block, 137 * This info is needed by oct-remote-profile to get Per cpu memory 138 * base address of each core of the named block. 139 */ 140 pcpu_cfg_blk = (cvmx_config_block_t *) eccb.config_blk_base_addr; 141 pcpu_cfg_blk->pcpu_base_addr[cpu] = eccb.cfg_blk.pcpu_base_addr[cpu]; 142} 143 144/** 145 * @INTERNAL 146 * Retrieve the info from the 'event_config' named block. 147 * 148 * Here events value is read(as passed to oct-remote-profile) to reset perf 149 * counters on every Perf counter overflow. 150 * 151 */ 152static 153void cvmx_read_config_blk(void) 154{ 155 eccb.config_blk_base_addr = (char *)cvmx_get_memory_addr(EVENT_BUFFER_CONFIG_BLOCK); 156 memcpy(&(eccb.cfg_blk.events), eccb.config_blk_base_addr + \ 157 offsetof(cvmx_config_block_t, events), sizeof(int64_t)); 158 159 cvmx_atomic_set32(&eccb.read_cfg_blk,1); 160 PRINTF("cfg_blk.events=%lu, sample_count=%ld\n", eccb.cfg_blk.events, eccb.cfg_blk.sample_count); 161} 162 163/** 164 * @INTERNAL 165 * Add new sample to the buffer and increment the head pointer and 166 * global sample count(i.e sum total of samples collected on all cores) 167 * 168 */ 169static 170void cvmx_add_sample_to_buffer(void) 171{ 172 uint32_t epc; 173 int cpu = cvmx_get_core_num(); 174 CVMX_MF_COP0(epc, COP0_EPC); 175 176 cvmx_ringbuf_t *cpu_buf = (cvmx_ringbuf_t *) eccb.cfg_blk.pcpu_base_addr[cpu]; 177 178 /* 179 * head/tail pointer can be NULL, and this case arises when oct-remote-profile is 180 * invoked afresh. To keep memory sane for current instance, we clear namedblock off 181 * previous data and this is accomplished by octeon_remote_write_mem from host. 182 */ 183 if (cvmx_unlikely(!cpu_buf->pcpu_blk_info.head && !cpu_buf->pcpu_blk_info.end)) { 184 /* Reread the event count as a different threshold val could be 185 * passed with profiler alongside --events flag */ 186 cvmx_read_config_blk(); 187 cvmx_init_pcpu_block(cpu, EVENT_PERCPU_BUFFER_SIZE); 188 } 189 190 /* In case of hitting end of buffer, reset head,data ptr to start */ 191 if (cpu_buf->pcpu_blk_info.head == cpu_buf->pcpu_blk_info.end) 192 cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data = cpu_buf->pcpu_data; 193 194 /* Store the pc, respective core no.*/ 195 cvmx_sample_entry_t *sample = (cvmx_sample_entry_t *) cpu_buf->pcpu_blk_info.data; 196 sample->pc = epc; 197 sample->core = cpu; 198 199 /* Update Per CPU stats */ 200 cpu_buf->pcpu_blk_info.sample_count++; 201 cpu_buf->pcpu_blk_info.data += sizeof(cvmx_sample_entry_t); 202 cpu_buf->pcpu_blk_info.head = cpu_buf->pcpu_blk_info.data; 203 204 /* Increment the global sample count i.e sum total of samples on all cores*/ 205 cvmx_atomic_add64(&(pcpu_cfg_blk->sample_count), 1); 206 207 PRINTF("the core%d:pc 0x%016lx, sample_count=%ld\n", cpu, sample->pc, cpu_buf->pcpu_blk_info.sample_count); 208} 209 210/** 211 * @INTERNAL 212 * Reset performance counters 213 * 214 * @param pf The performance counter Number (0, 1) 215 * @param events The threshold value for which interrupt has to be asserted 216 */ 217static 218void cvmx_reset_perf_counter(int pf, uint64_t events) 219{ 220 uint64_t pfc; 221 pfc = (1ull << 63) - events; 222 223 if (!pf) { 224 CVMX_MT_COP0(pfc, COP0_PERFVALUE0); 225 } else 226 CVMX_MT_COP0(pfc, COP0_PERFVALUE1); 227} 228 229void cvmx_collect_sample(void) 230{ 231 if (!eccb.read_cfg_blk) 232 cvmx_read_config_blk(); 233 234 if (read_percpu_block) 235 cvmx_init_pcpu_block(cvmx_get_core_num(), EVENT_PERCPU_BUFFER_SIZE); 236 237 cvmx_add_sample_to_buffer(); 238 cvmx_reset_perf_counter(0, eccb.cfg_blk.events); 239} 240