dis: power consumption annotations.

This commit is contained in:
Daniel Beer 2012-10-04 12:10:36 +13:00
parent 1959b8b895
commit ca6a30b2e7
6 changed files with 218 additions and 11 deletions

View File

@ -50,7 +50,7 @@ int cmd_regs(char **arg)
if (device_readmem(regs[0], code, len) < 0) if (device_readmem(regs[0], code, len) < 0)
return 0; return 0;
disassemble(regs[0], (uint8_t *)code, len); disassemble(regs[0], (uint8_t *)code, len, device_default->power_buf);
return 0; return 0;
} }
@ -324,7 +324,7 @@ int cmd_dis(char **arg)
} }
reader_set_repeat("dis 0x%x 0x%x", offset + length, length); reader_set_repeat("dis 0x%x 0x%x", offset + length, length);
disassemble(offset, buf, length); disassemble(offset, buf, length, device_default->power_buf);
free(buf); free(buf);
return 0; return 0;
} }

View File

@ -371,7 +371,8 @@ static int do_isearch(address_t addr, address_t len,
int count = dis_decode(mbuf + i, addr + i, len - i, &insn); int count = dis_decode(mbuf + i, addr + i, len - i, &insn);
if (count >= 0 && isearch_match(&insn, q)) if (count >= 0 && isearch_match(&insn, q))
disassemble(addr + i, mbuf + i, count); disassemble(addr + i, mbuf + i, count,
device_default->power_buf);
} }
free(mbuf); free(mbuf);

View File

@ -136,10 +136,10 @@ static int dis_format(const struct msp430_instruction *insn)
insn->src_addr, insn->src_addr,
insn->src_reg); insn->src_reg);
printc(","); len += printc(",");
while (len < 15) while (len < 15)
len += printc(" "); len += printc(" ");
printc(" "); len += printc(" ");
} }
/* Destination operand */ /* Destination operand */
@ -157,9 +157,12 @@ static int dis_format(const struct msp430_instruction *insn)
return len; return len;
} }
void disassemble(address_t offset, const uint8_t *data, int length) void disassemble(address_t offset, const uint8_t *data, int length,
powerbuf_t power)
{ {
int first_line = 1; int first_line = 1;
unsigned long long ua_total = 0;
int samples_total = 0;
while (length) { while (length) {
struct msp430_instruction insn = {0}; struct msp430_instruction insn = {0};
@ -194,13 +197,39 @@ void disassemble(address_t offset, const uint8_t *data, int length)
} }
if (retval >= 0) if (retval >= 0)
dis_format(&insn); i = dis_format(&insn);
if (power) {
unsigned long long ua;
int samples;
while (i < 40) {
printc(" ");
i++;
}
samples = powerbuf_get_by_mab(power, offset, &ua);
if (samples) {
printc(" ;; %.01f uA",
(double)ua / (double)samples);
ua_total += ua;
samples_total += samples;
}
}
printc("\n"); printc("\n");
offset += count; offset += count;
length -= count; length -= count;
data += count; data += count;
} }
if (power && samples_total)
printc(";; Total over this block: "
"%.01f uAs in %.01f ms (%.01f uA avg)\n",
(double)(ua_total * power->interval_us) / 1000000.0,
(double)(samples_total * power->interval_us) / 1000.0,
(double)ua_total / (double)samples_total);
} }
void hexdump(address_t addr, const uint8_t *data, int data_len) void hexdump(address_t addr, const uint8_t *data, int data_len)
@ -256,9 +285,9 @@ void show_regs(const address_t *regs)
int print_address(address_t addr, char *out, int max_len) int print_address(address_t addr, char *out, int max_len)
{ {
char name[MAX_SYMBOL_LENGTH]; char name[MAX_SYMBOL_LENGTH];
address_t offset; address_t offset;
if (!stab_nearest(addr, name, sizeof(name), &offset)) { if (!stab_nearest(addr, name, sizeof(name), &offset)) {
int len; int len;
if (offset) if (offset)
len = snprintf(out, max_len, "%s+0x%x", name, offset); len = snprintf(out, max_len, "%s+0x%x", name, offset);
@ -270,7 +299,7 @@ int print_address(address_t addr, char *out, int max_len)
snprintf(out + len, max_len - len, " (%s)", demangled); snprintf(out + len, max_len - len, " (%s)", demangled);
} }
return 1; return 1;
} }
snprintf(out, max_len, "0x%04x", addr); snprintf(out, max_len, "0x%04x", addr);
return 0; return 0;

View File

@ -21,9 +21,11 @@
#include "output.h" #include "output.h"
#include "util.h" #include "util.h"
#include "powerbuf.h"
/* Print colorized disassembly on command processor standard output */ /* Print colorized disassembly on command processor standard output */
void disassemble(address_t addr, const uint8_t *buf, int len); void disassemble(address_t addr, const uint8_t *buf, int len,
powerbuf_t power);
/* Print colorized hexdump on standard output */ /* Print colorized hexdump on standard output */
void hexdump(address_t addr, const uint8_t *buf, int len); void hexdump(address_t addr, const uint8_t *buf, int len);

View File

@ -42,6 +42,12 @@ powerbuf_t powerbuf_new(unsigned int max_samples, unsigned int interval_us)
pb->mab = malloc(sizeof(pb->mab[0]) * max_samples); pb->mab = malloc(sizeof(pb->mab[0]) * max_samples);
if (!pb->mab) { if (!pb->mab) {
free(pb->current_ua);
return NULL;
}
pb->sorted = malloc(sizeof(pb->sorted[0]) * max_samples);
if (!pb->sorted) {
free(pb->current_ua); free(pb->current_ua);
free(pb->mab); free(pb->mab);
return NULL; return NULL;
@ -60,6 +66,7 @@ void powerbuf_free(powerbuf_t pb)
{ {
free(pb->current_ua); free(pb->current_ua);
free(pb->mab); free(pb->mab);
free(pb->sorted);
free(pb); free(pb);
} }
@ -67,6 +74,7 @@ void powerbuf_clear(powerbuf_t pb)
{ {
pb->session_head = pb->session_tail = 0; pb->session_head = pb->session_tail = 0;
pb->current_head = pb->current_tail = 0; pb->current_head = pb->current_tail = 0;
pb->sort_valid = 0;
} }
static unsigned int session_length(powerbuf_t pb, unsigned int idx) static unsigned int session_length(powerbuf_t pb, unsigned int idx)
@ -264,6 +272,8 @@ void powerbuf_add_samples(powerbuf_t pb, unsigned int count,
mab += cont_len; mab += cont_len;
count -= cont_len; count -= cont_len;
} }
pb->sort_valid = 0;
} }
address_t powerbuf_last_mab(powerbuf_t pb) address_t powerbuf_last_mab(powerbuf_t pb)
@ -277,3 +287,145 @@ address_t powerbuf_last_mab(powerbuf_t pb)
return pb->mab[last]; return pb->mab[last];
} }
static void sift_down(powerbuf_t pb, int start, int end)
{
int root = start;
while (root * 2 + 1 <= end) {
int left_child = root * 2 + 1;
int biggest = root;
unsigned int temp;
/* Find the largest of
* (root, left child, right child)
*/
if (pb->mab[pb->sorted[biggest]] <
pb->mab[pb->sorted[left_child]])
biggest = left_child;
if (left_child + 1 <= end &&
(pb->mab[pb->sorted[biggest]] <
pb->mab[pb->sorted[left_child + 1]]))
biggest = left_child + 1;
/* If no changes are needed, the heap property is ok and
* we can stop.
*/
if (biggest == root)
break;
/* Swap the root with its largest child */
temp = pb->sorted[biggest];
pb->sorted[biggest] = pb->sorted[root];
pb->sorted[root] = temp;
/* Continue to push down the old root (now a child) */
root = biggest;
}
}
static void heapify(powerbuf_t pb, int num_samples)
{
int start = (num_samples - 2) / 2;
while (start >= 0) {
sift_down(pb, start, num_samples - 1);
start--;
}
}
static void heap_extract(powerbuf_t pb, int num_samples)
{
int end = num_samples - 1;
while (end > 0) {
unsigned int temp;
/* Swap the top of the heap with the end of the array,
* and shrink the heap.
*/
temp = pb->sorted[0];
pb->sorted[0] = pb->sorted[end];
pb->sorted[end] = temp;
end--;
/* Fix up the heap (push down the new root) */
sift_down(pb, 0, end);
}
}
void powerbuf_sort(powerbuf_t pb)
{
const unsigned int num_samples =
(pb->current_head + pb->max_samples - pb->current_tail) %
pb->max_samples;
unsigned int i;
if (pb->sort_valid)
return;
/* Prepare an index list */
for (i = 0; i < num_samples; i++)
pb->sorted[i] = (pb->current_tail + i) % pb->max_samples;
if (num_samples < 2) {
pb->sort_valid = 1;
return;
}
heapify(pb, num_samples);
heap_extract(pb, num_samples);
pb->sort_valid = 1;
}
/* Find the index within the sorted index of the first sample with an
* MAB >= the given mab parameter.
*/
static int find_mab_ge(powerbuf_t pb, address_t mab)
{
const int num_samples =
(pb->current_head + pb->max_samples - pb->current_tail) %
pb->max_samples;
int low = 0;
int high = num_samples - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (pb->mab[pb->sorted[mid]] < mab)
low = mid + 1;
else if ((mid <= 0) || (pb->mab[pb->sorted[mid - 1]] < mab))
return mid;
else
high = mid - 1;
}
return -1;
}
int powerbuf_get_by_mab(powerbuf_t pb, address_t mab,
unsigned long long *sum_ua)
{
const unsigned int num_samples =
(pb->current_head + pb->max_samples - pb->current_tail) %
pb->max_samples;
int i;
int count = 0;
if (!pb->sort_valid)
powerbuf_sort(pb);
i = find_mab_ge(pb, mab);
if (i < 0)
return 0;
*sum_ua = 0;
while ((i < num_samples) && (pb->mab[pb->sorted[i]] == mab)) {
*sum_ua += pb->current_ua[pb->sorted[i]];
count++;
i++;
}
return count;
}

View File

@ -78,6 +78,17 @@ struct powerbuf {
address_t *mab; address_t *mab;
unsigned int current_head; unsigned int current_head;
unsigned int current_tail; unsigned int current_tail;
/* Index by MAB. This is a flat array which points to indices
* within current_ua/mab. The indices are sorted in order of
* increasing MAB.
*
* Note that this array is invalidated by any modification to
* the sample buffers. You need to call powerbuf_sort() before
* accessing it.
*/
int sort_valid;
unsigned int *sorted;
}; };
typedef struct powerbuf *powerbuf_t; typedef struct powerbuf *powerbuf_t;
@ -120,4 +131,16 @@ void powerbuf_add_samples(powerbuf_t pb, unsigned int count,
/* Retrieve the last known MAB for this session, or 0 if none exists. */ /* Retrieve the last known MAB for this session, or 0 if none exists. */
address_t powerbuf_last_mab(powerbuf_t pb); address_t powerbuf_last_mab(powerbuf_t pb);
/* Prepare the sorted MAB index. */
void powerbuf_sort(powerbuf_t pb);
/* Obtain charge consumption data by MAB over all sessions. This
* automatically calls powerbuf_sort() if necessary.
*
* Returns the number of samples found on success. The sum of all
* current samples is written to the sum_ua argument.
*/
int powerbuf_get_by_mab(powerbuf_t pb, address_t mab,
unsigned long long *sum_ua);
#endif #endif