static void da_relocate_base (DArray *d, TrieIndex s, TrieIndex new_base) { TrieIndex old_base; Symbols *symbols; int i; old_base = da_get_base (d, s); symbols = da_output_symbols (d, s); for (i = 0; i < symbols_num (symbols); i++) { TrieIndex old_next, new_next, old_next_base; old_next = old_base + symbols_get (symbols, i); new_next = new_base + symbols_get (symbols, i); old_next_base = da_get_base (d, old_next); /* allocate new next node and copy BASE value */ da_alloc_cell (d, new_next); da_set_check (d, new_next, s); da_set_base (d, new_next, old_next_base); /* old_next node is now moved to new_next * so, all cells belonging to old_next * must be given to new_next */ /* preventing the case of TAIL pointer */ if (old_next_base > 0) { TrieIndex c, max_c; max_c = MIN_VAL (TRIE_CHAR_MAX, TRIE_INDEX_MAX - old_next_base); for (c = 0; c < max_c; c++) { if (da_get_check (d, old_next_base + c) == old_next) da_set_check (d, old_next_base + c, new_next); } } /* free old_next node */ da_free_cell (d, old_next); } symbols_free (symbols); /* finally, make BASE[s] point to new_base */ da_set_base (d, s, new_base); }
static Bool da_enumerate_recursive (const DArray *d, TrieIndex state, DAEnumFunc enum_func, void *user_data) { Bool ret; TrieIndex base; base = da_get_base (d, state); if (base < 0) { TrieChar *key; key = da_get_state_key (d, state); ret = (*enum_func) (key, state, user_data); free (key); } else { Symbols *symbols; int i; ret = TRUE; symbols = da_output_symbols (d, state); for (i = 0; ret && i < symbols_num (symbols); i++) { ret = da_enumerate_recursive (d, base + symbols_get (symbols, i), enum_func, user_data); } symbols_free (symbols); } return ret; }
/** * @brief Get all walkable characters from state * * @param s : the state to get * @param chars : the storage for the result * @param chars_nelm : the size of @a chars[] in number of elements * * @return total walkable characters * * Get the list of all walkable characters from state @a s. At most * @a chars_nelm walkable characters are stored in @a chars[] on return. * * The function returns the actual number of walkable characters from @a s. * Note that this may not equal the number of characters stored in @a chars[] * if @a chars_nelm is less than the actual number. * * Available since: 0.2.6 */ int trie_state_walkable_chars (const TrieState *s, AlphaChar chars[], int chars_nelm) { int syms_num = 0; if (!s->is_suffix) { Symbols *syms = da_output_symbols (s->trie->da, s->index); int i; syms_num = symbols_num (syms); for (i = 0; i < syms_num && i < chars_nelm; i++) { TrieChar tc = symbols_get (syms, i); chars[i] = alpha_map_trie_to_char (s->trie->alpha_map, tc); } symbols_free (syms); } else { const TrieChar *suffix = tail_get_suffix (s->trie->tail, s->index); chars[0] = alpha_map_trie_to_char (s->trie->alpha_map, suffix[s->suffix_idx]); syms_num = 1; } return syms_num; }
void frame_dump_stack(FILE *out, uint16 fp) { char buf[10]; char *funcname; int lastpc = pc; int i; thread_info *thread; thread = fp == GET_REG16(7) ? current_thread : hash_get(&threads, fp); if (!thread) return; for (i = thread->num_frames; i >= 0; i--) { int fpc = thread->frames[i].pc & ~1; int fp = thread->frames[i].fp; funcname = symbols_get(fpc, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", fpc); funcname=buf; } fprintf(out, " %04x: %30s [%04x+%04x]\n", fp, funcname, fpc, lastpc - fpc); lastpc = (memory[fp] << 8 | memory[fp+1]); } return; }
static void frame_dump_function(unsigned int key, void *param) { char buf[10]; char *funcname; profile_info *prof = param; funcname = symbols_get(key, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", key); funcname=buf; } if (prof->calls) { fprintf(proffile, "%2s%30s: %11ld %11lu %11lu %11lu %11lu %11lu %11lu %11lu\n", prof->isIRQ ? "I:" : " ", funcname, prof->calls, prof->local_cycles, prof->total_cycles, prof->local_cycles / prof->calls, prof->total_cycles / prof->calls, prof->max_local_cycles, prof->max_total_cycles, prof->irq_cycles); } else { fprintf(proffile, "%2s%30s: never finished\n", prof->isIRQ ? "I:" : " ", funcname); } hash_enumerate(&prof->callees, frame_dump_callee); fprintf(proffile, "\n"); }
static void frame_dump_callee(unsigned int key, void *param) { char buf[10]; char *funcname; callee_info *callee = param; funcname = symbols_get(key & ~1, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", key & ~1); funcname=buf; } fprintf(proffile, " %2s%30s: %6ld calls %11ld cycles\n", key & 1 ? "I:" : " ", funcname, callee->calls, callee->cycles); }
static Bool da_fit_symbols (DArray *d, TrieIndex base, const Symbols *symbols) { int i; for (i = 0; i < symbols_num (symbols); i++) { TrieChar sym = symbols_get (symbols, i); /* if (base + sym) > TRIE_INDEX_MAX which means it's overflow, * or cell [base + sym] is not free, the symbol is not fit. */ if (base > TRIE_INDEX_MAX - sym || !da_check_free_cell (d, base + sym)) return FALSE; } return TRUE; }
static TrieIndex da_find_free_base (DArray *d, const Symbols *symbols) { TrieChar first_sym; TrieIndex s; /* find first free cell that is beyond the first symbol */ first_sym = symbols_get (symbols, 0); s = -da_get_check (d, da_get_free_list (d)); while (s != da_get_free_list (d) && s < (TrieIndex) first_sym + DA_POOL_BEGIN) { s = -da_get_check (d, s); } if (s == da_get_free_list (d)) { for (s = first_sym + DA_POOL_BEGIN; ; ++s) { if (!da_extend_pool (d, s)) return TRIE_INDEX_ERROR; if (da_get_check (d, s) < 0) break; } } /* search for next free cell that fits the symbols set */ while (!da_fit_symbols (d, s - first_sym, symbols)) { /* extend pool before getting exhausted */ if (-da_get_check (d, s) == da_get_free_list (d)) { if (!da_extend_pool (d, d->num_cells)) return TRIE_INDEX_ERROR; } s = -da_get_check (d, s); } return s - first_sym; }
/** * Handle a call instruction and add profile information for the * called and calling function. */ void frame_begin(uint16 fp, int in_irq) { frame_info *frame, *pframe; profile_info *pprof; /* If we there is no current thread, just return. The current thread * will be created by the opcode that initializes the stack pointer. * So there should be always a current thread at the moment we call * a function. */ if (!current_thread) return; if (fp < current_thread->minfp) current_thread->minfp = fp; /* Add a new frame to the current thread. Resize the stack structure * if necessary. */ frame_grow_num_frames(); /* Initialize the new frame. */ frame = ¤t_thread->frames[current_thread->num_frames]; frame->startcycle = cycles; frame->childcycles = 0; frame->irqcycles = 0; frame->threadcycles = 0; frame->pc = pc | (in_irq ? 1 : 0); frame->fp = fp; #ifdef LOG_CALLS #ifndef LOG_CALLS_IRQ int i, rec_in_irq = 0; /* Check if this frame was directly or indirectly called by interrupt. */ for (i = current_thread->num_frames; i >= 0; i--) { if (current_thread->frames[i].pc & 1) { rec_in_irq = 1; break; } } /* Log the call to framelog, unless called from interrupt. */ if (!rec_in_irq) #endif { char* funcname, buf[10]; funcname = symbols_get(pc, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", pc); funcname=buf; } fprintf(framelog, "%*s%s(%04x,%04x,%04x,%04x) fp: %04x klock: %d inirq: %d\n", current_thread->num_frames * 3, "", funcname, pc < 0x8000 ? GET_REG16(6) : GET_REG16(0), pc < 0x8000 ? READ_WORD(GET_REG16(7)+2) : GET_REG16(1), pc < 0x8000 ? READ_WORD(GET_REG16(7)+4) : GET_REG16(2), pc < 0x8000 ? READ_WORD(GET_REG16(7)+6) : GET_REG16(3), GET_REG16(7), memory[symbols_getaddr("_kernel_lock")], in_irq); } #endif /* get parent frame and add a new callee to its profile information. */ pframe = frame - 1; #ifdef HASH_PROFILES pprof = hash_get(&profiles, pframe->pc & ~1); #else pprof = profiles[pframe->pc & ~1]; #endif if (!pprof) { #ifdef HASH_PROFILES pprof = hash_create(&profiles, pframe->pc & ~1, sizeof(profile_info)); #else pprof = profiles[pframe->pc & ~1] = malloc(sizeof(profile_info)); #endif memset(pprof, 0, sizeof(profile_info)); hash_init(&pprof->callees, 5); } }
void frame_switch(uint16 oldframe, uint16 newframe) { if (oldframe == newframe) return; #ifdef LOG_CALLS if (current_thread) { int lastpc = pc; int i; char buf[10]; char *funcname; for (i = current_thread->num_frames; i >= 0; i--) { int fpc = current_thread->frames[i].pc & ~1; int fp = current_thread->frames[i].fp; funcname = symbols_get(fpc, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", fpc); funcname=buf; } fprintf(framelog, " %04x: %30s%s [%04x+%04x]\n", fp, funcname, current_thread->frames[i].pc & 1 ? "(I)" : " ", fpc, lastpc - fpc); lastpc = (memory[fp] << 8 | memory[fp+1]); } } #endif #ifdef VERBOSE_FRAME printf("Frame switch: %04x --> %04x cycles: %11ld\n", oldframe, newframe, cycles); #endif if (current_thread) { current_thread->switchcycle = cycles; current_thread->savefp = oldframe; hash_move(&threads, 0, oldframe); } current_thread = hash_move(&threads, newframe, 0); #ifdef LOG_CALLS fprintf(framelog, "Frame switch: %04x --> %04x\n", oldframe, newframe); if (current_thread) { int lastpc = pc; int i; char buf[10]; char *funcname; for (i = current_thread->num_frames; i >= 0; i--) { int fpc = current_thread->frames[i].pc & ~1; int fp = current_thread->frames[i].fp; funcname = symbols_get(fpc, 0); if (!funcname) { snprintf(buf, 10, "0x%04x", fpc); funcname=buf; } fprintf(framelog, " %04x: %30s%s [%04x+%04x]\n", fp, funcname, current_thread->frames[i].pc & 1 ? "(I)" : " ", fpc, lastpc - fpc); lastpc = (memory[fp] << 8 | memory[fp+1]); } } #endif if (!current_thread) { current_thread = hash_create(&threads, 0, sizeof(thread_info) + 2* sizeof(frame_info)); current_thread->minfp = newframe; current_thread->size_frames = 2; current_thread->num_frames = 0; current_thread->switchcycle = cycles; memset(¤t_thread->frames[0], 0, sizeof(frame_info)); current_thread->frames[0].startcycle = cycles; current_thread->frames[0].pc = pc; } current_thread->frames[current_thread->num_frames].threadcycles += cycles - current_thread->switchcycle; }