Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv50/nv50_query_hw_sm.c
4574 views
/*1* Copyright 2015 Samuel Pitoiset2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#define NV50_PUSH_EXPLICIT_SPACE_CHECKING2324#include "nv50/nv50_context.h"25#include "nv50/nv50_query_hw_sm.h"2627#include "nv_object.xml.h"28#include "nv50/nv50_compute.xml.h"2930/* === PERFORMANCE MONITORING COUNTERS for NV84+ === */3132/* NOTE: intentionally using the same names as NV */33static const char *nv50_hw_sm_query_names[] =34{35"branch",36"divergent_branch",37"instructions",38"prof_trigger_00",39"prof_trigger_01",40"prof_trigger_02",41"prof_trigger_03",42"prof_trigger_04",43"prof_trigger_05",44"prof_trigger_06",45"prof_trigger_07",46"sm_cta_launched",47"warp_serialize",48};4950static const uint64_t nv50_read_hw_sm_counters_code[] =51{52/* and b32 $r0 $r0 0x0000ffff53* add b32 $c0 $r0 $r0 $r054* (lg $c0) ret55* mov $r0 $pm056* mov $r1 $pm157* mov $r2 $pm258* mov $r3 $pm359* mov $r4 $physid60* ld $r5 b32 s[0x14]61* ld $r6 b32 s[0x18]62* and b32 $r4 $r4 0x000f000063* shr u32 $r4 $r4 0x1064* mul $r4 u24 $r4 0x1465* add b32 $r5 $r5 $r466* st b32 g15[$r5] $r067* add b32 $r5 $r5 0x0468* st b32 g15[$r5] $r169* add b32 $r5 $r5 0x0470* st b32 g15[$r5] $r271* add b32 $r5 $r5 0x0472* st b32 g15[$r5] $r373* add b32 $r5 $r5 0x0474* exit st b32 g15[$r5] $r6 */750x00000fffd03f0001ULL,760x040007c020000001ULL,770x0000028030000003ULL,780x6001078000000001ULL,790x6001478000000005ULL,800x6001878000000009ULL,810x6001c7800000000dULL,820x6000078000000011ULL,830x4400c78010000a15ULL,840x4400c78010000c19ULL,850x0000f003d0000811ULL,860xe410078030100811ULL,870x0000000340540811ULL,880x0401078020000a15ULL,890xa0c00780d00f0a01ULL,900x0000000320048a15ULL,910xa0c00780d00f0a05ULL,920x0000000320048a15ULL,930xa0c00780d00f0a09ULL,940x0000000320048a15ULL,950xa0c00780d00f0a0dULL,960x0000000320048a15ULL,970xa0c00781d00f0a19ULL,98};99100struct nv50_hw_sm_counter_cfg101{102uint32_t mode : 4; /* LOGOP, LOGOP_PULSE */103uint32_t unit : 8; /* UNK[0-5] */104uint32_t sig : 8; /* signal selection */105};106107struct nv50_hw_sm_query_cfg108{109struct nv50_hw_sm_counter_cfg ctr[4];110uint8_t num_counters;111};112113#define _Q(n, m, u, s) [NV50_HW_SM_QUERY_##n] = { { { NV50_COMPUTE_MP_PM_CONTROL_MODE_##m, NV50_COMPUTE_MP_PM_CONTROL_UNIT_##u, s, }, {}, {}, {} }, 1 }114115/* ==== Compute capability 1.1 (G84+) ==== */116static const struct nv50_hw_sm_query_cfg sm11_hw_sm_queries[] =117{118_Q(BRANCH, LOGOP, UNK4, 0x02),119_Q(DIVERGENT_BRANCH, LOGOP, UNK4, 0x09),120_Q(INSTRUCTIONS, LOGOP, UNK4, 0x04),121_Q(PROF_TRIGGER_0, LOGOP, UNK1, 0x26),122_Q(PROF_TRIGGER_1, LOGOP, UNK1, 0x27),123_Q(PROF_TRIGGER_2, LOGOP, UNK1, 0x28),124_Q(PROF_TRIGGER_3, LOGOP, UNK1, 0x29),125_Q(PROF_TRIGGER_4, LOGOP, UNK1, 0x2a),126_Q(PROF_TRIGGER_5, LOGOP, UNK1, 0x2b),127_Q(PROF_TRIGGER_6, LOGOP, UNK1, 0x2c),128_Q(PROF_TRIGGER_7, LOGOP, UNK1, 0x2d),129_Q(SM_CTA_LAUNCHED, LOGOP, UNK1, 0x33),130_Q(WARP_SERIALIZE, LOGOP, UNK0, 0x0b),131};132133static inline uint16_t nv50_hw_sm_get_func(uint8_t slot)134{135switch (slot) {136case 0: return 0xaaaa;137case 1: return 0xcccc;138case 2: return 0xf0f0;139case 3: return 0xff00;140}141return 0;142}143144static const struct nv50_hw_sm_query_cfg *145nv50_hw_sm_query_get_cfg(struct nv50_context *nv50, struct nv50_hw_query *hq)146{147struct nv50_query *q = &hq->base;148return &sm11_hw_sm_queries[q->type - NV50_HW_SM_QUERY(0)];149}150151static void152nv50_hw_sm_destroy_query(struct nv50_context *nv50, struct nv50_hw_query *hq)153{154struct nv50_query *q = &hq->base;155nv50_hw_query_allocate(nv50, q, 0);156nouveau_fence_ref(NULL, &hq->fence);157FREE(hq);158}159160static bool161nv50_hw_sm_begin_query(struct nv50_context *nv50, struct nv50_hw_query *hq)162{163struct nv50_screen *screen = nv50->screen;164struct nouveau_pushbuf *push = nv50->base.pushbuf;165struct nv50_hw_sm_query *hsq = nv50_hw_sm_query(hq);166const struct nv50_hw_sm_query_cfg *cfg;167uint16_t func;168int i, c;169170cfg = nv50_hw_sm_query_get_cfg(nv50, hq);171172/* check if we have enough free counter slots */173if (screen->pm.num_hw_sm_active + cfg->num_counters > 4) {174NOUVEAU_ERR("Not enough free MP counter slots !\n");175return false;176}177178assert(cfg->num_counters <= 4);179PUSH_SPACE(push, 4 * 4);180181/* set sequence field to 0 (used to check if result is available) */182for (i = 0; i < screen->MPsInTP; ++i) {183const unsigned b = (0x14 / 4) * i;184hq->data[b + 16] = 0;185}186hq->sequence++;187188for (i = 0; i < cfg->num_counters; i++) {189screen->pm.num_hw_sm_active++;190191/* find free counter slots */192for (c = 0; c < 4; ++c) {193if (!screen->pm.mp_counter[c]) {194hsq->ctr[i] = c;195screen->pm.mp_counter[c] = hsq;196break;197}198}199200/* select func to aggregate counters */201func = nv50_hw_sm_get_func(c);202203/* configure and reset the counter(s) */204BEGIN_NV04(push, NV50_CP(MP_PM_CONTROL(c)), 1);205PUSH_DATA (push, (cfg->ctr[i].sig << 24) | (func << 8)206| cfg->ctr[i].unit | cfg->ctr[i].mode);207BEGIN_NV04(push, NV50_CP(MP_PM_SET(c)), 1);208PUSH_DATA (push, 0);209}210return true;211}212213static void214nv50_hw_sm_end_query(struct nv50_context *nv50, struct nv50_hw_query *hq)215{216struct nv50_screen *screen = nv50->screen;217struct pipe_context *pipe = &nv50->base.pipe;218struct nouveau_pushbuf *push = nv50->base.pushbuf;219struct nv50_hw_sm_query *hsq = nv50_hw_sm_query(hq);220struct nv50_program *old = nv50->compprog;221struct pipe_grid_info info = {};222uint32_t mask;223uint32_t input[3];224const uint block[3] = { 32, 1, 1 };225const uint grid[3] = { screen->MPsInTP, screen->TPs, 1 };226int c, i;227228if (unlikely(!screen->pm.prog)) {229struct nv50_program *prog = CALLOC_STRUCT(nv50_program);230prog->type = PIPE_SHADER_COMPUTE;231prog->translated = true;232prog->max_gpr = 7;233prog->parm_size = 8;234prog->code = (uint32_t *)nv50_read_hw_sm_counters_code;235prog->code_size = sizeof(nv50_read_hw_sm_counters_code);236screen->pm.prog = prog;237}238239/* disable all counting */240PUSH_SPACE(push, 8);241for (c = 0; c < 4; c++) {242if (screen->pm.mp_counter[c]) {243BEGIN_NV04(push, NV50_CP(MP_PM_CONTROL(c)), 1);244PUSH_DATA (push, 0);245}246}247248/* release counters for this query */249for (c = 0; c < 4; c++) {250if (screen->pm.mp_counter[c] == hsq) {251screen->pm.num_hw_sm_active--;252screen->pm.mp_counter[c] = NULL;253}254}255256BCTX_REFN_bo(nv50->bufctx_cp, CP_QUERY, NOUVEAU_BO_GART | NOUVEAU_BO_WR,257hq->bo);258259PUSH_SPACE(push, 2);260BEGIN_NV04(push, SUBC_CP(NV50_GRAPH_SERIALIZE), 1);261PUSH_DATA (push, 0);262263pipe->bind_compute_state(pipe, screen->pm.prog);264input[0] = hq->bo->offset + hq->base_offset;265input[1] = hq->sequence;266267for (i = 0; i < 3; i++) {268info.block[i] = block[i];269info.grid[i] = grid[i];270}271info.pc = 0;272info.input = input;273pipe->launch_grid(pipe, &info);274pipe->bind_compute_state(pipe, old);275276nouveau_bufctx_reset(nv50->bufctx_cp, NV50_BIND_CP_QUERY);277278/* re-active other counters */279PUSH_SPACE(push, 8);280mask = 0;281for (c = 0; c < 4; c++) {282const struct nv50_hw_sm_query_cfg *cfg;283unsigned i;284285hsq = screen->pm.mp_counter[c];286if (!hsq)287continue;288289cfg = nv50_hw_sm_query_get_cfg(nv50, &hsq->base);290for (i = 0; i < cfg->num_counters; i++) {291uint16_t func;292293if (mask & (1 << hsq->ctr[i]))294break;295296mask |= 1 << hsq->ctr[i];297func = nv50_hw_sm_get_func(hsq->ctr[i]);298299BEGIN_NV04(push, NV50_CP(MP_PM_CONTROL(hsq->ctr[i])), 1);300PUSH_DATA (push, (cfg->ctr[i].sig << 24) | (func << 8)301| cfg->ctr[i].unit | cfg->ctr[i].mode);302}303}304}305306static inline bool307nv50_hw_sm_query_read_data(uint32_t count[32][4],308struct nv50_context *nv50, bool wait,309struct nv50_hw_query *hq,310const struct nv50_hw_sm_query_cfg *cfg,311unsigned mp_count)312{313struct nv50_hw_sm_query *hsq = nv50_hw_sm_query(hq);314unsigned p, c;315316for (p = 0; p < mp_count; ++p) {317const unsigned b = (0x14 / 4) * p;318319for (c = 0; c < cfg->num_counters; ++c) {320if (hq->data[b + 4] != hq->sequence) {321if (!wait)322return false;323if (nouveau_bo_wait(hq->bo, NOUVEAU_BO_RD, nv50->base.client))324return false;325}326count[p][c] = hq->data[b + hsq->ctr[c]];327}328}329return true;330}331332static bool333nv50_hw_sm_get_query_result(struct nv50_context *nv50, struct nv50_hw_query *hq,334bool wait, union pipe_query_result *result)335{336uint32_t count[32][4];337uint64_t value = 0;338unsigned mp_count = MIN2(nv50->screen->MPsInTP, 32);339unsigned p, c;340const struct nv50_hw_sm_query_cfg *cfg;341bool ret;342343cfg = nv50_hw_sm_query_get_cfg(nv50, hq);344345ret = nv50_hw_sm_query_read_data(count, nv50, wait, hq, cfg, mp_count);346if (!ret)347return false;348349for (c = 0; c < cfg->num_counters; ++c)350for (p = 0; p < mp_count; ++p)351value += count[p][c];352353/* We only count a single TP, and simply multiply by the total number of354* TPs to compute result over all TPs. This is inaccurate, but enough! */355value *= nv50->screen->TPs;356357*(uint64_t *)result = value;358return true;359}360361static const struct nv50_hw_query_funcs hw_sm_query_funcs = {362.destroy_query = nv50_hw_sm_destroy_query,363.begin_query = nv50_hw_sm_begin_query,364.end_query = nv50_hw_sm_end_query,365.get_query_result = nv50_hw_sm_get_query_result,366};367368struct nv50_hw_query *369nv50_hw_sm_create_query(struct nv50_context *nv50, unsigned type)370{371struct nv50_hw_sm_query *hsq;372struct nv50_hw_query *hq;373unsigned space;374375if (type < NV50_HW_SM_QUERY(0) || type > NV50_HW_SM_QUERY_LAST)376return NULL;377378hsq = CALLOC_STRUCT(nv50_hw_sm_query);379if (!hsq)380return NULL;381382hq = &hsq->base;383hq->funcs = &hw_sm_query_funcs;384hq->base.type = type;385386/*387* for each MP:388* [00] = MP.C0389* [04] = MP.C1390* [08] = MP.C2391* [0c] = MP.C3392* [10] = MP.sequence393*/394space = (4 + 1) * nv50->screen->MPsInTP * sizeof(uint32_t);395396if (!nv50_hw_query_allocate(nv50, &hq->base, space)) {397FREE(hq);398return NULL;399}400401return hq;402}403404int405nv50_hw_sm_get_driver_query_info(struct nv50_screen *screen, unsigned id,406struct pipe_driver_query_info *info)407{408int count = 0;409410if (screen->compute)411if (screen->base.class_3d >= NV84_3D_CLASS)412count += NV50_HW_SM_QUERY_COUNT;413414if (!info)415return count;416417if (id < count) {418if (screen->compute) {419if (screen->base.class_3d >= NV84_3D_CLASS) {420info->name = nv50_hw_sm_query_names[id];421info->query_type = NV50_HW_SM_QUERY(id);422info->group_id = NV50_HW_SM_QUERY_GROUP;423return 1;424}425}426}427return 0;428}429430431