/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2006 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \*------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #if defined(CONFIG_MIPS) #include #include #endif #if defined(CONFIG_ARM) #endif #include "avm_sammel.h" #include "avm_profile.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #include #if defined(CONFIG_PROC_FS) #include #include #include #include /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ struct _pid_field { unsigned short pid; unsigned char comm[TASK_COMM_LEN]; }; #define MIPS_PERFOMANCE_HAS_MORE (1 << 31) #define MIPS_PERFOMANCE_IRQ_ENABLE (1 << 4) #define MIPS_PERFOMANCE_USER_MODE_ENABLE (1 << 3) #define MIPS_PERFOMANCE_SUPERVISOR_MODE_ENABLE (1 << 2) #define MIPS_PERFOMANCE_KERNEL_MODE_ENABLE (1 << 1) #define MIPS_PERFOMANCE_EXCEPTION_ENABLE (1 << 0) #define MIPS_PERFORMANCE_VPE_SPECIFIC_ENABLE (0x01 << 20) #define MIPS_PERFORMANCE_TC_SPECIFIC_ENABLE (0x02 << 20) #define MIPS_PERFORMANCE_VPEID(x) (((x) & 0x0F) << 16) #define MIPS_PERFORMANCE_TCID(x) (((x) & 0xFF) << 22) char *print_perfomance_counter_mode(unsigned int mode) { static char Buffer[128]; snprintf(Buffer, sizeof(Buffer), "User-Mode %s Supervisor-Mode %s Kernel-Mode %s Exeption-Mode %s", (MIPS_PERFOMANCE_USER_MODE_ENABLE & mode) ? "enabled" : "disable", (MIPS_PERFOMANCE_SUPERVISOR_MODE_ENABLE & mode) ? "enabled" : "disable", (MIPS_PERFOMANCE_KERNEL_MODE_ENABLE & mode) ? "enabled" : "disable", (MIPS_PERFOMANCE_EXCEPTION_ENABLE & mode) ? "enabled" : "disable"); return Buffer; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static char *avm_profile_data_short_names[] = { [avm_profile_data_type_code_address_info] "CODE", [avm_profile_data_type_trace_skb] "SKB", [avm_profile_data_type_hw_irq_begin] "BIRQ", [avm_profile_data_type_hw_irq_end] "EIRQ", [avm_profile_data_type_sw_irq_begin] "BSWI", [avm_profile_data_type_sw_irq_end] "ESWI", [avm_profile_data_type_timer_begin] "BTIM", [avm_profile_data_type_timer_end] "ETIM", [avm_profile_data_type_tasklet_begin] "BLET", [avm_profile_data_type_tasklet_end] "ELET", [avm_profile_data_type_hi_tasklet_begin] "BLHT", [avm_profile_data_type_hi_tasklet_end] "ELHT", [avm_profile_data_type_workitem_begin] "BWRK", [avm_profile_data_type_workitem_end] "EWRK", [avm_profile_data_type_func_begin] "BFUN", [avm_profile_data_type_func_end] "EFUN", [avm_profile_data_type_trigger_tasklet_begin] "BTLT", [avm_profile_data_type_trigger_tasklet_end] "ETLT", [avm_profile_data_type_trigger_user_begin] "BUST", [avm_profile_data_type_trigger_user_end] "EUST", [avm_profile_data_type_unknown] "ERROR" }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static char *avm_profile_data_long_names[] = { [avm_profile_data_type_code_address_info] "code", [avm_profile_data_type_trace_skb] "skb", [avm_profile_data_type_hw_irq_begin] "begin hw irq", [avm_profile_data_type_hw_irq_end] "end hw irq", [avm_profile_data_type_sw_irq_begin] "begin sw irq", [avm_profile_data_type_sw_irq_end] "end sw irq", [avm_profile_data_type_timer_begin] "begin timer", [avm_profile_data_type_timer_end] "end timer", [avm_profile_data_type_tasklet_begin] "begin tasklet", [avm_profile_data_type_tasklet_end] "end tasklet", [avm_profile_data_type_hi_tasklet_begin] "begin hitasklet", [avm_profile_data_type_hi_tasklet_end] "end hitasklet", [avm_profile_data_type_workitem_begin] "begin workitem", [avm_profile_data_type_workitem_end] "end workitem", [avm_profile_data_type_func_begin] "begin function", [avm_profile_data_type_func_end] "end function", [avm_profile_data_type_trigger_tasklet_begin] "begin tasklet-trigger", [avm_profile_data_type_trigger_tasklet_end] "end tasklet trigger", [avm_profile_data_type_trigger_user_begin] "begin user trigger", [avm_profile_data_type_trigger_user_end] "end user trigger", [avm_profile_data_type_unknown] "unknown" }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #ifdef CONFIG_MIPS char *perfomance_counter_options[4][64] = { #if !defined(CONFIG_CPU_MIPS_74K) [0] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "branch instructions completed", [ 3] = "JR r31 (return) instructions", [ 4] = "JR (not r31) instructions", [ 5] = "ITLB accesses", [ 6] = "DTLB accesses", [ 7] = "JTLB instruction accesses", [ 8] = "JTLB data accesses", [ 9] = "Instruction Cache accesses", [10] = "Data cache load/stores", [11] = "Data cache load/store misses", [14] = "integer instructions completed", [15] = "loads completed", [16] = "J/JAL completed", [17] = "no-ops completed", [18] = "Main pipeline stalls", [19] = "SC instructions completed", [20] = "Prefetch instructions to cached addresses", [21] = "L2 cache writebacks", [22] = "L2 cache misses", [23] = "Exceptions taken", [24] = "cache fixup", [26] = "DSP Instructions Completed", [28] = "Impl. specific PM event", [29] = "Impl. specific ISPRAM event", [30] = "Impl. specific CorExtend event", [32] = "ITC loads", [33] = "Uncached loads", [34] = "fork instructions completed", [35] = "CP2 register-to-register Instns Completed", [37] = "I$ Miss Stall cycles", [38] = "L2 I-miss stall cycles", [39] = "D$ miss cycles", [40] = "Uncached access block cycles", [41] = "MDU stall cycles", [42] = "CP2 stall cycles", [43] = "ISPRAM Stall Cycles", [44] = "CACHE Instn stall cycles", [45] = "Load to Use stalls", [46] = "Read-CP0-value interlock stalls", [47] = "Relax bubbles", [48] = "IFU FB full refetches", [49] = "EJTAG Instruction Triggerpoints", [50] = "FSB < 1/4 full", [51] = "FSB > 1/2 full", [52] = "LDQ < 1/4 full", [53] = "LDQ > 1/2 full", [54] = "WBB < 1/4 full", [55] = "WBB > 1/2 full", #if defined(CONFIG_CPU_MIPS_34K) [25] = "Cycles with no Instns for any TC", [31] = "Impl. specific customer yield manager event", [63] = NULL #endif /*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ }, [1] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "Branch mispredictions", [ 3] = "JR r31 mispredictions", [ 4] = "JR r31 not predicted", [ 5] = "ITLB misses", [ 6] = "DTLB misses", [ 7] = "JTLB instruction misses", [ 8] = "JTLB data misses", [ 9] = "Instruction cache misses", [10] = "Data cache writebacks", [11] = "Data cache load/store misses", [14] = "FPU instructions completed", [15] = "stores completed", [16] = "MIPS16 instructions completed", [17] = "integer multiply/divide completed", [18] = "replay traps (other than uTLB)", [19] = "SC instructions failed", [20] = "Prefetch instructions completed with cache hit", [21] = "L2 cache accesses", [22] = "L2 cache single bit errors corrected", [24] = "Refetches: refetched and reissued by IFU", [25] = "ALU stalls", [26] = "ALU-DSP Saturations Done", [27] = "MDU-DSP Saturations Done", [28] = "Impl. specific Cp2 event", [29] = "Impl. specific DSPRAM event", [33] = "Uncached Stores", [34] = "yield instructions completed", [35] = "CP2 To/From Instns completed", [37] = "D$ miss stall cycles", [39] = "L2 miss cycles", [41] = "FPU stall cycles", [42] = "CorExtend stall cycles", [43] = "DSPRAM stall cycles", [45] = "ALU to AGEN stalls", [46] = "Branch mispredict stalls", [48] = "FB entry allocated", [49] = "EJTAG Data Triggerpoints", [50] = "FSB 1/4-1/2 full", [51] = "FSB full pipeline stalls", [52] = "LDQ 1/4-1/2 full", [53] = "LDQ full pipeline stalls", [54] = "WBB 1/4-1/2 full", [55] = "WBB full pipeline stalls", #if defined(CONFIG_CPU_MIPS_34K) [23] = "Cycles spent in Single Threaded Mode", [31] = "Custom ITC event", [44] = "Cycles spent waiting in ST mode", #endif /*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ [63] = NULL }, [2] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "branch instructions completed", [ 3] = "JR r31 (return) instructions", [ 4] = "JR (not r31) instructions", [ 5] = "ITLB accesses", [ 6] = "DTLB accesses", [ 7] = "JTLB instruction accesses", [ 8] = "JTLB data accesses", [ 9] = "Instruction Cache accesses", [10] = "Data cache load/stores", [11] = "Data cache load/store misses", [14] = "integer instructions completed", [15] = "loads completed", [16] = "J/JAL completed", [17] = "no-ops completed", [18] = "Main pipeline stalls", [19] = "SC instructions completed", [20] = "Prefetch instructions to cached addresses", [21] = "L2 cache writebacks", [22] = "L2 cache misses", [23] = "Exceptions taken", [24] = "cache fixup", [26] = "DSP Instructions Completed", [28] = "Impl. specific PM event", [29] = "Impl. specific ISPRAM event", [30] = "Impl. specific CorExtend event", [32] = "ITC loads", [33] = "Uncached loads", [34] = "fork instructions completed", [35] = "CP2 register-to-register Instns Completed", [37] = "I$ Miss Stall cycles", [38] = "L2 I-miss stall cycles", [39] = "D$ miss cycles", [40] = "Uncached access block cycles", [41] = "MDU stall cycles", [42] = "CP2 stall cycles", [43] = "ISPRAM Stall Cycles", [44] = "CACHE Instn stall cycles", [45] = "Load to Use stalls", [46] = "Read-CP0-value interlock stalls", [47] = "Relax bubbles", [48] = "IFU FB full refetches", [49] = "EJTAG Instruction Triggerpoints", [50] = "FSB < 1/4 full", [51] = "FSB > 1/2 full", [52] = "LDQ < 1/4 full", [53] = "LDQ > 1/2 full", [54] = "WBB < 1/4 full", [55] = "WBB > 1/2 full", #if defined(CONFIG_CPU_MIPS_34K) [25] = "Cycles with no Instns for any TC", [31] = "Impl. specific customer yield manager event", #endif /*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ [63] = NULL }, [3] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "Branch mispredictions", [ 3] = "JR r31 mispredictions", [ 4] = "JR r31 not predicted", [ 5] = "ITLB misses", [ 6] = "DTLB misses", [ 7] = "JTLB instruction misses", [ 8] = "JTLB data misses", [ 9] = "Instruction cache misses", [10] = "Data cache writebacks", [11] = "Data cache load/store misses", [14] = "FPU instructions completed", [15] = "stores completed", [16] = "MIPS16 instructions completed", [17] = "integer multiply/divide completed", [18] = "replay traps (other than uTLB)", [19] = "SC instructions failed", [20] = "Prefetch instructions completed with cache hit", [21] = "L2 cache accesses", [22] = "L2 cache single bit errors corrected", [24] = "Refetches: refetched and reissued by IFU", [25] = "ALU stalls", [26] = "ALU-DSP Saturations Done", [27] = "MDU-DSP Saturations Done", [28] = "Impl. specific Cp2 event", [29] = "Impl. specific DSPRAM event", [33] = "Uncached Stores", [34] = "yield instructions completed", [35] = "CP2 To/From Instns completed", [37] = "D$ miss stall cycles", [39] = "L2 miss cycles", [41] = "FPU stall cycles", [42] = "CorExtend stall cycles", [43] = "DSPRAM stall cycles", [45] = "ALU to AGEN stalls", [46] = "Branch mispredict stalls", [48] = "FB entry allocated", [49] = "EJTAG Data Triggerpoints", [50] = "FSB 1/4-1/2 full", [51] = "FSB full pipeline stalls", [52] = "LDQ 1/4-1/2 full", [53] = "LDQ full pipeline stalls", [54] = "WBB 1/4-1/2 full", [55] = "WBB full pipeline stalls", #if defined(CONFIG_CPU_MIPS_34K) [23] = "Cycles spent in Single Threaded Mode", [31] = "Custom ITC event", [44] = "Cycles spent waiting in ST mode", #endif /*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ [63] = NULL } #else /*--- !defined(CONFIG_CPU_MIPS_74K) ---*/ [0] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "JR r31 (return) instructions", [ 3] = "Cycles where no instn is fetched or after wait", [ 4] = "ITLB accesses", [ 6] = "Instruction cache accesses", [ 7] = "Cycles without Instn fetch due to I-cache miss", [ 8] = "Cycles waiting for direct Instn fetch", [ 9] = "Replays in IFU due to full Instn buffer", [13] = "Cycles with no Instn to ALU due to full buffer", [14] = "Cycles with no Instn to ALU due to no free ALU CB", [15] = "Cycles without Instn added to ALU due to no free FIFOs", [16] = "Cycles with no ALU-pipe issue: no Instn avail.", [17] = "Cycles with no ALU-pipe issue: no operands ready", [18] = "Cycles with no ALU-pipe issue: ressource busy", [19] = "ALU pipe-bubbles issued", [20] = "Cycles with no Instn issued", [21] = "Out-of-order ALU issue", [22] = "Graduated JAR/JALR.HB", [23] = "Cacheable loads", [24] = "D-Cache writebacks", [26] = "D-side JTLB accesses", [28] = "L2 cache writebacks", [29] = "L2 cache misses", [30] = "Pipe stalls due to full FSB", [31] = "Pipe stalls due to full LDQ", [32] = "Pipe stalls due to full WBB", [35] = "Redirects following optimistic instn issue which failed", [36] = "JR (not r31) instructions", [37] = "Branch-likely instns graduated", [38] = "L2 I-miss stall cycles", [39] = "Branches graduated", [40] = "Integer instns graduated", [41] = "Loads graduated", [42] = "j/ja1 graduated", [43] = "Co-ops graduated", [44] = "DSP instructions graduated", [45] = "DSP branch instructions graduated", [46] = "Uncached loads graduated", [49] = "EJTAG Instruction Triggerpoints", [50] = "CP1 branches mispredicted", [51] = "sc instructions graduated", [52] = "prefetch instns graduated top of LSGB", [53] = "Cycles where no instns graduated", [54] = "Cycles where one instn graduated", [55] = "GFifo blocked cycles", [56] = "Cycles where 0 instns graduated", [58] = "Exceptions taken", [59] = "Impl. specific CorExtend event", [62] = "Impl. specific ISPRAM event", [63] = "L2 single bit errors corrected" }, [1] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "JR r31 mispredictions", [ 3] = "JR r31 not predicted", [ 4] = "ITLB misses", [ 5] = "JTLB instruction access fails", [ 6] = "Instruction cache misses", [ 7] = "L2 I-miss cycles", [ 8] = "PDTrace back stalls", [ 9] = "Fetch slots killed in IFU", [13] = "AGEN issue pool full", [14] = "run out of AGEN CBs", [15] = "IOIQ FIFO full", [16] = "No instns avail. for AGEN-pipe issue", [17] = "No operands avail. for AGEN-pipe issue", [18] = "No AGEN-pipe issue, waiting for data", [20] = "Cycles with two instns issued", [21] = "Out-of-order AGEN issue", [22] = "D-cache line refill (not LD/ST misses)", [23] = "All D-cache accesses", [24] = "D-Cache misses", [25] = "D-side JTBL translt. fails", [26] = "Bogus D-ache misses", [28] = "L2 cache accesses", [29] = "L2 cache misses", [30] = "FSB >1/2 full", [31] = "LDQ >1/2 full", [32] = "WBB >1/2 full", [35] = "Copro. load instns.", [36] = "jr $31 graduated after mispredict", [37] = "CP1/CP2 conditional branch instns. graduated", [38] = "Mispredicted branch-like ins. graduated", [39] = "Mispredicted branches graduated", [40] = "FPU instructions graduated", [41] = "Stores graduated", [42] = "MIPS16 instn. graduated", [43] = "integer multiply/divide graduated", [44] = "ALU-DSP graduated, result saturated", [45] = "MDU-DSP graduated, result saturated", [46] = "Uncached stores graduated", [49] = "EJTAG data triggers", [51] = "sc instrns. failed", [52] = "prefetch instns. cache hits", [53] = "load misses graduated", [54] = "Two instns. graduated", [55] = "Floating point stores graduated", [56] = "Cycles where 0 instns. graduated", [58] = "Replays initiated from graduation", [59] = "Impl. specific system event", [61] = "Reserved for CP2 event", [62] = "Impl. specific DSPRAM block event" }, [2] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "JR r31 (return) instructions", [ 3] = "Cycles where no instn is fetched or after wait", [ 4] = "ITLB accesses", [ 6] = "Instruction cache accesses", [ 7] = "Cycles without Instn fetch due to I-cache miss", [ 8] = "Cycles waiting for direct Instn fetch", [ 9] = "Replays in IFU due to full Instn buffer", [13] = "Cycles with no Instn to ALU due to full buffer", [14] = "Cycles with no Instn to ALU due to no free ALU CB", [15] = "Cycles without Instn added to ALU due to no free FIFOs", [16] = "Cycles with no ALU-pipe issue: no Instn avail.", [17] = "Cycles with no ALU-pipe issue: no operands ready", [18] = "Cycles with no ALU-pipe issue: ressource busy", [19] = "ALU pipe-bubbles issued", [20] = "Cycles with no Instn issued", [21] = "Out-of-order ALU issue", [22] = "Graduated JAR/JALR.HB", [23] = "Cacheable loads", [24] = "D-Cache writebacks", [26] = "D-side JTLB accesses", [28] = "L2 cache writebacks", [29] = "L2 cache misses", [30] = "Pipe stalls due to full FSB", [31] = "Pipe stalls due to full LDQ", [32] = "Pipe stalls due to full WBB", [35] = "Redirects following optimistic instn issue which failed", [36] = "JR (not r31) instructions", [37] = "Branch-likely instns graduated", [38] = "L2 I-miss stall cycles", [39] = "Branches graduated", [40] = "Integer instns graduated", [41] = "Loads graduated", [42] = "j/ja1 graduated", [43] = "Co-ops graduated", [44] = "DSP instructions graduated", [45] = "DSP branch instructions graduated", [46] = "Uncached loads graduated", [49] = "EJTAG Instruction Triggerpoints", [50] = "CP1 branches mispredicted", [51] = "sc instructions graduated", [52] = "prefetch instns graduated top of LSGB", [53] = "Cycles where no instns graduated", [54] = "Cycles where one instn graduated", [55] = "GFifo blocked cycles", [56] = "Cycles where 0 instns graduated", [58] = "Exceptions taken", [59] = "Impl. specific CorExtend event", [62] = "Impl. specific ISPRAM event", [63] = "L2 single bit errors corrected" }, [3] = { [ 0] = "Cycles", [ 1] = "Instructions completed", [ 2] = "JR r31 mispredictions", [ 3] = "JR r31 not predicted", [ 4] = "ITLB misses", [ 5] = "JTLB instruction access fails", [ 6] = "Instruction cache misses", [ 7] = "L2 I-miss cycles", [ 8] = "PDTrace back stalls", [ 9] = "Fetch slots killed in IFU", [13] = "AGEN issue pool full", [14] = "run out of AGEN CBs", [15] = "IOIQ FIFO full", [16] = "No instns avail. for AGEN-pipe issue", [17] = "No operands avail. for AGEN-pipe issue", [18] = "No AGEN-pipe issue, waiting for data", [20] = "Cycles with two instns issued", [21] = "Out-of-order AGEN issue", [22] = "D-cache line refill (not LD/ST misses)", [23] = "All D-cache accesses", [24] = "D-Cache misses", [25] = "D-side JTBL translt. fails", [26] = "Bogus D-ache misses", [28] = "L2 cache accesses", [29] = "L2 cache misses", [30] = "FSB >1/2 full", [31] = "LDQ >1/2 full", [32] = "WBB >1/2 full", [35] = "Copro. load instns.", [36] = "jr $31 graduated after mispredict", [37] = "CP1/CP2 conditional branch instns. graduated", [38] = "Mispredicted branch-like ins. graduated", [39] = "Mispredicted branches graduated", [40] = "FPU instructions graduated", [41] = "Stores graduated", [42] = "MIPS16 instn. graduated", [43] = "integer multiply/divide graduated", [44] = "ALU-DSP graduated, result saturated", [45] = "MDU-DSP graduated, result saturated", [46] = "Uncached stores graduated", [49] = "EJTAG data triggers", [51] = "sc instrns. failed", [52] = "prefetch instns. cache hits", [53] = "load misses graduated", [54] = "Two instns. graduated", [55] = "Floating point stores graduated", [56] = "Cycles where 0 instns. graduated", [58] = "Replays initiated from graduation", [59] = "Impl. specific system event", [61] = "Reserved for CP2 event", [62] = "Impl. specific DSPRAM block event" } #endif /*--- !defined(CONFIG_CPU_MIPS_74K) ---*/ }; #endif /*--- #ifdef CONFIG_MIPS ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int get_user_info(char *buf, unsigned int maxbuflen, pid_t pid, unsigned long addr) { struct pid *ppid; unsigned int pc_value __attribute__((unused)), ret = 1; buf[0] = 0; #if defined(CONFIG_MIPS) if(addr >= KSEG0) { return 1; } #endif/*--- #if defined(CONFIG_MIPS) ---*/ if(__get_user(pc_value, (unsigned int __user *)addr)) { return 1; } if(pid && (ppid = find_get_pid(pid))) { struct task_struct *tsk = get_pid_task(ppid, PIDTYPE_PID); if (tsk) { /*--- printk(KERN_INFO"%s: %s: addr=%x pc_value=%x\n", __func__, tsk->comm, addr, pc_value); ---*/ if((ret = __get_userinfo(buf, maxbuflen, tsk->active_mm, addr))) { ret = __get_userinfo(buf, maxbuflen, tsk->mm, addr); } put_task_struct(tsk); } put_pid(ppid); } return ret; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ unsigned int format_profile_header(char *p, unsigned long timediff) { unsigned int len; len = sprintf(p, "# measure time %lu msec\n", timediff); #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) { unsigned int i; i = read_c0_perfctrl0(); /*--- printk(KERN_ERR "read_c0_perfctrl0: 0x%x\n", i); ---*/ len += sprintf(p + len, "# performance 0 \"%s\" (%s)\n", perfomance_counter_options[0][(i >> 5) & ((1 << 7) - 1)], print_perfomance_counter_mode(i)); i = read_c0_perfctrl1(); /*--- printk(KERN_ERR "read_c0_perfctrl1: 0x%x\n", i); ---*/ len += sprintf(p + len, "# performance 1 \"%s\" (%s)\n", perfomance_counter_options[1][(i >> 5) & ((1 << 7) - 1)], print_perfomance_counter_mode(i)); } #endif /*--- #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) ---*/ return len; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ unsigned int format_profile_line(char *p, struct _avm_profile_data *data, struct _pid_field act_pid_percpu[], unsigned int mode, unsigned int supress_kernel_output) { char *description = ""; unsigned char Symbols[256]; unsigned int len = 0; struct task_struct *tsk = NULL; struct pid *pid; pid_t act_pid = 0; char *comm = NULL; p[0] = 0; if(data->cpu_id > NR_CPUS) { return len; } act_pid = act_pid_percpu[data->cpu_id].pid; comm = act_pid_percpu[data->cpu_id].comm; switch(data->type) { case avm_profile_data_type_unknown: default: printk(KERN_ERR"[profiling] internal error data type %d unknown (time=%x)\n", data->type, data->time); break; case avm_profile_data_type_code_address_info: act_pid = data->id; if(act_pid != act_pid_percpu[data->cpu_id].pid) { if(act_pid == AVM_PROFILE_IDLE_ID) { strncpy(comm, "IDLE", sizeof(act_pid_percpu[data->cpu_id].comm)); } else if(act_pid && (pid = find_get_pid(act_pid))) { tsk = get_pid_task(pid, PIDTYPE_PID); if (tsk) { strncpy(comm, tsk->comm, sizeof(act_pid_percpu[data->cpu_id].comm)); put_task_struct(tsk); } put_pid(pid); } else { snprintf(comm, sizeof(act_pid_percpu[data->cpu_id].comm), "PID_%u", act_pid); } } act_pid_percpu[data->cpu_id].pid = act_pid; if(get_user_info(Symbols, sizeof(Symbols), act_pid, data->addr #if defined(CONFIG_MIPS) || defined(CONFIG_ARM) & ~0x3 /*--- falls mips16/tumb-code: keine Unaligneds provozieren ---*/ #endif/*--- #if defined(CONFIG_MIPS) || defined(CONFIG_ARM) ---*/ )){ sprint_symbol(Symbols, data->addr); } switch(mode) { case 3: len = sprintf(p, "%x;0x%08X;0x%08X;0x%08X;CODE;0x%08x;%s;%.*s;%u\n", data->cpu_id, data->time, #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) data->total_access, data->total_activate, #else/*--- #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) ---*/ 0,0, #endif/*--- #else ---*//*--- #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) ---*/ data->addr, Symbols, TASK_COMM_LEN, comm, data->id); if(supress_kernel_output == 0) printk("c"); break; case 4: len = sprintf(p, "%x;0x%08X: CODE 0x%08x %s %.*s pid=%u\n", data->cpu_id, data->time, data->addr, Symbols, TASK_COMM_LEN, comm, data->id); if(supress_kernel_output == 0)printk("c"); break; case 5: printk(KERN_INFO"%x;0x%08X: CODE 0x%08x %s %.*s pid=%u\n", data->cpu_id, data->time, data->addr, Symbols, TASK_COMM_LEN, comm, data->id); break; } break; case avm_profile_data_type_trace_skb: if(supress_kernel_output == 0)printk("s"); goto print_work_trace; case avm_profile_data_type_hw_irq_begin: case avm_profile_data_type_hw_irq_end: description = "interrupted by irq"; goto print_work_trace; case avm_profile_data_type_code_address_yield: case avm_profile_data_type_sw_irq_begin: case avm_profile_data_type_sw_irq_end: case avm_profile_data_type_timer_begin: case avm_profile_data_type_timer_end: case avm_profile_data_type_tasklet_begin: case avm_profile_data_type_tasklet_end: case avm_profile_data_type_hi_tasklet_begin: case avm_profile_data_type_hi_tasklet_end: case avm_profile_data_type_trigger_tasklet_begin: case avm_profile_data_type_trigger_tasklet_end: case avm_profile_data_type_workitem_begin: case avm_profile_data_type_workitem_end: case avm_profile_data_type_func_begin: case avm_profile_data_type_func_end: case avm_profile_data_type_trigger_user_begin: case avm_profile_data_type_trigger_user_end: description = "id:"; /*--- kein break ---*/ print_work_trace: if(get_user_info(Symbols, sizeof(Symbols), act_pid, data->addr)){ sprint_symbol(Symbols, data->addr); } switch(mode) { case 3: len = sprintf(p, "%x;0x%08X;0x%08X;0x%08X;%s;0x%08x;%s;%.*s;%u;\n", data->cpu_id, data->time, #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) data->total_access, data->total_activate, #else/*--- #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) ---*/ 0,0, #endif/*--- #else ---*//*--- #if defined(AVM_PROFILE_ACTIVITY_INCLUDED) ---*/ avm_profile_data_short_names[data->type], data->addr, Symbols, TASK_COMM_LEN, comm, data->id); if(supress_kernel_output == 0)printk("d"); break; case 4: len = sprintf(p, "%x;0x%08X:%s 0x%08x %s (%.*s %s %u);\n", data->cpu_id, data->time, avm_profile_data_short_names[data->type], data->addr, Symbols, TASK_COMM_LEN, comm, description, data->id); if(supress_kernel_output == 0)printk("d"); break; case 5: printk(KERN_INFO"%x;0x%08X: %s 0x%08x %s (%.*s %s %u)\n", data->cpu_id, data->time, avm_profile_data_long_names[data->type], data->addr, Symbols, TASK_COMM_LEN, comm, description, data->id); break; } } return len; } #define SKIP_SPACE(a) while(*(a) && ((*(a) == ' ') || (*(a) == '\t'))) (a)++ #define SKIP_NON_SPACE(a) while(*(a) && ((*(a) != ' ') && (*(a) != '\t'))) (a)++ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #if defined(CONFIG_CPU_MIPS_34K) #define PERFCNT_RELOAD_LAST_VAL 0xFFFFFFFF #define MAX_COUNT_TCS 4 #define MAX_COUNT_REGS 4 static unsigned int preset_counter_value_storage[MAX_COUNT_TCS][MAX_COUNT_REGS]; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static unsigned int supportet_tcs(void){ unsigned int mvpconf0; mvpconf0 = read_c0_mvpconf0(); return ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void write_c0_perfctl(unsigned int ctl_reg, unsigned int tc, unsigned int val){ unsigned long vpflags; #if 0 if (tc == raw_smp_processor_id() ) { // printk(KERN_ERR "direct access for tc=%d\n", tc); switch(ctl_reg){ case 0: write_c0_perfctrl0( val ); break; case 1: write_c0_perfctrl1( val ); break; default: printk(KERN_ERR "count reg %d is not supported\n", ctl_reg); break; } return; } #endif vpflags = dvpe(); settc(tc); switch(ctl_reg){ case 0: mttc0(25, 0, val); break; case 1: mttc0(25, 2, val); break; default: printk(KERN_ERR "performance ctrl reg %d is not supported\n", ctl_reg); break; } evpe(vpflags); } #if 0 /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static unsigned int current_tc(void){ unsigned int tcs = supportet_tcs(); unsigned int tc; for (tc = 0; tc < tcs; tc++){ settc(tc); if (read_tc_c0_tcbind() == (unsigned int)read_c0_tcbind()) return tc; } BUG(); return 0; } #endif /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void write_c0_perfcnt(unsigned int count_reg, unsigned int tc, unsigned int val){ unsigned long vpflags; BUG_ON( count_reg >= MAX_COUNT_REGS ); BUG_ON( tc >= MAX_COUNT_TCS ); if (val == PERFCNT_RELOAD_LAST_VAL){ val = preset_counter_value_storage[tc][count_reg]; // printk(KERN_ERR "restore[%d][%d]=%#x\n", tc,count_reg, val); } else { preset_counter_value_storage[tc][count_reg] = val; // printk(KERN_ERR "store[%d][%d]=%#x\n", tc, count_reg, val); } #if 0 if (tc == raw_smp_processor_id() ){ // printk(KERN_ERR "direct access for tc=%d\n", tc); switch(count_reg){ case 0: write_c0_perfcntr0( val ); break; case 1: write_c0_perfcntr1( val ); break; default: printk(KERN_ERR "count reg %d is not supported\n", count_reg); break; } return; } #endif // printk(KERN_ERR "indirect access for tc=%d\n", tc); vpflags = dvpe(); settc(tc); switch(count_reg){ case 0: mttc0(25, 1, val); break; case 1: mttc0(25, 3, val); break; default: printk(KERN_ERR "count reg %d is not supported\n", count_reg); break; } evpe(vpflags); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ unsigned int read_c0_perfcnt(unsigned int count_reg, unsigned int tc){ unsigned long vpflags; unsigned int res = 0; vpflags = dvpe(); settc(tc); switch(count_reg){ case 0: res = mftc0(25, 1); break; case 1: res = mftc0(25, 3); break; default: printk(KERN_ERR "count reg %d is not supported\n", count_reg); break; } evpe(vpflags); return res; } EXPORT_SYMBOL(read_c0_perfcnt); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static unsigned int read_c0_perfctl(unsigned int ctl_reg, unsigned int tc){ unsigned long vpflags; unsigned int res = 0; vpflags = dvpe(); settc(tc); switch(ctl_reg){ case 0: res = mftc0(25, 0); break; case 1: res = mftc0(25, 2); break; default: printk(KERN_ERR "ctl reg %d is not supported\n", ctl_reg); break; } evpe(vpflags); return res; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void write_c0_perfctl_for_counting_tc_mask(unsigned int perf_ctl_reg, unsigned int val, unsigned int counting_tc_mask){ unsigned int i; unsigned int ntc = supportet_tcs(); for ( i = 0; i < ntc; i++){ if (( 1 << i) & counting_tc_mask ) write_c0_perfctl(perf_ctl_reg, i, val); } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void write_c0_perfcnt_for_counting_tc_mask(unsigned int perf_ctl_reg, unsigned int val, unsigned int counting_tc_mask){ unsigned int i; unsigned int ntc = supportet_tcs(); for ( i = 0; i < ntc; i++){ if (( 1 << i) & counting_tc_mask ) write_c0_perfcnt(perf_ctl_reg, i, val); } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ unsigned int ack_irqs_reload_counter(void) { unsigned int tc; unsigned int reloaded_tcs_mask = 0; unsigned int ntc = supportet_tcs(); for ( tc = 0; tc < ntc; tc++ ) { unsigned int pcntr = 0; unsigned int pcntr_control = 0; do { pcntr_control = read_c0_perfctl( pcntr, tc ); if ( pcntr_control & MIPS_PERFOMANCE_IRQ_ENABLE ) { // printk(KERN_ERR "irq_enabled in tc=%d, pctr=%d \n",tc, pcntr ); if (read_c0_perfcnt(pcntr, tc) & (1<< 31)){ write_c0_perfcnt(pcntr, tc, PERFCNT_RELOAD_LAST_VAL); // printk(KERN_ERR "bit 31 set in tc=%d, pctr=%d, reload=%#x \n",tc, pcntr, read_c0_perfcnt(pcntr, tc) ); reloaded_tcs_mask |= ( 1 << tc ); } } pcntr += 1; } while (pcntr_control & MIPS_PERFOMANCE_HAS_MORE); } return reloaded_tcs_mask; } EXPORT_SYMBOL(ack_irqs_reload_counter); /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #endif #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) /*--------------------------------------------------------------------------------*\ * liefert Anzahl der Performance-Counter \*--------------------------------------------------------------------------------*/ static unsigned int performance_counter_avail(void) { unsigned int perf_max_registers = 0; unsigned int val, config7; val = read_c0_config1(); if((val & (1 << 4)) == 0) { printk(KERN_ERR "[simple-profiling]: no performance counters implemented\n"); return perf_max_registers; } perf_max_registers = 1; config7 = read_c0_config7(); val = read_c0_perfctrl0(); if(val & (1U << 31)) { perf_max_registers = 2; val = read_c0_perfctrl1(); if(val & (1U << 31)) { perf_max_registers = 3; val = read_c0_perfctrl2(); if(val & (1U << 31)) { perf_max_registers = 4; val = read_c0_perfctrl3(); if(val & (1U << 31)) { perf_max_registers = 5; } } } } printk(KERN_ERR "[simple-profiling]: %d performance counters implemented, %s\n", perf_max_registers, (config7 & (1 << 19))?"NEW_34K":"OLD_34K" ); return perf_max_registers; } #endif/*--- #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void performance_counter_action(char *p __attribute__((unused))) { #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) unsigned int perf_reg_number = 0; int perf_reg_flags = 0; int perf_reg_index = 0; unsigned int i; unsigned int perf_max_registers; #if defined(CONFIG_CPU_MIPS_34K) char *p1 __attribute__((unused)); int perf_vpeid = -1; int perf_tcid = -1; #endif int new_perf_ctl = 0; #if defined(CONFIG_CPU_MIPS_34K) unsigned int current_tc_mask = (1 << raw_smp_processor_id()); int counting_tc_mask = current_tc_mask; int set_perf_irq = 0; int preset_count = 0; #endif /* * NEW_34K: the core has two performance counters, replicated per-TC * OLD_34K: had four performance counters, not replicated */ perf_max_registers = performance_counter_avail(); if(perf_max_registers == 0) { return; } SKIP_SPACE(p); #if defined(CONFIG_CPU_MIPS_34K) if(strstr(p, "readcount")) { unsigned int tc, count_reg; unsigned int ntc = supportet_tcs(); SKIP_NON_SPACE(p); SKIP_SPACE(p); for (tc = 0; tc < ntc; tc++) for (count_reg = 0; count_reg < perf_max_registers; count_reg++) printk(KERN_ERR "performance_count[tc=%d, counter=%d] = %#x\n", tc, count_reg, read_c0_perfcnt(count_reg, tc)); } else if(strstr(p, "readconfig")) { unsigned int tc, count_reg; unsigned int ntc = supportet_tcs(); SKIP_NON_SPACE(p); SKIP_SPACE(p); for (tc = 0; tc < ntc; tc++) for (count_reg = 0; count_reg < perf_max_registers; count_reg++) printk(KERN_ERR "performance_control[tc=%d, counter=%d] = %#x\n", tc, count_reg, read_c0_perfctl(count_reg, tc)); return; } else if(strstr(p, "touchconfig")) { unsigned int ntc = supportet_tcs(); unsigned int touch_tc = ntc; unsigned int touch_reg = perf_max_registers; SKIP_NON_SPACE(p); SKIP_SPACE(p); if((*p >= '0') && (*p <= '9')) { sscanf(p, "%u", &touch_tc); } SKIP_NON_SPACE(p); SKIP_SPACE(p); if((*p >= '0') && (*p <= '9')) { sscanf(p, "%u", &touch_reg); } SKIP_NON_SPACE(p); SKIP_SPACE(p); if ( ( touch_tc <= ntc ) && ( touch_reg <= perf_max_registers )){ unsigned int val = read_c0_perfctl(touch_reg, touch_tc); printk(KERN_ERR "read [tc=%d, counter=%d] = %#x\n", touch_tc, touch_reg, val); write_c0_perfctl(touch_reg, touch_tc, val); printk(KERN_ERR "write [tc=%d, counter=%d] = %#x\n", touch_tc, touch_reg, val); } return; } else if (strstr(p, "resetconfig")) { unsigned int ntc = supportet_tcs(); unsigned int touch_tc = ntc; unsigned int touch_reg = perf_max_registers; SKIP_NON_SPACE(p); SKIP_SPACE(p); if((*p >= '0') && (*p <= '9')) { sscanf(p, "%u", &touch_tc); } SKIP_NON_SPACE(p); SKIP_SPACE(p); if((*p >= '0') && (*p <= '9')) { sscanf(p, "%u", &touch_reg); } SKIP_NON_SPACE(p); SKIP_SPACE(p); if ( ( touch_tc <= ntc ) && ( touch_reg <= perf_max_registers )){ unsigned int val = read_c0_perfctl(touch_reg, touch_tc); printk(KERN_ERR "read [tc=%d, counter=%d] = %#x\n", touch_tc, touch_reg, val); val = 0; write_c0_perfctl(touch_reg, touch_tc, val); printk(KERN_ERR "write [tc=%d, counter=%d] = %#x\n", touch_tc, touch_reg, val); } return; } #endif if((*p >= '0') && (*p <= '3')) { sscanf(p, "%u", &perf_reg_number); } if (perf_reg_number >= perf_max_registers){ printk(KERN_INFO "Error: you cannot access perf_reg %d, we have just %d regs available:\n", perf_reg_number, perf_max_registers); return; } SKIP_NON_SPACE(p); SKIP_SPACE(p); if(!*p) { show_performance_counter_options: printk(KERN_INFO "Option of performance counter %d:\n", perf_reg_number); for(i = 0 ; i < 64 ; i++) { if(perfomance_counter_options[perf_reg_number][i] == NULL) continue; printk(KERN_INFO "\t[%2d]: %s\n", i, perfomance_counter_options[perf_reg_number][i]); } return; } if((*p >= '0') && (*p <= '9')) { sscanf(p, "%d", &perf_reg_index); } else { for(i = 0 ; i < 64 ; i++) { if(perfomance_counter_options[perf_reg_number][i] == NULL) continue; if(!strncmp(perfomance_counter_options[perf_reg_number][i], p , strlen(p))) { perf_reg_index = i; break; } } if(i == 64) { goto show_performance_counter_options; } } if(perf_reg_index >= 64) { goto show_performance_counter_options; } SKIP_NON_SPACE(p); SKIP_SPACE(p); #if defined(CONFIG_CPU_MIPS_34K) if((p1 = strstr(p, "examine_vpe="))){ unsigned int param; sscanf(p1, "examine_vpe=%x", ¶m); perf_vpeid = param; SKIP_NON_SPACE(p); SKIP_SPACE(p); } if((p1 = strstr(p, "examine_tc="))) { unsigned int param; sscanf(p1, "examine_tc=%x", ¶m); perf_tcid = param; SKIP_NON_SPACE(p); SKIP_SPACE(p); } if((p1 = strstr(p, "counting_tc_mask="))) { unsigned int param; sscanf(p1 , "counting_tc_mask=%x", ¶m); counting_tc_mask = param; printk(KERN_INFO "setup counting_tc_mask=%#x\n",counting_tc_mask); SKIP_NON_SPACE(p); SKIP_SPACE(p); } if((p1 = strstr(p, "preset_count="))) { unsigned int param; sscanf(p1, "preset_count=%x", ¶m); preset_count = param; printk(KERN_INFO "setup preset_count=%#x\n", preset_count); SKIP_NON_SPACE(p); SKIP_SPACE(p); } if((p1 = strstr(p, "irq="))) { sscanf(p1, "irq=%d", &set_perf_irq); SKIP_NON_SPACE(p); SKIP_SPACE(p); } #endif perf_reg_flags = MIPS_PERFOMANCE_USER_MODE_ENABLE | MIPS_PERFOMANCE_SUPERVISOR_MODE_ENABLE | MIPS_PERFOMANCE_KERNEL_MODE_ENABLE | /*--- MIPS_PERFOMANCE_EXCEPTION_ENABLE | ---*/ 0; #if defined(CONFIG_CPU_MIPS_34K) if (set_perf_irq){ printk(KERN_INFO "Enable Performance Counter irq\n"); perf_reg_flags |= MIPS_PERFOMANCE_IRQ_ENABLE; } if( (perf_vpeid != -1)&&(perf_tcid != -1)) { printk(KERN_INFO "Error: you cannot use VPEID and TCID together\n"); return; } if(perf_vpeid != -1){ perf_reg_flags |= MIPS_PERFORMANCE_VPE_SPECIFIC_ENABLE | MIPS_PERFORMANCE_VPEID(perf_vpeid); } if(perf_tcid != -1){ perf_reg_flags |= MIPS_PERFORMANCE_TC_SPECIFIC_ENABLE | MIPS_PERFORMANCE_TCID(perf_tcid); } #endif /*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ printk(KERN_INFO "Enable Performance Counter %d for %s (%s)\n", perf_reg_number, perfomance_counter_options[perf_reg_number][perf_reg_index], print_perfomance_counter_mode(perf_reg_flags)); new_perf_ctl = (perf_reg_index << 5) | perf_reg_flags; switch(perf_reg_number) { case 0: #if defined(CONFIG_CPU_MIPS_34K) printk(KERN_INFO "Setup tcs=%#x current_tc_mask=%#x, reg=%d\n",counting_tc_mask, current_tc_mask, perf_reg_number); if ( preset_count != -1) write_c0_perfcnt_for_counting_tc_mask(0, preset_count, counting_tc_mask); write_c0_perfctl_for_counting_tc_mask(0, new_perf_ctl, counting_tc_mask); #else write_c0_perfctrl0(new_perf_ctl); #endif break; case 1: #if defined(CONFIG_CPU_MIPS_34K) printk(KERN_INFO "Setup tcs=%#x current_tc_mask=%#x, reg=%d\n",counting_tc_mask, current_tc_mask, perf_reg_number); if ( preset_count != -1) write_c0_perfcnt_for_counting_tc_mask(1, preset_count, counting_tc_mask); write_c0_perfctl_for_counting_tc_mask(1, new_perf_ctl, counting_tc_mask); #else write_c0_perfctrl1(new_perf_ctl); #endif break; case 2: write_c0_perfctrl2(new_perf_ctl); break; case 3: write_c0_perfctrl3(new_perf_ctl); break; default: break; } /*--- #define read_c0_perfctrl0() __read_32bit_c0_register($25, 0) ---*/ /*--- #define read_c0_perfcntr0() __read_32bit_c0_register($25, 1) ---*/ /*--- #define write_c0_perfcntr0(val) __write_32bit_c0_register($25, 1, val) ---*/ /*--- #define read_c0_perfctrl1() __read_32bit_c0_register($25, 2) ---*/ /*--- #define read_c0_perfcntr1() __read_32bit_c0_register($25, 3) ---*/ /*--- #define write_c0_perfcntr1(val) __write_32bit_c0_register($25, 3, val) ---*/ /*--- #define read_c0_perfctrl2() __read_32bit_c0_register($25, 4) ---*/ /*--- #define write_c0_perfctrl2(val) __write_32bit_c0_register($25, 4, val) ---*/ /*--- #define read_c0_perfcntr2() __read_32bit_c0_register($25, 5) ---*/ /*--- #define write_c0_perfcntr2(val) __write_32bit_c0_register($25, 5, val) ---*/ /*--- #define read_c0_perfctrl3() __read_32bit_c0_register($25, 6) ---*/ /*--- #define write_c0_perfctrl3(val) __write_32bit_c0_register($25, 6, val) ---*/ /*--- #define read_c0_perfcntr3() __read_32bit_c0_register($25, 7) ---*/ /*--- #define write_c0_perfcntr3(val) __write_32bit_c0_register($25, 7, val) ---*/ #endif/*--- #if defined(CONFIG_MIPS) && !defined(CONFIG_MIPS_UR8) ---*/ } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ struct _profile_readcsv { unsigned int pos; unsigned int entries; unsigned long timediff; struct _pid_field act_pid[NR_CPUS]; struct _avm_profile_data *data; unsigned int cnt; }; /*--------------------------------------------------------------------------------*\ Returns false if pos at or past end of file. \*--------------------------------------------------------------------------------*/ static int update_iter(struct _profile_readcsv *iter, loff_t pos) { /* Module symbols can be accessed randomly. */ iter->data = avm_simple_profiling_by_idx(pos); iter->pos = pos; if(iter->data == NULL) { avm_simple_profiling_unset_busy(); return 0; } return 1; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void *s_next(struct seq_file *m, void *p, loff_t *pos) { (*pos)++; if (!update_iter(m->private, *pos)) { return NULL; } return p; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void *s_start(struct seq_file *m, loff_t *pos) { if (!update_iter(m->private, *pos)) { return NULL; } return m->private; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void s_stop(struct seq_file *m __attribute__((unused)), void *p __attribute__((unused))) { avm_simple_profiling_unset_busy(); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int s_show(struct seq_file *m, void *p __attribute__((unused))) { struct _profile_readcsv *iter = m->private; char seqbuf[512]; if(iter->pos == 0) { format_profile_header(seqbuf, iter->timediff); seq_printf(m, "%s",seqbuf); } if (iter->data == NULL) { avm_simple_profiling_unset_busy(); return 0; } if(iter->cnt++ > 2000) { iter->cnt = 0; printk("*"); } format_profile_line(seqbuf, iter->data, iter->act_pid, 3, 1); seq_printf(m, "%s",seqbuf); return 0; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static const struct seq_operations readcsv_op = { .start = s_start, .next = s_next, .stop = s_stop, .show = s_show }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void reset_iter(struct _profile_readcsv *iter, loff_t new_pos) { unsigned int i; avm_simple_profiling_enable(0, 0, &iter->entries, &iter->timediff, 1); iter->pos = new_pos; iter->cnt = 0; for(i = 0; i < sizeof(iter->act_pid) / sizeof(iter->act_pid[0]); i++) { strcpy(iter->act_pid[i].comm, "PID_0"); iter->act_pid[i].pid = 0; } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int readcsv_open(struct inode *inode __attribute__((unused)), struct file *file) { /* * We keep iterator in m->private, since normal case is to * s_start from where we left off, so we avoid doing */ struct _profile_readcsv *iter; int ret; iter = kmalloc(sizeof(*iter), GFP_KERNEL); if (!iter) { return -ENOMEM; } reset_iter(iter, 0); ret = seq_open(file, &readcsv_op); ((struct seq_file *)file->private_data)->private = iter; return ret; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static const struct file_operations readcsv_operations = { .open = readcsv_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, }; #if defined(CONFIG_KALLSYMS) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int profilestat_show(struct seq_file *seq, void *data __attribute__((unused))) { /*--- printk("%s %p %p\n", __func__, seq->private, data); ---*/ if(seq->private) { seq_printf(seq, "%s", (char *)seq->private); } return 0; } #define PROFILE_BUF_SIZE (128 << 10) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int profilestat_open(struct inode *inode __attribute__((unused)), struct file *file) { unsigned int bufsize = PROFILE_BUF_SIZE; unsigned int full = 0; char *filename; char *buf; buf = kmalloc(bufsize, GFP_KERNEL); if(buf == NULL) { return -ENOMEM; } buf[0] = 0; filename = file->f_path.dentry ? (char *)file->f_path.dentry->d_name.name : ""; if(strcmp(filename, "statistic") == 0) { #if defined(CONFIG_MIPS) /*--- vpes ---*/ profilestat_category(buf, bufsize, 0, VPE_NR_CPUS, full); #else/*--- #if defined(CONFIG_LANTIQ) ---*/ unsigned int cpu; unsigned char *pbuf = buf; for(cpu = 0; cpu < NR_CPUS; cpu++) { unsigned int txtlen = profilestat_category(pbuf, bufsize, cpu, 1, full); pbuf += txtlen; bufsize -= txtlen; } #endif/*--- #else ---*//*--- #if defined(CONFIG_LANTIQ) ---*/ } else if(strcmp(filename, "totalcall") == 0) { profilestat_totalcall(buf, bufsize, 0, NR_CPUS, 0); } else if(strcmp(filename, "totalweight") == 0) { profilestat_totalcall(buf, bufsize, 0, NR_CPUS, 1); /*--- } else if(strcmp(filename, "totalweight2") == 0) { ---*/ /*--- profilestat_totalcall(buf, PROFILE_BUF_SIZE, 0, NR_CPUS, 2); ---*/ } avm_simple_profiling_unset_busy(); /*--- printk("%s %p\n", __func__, buf); ---*/ return single_open(file, profilestat_show, buf); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static const struct file_operations profilestat_fops = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) .owner = THIS_MODULE, #endif .open = profilestat_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, }; #endif /*--- #if defined(CONFIG_KALLSYMS) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static struct _profile_helper { char *action; char *help; unsigned int tracemask; unsigned int mode; } profile_helper[] = { { action: "all", help: "trace all entries", tracemask: (1 << avm_profile_data_type_code_address_info) | (1 << avm_profile_data_type_hw_irq_begin) | (1 << avm_profile_data_type_hw_irq_end) | (1 << avm_profile_data_type_sw_irq_begin) | (1 << avm_profile_data_type_sw_irq_end) | (1 << avm_profile_data_type_timer_begin) | (1 << avm_profile_data_type_timer_end) | (1 << avm_profile_data_type_tasklet_begin) | (1 << avm_profile_data_type_tasklet_end) | (1 << avm_profile_data_type_hi_tasklet_begin) | (1 << avm_profile_data_type_hi_tasklet_end) | (1 << avm_profile_data_type_workitem_begin) | (1 << avm_profile_data_type_workitem_end) | (1 << avm_profile_data_type_tasklet_end) | (1 << avm_profile_data_type_hi_tasklet_end) | (1 << avm_profile_data_type_trigger_tasklet_begin) | (1 << avm_profile_data_type_trigger_tasklet_end) | (1 << avm_profile_data_type_trigger_user_begin) | (1 << avm_profile_data_type_trigger_user_end) | (1 << avm_profile_data_type_func_begin) | (1 << avm_profile_data_type_func_end) | 0, mode: 0x1 }, { action: "stop", help: "stop tracing", tracemask: 0x0, mode: 0x3 }, { action: "wrap", help: "wrap if buffer full", tracemask: 0x0, mode: 0x2 }, { action: "code", help: "only code-trace", tracemask: 1 << avm_profile_data_type_code_address_info, mode: 0x1 }, { action: "hwirq", help: "hardware irqs", tracemask: 1 << avm_profile_data_type_hw_irq_begin | 1 << avm_profile_data_type_hw_irq_end, mode: 0x1 }, { action: "swirq", help: "software irqs", tracemask: 1 << avm_profile_data_type_sw_irq_begin | 1 << avm_profile_data_type_sw_irq_end, mode: 0x1 }, { action: "timer", help: "timer irqs", tracemask: 1 << avm_profile_data_type_timer_begin | 1 << avm_profile_data_type_timer_end, mode: 0x1 }, { action: "tasklet", help: "(hi-)tasklets", tracemask: 1 << avm_profile_data_type_tasklet_begin | 1 << avm_profile_data_type_tasklet_begin | 1 << avm_profile_data_type_hi_tasklet_begin | 1 << avm_profile_data_type_hi_tasklet_begin , mode: 0x1 }, { action: "workitem", help: "workqueues", tracemask: 1 << avm_profile_data_type_workitem_begin | 1 << avm_profile_data_type_workitem_end, mode: 0x1 }, { action: "trigger", help: "tasklet-trigger an user-defined trigger", tracemask: 1 << avm_profile_data_type_trigger_tasklet_begin | 1 << avm_profile_data_type_trigger_tasklet_end | 1 << avm_profile_data_type_trigger_user_begin | 1 << avm_profile_data_type_trigger_user_end, mode: 0x1 }, { action: "func", help: "user defined function", tracemask: 1 << avm_profile_data_type_func_begin | 1 << avm_profile_data_type_func_end, mode: 0x1 }, { action: "bh", help: "bottom half (sw-irq, tasklets, timer)", tracemask: 1 << avm_profile_data_type_timer_begin | 1 << avm_profile_data_type_timer_end | 1 << avm_profile_data_type_tasklet_begin | 1 << avm_profile_data_type_tasklet_end | 1 << avm_profile_data_type_sw_irq_begin | 1<< avm_profile_data_type_sw_irq_end, mode: 0x1 }, { action: NULL, mode: 0x0 } }; /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void lproc_profile_help(struct seq_file *seq, void *priv){ struct _profile_helper *ph = (struct _profile_helper *)priv; seq_printf(seq, "AVM Profiler Version 3.0\n" "csv - get raw-profile-list for offline evaluation\n" #if defined(CONFIG_KALLSYMS) "statistic - get profile statistic (consumption/latency)\n" "totalcall - get top of function calls\n" "totalweight - get top of function calls weighted with codelength\n" /*--- "totalweight2 - get top of function calls weighted with square-codelength\n" ---*/ #endif/*--- #if defined(CONFIG_KALLSYMS) ---*/ "action - all, stop, ... mbytes=x (see below)\n\n" "perform - [] [||liste]\n" #if defined(CONFIG_CPU_MIPS_34K) "alternative use: echo perform \n" "param: readcount,readconfig,touchconfig, resetconfig\n" #endif/*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ ); seq_printf(seq, "parameter(s) for action:\n"); while(ph->action) { seq_printf(seq, "%s - %s\n", ph->action, ph->help); ph++; } seq_printf(seq, "mbytes=: size of profiler-buffer (actual: %u MiB)\n\n", (profile_BlockNeeded * (1 << PAGE_SHIFT)) / (1 << 20)); seq_printf(seq, "example: echo bh workitem wrap > /proc/avm/profile/action\n"); } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int proc_write_profiler_perform(char *buffer, void *priv __attribute__((unused))) { char parsbuf[256]; strncpy(parsbuf, buffer, sizeof(parsbuf) - 1); parsbuf[sizeof(parsbuf) -1] = '\0'; /*--- printk(KERN_INFO"%s parsbuf='%s'\n", __func__, parsbuf); ---*/ if((strstr(parsbuf, "help"))) { printk(KERN_ERR "use: echo perform [] [||liste]\n"); #if defined(CONFIG_CPU_MIPS_34K) printk(KERN_ERR "alternative use: echo perform \n"); printk(KERN_ERR "param: readcount,readconfig,touchconfig, resetconfig\n"); #endif/*--- #if defined(CONFIG_CPU_MIPS_34K) ---*/ return 0; } performance_counter_action(parsbuf); return 0; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int proc_write_profiler_action(char *buffer, void *priv) { struct _profile_helper *ph = (struct _profile_helper *)priv; unsigned int tracemask = 0, mode = 0, mbytes, BlockNeeded; char parsbuf[256], *p; strncpy(parsbuf, buffer, sizeof(parsbuf) - 1); parsbuf[sizeof(parsbuf) -1] = '\0'; /*--- printk(KERN_INFO"%s parsbuf='%s'\n", __func__, parsbuf); ---*/ if((p = strstr(parsbuf, "mbytes="))) { sscanf(p, "mbytes=%u", &mbytes); if(mbytes == 0) { mbytes = 2; } BlockNeeded = mbytes * (1 << (20 - PAGE_SHIFT)); avm_simple_profiling_memresize(BlockNeeded); } while(ph->action) { if(strstr(parsbuf, ph->action)) { if((ph->mode & 0xFF) > mode) { mode = ph->mode; } tracemask |= ph->tracemask; } ph++; } if(mode > 2) { mode = 0; } /*--- printk(KERN_INFO"%s %x %x\n", __func__, mode, tracemask); ---*/ avm_simple_profiling_enable(mode, tracemask, NULL, NULL, 0); return 0; } static struct proc_dir_entry *profileprocdir; #define PROC_PROFILEDIR "avm/profile" /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int __init avm_profiler_init(void) { profileprocdir = proc_mkdir(PROC_PROFILEDIR, NULL); if(profileprocdir == NULL) { return 0; } proc_create("csv", 0444, profileprocdir, &readcsv_operations); #if defined(CONFIG_KALLSYMS) proc_create("statistic", 0444, profileprocdir, &profilestat_fops); proc_create("totalcall", 0444, profileprocdir, &profilestat_fops); proc_create("totalweight", 0444, profileprocdir, &profilestat_fops); /*--- proc_create("totalweight2", 0444, profileprocdir, &profilestat_fops); ---*/ #endif /*--- #if defined(CONFIG_KALLSYMS) ---*/ add_simple_proc_file( "avm/profile/help", NULL, lproc_profile_help, profile_helper); add_simple_proc_file( "avm/profile/action", proc_write_profiler_action, NULL, profile_helper); add_simple_proc_file( "avm/profile/perform", proc_write_profiler_perform, NULL, profile_helper); #if defined(CONFIG_MIPS) && !defined(CONFIG_AVM_SIMPLE_PROFILING_YIELD_PCNT) performance_counter_action("0 10"); performance_counter_action("1 11"); #endif printk("AVM Simple Profiling enabled Version %u.0\n", AVM_PROFILING_VERSION); return 0; } late_initcall(avm_profiler_init); #if defined(CONFIG_AVM_DEBUG_MODULE) && (CONFIG_AVM_DEBUG_MODULE == 1) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void avm_profiler_exit(void) { #if defined(CONFIG_AVM_DEBUG_MODULE) && (CONFIG_AVM_DEBUG_MODULE == 1) if(profileprocdir) { remove_proc_entry("csv", profileprocdir); #if defined(CONFIG_KALLSYMS) remove_proc_entry("statistic", profileprocdir); remove_proc_entry("totalcall", profileprocdir); remove_proc_entry("totalweight", profileprocdir); /*--- remove_proc_entry("totalweight2", profileprocdir); ---*/ #endif /*--- #if defined(CONFIG_KALLSYMS) ---*/ remove_simple_proc_file("avm/profile/action"); remove_simple_proc_file("avm/profile/perform"); remove_simple_proc_file("avm/profile/help"); remove_proc_entry(PROC_PROFILEDIR, NULL); profileprocdir= NULL; } } #endif/*--- #if defined(CONFIG_AVM_DEBUG_MODULE) && (CONFIG_AVM_DEBUG_MODULE == 1) ---*/ } module_exit(avm_profiler_exit); #endif/*--- #if defined(CONFIG_AVM_DEBUG_MODULE) && (CONFIG_AVM_DEBUG_MODULE == 1) ---*/ #endif/*--- #if defined(CONFIG_PROC_FS) ---*/