/* * Copyright (c) 2012 Rob Clark * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * Helper lib to track gpu buffers contents/address, and map between gpu and * host address while decoding cmdstream/crashdumps */ #include #include #include "buffers.h" struct buffer { void *hostptr; unsigned int len; uint64_t gpuaddr; /* for 'once' mode, for buffers containing cmdstream keep track per offset * into buffer of which modes it has already been dumped; */ struct { unsigned offset; unsigned dumped_mask; } offsets[64]; unsigned noffsets; }; static struct buffer buffers[512]; static int nbuffers; static int buffer_contains_gpuaddr(struct buffer *buf, uint64_t gpuaddr, uint32_t len) { return (buf->gpuaddr <= gpuaddr) && (gpuaddr < (buf->gpuaddr + buf->len)); } static int buffer_contains_hostptr(struct buffer *buf, void *hostptr) { return (buf->hostptr <= hostptr) && (hostptr < (buf->hostptr + buf->len)); } uint64_t gpuaddr(void *hostptr) { int i; for (i = 0; i < nbuffers; i++) if (buffer_contains_hostptr(&buffers[i], hostptr)) return buffers[i].gpuaddr + (hostptr - buffers[i].hostptr); return 0; } uint64_t gpubaseaddr(uint64_t gpuaddr) { int i; if (!gpuaddr) return 0; for (i = 0; i < nbuffers; i++) if (buffer_contains_gpuaddr(&buffers[i], gpuaddr, 0)) return buffers[i].gpuaddr; return 0; } void * hostptr(uint64_t gpuaddr) { int i; if (!gpuaddr) return 0; for (i = 0; i < nbuffers; i++) if (buffer_contains_gpuaddr(&buffers[i], gpuaddr, 0)) return buffers[i].hostptr + (gpuaddr - buffers[i].gpuaddr); return 0; } unsigned hostlen(uint64_t gpuaddr) { int i; if (!gpuaddr) return 0; for (i = 0; i < nbuffers; i++) if (buffer_contains_gpuaddr(&buffers[i], gpuaddr, 0)) return buffers[i].len + buffers[i].gpuaddr - gpuaddr; return 0; } bool has_dumped(uint64_t gpuaddr, unsigned enable_mask) { if (!gpuaddr) return false; for (int i = 0; i < nbuffers; i++) { if (buffer_contains_gpuaddr(&buffers[i], gpuaddr, 0)) { struct buffer *b = &buffers[i]; assert(gpuaddr >= b->gpuaddr); unsigned offset = gpuaddr - b->gpuaddr; unsigned n = 0; while (n < b->noffsets) { if (offset == b->offsets[n].offset) break; n++; } /* if needed, allocate a new offset entry: */ if (n == b->noffsets) { b->noffsets++; assert(b->noffsets < ARRAY_SIZE(b->offsets)); b->offsets[n].dumped_mask = 0; b->offsets[n].offset = offset; } if ((b->offsets[n].dumped_mask & enable_mask) == enable_mask) return true; b->offsets[n].dumped_mask |= enable_mask; return false; } } return false; } void reset_buffers(void) { for (int i = 0; i < nbuffers; i++) { free(buffers[i].hostptr); buffers[i].hostptr = NULL; buffers[i].len = 0; buffers[i].noffsets = 0; } nbuffers = 0; } /** * Record buffer contents, takes ownership of hostptr (freed in * reset_buffers()) */ void add_buffer(uint64_t gpuaddr, unsigned int len, void *hostptr) { int i; for (i = 0; i < nbuffers; i++) { if (buffers[i].gpuaddr == gpuaddr) break; } if (i == nbuffers) { /* some traces, like test-perf, with some blob versions, * seem to generate an unreasonable # of gpu buffers (a * leak?), so just ignore them. */ if (nbuffers >= ARRAY_SIZE(buffers)) { free(hostptr); return; } nbuffers++; } buffers[i].hostptr = hostptr; buffers[i].len = len; buffers[i].gpuaddr = gpuaddr; }