[Mesa-dev] [PATCH 09/14] intel: tools: split memory management out of aubinator

Rafael Antognolli rafael.antognolli at intel.com
Sat Aug 4 00:43:38 UTC 2018


This also looks like a harmless and useful refactory.

Reviewed-by: Rafael Antognolli <rafael.antognolli at intel.com>

On Thu, Aug 02, 2018 at 10:39:21AM +0100, Lionel Landwerlin wrote:
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
> ---
>  src/intel/tools/aub_mem.c   | 391 ++++++++++++++++++++++++++++++++++++
>  src/intel/tools/aub_mem.h   |  72 +++++++
>  src/intel/tools/aubinator.c | 379 +++-------------------------------
>  src/intel/tools/meson.build |   2 +-
>  4 files changed, 491 insertions(+), 353 deletions(-)
>  create mode 100644 src/intel/tools/aub_mem.c
>  create mode 100644 src/intel/tools/aub_mem.h
> 
> diff --git a/src/intel/tools/aub_mem.c b/src/intel/tools/aub_mem.c
> new file mode 100644
> index 00000000000..788a2461130
> --- /dev/null
> +++ b/src/intel/tools/aub_mem.c
> @@ -0,0 +1,391 @@
> +/*
> + * Copyright © 2016-2018 Intel Corporation
> + *
> + * 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.
> + */
> +
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +
> +#include "aub_mem.h"
> +
> +#ifndef HAVE_MEMFD_CREATE
> +#include <sys/syscall.h>
> +
> +static inline int
> +memfd_create(const char *name, unsigned int flags)
> +{
> +   return syscall(SYS_memfd_create, name, flags);
> +}
> +#endif
> +
> +struct bo_map {
> +   struct list_head link;
> +   struct gen_batch_decode_bo bo;
> +   bool unmap_after_use;
> +};
> +
> +struct ggtt_entry {
> +   struct rb_node node;
> +   uint64_t virt_addr;
> +   uint64_t phys_addr;
> +};
> +
> +struct phys_mem {
> +   struct rb_node node;
> +   uint64_t fd_offset;
> +   uint64_t phys_addr;
> +   uint8_t *data;
> +};
> +
> +static void
> +add_gtt_bo_map(struct aub_mem *mem, struct gen_batch_decode_bo bo, bool unmap_after_use)
> +{
> +   struct bo_map *m = calloc(1, sizeof(*m));
> +
> +   m->bo = bo;
> +   m->unmap_after_use = unmap_after_use;
> +   list_add(&m->link, &mem->maps);
> +}
> +
> +void
> +aub_mem_clear_bo_maps(struct aub_mem *mem)
> +{
> +   list_for_each_entry_safe(struct bo_map, i, &mem->maps, link) {
> +      if (i->unmap_after_use)
> +         munmap((void *)i->bo.map, i->bo.size);
> +      list_del(&i->link);
> +      free(i);
> +   }
> +}
> +
> +static inline struct ggtt_entry *
> +ggtt_entry_next(struct ggtt_entry *entry)
> +{
> +   if (!entry)
> +      return NULL;
> +   struct rb_node *node = rb_node_next(&entry->node);
> +   if (!node)
> +      return NULL;
> +   return rb_node_data(struct ggtt_entry, node, node);
> +}
> +
> +static inline int
> +cmp_uint64(uint64_t a, uint64_t b)
> +{
> +   if (a < b)
> +      return -1;
> +   if (a > b)
> +      return 1;
> +   return 0;
> +}
> +
> +static inline int
> +cmp_ggtt_entry(const struct rb_node *node, const void *addr)
> +{
> +   struct ggtt_entry *entry = rb_node_data(struct ggtt_entry, node, node);
> +   return cmp_uint64(entry->virt_addr, *(const uint64_t *)addr);
> +}
> +
> +static struct ggtt_entry *
> +ensure_ggtt_entry(struct aub_mem *mem, uint64_t virt_addr)
> +{
> +   struct rb_node *node = rb_tree_search_sloppy(&mem->ggtt, &virt_addr,
> +                                                cmp_ggtt_entry);
> +   int cmp = 0;
> +   if (!node || (cmp = cmp_ggtt_entry(node, &virt_addr))) {
> +      struct ggtt_entry *new_entry = calloc(1, sizeof(*new_entry));
> +      new_entry->virt_addr = virt_addr;
> +      rb_tree_insert_at(&mem->ggtt, node, &new_entry->node, cmp > 0);
> +      node = &new_entry->node;
> +   }
> +
> +   return rb_node_data(struct ggtt_entry, node, node);
> +}
> +
> +static struct ggtt_entry *
> +search_ggtt_entry(struct aub_mem *mem, uint64_t virt_addr)
> +{
> +   virt_addr &= ~0xfff;
> +
> +   struct rb_node *node = rb_tree_search(&mem->ggtt, &virt_addr, cmp_ggtt_entry);
> +
> +   if (!node)
> +      return NULL;
> +
> +   return rb_node_data(struct ggtt_entry, node, node);
> +}
> +
> +static inline int
> +cmp_phys_mem(const struct rb_node *node, const void *addr)
> +{
> +   struct phys_mem *mem = rb_node_data(struct phys_mem, node, node);
> +   return cmp_uint64(mem->phys_addr, *(uint64_t *)addr);
> +}
> +
> +static struct phys_mem *
> +ensure_phys_mem(struct aub_mem *mem, uint64_t phys_addr)
> +{
> +   struct rb_node *node = rb_tree_search_sloppy(&mem->mem, &phys_addr, cmp_phys_mem);
> +   int cmp = 0;
> +   if (!node || (cmp = cmp_phys_mem(node, &phys_addr))) {
> +      struct phys_mem *new_mem = calloc(1, sizeof(*new_mem));
> +      new_mem->phys_addr = phys_addr;
> +      new_mem->fd_offset = mem->mem_fd_len;
> +
> +      int ftruncate_res = ftruncate(mem->mem_fd, mem->mem_fd_len += 4096);
> +      assert(ftruncate_res == 0);
> +
> +      new_mem->data = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,
> +                           mem->mem_fd, new_mem->fd_offset);
> +      assert(new_mem->data != MAP_FAILED);
> +
> +      rb_tree_insert_at(&mem->mem, node, &new_mem->node, cmp > 0);
> +      node = &new_mem->node;
> +   }
> +
> +   return rb_node_data(struct phys_mem, node, node);
> +}
> +
> +static struct phys_mem *
> +search_phys_mem(struct aub_mem *mem, uint64_t phys_addr)
> +{
> +   phys_addr &= ~0xfff;
> +
> +   struct rb_node *node = rb_tree_search(&mem->mem, &phys_addr, cmp_phys_mem);
> +
> +   if (!node)
> +      return NULL;
> +
> +   return rb_node_data(struct phys_mem, node, node);
> +}
> +
> +void
> +aub_mem_local_write(void *_mem, uint64_t address,
> +                    const void *data, uint32_t size)
> +{
> +   struct aub_mem *mem = _mem;
> +   struct gen_batch_decode_bo bo = {
> +      .map = data,
> +      .addr = address,
> +      .size = size,
> +   };
> +   add_gtt_bo_map(mem, bo, false);
> +}
> +
> +void
> +aub_mem_ggtt_entry_write(void *_mem, uint64_t address,
> +                         const void *_data, uint32_t _size)
> +{
> +   struct aub_mem *mem = _mem;
> +   uint64_t virt_addr = (address / sizeof(uint64_t)) << 12;
> +   const uint64_t *data = _data;
> +   size_t size = _size / sizeof(*data);
> +   for (const uint64_t *entry = data;
> +        entry < data + size;
> +        entry++, virt_addr += 4096) {
> +      struct ggtt_entry *pt = ensure_ggtt_entry(mem, virt_addr);
> +      pt->phys_addr = *entry;
> +   }
> +}
> +
> +void
> +aub_mem_phys_write(void *_mem, uint64_t phys_address,
> +                   const void *data, uint32_t size)
> +{
> +   struct aub_mem *mem = _mem;
> +   uint32_t to_write = size;
> +   for (uint64_t page = phys_address & ~0xfff; page < phys_address + size; page += 4096) {
> +      struct phys_mem *pmem = ensure_phys_mem(mem, page);
> +      uint64_t offset = MAX2(page, phys_address) - page;
> +      uint32_t size_this_page = MIN2(to_write, 4096 - offset);
> +      to_write -= size_this_page;
> +      memcpy(pmem->data + offset, data, size_this_page);
> +      data = (const uint8_t *)data + size_this_page;
> +   }
> +}
> +
> +void
> +aub_mem_ggtt_write(void *_mem, uint64_t virt_address,
> +                   const void *data, uint32_t size)
> +{
> +   struct aub_mem *mem = _mem;
> +   uint32_t to_write = size;
> +   for (uint64_t page = virt_address & ~0xfff; page < virt_address + size; page += 4096) {
> +      struct ggtt_entry *entry = search_ggtt_entry(mem, page);
> +      assert(entry && entry->phys_addr & 0x1);
> +
> +      uint64_t offset = MAX2(page, virt_address) - page;
> +      uint32_t size_this_page = MIN2(to_write, 4096 - offset);
> +      to_write -= size_this_page;
> +
> +      uint64_t phys_page = entry->phys_addr & ~0xfff; /* Clear the validity bits. */
> +      aub_mem_phys_write(mem, phys_page + offset, data, size_this_page);
> +      data = (const uint8_t *)data + size_this_page;
> +   }
> +}
> +
> +struct gen_batch_decode_bo
> +aub_mem_get_ggtt_bo(void *_mem, uint64_t address)
> +{
> +   struct aub_mem *mem = _mem;
> +   struct gen_batch_decode_bo bo = {0};
> +
> +   list_for_each_entry(struct bo_map, i, &mem->maps, link)
> +      if (i->bo.addr <= address && i->bo.addr + i->bo.size > address)
> +         return i->bo;
> +
> +   address &= ~0xfff;
> +
> +   struct ggtt_entry *start =
> +      (struct ggtt_entry *)rb_tree_search_sloppy(&mem->ggtt, &address,
> +                                                 cmp_ggtt_entry);
> +   if (start && start->virt_addr < address)
> +      start = ggtt_entry_next(start);
> +   if (!start)
> +      return bo;
> +
> +   struct ggtt_entry *last = start;
> +   for (struct ggtt_entry *i = ggtt_entry_next(last);
> +        i && last->virt_addr + 4096 == i->virt_addr;
> +        last = i, i = ggtt_entry_next(last))
> +      ;
> +
> +   bo.addr = MIN2(address, start->virt_addr);
> +   bo.size = last->virt_addr - bo.addr + 4096;
> +   bo.map = mmap(NULL, bo.size, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +   assert(bo.map != MAP_FAILED);
> +
> +   for (struct ggtt_entry *i = start;
> +        i;
> +        i = i == last ? NULL : ggtt_entry_next(i)) {
> +      uint64_t phys_addr = i->phys_addr & ~0xfff;
> +      struct phys_mem *phys_mem = search_phys_mem(mem, phys_addr);
> +
> +      if (!phys_mem)
> +         continue;
> +
> +      uint32_t map_offset = i->virt_addr - address;
> +      void *res = mmap((uint8_t *)bo.map + map_offset, 4096, PROT_READ,
> +                       MAP_SHARED | MAP_FIXED, mem->mem_fd, phys_mem->fd_offset);
> +      assert(res != MAP_FAILED);
> +   }
> +
> +   add_gtt_bo_map(mem, bo, true);
> +
> +   return bo;
> +}
> +
> +static struct phys_mem *
> +ppgtt_walk(struct aub_mem *mem, uint64_t pml4, uint64_t address)
> +{
> +   uint64_t shift = 39;
> +   uint64_t addr = pml4;
> +   for (int level = 4; level > 0; level--) {
> +      struct phys_mem *table = search_phys_mem(mem, addr);
> +      if (!table)
> +         return NULL;
> +      int index = (address >> shift) & 0x1ff;
> +      uint64_t entry = ((uint64_t *)table->data)[index];
> +      if (!(entry & 1))
> +         return NULL;
> +      addr = entry & ~0xfff;
> +      shift -= 9;
> +   }
> +   return search_phys_mem(mem, addr);
> +}
> +
> +static bool
> +ppgtt_mapped(struct aub_mem *mem, uint64_t pml4, uint64_t address)
> +{
> +   return ppgtt_walk(mem, pml4, address) != NULL;
> +}
> +
> +struct gen_batch_decode_bo
> +aub_mem_get_ppgtt_bo(void *_mem, uint64_t address)
> +{
> +   struct aub_mem *mem = _mem;
> +   struct gen_batch_decode_bo bo = {0};
> +
> +   address &= ~0xfff;
> +
> +   if (!ppgtt_mapped(mem, mem->pml4, address))
> +      return bo;
> +
> +   /* Map everything until the first gap since we don't know how much the
> +    * decoder actually needs.
> +    */
> +   uint64_t end = address;
> +   while (ppgtt_mapped(mem, mem->pml4, end))
> +      end += 4096;
> +
> +   bo.addr = address;
> +   bo.size = end - address;
> +   bo.map = mmap(NULL, bo.size, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +   assert(bo.map != MAP_FAILED);
> +
> +   for (uint64_t page = address; page < end; page += 4096) {
> +      struct phys_mem *phys_mem = ppgtt_walk(mem, mem->pml4, page);
> +
> +      void *res = mmap((uint8_t *)bo.map + (page - bo.addr), 4096, PROT_READ,
> +                       MAP_SHARED | MAP_FIXED, mem->mem_fd, phys_mem->fd_offset);
> +      assert(res != MAP_FAILED);
> +   }
> +
> +   add_gtt_bo_map(mem, bo, true);
> +
> +   return bo;
> +}
> +
> +bool
> +aub_mem_init(struct aub_mem *mem)
> +{
> +   memset(mem, 0, sizeof(*mem));
> +
> +   list_inithead(&mem->maps);
> +
> +   mem->mem_fd = memfd_create("phys memory", 0);
> +
> +   return mem->mem_fd != -1;
> +}
> +
> +void
> +aub_mem_fini(struct aub_mem *mem)
> +{
> +   if (mem->mem_fd == -1)
> +      return;
> +
> +   aub_mem_clear_bo_maps(mem);
> +
> +
> +   rb_tree_foreach_safe(struct ggtt_entry, entry, &mem->ggtt, node) {
> +      rb_tree_remove(&mem->ggtt, &entry->node);
> +      free(entry);
> +   }
> +   rb_tree_foreach_safe(struct phys_mem, entry, &mem->mem, node) {
> +      rb_tree_remove(&mem->mem, &entry->node);
> +      free(entry);
> +   }
> +
> +   close(mem->mem_fd);
> +   mem->mem_fd = -1;
> +}
> diff --git a/src/intel/tools/aub_mem.h b/src/intel/tools/aub_mem.h
> new file mode 100644
> index 00000000000..98e64214b98
> --- /dev/null
> +++ b/src/intel/tools/aub_mem.h
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef INTEL_AUB_MEM
> +#define INTEL_AUB_MEM
> +
> +#include <stdint.h>
> +
> +#include "util/list.h"
> +#include "util/rb_tree.h"
> +
> +#include "dev/gen_device_info.h"
> +#include "common/gen_decoder.h"
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +struct aub_mem {
> +   uint64_t pml4;
> +
> +   int mem_fd;
> +   off_t mem_fd_len;
> +
> +   struct list_head maps;
> +   struct rb_tree ggtt;
> +   struct rb_tree mem;
> +};
> +
> +bool aub_mem_init(struct aub_mem *mem);
> +void aub_mem_fini(struct aub_mem *mem);
> +
> +void aub_mem_clear_bo_maps(struct aub_mem *mem);
> +
> +void aub_mem_phys_write(void *mem, uint64_t virt_address,
> +                        const void *data, uint32_t size);
> +void aub_mem_ggtt_write(void *mem, uint64_t virt_address,
> +                        const void *data, uint32_t size);
> +void aub_mem_ggtt_entry_write(void *mem, uint64_t virt_address,
> +                              const void *data, uint32_t size);
> +void aub_mem_local_write(void *mem, uint64_t virt_address,
> +                         const void *data, uint32_t size);
> +
> +struct gen_batch_decode_bo aub_mem_get_ggtt_bo(void *mem, uint64_t address);
> +struct gen_batch_decode_bo aub_mem_get_ppgtt_bo(void *mem, uint64_t address);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* INTEL_AUB_MEM */
> diff --git a/src/intel/tools/aubinator.c b/src/intel/tools/aubinator.c
> index b5622ff9eaa..ae80626b986 100644
> --- a/src/intel/tools/aubinator.c
> +++ b/src/intel/tools/aubinator.c
> @@ -37,29 +37,11 @@
>  #include <sys/wait.h>
>  #include <sys/mman.h>
>  
> -#include "util/list.h"
>  #include "util/macros.h"
> -#include "util/rb_tree.h"
>  
>  #include "common/gen_decoder.h"
> -#include "intel_aub.h"
>  #include "aub_read.h"
> -
> -#ifndef HAVE_MEMFD_CREATE
> -#include <sys/syscall.h>
> -
> -static inline int
> -memfd_create(const char *name, unsigned int flags)
> -{
> -   return syscall(SYS_memfd_create, name, flags);
> -}
> -#endif
> -
> -/* Below is the only command missing from intel_aub.h in libdrm
> - * So, reuse intel_aub.h from libdrm and #define the
> - * AUB_MI_BATCH_BUFFER_END as below
> - */
> -#define AUB_MI_BATCH_BUFFER_END (0x0500 << 16)
> +#include "aub_mem.h"
>  
>  #define CSI "\e["
>  #define BLUE_HEADER  CSI "0;44m"
> @@ -79,326 +61,12 @@ uint16_t pci_id = 0;
>  char *input_file = NULL, *xml_path = NULL;
>  struct gen_device_info devinfo;
>  struct gen_batch_decode_ctx batch_ctx;
> -
> -struct bo_map {
> -   struct list_head link;
> -   struct gen_batch_decode_bo bo;
> -   bool unmap_after_use;
> -};
> -
> -struct ggtt_entry {
> -   struct rb_node node;
> -   uint64_t virt_addr;
> -   uint64_t phys_addr;
> -};
> -
> -struct phys_mem {
> -   struct rb_node node;
> -   uint64_t fd_offset;
> -   uint64_t phys_addr;
> -   uint8_t *data;
> -};
> -
> -static struct list_head maps;
> -static struct rb_tree ggtt = {NULL};
> -static struct rb_tree mem = {NULL};
> -int mem_fd = -1;
> -off_t mem_fd_len = 0;
> +struct aub_mem mem;
>  
>  FILE *outfile;
>  
>  struct brw_instruction;
>  
> -static void
> -add_gtt_bo_map(struct gen_batch_decode_bo bo, bool unmap_after_use)
> -{
> -   struct bo_map *m = calloc(1, sizeof(*m));
> -
> -   m->bo = bo;
> -   m->unmap_after_use = unmap_after_use;
> -   list_add(&m->link, &maps);
> -}
> -
> -static void
> -clear_bo_maps(void)
> -{
> -   list_for_each_entry_safe(struct bo_map, i, &maps, link) {
> -      if (i->unmap_after_use)
> -         munmap((void *)i->bo.map, i->bo.size);
> -      list_del(&i->link);
> -      free(i);
> -   }
> -}
> -
> -static inline struct ggtt_entry *
> -ggtt_entry_next(struct ggtt_entry *entry)
> -{
> -   if (!entry)
> -      return NULL;
> -   struct rb_node *node = rb_node_next(&entry->node);
> -   if (!node)
> -      return NULL;
> -   return rb_node_data(struct ggtt_entry, node, node);
> -}
> -
> -static inline int
> -cmp_uint64(uint64_t a, uint64_t b)
> -{
> -   if (a < b)
> -      return -1;
> -   if (a > b)
> -      return 1;
> -   return 0;
> -}
> -
> -static inline int
> -cmp_ggtt_entry(const struct rb_node *node, const void *addr)
> -{
> -   struct ggtt_entry *entry = rb_node_data(struct ggtt_entry, node, node);
> -   return cmp_uint64(entry->virt_addr, *(const uint64_t *)addr);
> -}
> -
> -static struct ggtt_entry *
> -ensure_ggtt_entry(struct rb_tree *tree, uint64_t virt_addr)
> -{
> -   struct rb_node *node = rb_tree_search_sloppy(&ggtt, &virt_addr,
> -                                                cmp_ggtt_entry);
> -   int cmp = 0;
> -   if (!node || (cmp = cmp_ggtt_entry(node, &virt_addr))) {
> -      struct ggtt_entry *new_entry = calloc(1, sizeof(*new_entry));
> -      new_entry->virt_addr = virt_addr;
> -      rb_tree_insert_at(&ggtt, node, &new_entry->node, cmp > 0);
> -      node = &new_entry->node;
> -   }
> -
> -   return rb_node_data(struct ggtt_entry, node, node);
> -}
> -
> -static struct ggtt_entry *
> -search_ggtt_entry(uint64_t virt_addr)
> -{
> -   virt_addr &= ~0xfff;
> -
> -   struct rb_node *node = rb_tree_search(&ggtt, &virt_addr, cmp_ggtt_entry);
> -
> -   if (!node)
> -      return NULL;
> -
> -   return rb_node_data(struct ggtt_entry, node, node);
> -}
> -
> -static inline int
> -cmp_phys_mem(const struct rb_node *node, const void *addr)
> -{
> -   struct phys_mem *mem = rb_node_data(struct phys_mem, node, node);
> -   return cmp_uint64(mem->phys_addr, *(uint64_t *)addr);
> -}
> -
> -static struct phys_mem *
> -ensure_phys_mem(uint64_t phys_addr)
> -{
> -   struct rb_node *node = rb_tree_search_sloppy(&mem, &phys_addr, cmp_phys_mem);
> -   int cmp = 0;
> -   if (!node || (cmp = cmp_phys_mem(node, &phys_addr))) {
> -      struct phys_mem *new_mem = calloc(1, sizeof(*new_mem));
> -      new_mem->phys_addr = phys_addr;
> -      new_mem->fd_offset = mem_fd_len;
> -
> -      int ftruncate_res = ftruncate(mem_fd, mem_fd_len += 4096);
> -      assert(ftruncate_res == 0);
> -
> -      new_mem->data = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,
> -                           mem_fd, new_mem->fd_offset);
> -      assert(new_mem->data != MAP_FAILED);
> -
> -      rb_tree_insert_at(&mem, node, &new_mem->node, cmp > 0);
> -      node = &new_mem->node;
> -   }
> -
> -   return rb_node_data(struct phys_mem, node, node);
> -}
> -
> -static struct phys_mem *
> -search_phys_mem(uint64_t phys_addr)
> -{
> -   phys_addr &= ~0xfff;
> -
> -   struct rb_node *node = rb_tree_search(&mem, &phys_addr, cmp_phys_mem);
> -
> -   if (!node)
> -      return NULL;
> -
> -   return rb_node_data(struct phys_mem, node, node);
> -}
> -
> -static void
> -handle_local_write(void *user_data, uint64_t address, const void *data, uint32_t size)
> -{
> -   struct gen_batch_decode_bo bo = {
> -      .map = data,
> -      .addr = address,
> -      .size = size,
> -   };
> -   add_gtt_bo_map(bo, false);
> -}
> -
> -static void
> -handle_ggtt_entry_write(void *user_data, uint64_t address, const void *_data, uint32_t _size)
> -{
> -   uint64_t virt_addr = (address / sizeof(uint64_t)) << 12;
> -   const uint64_t *data = _data;
> -   size_t size = _size / sizeof(*data);
> -   for (const uint64_t *entry = data;
> -        entry < data + size;
> -        entry++, virt_addr += 4096) {
> -      struct ggtt_entry *pt = ensure_ggtt_entry(&ggtt, virt_addr);
> -      pt->phys_addr = *entry;
> -   }
> -}
> -
> -static void
> -handle_physical_write(void *user_data, uint64_t phys_address, const void *data, uint32_t size)
> -{
> -   uint32_t to_write = size;
> -   for (uint64_t page = phys_address & ~0xfff; page < phys_address + size; page += 4096) {
> -      struct phys_mem *mem = ensure_phys_mem(page);
> -      uint64_t offset = MAX2(page, phys_address) - page;
> -      uint32_t size_this_page = MIN2(to_write, 4096 - offset);
> -      to_write -= size_this_page;
> -      memcpy(mem->data + offset, data, size_this_page);
> -      data = (const uint8_t *)data + size_this_page;
> -   }
> -}
> -
> -static void
> -handle_ggtt_write(void *user_data, uint64_t virt_address, const void *data, uint32_t size)
> -{
> -   uint32_t to_write = size;
> -   for (uint64_t page = virt_address & ~0xfff; page < virt_address + size; page += 4096) {
> -      struct ggtt_entry *entry = search_ggtt_entry(page);
> -      assert(entry && entry->phys_addr & 0x1);
> -
> -      uint64_t offset = MAX2(page, virt_address) - page;
> -      uint32_t size_this_page = MIN2(to_write, 4096 - offset);
> -      to_write -= size_this_page;
> -
> -      uint64_t phys_page = entry->phys_addr & ~0xfff; /* Clear the validity bits. */
> -      handle_physical_write(user_data, phys_page + offset, data, size_this_page);
> -      data = (const uint8_t *)data + size_this_page;
> -   }
> -}
> -
> -static struct gen_batch_decode_bo
> -get_ggtt_batch_bo(void *user_data, uint64_t address)
> -{
> -   struct gen_batch_decode_bo bo = {0};
> -
> -   list_for_each_entry(struct bo_map, i, &maps, link)
> -      if (i->bo.addr <= address && i->bo.addr + i->bo.size > address)
> -         return i->bo;
> -
> -   address &= ~0xfff;
> -
> -   struct ggtt_entry *start =
> -      (struct ggtt_entry *)rb_tree_search_sloppy(&ggtt, &address,
> -                                                 cmp_ggtt_entry);
> -   if (start && start->virt_addr < address)
> -      start = ggtt_entry_next(start);
> -   if (!start)
> -      return bo;
> -
> -   struct ggtt_entry *last = start;
> -   for (struct ggtt_entry *i = ggtt_entry_next(last);
> -        i && last->virt_addr + 4096 == i->virt_addr;
> -        last = i, i = ggtt_entry_next(last))
> -      ;
> -
> -   bo.addr = MIN2(address, start->virt_addr);
> -   bo.size = last->virt_addr - bo.addr + 4096;
> -   bo.map = mmap(NULL, bo.size, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> -   assert(bo.map != MAP_FAILED);
> -
> -   for (struct ggtt_entry *i = start;
> -        i;
> -        i = i == last ? NULL : ggtt_entry_next(i)) {
> -      uint64_t phys_addr = i->phys_addr & ~0xfff;
> -      struct phys_mem *phys_mem = search_phys_mem(phys_addr);
> -
> -      if (!phys_mem)
> -         continue;
> -
> -      uint32_t map_offset = i->virt_addr - address;
> -      void *res = mmap((uint8_t *)bo.map + map_offset, 4096, PROT_READ,
> -                       MAP_SHARED | MAP_FIXED, mem_fd, phys_mem->fd_offset);
> -      assert(res != MAP_FAILED);
> -   }
> -
> -   add_gtt_bo_map(bo, true);
> -
> -   return bo;
> -}
> -
> -static struct phys_mem *
> -ppgtt_walk(uint64_t pml4, uint64_t address)
> -{
> -   uint64_t shift = 39;
> -   uint64_t addr = pml4;
> -   for (int level = 4; level > 0; level--) {
> -      struct phys_mem *table = search_phys_mem(addr);
> -      if (!table)
> -         return NULL;
> -      int index = (address >> shift) & 0x1ff;
> -      uint64_t entry = ((uint64_t *)table->data)[index];
> -      if (!(entry & 1))
> -         return NULL;
> -      addr = entry & ~0xfff;
> -      shift -= 9;
> -   }
> -   return search_phys_mem(addr);
> -}
> -
> -static bool
> -ppgtt_mapped(uint64_t pml4, uint64_t address)
> -{
> -   return ppgtt_walk(pml4, address) != NULL;
> -}
> -
> -static struct gen_batch_decode_bo
> -get_ppgtt_batch_bo(void *user_data, uint64_t address)
> -{
> -   struct gen_batch_decode_bo bo = {0};
> -   uint64_t pml4 = *(uint64_t *)user_data;
> -
> -   address &= ~0xfff;
> -
> -   if (!ppgtt_mapped(pml4, address))
> -      return bo;
> -
> -   /* Map everything until the first gap since we don't know how much the
> -    * decoder actually needs.
> -    */
> -   uint64_t end = address;
> -   while (ppgtt_mapped(pml4, end))
> -      end += 4096;
> -
> -   bo.addr = address;
> -   bo.size = end - address;
> -   bo.map = mmap(NULL, bo.size, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> -   assert(bo.map != MAP_FAILED);
> -
> -   for (uint64_t page = address; page < end; page += 4096) {
> -      struct phys_mem *phys_mem = ppgtt_walk(pml4, page);
> -
> -      void *res = mmap((uint8_t *)bo.map + (page - bo.addr), 4096, PROT_READ,
> -                       MAP_SHARED | MAP_FIXED, mem_fd, phys_mem->fd_offset);
> -      assert(res != MAP_FAILED);
> -   }
> -
> -   add_gtt_bo_map(bo, true);
> -
> -   return bo;
> -}
> -
>  static void
>  aubinator_init(void *user_data, int aub_pci_id, const char *app_name)
>  {
> @@ -448,7 +116,7 @@ handle_execlist_write(void *user_data, enum gen_engine engine, uint64_t context_
>  {
>     const uint32_t pphwsp_size = 4096;
>     uint32_t pphwsp_addr = context_descriptor & 0xfffff000;
> -   struct gen_batch_decode_bo pphwsp_bo = get_ggtt_batch_bo(NULL, pphwsp_addr);
> +   struct gen_batch_decode_bo pphwsp_bo = aub_mem_get_ggtt_bo(&mem, pphwsp_addr);
>     uint32_t *context = (uint32_t *)((uint8_t *)pphwsp_bo.map +
>                                      (pphwsp_addr - pphwsp_bo.addr) +
>                                      pphwsp_size);
> @@ -456,35 +124,37 @@ handle_execlist_write(void *user_data, enum gen_engine engine, uint64_t context_
>     uint32_t ring_buffer_head = context[5];
>     uint32_t ring_buffer_tail = context[7];
>     uint32_t ring_buffer_start = context[9];
> -   uint64_t pml4 = (uint64_t)context[49] << 32 | context[51];
>  
> -   struct gen_batch_decode_bo ring_bo = get_ggtt_batch_bo(NULL,
> -                                                          ring_buffer_start);
> +   mem.pml4 = (uint64_t)context[49] << 32 | context[51];
> +   batch_ctx.user_data = &mem;
> +
> +   struct gen_batch_decode_bo ring_bo = aub_mem_get_ggtt_bo(&mem,
> +                                                            ring_buffer_start);
>     assert(ring_bo.size > 0);
>     void *commands = (uint8_t *)ring_bo.map + (ring_buffer_start - ring_bo.addr);
>  
>     if (context_descriptor & 0x100 /* ppgtt */) {
> -      batch_ctx.get_bo = get_ppgtt_batch_bo;
> -      batch_ctx.user_data = &pml4;
> +      batch_ctx.get_bo = aub_mem_get_ppgtt_bo;
>     } else {
> -      batch_ctx.get_bo = get_ggtt_batch_bo;
> +      batch_ctx.get_bo = aub_mem_get_ggtt_bo;
>     }
>  
>     (void)engine; /* TODO */
>     gen_print_batch(&batch_ctx, commands, ring_buffer_tail - ring_buffer_head,
>                     0);
> -   clear_bo_maps();
> +   aub_mem_clear_bo_maps(&mem);
>  }
>  
>  static void
>  handle_ring_write(void *user_data, enum gen_engine engine,
>                    const void *data, uint32_t data_len)
>  {
> -   batch_ctx.get_bo = get_ggtt_batch_bo;
> +   batch_ctx.user_data = &mem;
> +   batch_ctx.get_bo = aub_mem_get_ggtt_bo;
>  
>     gen_print_batch(&batch_ctx, data, data_len, 0);
>  
> -   clear_bo_maps();
> +   aub_mem_clear_bo_maps(&mem);
>  }
>  
>  struct aub_file {
> @@ -649,19 +319,22 @@ int main(int argc, char *argv[])
>     if (isatty(1) && pager)
>        setup_pager();
>  
> -   mem_fd = memfd_create("phys memory", 0);
> -
> -   list_inithead(&maps);
> +   if (!aub_mem_init(&mem)) {
> +      fprintf(stderr, "Unable to create GTT\n");
> +      exit(EXIT_FAILURE);
> +   }
>  
>     file = aub_file_open(input_file);
>  
>     struct aub_read aub_read = {
> -      .user_data = NULL,
> +      .user_data = &mem,
>        .info = aubinator_init,
> -      .local_write = handle_local_write,
> -      .phys_write = handle_physical_write,
> -      .ggtt_write = handle_ggtt_write,
> -      .ggtt_entry_write = handle_ggtt_entry_write,
> +
> +      .local_write = aub_mem_local_write,
> +      .phys_write = aub_mem_phys_write,
> +      .ggtt_write = aub_mem_ggtt_write,
> +      .ggtt_entry_write = aub_mem_ggtt_entry_write,
> +
>        .execlist_write = handle_execlist_write,
>        .ring_write = handle_ring_write,
>     };
> @@ -672,6 +345,8 @@ int main(int argc, char *argv[])
>        file->cursor += consumed;
>     }
>  
> +   aub_mem_fini(&mem);
> +
>     fflush(stdout);
>     /* close the stdout which is opened to write the output */
>     close(1);
> diff --git a/src/intel/tools/meson.build b/src/intel/tools/meson.build
> index 6be9fcf6413..8f9e2bd8e3e 100644
> --- a/src/intel/tools/meson.build
> +++ b/src/intel/tools/meson.build
> @@ -22,7 +22,7 @@ build_intel_tools = with_tools.contains('intel')
>  
>  aubinator = executable(
>    'aubinator',
> -  files('aubinator.c', 'intel_aub.h', 'aub_read.h', 'aub_read.c'),
> +  files('aubinator.c', 'intel_aub.h', 'aub_read.h', 'aub_read.c', 'aub_mem.h', 'aub_mem.c'),
>    dependencies : [dep_expat, dep_zlib, dep_dl, dep_thread, dep_m],
>    include_directories : [inc_common, inc_intel],
>    link_with : [libintel_common, libintel_compiler, libintel_dev, libmesa_util],
> -- 
> 2.18.0
> 
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list