1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2018 Jonathan Marek <jonathan@marek.ca> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Jonathan Marek <jonathan@marek.ca> 25bf215546Sopenharmony_ci * Rob Clark <robclark@freedesktop.org> 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/* NOTE: perfcntrs are 48-bits but we only have 32-bit accumulate (?) 29bf215546Sopenharmony_ci * so we work with 32-bits only. we accumulate start/stop separately, 30bf215546Sopenharmony_ci * which differs from a5xx but works with only accumulate (no add/neg) 31bf215546Sopenharmony_ci */ 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "freedreno_query_acc.h" 34bf215546Sopenharmony_ci#include "freedreno_resource.h" 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "fd2_context.h" 37bf215546Sopenharmony_ci#include "fd2_query.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_cistruct PACKED fd2_query_sample { 40bf215546Sopenharmony_ci uint32_t start; 41bf215546Sopenharmony_ci uint32_t stop; 42bf215546Sopenharmony_ci}; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci/* offset of a single field of an array of fd2_query_sample: */ 45bf215546Sopenharmony_ci#define query_sample_idx(aq, idx, field) \ 46bf215546Sopenharmony_ci fd_resource((aq)->prsc)->bo, \ 47bf215546Sopenharmony_ci (idx * sizeof(struct fd2_query_sample)) + \ 48bf215546Sopenharmony_ci offsetof(struct fd2_query_sample, field), \ 49bf215546Sopenharmony_ci 0, 0 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci/* offset of a single field of fd2_query_sample: */ 52bf215546Sopenharmony_ci#define query_sample(aq, field) query_sample_idx(aq, 0, field) 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci/* 55bf215546Sopenharmony_ci * Performance Counter (batch) queries: 56bf215546Sopenharmony_ci * 57bf215546Sopenharmony_ci * Only one of these is active at a time, per design of the gallium 58bf215546Sopenharmony_ci * batch_query API design. On perfcntr query tracks N query_types, 59bf215546Sopenharmony_ci * each of which has a 'fd_batch_query_entry' that maps it back to 60bf215546Sopenharmony_ci * the associated group and counter. 61bf215546Sopenharmony_ci */ 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_cistruct fd_batch_query_entry { 64bf215546Sopenharmony_ci uint8_t gid; /* group-id */ 65bf215546Sopenharmony_ci uint8_t cid; /* countable-id within the group */ 66bf215546Sopenharmony_ci}; 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_cistruct fd_batch_query_data { 69bf215546Sopenharmony_ci struct fd_screen *screen; 70bf215546Sopenharmony_ci unsigned num_query_entries; 71bf215546Sopenharmony_ci struct fd_batch_query_entry query_entries[]; 72bf215546Sopenharmony_ci}; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cistatic void 75bf215546Sopenharmony_ciperfcntr_resume(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt 76bf215546Sopenharmony_ci{ 77bf215546Sopenharmony_ci struct fd_batch_query_data *data = aq->query_data; 78bf215546Sopenharmony_ci struct fd_screen *screen = data->screen; 79bf215546Sopenharmony_ci struct fd_ringbuffer *ring = batch->draw; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci unsigned counters_per_group[screen->num_perfcntr_groups]; 82bf215546Sopenharmony_ci memset(counters_per_group, 0, sizeof(counters_per_group)); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci fd_wfi(batch, ring); 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci /* configure performance counters for the requested queries: */ 87bf215546Sopenharmony_ci for (unsigned i = 0; i < data->num_query_entries; i++) { 88bf215546Sopenharmony_ci struct fd_batch_query_entry *entry = &data->query_entries[i]; 89bf215546Sopenharmony_ci const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; 90bf215546Sopenharmony_ci unsigned counter_idx = counters_per_group[entry->gid]++; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci assert(counter_idx < g->num_counters); 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci OUT_PKT0(ring, g->counters[counter_idx].select_reg, 1); 95bf215546Sopenharmony_ci OUT_RING(ring, g->countables[entry->cid].selector); 96bf215546Sopenharmony_ci } 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci memset(counters_per_group, 0, sizeof(counters_per_group)); 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci /* and snapshot the start values */ 101bf215546Sopenharmony_ci for (unsigned i = 0; i < data->num_query_entries; i++) { 102bf215546Sopenharmony_ci struct fd_batch_query_entry *entry = &data->query_entries[i]; 103bf215546Sopenharmony_ci const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; 104bf215546Sopenharmony_ci unsigned counter_idx = counters_per_group[entry->gid]++; 105bf215546Sopenharmony_ci const struct fd_perfcntr_counter *counter = &g->counters[counter_idx]; 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci OUT_PKT3(ring, CP_REG_TO_MEM, 2); 108bf215546Sopenharmony_ci OUT_RING(ring, counter->counter_reg_lo | CP_REG_TO_MEM_0_ACCUMULATE); 109bf215546Sopenharmony_ci OUT_RELOC(ring, query_sample_idx(aq, i, start)); 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci} 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_cistatic void 114bf215546Sopenharmony_ciperfcntr_pause(struct fd_acc_query *aq, struct fd_batch *batch) assert_dt 115bf215546Sopenharmony_ci{ 116bf215546Sopenharmony_ci struct fd_batch_query_data *data = aq->query_data; 117bf215546Sopenharmony_ci struct fd_screen *screen = data->screen; 118bf215546Sopenharmony_ci struct fd_ringbuffer *ring = batch->draw; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci unsigned counters_per_group[screen->num_perfcntr_groups]; 121bf215546Sopenharmony_ci memset(counters_per_group, 0, sizeof(counters_per_group)); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci fd_wfi(batch, ring); 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci /* TODO do we need to bother to turn anything off? */ 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci /* snapshot the end values: */ 128bf215546Sopenharmony_ci for (unsigned i = 0; i < data->num_query_entries; i++) { 129bf215546Sopenharmony_ci struct fd_batch_query_entry *entry = &data->query_entries[i]; 130bf215546Sopenharmony_ci const struct fd_perfcntr_group *g = &screen->perfcntr_groups[entry->gid]; 131bf215546Sopenharmony_ci unsigned counter_idx = counters_per_group[entry->gid]++; 132bf215546Sopenharmony_ci const struct fd_perfcntr_counter *counter = &g->counters[counter_idx]; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci OUT_PKT3(ring, CP_REG_TO_MEM, 2); 135bf215546Sopenharmony_ci OUT_RING(ring, counter->counter_reg_lo | CP_REG_TO_MEM_0_ACCUMULATE); 136bf215546Sopenharmony_ci OUT_RELOC(ring, query_sample_idx(aq, i, stop)); 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci} 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_cistatic void 141bf215546Sopenharmony_ciperfcntr_accumulate_result(struct fd_acc_query *aq, void *buf, 142bf215546Sopenharmony_ci union pipe_query_result *result) 143bf215546Sopenharmony_ci{ 144bf215546Sopenharmony_ci struct fd_batch_query_data *data = aq->query_data; 145bf215546Sopenharmony_ci struct fd2_query_sample *sp = buf; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci for (unsigned i = 0; i < data->num_query_entries; i++) 148bf215546Sopenharmony_ci result->batch[i].u64 = sp[i].stop - sp[i].start; 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_cistatic const struct fd_acc_sample_provider perfcntr = { 152bf215546Sopenharmony_ci .query_type = FD_QUERY_FIRST_PERFCNTR, 153bf215546Sopenharmony_ci .always = true, 154bf215546Sopenharmony_ci .resume = perfcntr_resume, 155bf215546Sopenharmony_ci .pause = perfcntr_pause, 156bf215546Sopenharmony_ci .result = perfcntr_accumulate_result, 157bf215546Sopenharmony_ci}; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_cistatic struct pipe_query * 160bf215546Sopenharmony_cifd2_create_batch_query(struct pipe_context *pctx, unsigned num_queries, 161bf215546Sopenharmony_ci unsigned *query_types) 162bf215546Sopenharmony_ci{ 163bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 164bf215546Sopenharmony_ci struct fd_screen *screen = ctx->screen; 165bf215546Sopenharmony_ci struct fd_query *q; 166bf215546Sopenharmony_ci struct fd_acc_query *aq; 167bf215546Sopenharmony_ci struct fd_batch_query_data *data; 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci data = CALLOC_VARIANT_LENGTH_STRUCT( 170bf215546Sopenharmony_ci fd_batch_query_data, num_queries * sizeof(data->query_entries[0])); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci data->screen = screen; 173bf215546Sopenharmony_ci data->num_query_entries = num_queries; 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci /* validate the requested query_types and ensure we don't try 176bf215546Sopenharmony_ci * to request more query_types of a given group than we have 177bf215546Sopenharmony_ci * counters: 178bf215546Sopenharmony_ci */ 179bf215546Sopenharmony_ci unsigned counters_per_group[screen->num_perfcntr_groups]; 180bf215546Sopenharmony_ci memset(counters_per_group, 0, sizeof(counters_per_group)); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci for (unsigned i = 0; i < num_queries; i++) { 183bf215546Sopenharmony_ci unsigned idx = query_types[i] - FD_QUERY_FIRST_PERFCNTR; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci /* verify valid query_type, ie. is it actually a perfcntr? */ 186bf215546Sopenharmony_ci if ((query_types[i] < FD_QUERY_FIRST_PERFCNTR) || 187bf215546Sopenharmony_ci (idx >= screen->num_perfcntr_queries)) { 188bf215546Sopenharmony_ci mesa_loge("invalid batch query query_type: %u", query_types[i]); 189bf215546Sopenharmony_ci goto error; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci struct fd_batch_query_entry *entry = &data->query_entries[i]; 193bf215546Sopenharmony_ci struct pipe_driver_query_info *pq = &screen->perfcntr_queries[idx]; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci entry->gid = pq->group_id; 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci /* the perfcntr_queries[] table flattens all the countables 198bf215546Sopenharmony_ci * for each group in series, ie: 199bf215546Sopenharmony_ci * 200bf215546Sopenharmony_ci * (G0,C0), .., (G0,Cn), (G1,C0), .., (G1,Cm), ... 201bf215546Sopenharmony_ci * 202bf215546Sopenharmony_ci * So to find the countable index just step back through the 203bf215546Sopenharmony_ci * table to find the first entry with the same group-id. 204bf215546Sopenharmony_ci */ 205bf215546Sopenharmony_ci while (pq > screen->perfcntr_queries) { 206bf215546Sopenharmony_ci pq--; 207bf215546Sopenharmony_ci if (pq->group_id == entry->gid) 208bf215546Sopenharmony_ci entry->cid++; 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci if (counters_per_group[entry->gid] >= 212bf215546Sopenharmony_ci screen->perfcntr_groups[entry->gid].num_counters) { 213bf215546Sopenharmony_ci mesa_loge("too many counters for group %u", entry->gid); 214bf215546Sopenharmony_ci goto error; 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci counters_per_group[entry->gid]++; 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci q = fd_acc_create_query2(ctx, 0, 0, &perfcntr); 221bf215546Sopenharmony_ci aq = fd_acc_query(q); 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* sample buffer size is based on # of queries: */ 224bf215546Sopenharmony_ci aq->size = num_queries * sizeof(struct fd2_query_sample); 225bf215546Sopenharmony_ci aq->query_data = data; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci return (struct pipe_query *)q; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_cierror: 230bf215546Sopenharmony_ci free(data); 231bf215546Sopenharmony_ci return NULL; 232bf215546Sopenharmony_ci} 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_civoid 235bf215546Sopenharmony_cifd2_query_context_init(struct pipe_context *pctx) disable_thread_safety_analysis 236bf215546Sopenharmony_ci{ 237bf215546Sopenharmony_ci struct fd_context *ctx = fd_context(pctx); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci ctx->create_query = fd_acc_create_query; 240bf215546Sopenharmony_ci ctx->query_update_batch = fd_acc_query_update_batch; 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci pctx->create_batch_query = fd2_create_batch_query; 243bf215546Sopenharmony_ci} 244