#include #include #include #include #include #include /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AVM_SIMPLE_PROFILING) #include #include #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) struct _simple_profiling simple_profiling; #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ # define PROFILE_BUFFER_LEN (CONFIG_AVM_PROFILING_TRACE_MODE * 1024) struct _simple_profiling { struct _avm_profile_data data[PROFILE_BUFFER_LEN]; atomic_t pos; spinlock_t lock; unsigned int len; unsigned int enabled; unsigned int mode; unsigned long start_time; unsigned long end_time; unsigned int wraparround; } simple_profiling; #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static unsigned int lavm_simple_profiling_incpos(void) { unsigned int pos = 0; long flags; if(simple_profiling.enabled == 1) { pos = atomic_inc_return(&(simple_profiling.pos)) - 1; if(pos >= simple_profiling.len - 1) { simple_profiling.enabled = 0; simple_profiling.end_time = jiffies | 1; printk("[simple_profiling] buffer full: %u entries recorded\n", simple_profiling.len); } } else if(simple_profiling.enabled == 2) { spin_lock_irqsave(&simple_profiling.lock, flags); pos = atomic_inc_return(&(simple_profiling.pos)) - 1; if(pos >= simple_profiling.len) { printk("[simple_profiling] wraparround: %u entries recorded\n", simple_profiling.len); if(simple_profiling.end_time == 0) simple_profiling.end_time = jiffies | 1; simple_profiling.wraparround = 1; simple_profiling.pos.counter = pos = 0; } spin_unlock_irqrestore(&simple_profiling.lock, flags); } return pos; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int avm_simple_profiling(struct pt_regs *regs, unsigned int irq_num) { unsigned int pos, epc, time; #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) struct _avm_profile_data *data; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ if(simple_profiling.enabled == 0) return 0; if(simple_profiling.mode != 1) return 0; #if defined(CONFIG_ARM) epc = regs->ARM_pc; #endif /*--- #if defined(CONFIG_ARM) ---*/ #if defined(CONFIG_MIPS) epc = regs->cp0_epc; #endif /*--- #if defined(CONFIG_MIPS) ---*/ time = avm_profile_counter(); pos = lavm_simple_profiling_incpos(); #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = &((struct _avm_profile_data *)(simple_profiling.data[pos / profile_DataSetsPerBlock]))[pos % profile_DataSetsPerBlock]; data->type = avm_profile_data_type_code_address_info; data->curr = current; data->id = irq_num; data->addr = epc; data->time = time; data->total_access = avm_profile_sdramacess(); data->total_activate = avm_profile_sdramactivate(); #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.data[pos].type = avm_profile_data_type_code_address_info; simple_profiling.data[pos].curr = current; simple_profiling.data[pos].id = irq_num; simple_profiling.data[pos].addr = epc; simple_profiling.data[pos].time = time; simple_profiling.data[pos].total_access = avm_profile_sdramacess(); simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ return time; } EXPORT_SYMBOL(avm_simple_profiling); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void avm_simple_profiling_skb(unsigned int addr, unsigned int where, struct sk_buff *skb) { unsigned int pos, time; #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) struct _avm_profile_data *data; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ if(simple_profiling.enabled == 0) return; if(simple_profiling.mode != 2) return; time = avm_profile_counter(); pos = lavm_simple_profiling_incpos(); #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = (struct _avm_profile_data *)(simple_profiling.data[pos / profile_DataSetsPerBlock]) + (pos % profile_DataSetsPerBlock); data->curr = current; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data->type = avm_profile_data_type_trace_skb; data->id = skb_cloned(skb); data->addr = addr; data->time = time; data->total_access = skb->uniq_id & 0xFFFFFF; data->total_activate = where; #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.data[pos].type = avm_profile_data_type_trace_skb; simple_profiling.data[pos].id = skb_cloned(skb); simple_profiling.data[pos].addr = addr; simple_profiling.data[pos].time = time; simple_profiling.data[pos].total_access = skb->uniq_id & 0xFFFFFF; simple_profiling.data[pos].total_activate = where; #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ } EXPORT_SYMBOL(avm_simple_profiling_skb); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void avm_simple_profiling_log(enum _avm_profile_data_type type, unsigned int addr, unsigned int id) { unsigned int pos, time; #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) struct _avm_profile_data *data; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ if(simple_profiling.enabled == 0) return; if(simple_profiling.mode != 1) return; time = avm_profile_counter(); pos = lavm_simple_profiling_incpos(); #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = (struct _avm_profile_data *)(simple_profiling.data[pos / profile_DataSetsPerBlock]) + (pos % profile_DataSetsPerBlock); data->curr = current; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ switch(type) { default: case avm_profile_data_type_free: case avm_profile_data_type_unknown: break; case avm_profile_data_type_text: case avm_profile_data_type_code_address_info: case avm_profile_data_type_data_address_info: #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data->type = type; data->addr = addr; data->time = time; data->total_access = avm_profile_sdramacess(); data->total_activate = avm_profile_sdramactivate(); #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.data[pos].type = type; simple_profiling.data[pos].addr = addr; simple_profiling.data[pos].time = time; simple_profiling.data[pos].total_access = avm_profile_sdramacess(); simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ break; case avm_profile_data_type_hw_irq_begin: case avm_profile_data_type_hw_irq_end: 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_workitem_begin: case avm_profile_data_type_workitem_end: case avm_profile_data_type_cpphytx_begin: case avm_profile_data_type_cpphytx_end: case avm_profile_data_type_cpphyrx_begin: case avm_profile_data_type_cpphyrx_end: case avm_profile_data_type_func_begin: case avm_profile_data_type_func_end: #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data->type = type; data->id = id; data->addr = addr; data->time = time; data->total_access = avm_profile_sdramacess(); data->total_activate = avm_profile_sdramactivate(); #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.data[pos].type = type; simple_profiling.data[pos].id = id; simple_profiling.data[pos].addr = addr; simple_profiling.data[pos].time = time; simple_profiling.data[pos].total_access = avm_profile_sdramacess(); simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ break; } } EXPORT_SYMBOL(avm_simple_profiling_log); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void avm_simple_profiling_text(const char *text) { unsigned int pos; #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) struct _avm_profile_data *data; #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ if(simple_profiling.enabled == 0) return; if(simple_profiling.mode != 1) return; pos = lavm_simple_profiling_incpos(); #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = (struct _avm_profile_data *)(simple_profiling.data[pos / profile_DataSetsPerBlock]) + (pos % profile_DataSetsPerBlock); data->type = avm_profile_data_type_text; data->time = avm_profile_counter(); data->addr = (unsigned int)text; data->total_access = avm_profile_sdramacess(); data->total_activate = avm_profile_sdramactivate(); #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.data[pos].type = avm_profile_data_type_text; simple_profiling.data[pos].time = avm_profile_counter(); simple_profiling.data[pos].addr = (unsigned int)text; simple_profiling.data[pos].total_access = avm_profile_sdramacess(); simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ return; } EXPORT_SYMBOL(avm_simple_profiling_text); /*------------------------------------------------------------------------------------------*\ * on = 2: wraparround-mode \*------------------------------------------------------------------------------------------*/ void avm_simple_profiling_enable(unsigned int on, unsigned int *count, unsigned long *timediff) { if(on) { #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) if(simple_profiling.data[0] == NULL) { int i; for(i = 0 ; i < profile_BlockNeeded ; i++) { struct page *ptr = alloc_pages(__GFP_NORETRY, 1); if(ptr == NULL) { simple_profiling.len = profile_DataSetsPerBlock * i; printk("[avm_simple_profiling_enable] resize %d pages instead %d pages\n", i, profile_BlockNeeded); break; } simple_profiling.data[i] = (void *)lowmem_page_address(ptr); /*--- printk("\t%d: %x ==> %x\n", i, ptr, simple_profiling.data[i]); ---*/ } printk("[avm_simple_profiling_enable] need %d pages for %d bytes Buffer %d samples per block\n", i, simple_profiling.len, profile_DataSetsPerBlock); } #endif /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ atomic_set(&(simple_profiling.pos), 0); simple_profiling.start_time = jiffies; simple_profiling.end_time = 0; simple_profiling.wraparround = 0; switch (on) { default: printk(KERN_ERR "Unknown profiling mode. Assuming normal profiling without waparound.\n"); case 2: simple_profiling.enabled = 1; simple_profiling.mode = 1; break; case 6: simple_profiling.enabled = 2; simple_profiling.mode = 1; break; case 7: simple_profiling.enabled = 1; simple_profiling.mode = 2; break; case 8: simple_profiling.enabled = 2; simple_profiling.mode = 2; break; } if(count) *count = 0; if(timediff)*timediff = 0; return; } simple_profiling.enabled = 0; if(simple_profiling.end_time == 0) simple_profiling.end_time = jiffies; if(count) { if(simple_profiling.wraparround == 0) { *count = simple_profiling.pos.counter; } else { *count = simple_profiling.len; } } printk("[simple_profiling] off: %u entries\n", simple_profiling.wraparround ? simple_profiling.len : simple_profiling.pos.counter); if(timediff) { if(time_after(simple_profiling.start_time, simple_profiling.end_time)) { *timediff = simple_profiling.end_time + 0xFFFFFFFF - simple_profiling.start_time; } else { *timediff = simple_profiling.end_time - simple_profiling.start_time; } } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ struct _avm_profile_data *avm_simple_profiling_by_idx(unsigned int idx) { unsigned int pos; struct _avm_profile_data *data; if(simple_profiling.wraparround == 0) { if(idx < simple_profiling.pos.counter) { #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = ((struct _avm_profile_data *)(simple_profiling.data[idx / profile_DataSetsPerBlock]) + (idx % profile_DataSetsPerBlock)); #else/*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ data = &simple_profiling.data[idx]; #endif/*--- #else ---*//*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ return data; } return NULL; } pos = simple_profiling.pos.counter + idx; if(pos >= simple_profiling.len) { pos -= simple_profiling.len; if(pos >= simple_profiling.pos.counter) { return NULL; } } #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) data = ((struct _avm_profile_data *)(simple_profiling.data[pos / profile_DataSetsPerBlock]) + (pos % profile_DataSetsPerBlock)); #else/*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ data = &simple_profiling.data[pos]; #endif/*--- #else ---*//*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ return data; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int avm_simple_profiling_init(void) { spin_lock_init(&simple_profiling.lock); #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) simple_profiling.len = profile_DataSetsPerBlock * profile_BlockNeeded; #else /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.len = PROFILE_BUFFER_LEN; #endif /*--- #else ---*/ /*--- #if defined(AVM_PROFILING_VERSION) && (AVM_PROFILING_VERSION == 2) ---*/ simple_profiling.enabled = 0; atomic_set(&(simple_profiling.pos), 0); printk("[simple_profiling] %u entries %u min\n", simple_profiling.len, CONFIG_AVM_PROFILING_TRACE_MODE); return 0; } module_init(avm_simple_profiling_init); #endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/