summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2013-09-19 12:50:39 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2013-09-19 12:50:39 +0200
commit23a0d9edd2194df0edc4d47cfdd38a46ae8c61db (patch)
treef4515381547f871708fe7d03c88fcced6d26f38f
parent47491ec92da4c00f892f904315f94268772ce78d (diff)
utils: add dma occupancy mode to viv_gpu_top
-rw-r--r--native/etnaviv/viv.c20
-rw-r--r--native/etnaviv/viv.h12
-rw-r--r--native/utils/viv_gpu_top.c254
3 files changed, 253 insertions, 33 deletions
diff --git a/native/etnaviv/viv.c b/native/etnaviv/viv.c
index 9b89987..76afb8c 100644
--- a/native/etnaviv/viv.c
+++ b/native/etnaviv/viv.c
@@ -542,3 +542,23 @@ int viv_unmap_user_memory(struct viv_conn *conn, void *memory, size_t size, viv_
return viv_invoke(conn, &id);
}
+int viv_read_register(struct viv_conn *conn, uint32_t address, uint32_t *data)
+{
+ gcsHAL_INTERFACE id;
+ int rv;
+ id.command = gcvHAL_READ_REGISTER;
+ id.u.ReadRegisterData.address = address;
+ rv = viv_invoke(conn, &id);
+ *data = id.u.ReadRegisterData.data;
+ return rv;
+}
+
+int viv_write_register(struct viv_conn *conn, uint32_t address, uint32_t data)
+{
+ gcsHAL_INTERFACE id;
+ id.command = gcvHAL_WRITE_REGISTER;
+ id.u.WriteRegisterData.address = address;
+ id.u.WriteRegisterData.data = data;
+ return viv_invoke(conn, &id);
+}
+
diff --git a/native/etnaviv/viv.h b/native/etnaviv/viv.h
index 74c7b37..4d0ebd4 100644
--- a/native/etnaviv/viv.h
+++ b/native/etnaviv/viv.h
@@ -277,6 +277,18 @@ void viv_show_chip_info(struct viv_conn *conn);
*/
int viv_reset(struct viv_conn *conn);
+/** Read register from GPU.
+ * @note Needs kernel module compiled with user space register access
+ * (gcdREGISTER_ACCESS_FROM_USER=1)
+ */
+int viv_read_register(struct viv_conn *conn, uint32_t address, uint32_t *data);
+
+/** Write register to GPU.
+ * @note Needs kernel module compiled with user space register access
+ * (gcdREGISTER_ACCESS_FROM_USER=1)
+ */
+int viv_write_register(struct viv_conn *conn, uint32_t address, uint32_t data);
+
/** Convenience macro to probe features from state.xml.h:
* VIV_FEATURE(chipFeatures, FAST_CLEAR)
* VIV_FEATURE(chipMinorFeatures1, AUTO_DISABLE)
diff --git a/native/utils/viv_gpu_top.c b/native/utils/viv_gpu_top.c
index f62df7f..7dbb3e1 100644
--- a/native/utils/viv_gpu_top.c
+++ b/native/utils/viv_gpu_top.c
@@ -26,6 +26,8 @@
#include <etnaviv/viv.h>
#include <etnaviv/viv_profile.h>
+#include <etnaviv/state_hi.xml.h>
+#include <etnaviv/state.xml.h>
static const char *bars[] = {
" ",
@@ -47,15 +49,18 @@ static const char color_num_max[] = "\x1b[1;37m";
static const char color_num_zero[] = "\x1b[1;30m";
static const char color_num[] = "\x1b[1;33m";
static const char color_reset[] = "\x1b[0m";
+static const char color_percentage_1[] = "\x1b[38;5;154;48;5;236m";
+static const char color_percentage_2[] = "\x1b[38;5;112;48;5;236m";
+static const char color_title[] = "\x1b[38;5;249m";
-#define STATS_LEN (20)
-#define PERCENTAGE_BAR_END (79 - STATS_LEN)
-
-static void print_percentage_bar(float percent, int cur_line_len)
+static void print_percentage_bar(float percent, int bar_width)
{
- int bar_avail_len = (PERCENTAGE_BAR_END - cur_line_len - 1) * 8;
+ int bar_avail_len = bar_width * 8;
int bar_len = bar_avail_len * (percent + .5) / 100.0;
+ int cur_line_len = 0;
int i;
+ if(bar_len > bar_avail_len)
+ bar_len = bar_avail_len;
for (i = bar_len; i >= 8; i -= 8) {
printf("%s", bars[8]);
@@ -68,7 +73,8 @@ static void print_percentage_bar(float percent, int cur_line_len)
/* NB: We can't use a field width with utf8 so we manually
* guarantee a field with of 45 chars for any bar. */
- printf("%*s", PERCENTAGE_BAR_END - cur_line_len, "");
+
+ printf("%*s", bar_width - cur_line_len, "");
}
/* Get time in microseconds */
@@ -132,23 +138,13 @@ struct counter_rec
uint64_t events_per_s;
};
-/* Sort counters descending */
-static int counter_rec_compar(const void *a, const void *b)
-{
- uint64_t ca = ((const struct counter_rec*)a)->events_per_s;
- uint64_t cb = ((const struct counter_rec*)b)->events_per_s;
- if(ca < cb)
- return 1;
- else if(cb > ca)
- return -1;
- else return 0;
-}
-
enum display_mode
{
MODE_ALL = 0,
MODE_MAX = 1,
- MODE_SORTED = 2
+ MODE_SORTED = 2,
+ MODE_OCCUPANCY = 3,
+ MODE_DMA = 4
};
/* derived counters (derived information computed from existing counters) */
@@ -160,6 +156,71 @@ static struct viv_profile_counter_info derived_counter_info[] = {
[0] = {"TOTAL_INST_COUNTER", "Total inst counter"},
};
+static struct {
+ const char *name;
+ uint32_t bit;
+ bool inv; /* show inverted value */
+} idle_module_names[] = {
+ {"FE", VIVS_HI_IDLE_STATE_FE, true},
+ {"DE", VIVS_HI_IDLE_STATE_DE, true},
+ {"PE", VIVS_HI_IDLE_STATE_PE, true},
+ {"SH", VIVS_HI_IDLE_STATE_SH, true},
+ {"PA", VIVS_HI_IDLE_STATE_PA, true},
+ {"SE", VIVS_HI_IDLE_STATE_SE, true},
+ {"RA", VIVS_HI_IDLE_STATE_RA, true},
+ {"TX", VIVS_HI_IDLE_STATE_TX, true},
+ {"VG", VIVS_HI_IDLE_STATE_VG, true},
+ {"IM", VIVS_HI_IDLE_STATE_IM, true},
+ {"FP", VIVS_HI_IDLE_STATE_FP, true},
+ {"TS", VIVS_HI_IDLE_STATE_TS, true},
+ {"AXI_LP", VIVS_HI_IDLE_STATE_AXI_LP, false}
+};
+#define NUM_IDLE_MODULES (sizeof(idle_module_names)/sizeof(idle_module_names[0]))
+
+static const char* cmd_state_names[]={
+"IDLE", "DEC", "ADR0", "LOAD0", "ADR1", "LOAD1", "3DADR", "3DCMD",
+"3DCNTL", "3DIDXCNTL", "INITREQDMA", "DRAWIDX", "DRAW", "2DRECT0", "2DRECT1", "2DDATA0",
+"2DDATA1", "WAITFIFO", "WAIT", "LINK", "END", "STALL", "UNKNOWN"
+};
+#define NUM_CMD_STATE_NAMES (sizeof(cmd_state_names)/sizeof(cmd_state_names[0]))
+
+static const char* cmd_dma_state_names[]={
+ "IDLE", "START", "REQ", "END"
+};
+#define NUM_CMD_DMA_STATE_NAMES (sizeof(cmd_dma_state_names)/sizeof(cmd_dma_state_names[0]))
+
+static const char* cmd_fetch_state_names[]={
+ "IDLE", "RAMVALID", "VALID", "UNKNOWN"
+};
+#define NUM_CMD_FETCH_STATE_NAMES (sizeof(cmd_fetch_state_names)/sizeof(cmd_fetch_state_names[0]))
+
+static const char* req_dma_state_names[]={
+ "IDLE", "START", "REQ", "END"
+};
+#define NUM_REQ_DMA_STATE_NAMES (sizeof(req_dma_state_names)/sizeof(req_dma_state_names[0]))
+
+static const char* cal_state_names[]={
+ "IDLE", "LDADR", "IDXCALC", "UNKNOWN"
+};
+#define NUM_CAL_STATE_NAMES (sizeof(cal_state_names)/sizeof(cal_state_names[0]))
+
+static const char* ve_req_state_names[]={
+ "IDLE", "CKCACHE", "MISS", "UNKNOWN"
+};
+#define NUM_VE_REQ_STATE_NAMES (sizeof(ve_req_state_names)/sizeof(ve_req_state_names[0]))
+
+/* Sort counters descending */
+static int counter_rec_compar(const void *a, const void *b)
+{
+ uint64_t ca = ((const struct counter_rec*)a)->events_per_s;
+ uint64_t cb = ((const struct counter_rec*)b)->events_per_s;
+ if(ca < cb)
+ return 1;
+ else if(cb > ca)
+ return -1;
+ else return 0;
+}
+
static struct viv_profile_counter_info *get_counter_info(uint32_t idx)
{
if(idx < derived_counters_base)
@@ -168,6 +229,26 @@ static struct viv_profile_counter_info *get_counter_info(uint32_t idx)
return &derived_counter_info[idx - derived_counters_base];
}
+static void print_percentage_row(int l, double percent, const char *name, int name_width, bool color, int bar_width)
+{
+ printf("%-*s ", name_width, name);
+ if(color)
+ {
+ if(percent > 99.0)
+ printf("%s", color_num_max);
+ else if(percent < 1.0)
+ printf("%s", color_num_zero);
+ else
+ printf("%s", color_num);
+ }
+ printf("%5.1f%% ", percent);
+ if(color)
+ printf("%s%s", color_reset, (l%2) ? color_percentage_1 : color_percentage_2);
+ print_percentage_bar(percent, bar_width);
+ if(color)
+ printf("%s", color_reset);
+}
+
int main(int argc, char **argv)
{
struct viv_conn *conn = 0;
@@ -197,6 +278,8 @@ int main(int argc, char **argv)
case 'm': mode = MODE_MAX; break;
case 'a': mode = MODE_ALL; break;
case 's': mode = MODE_SORTED; break;
+ case 'o': mode = MODE_OCCUPANCY; break;
+ case 'd': mode = MODE_DMA; break;
default:
printf("Unknown mode %s\n", optarg);
}
@@ -230,28 +313,59 @@ int main(int argc, char **argv)
events_per_s[c] = 0;
}
+ uint32_t idle_states[NUM_IDLE_MODULES] = {};
+ uint32_t cmd_state[32] = {};
+ uint32_t cmd_dma_state[4] = {};
+ uint32_t cmd_fetch_state[4] = {};
+ uint32_t req_dma_state[4] = {};
+ uint32_t cal_state[4] = {};
+ uint32_t ve_req_state[4] = {};
for(int sample=0; sample<samples_per_second; ++sample)
{
- if(viv_read_profile_counters_3d(conn, counter_data) != 0)
+ if(mode == MODE_OCCUPANCY)
{
- fprintf(stderr, "Error querying counters (probably unsupported with this kernel, or not built into libetnaviv)\n");
- exit(1);
- }
- for(int c=0; c<num_profile_counters; ++c)
+ uint32_t data = 0;
+ viv_read_register(conn, VIVS_HI_IDLE_STATE, &data);
+ for(int mid=0; mid<NUM_IDLE_MODULES; ++mid)
+ {
+ if(data & idle_module_names[mid].bit)
+ idle_states[mid]++;
+ }
+ } else if(mode == MODE_DMA)
{
- if(!reset_after_read[c])
+ uint32_t data = 0;
+ viv_read_register(conn, VIVS_FE_DMA_DEBUG_STATE, &data);
+ int cmd_state_idx = data & 0x1F;
+ if(cmd_state_idx >= (NUM_CMD_STATE_NAMES-1)) /* Mark unknowns as UNKNOWN */
+ cmd_state_idx = NUM_CMD_STATE_NAMES-1;
+ cmd_state[cmd_state_idx]++;
+ cmd_dma_state[(data>>8) & 3]++;
+ cmd_fetch_state[(data>>10) & 3]++;
+ req_dma_state[(data>>12) & 3]++;
+ cal_state[(data>>14) & 3]++;
+ ve_req_state[(data>>16) & 3]++;
+ } else {
+ if(viv_read_profile_counters_3d(conn, counter_data) != 0)
{
- if(counter_data_last[c] > counter_data[c])
+ fprintf(stderr, "Error querying counters (probably unsupported with this kernel, or not built into libetnaviv)\n");
+ exit(1);
+ }
+ for(int c=0; c<num_profile_counters; ++c)
+ {
+ if(!reset_after_read[c])
{
+ if(counter_data_last[c] > counter_data[c])
+ {
+ events_per_s[c] += counter_data[c];
+ } else {
+ events_per_s[c] += (uint32_t)(counter_data[c] - counter_data_last[c]);
+ }
+ } else
events_per_s[c] += counter_data[c];
- } else {
- events_per_s[c] += (uint32_t)(counter_data[c] - counter_data_last[c]);
- }
- } else
- events_per_s[c] += counter_data[c];
+ }
+ for(int c=0; c<num_profile_counters; ++c)
+ counter_data_last[c] = counter_data[c];
}
- for(int c=0; c<num_profile_counters; ++c)
- counter_data_last[c] = counter_data[c];
usleep(interval);
}
@@ -349,6 +463,80 @@ int main(int argc, char **argv)
}
printf("\n");
}
+ } else if(mode == MODE_OCCUPANCY)
+ {
+ int lines = NUM_IDLE_MODULES;
+ if(lines > max_lines)
+ lines = max_lines;
+
+ if(color)
+ printf("%s", color_title);
+ printf("Module occupancy\n");
+ if(color)
+ printf("%s", color_reset);
+ for(int l=0; l<lines; ++l)
+ {
+ double percent = 100.0 * (double)idle_states[l] / (double)samples_per_second;
+ if(idle_module_names[l].inv)
+ percent = 100.0 - percent;
+ print_percentage_row(l, percent, idle_module_names[l].name, 6, color, 40);
+ printf("\n");
+ }
+ } else if(mode == MODE_DMA)
+ {
+ const struct dma_table {
+ int column;
+ int base_y;
+ const char *title;
+ int data_size;
+ const char **data_names;
+ uint32_t *data;
+ } dma_tables[] = {
+ {0, 1, "Command state", NUM_CMD_STATE_NAMES, cmd_state_names, cmd_state},
+ {1, 1, "Command DMA state", NUM_CMD_DMA_STATE_NAMES, cmd_dma_state_names, cmd_dma_state},
+ {1, 7, "Command fetch state", NUM_CMD_FETCH_STATE_NAMES, cmd_fetch_state_names, cmd_fetch_state},
+ {1, 13, "DMA request state", NUM_REQ_DMA_STATE_NAMES, req_dma_state_names, req_dma_state},
+ {1, 19, "Cal state", NUM_CAL_STATE_NAMES, cal_state_names, cal_state},
+ {1, 25, "VE req state", NUM_VE_REQ_STATE_NAMES, ve_req_state_names, ve_req_state}
+ };
+#define NUM_DMA_TABLES (sizeof(dma_tables) / sizeof(dma_tables[0]))
+ for(int l=0; l<max_lines; ++l)
+ {
+ for(int column=0; column<2; ++column)
+ {
+ bool match = false;
+ for(int t=0; t<NUM_DMA_TABLES; ++t) /* find table that this column,row slot is part of, if any */
+ {
+ const struct dma_table *table = &dma_tables[t];
+ if(table->column == column)
+ {
+ if(l == table->base_y-1)
+ {
+ if(color)
+ printf("%s", color_title);
+ printf("%-59s", table->title);
+ if(color)
+ printf("%s", color_reset);
+ match = true;
+ break;
+ } else if(l >= table->base_y && l < (table->base_y + table->data_size))
+ {
+ int y = l - table->base_y;
+ double percent = 100.0 * (double)table->data[y] / (double)samples_per_second;
+ print_percentage_row(y, percent, table->data_names[y], 10, color, 40);
+ match = true;
+ break;
+ }
+ }
+ }
+ if(!match) /* empty slot */
+ {
+ printf("%-59s", "");
+ }
+ printf(" ");
+ }
+ printf("\n");
+ }
}
}
begin_time = end_time;