dis: power consumption annotations.
This commit is contained in:
parent
1959b8b895
commit
ca6a30b2e7
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
152
util/powerbuf.c
152
util/powerbuf.c
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue