From: Dave Airlie <airl...@redhat.com>

Doing proper integration of TTM system memory allocations with
memcg is a difficult ask, primarily due to difficulties around
accounting for evictions properly.

However there are systems where userspace will be allocating
objects in system memory and they won't be prone to migrating
or evicting and we should start with at least accounting those.

This adds a memcg group to ttm bo and tt objects. If this object
allocates pages directly (not from a TTM pool, so cached non-dma
pages), then they will be accounted for using __GFP_ACCOUNT,
and added to the memcg GPU statistic.

Only operations which set the account_op flag in the ttm operation
context will have this accounting happen. This patch disables the
flag around object evictions, but any operation that could populate
a TTM tt object in process context should set the account_op flag.

This doesn't account for uncached pages due to the page pool,
and it doesn't account for dma allocated pages. However for a lot
of use cases this should be a sufficient first step. Adding uncached
page support would mean hooking into memcg for the uncached pool
interactions, and I need to consider dma paths further.

Signed-off-by: Dave Airlie <airl...@redhat.com>
---
 drivers/gpu/drm/ttm/ttm_bo.c    |  4 ++++
 drivers/gpu/drm/ttm/ttm_bo_vm.c |  3 ++-
 drivers/gpu/drm/ttm/ttm_pool.c  | 19 ++++++++++++++++++-
 drivers/gpu/drm/ttm/ttm_tt.c    |  1 +
 include/drm/ttm/ttm_bo.h        |  8 ++++++++
 include/drm/ttm/ttm_tt.h        |  6 +++++-
 6 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 95b86003c50d..631984fd459b 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -744,8 +744,12 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object 
*bo,
                                continue;
                        }
 
+                       /* we don't want to account evictions at this point */
+                       bool old_ctx_account = ctx->account_op;
+                       ctx->account_op = false;
                        ret = ttm_bo_evict_alloc(bdev, man, place, bo, ctx,
                                                 ticket, res, limit_pool);
+                       ctx->account_op = old_ctx_account;
                        dmem_cgroup_pool_state_put(limit_pool);
                        if (ret == -EBUSY)
                                continue;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index a194db83421d..163039cf40a5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -220,7 +220,8 @@ vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
                struct ttm_operation_ctx ctx = {
                        .interruptible = true,
                        .no_wait_gpu = false,
-                       .force_alloc = true
+                       .force_alloc = true,
+                       .account_op = true,
                };
 
                ttm = bo->ttm;
diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
index 83b10706ba89..934bbf2c0ff6 100644
--- a/drivers/gpu/drm/ttm/ttm_pool.c
+++ b/drivers/gpu/drm/ttm/ttm_pool.c
@@ -672,6 +672,9 @@ static void ttm_pool_free_range(struct ttm_pool *pool, 
struct ttm_tt *tt,
                                tt->dma_address + i : NULL;
 
                        nr = ttm_pool_unmap_and_free(pool, p, dma_addr, 
caching);
+                       if (tt->page_flags & TTM_TT_FLAG_ACCOUNTED) {
+                               mod_memcg_state(tt->memcg, MEMCG_GPU, -nr);
+                       }
                }
        }
 }
@@ -742,9 +745,17 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct 
ttm_tt *tt,
                 * that behaviour.
                 */
                if (!p) {
+                       gfp_t account_flags = gfp_flags;
                        page_caching = ttm_cached;
                        allow_pools = false;
-                       p = ttm_pool_alloc_page(pool, gfp_flags, order);
+
+                       if (!pool->use_dma_alloc && tt->memcg && 
ctx->account_op) {
+                               account_flags |= __GFP_ACCOUNT;
+                               tt->page_flags |= TTM_TT_FLAG_ACCOUNTED;
+                       } else {
+                               tt->page_flags &= ~TTM_TT_FLAG_ACCOUNTED;
+                       }
+                       p = ttm_pool_alloc_page(pool, account_flags, order);
                }
                /* If that fails, lower the order if possible and retry. */
                if (!p) {
@@ -757,6 +768,12 @@ static int __ttm_pool_alloc(struct ttm_pool *pool, struct 
ttm_tt *tt,
                        r = -ENOMEM;
                        goto error_free_all;
                }
+
+               /* only deal with non-pool pages for memcg for now */
+               if (tt->page_flags & TTM_TT_FLAG_ACCOUNTED) {
+                       mod_memcg_state(tt->memcg, MEMCG_GPU, (1 << order));
+               }
+
                r = ttm_pool_page_allocated(pool, order, p, page_caching, alloc,
                                            restore);
                if (r)
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index df0aa6c4b8b8..cf9852560d9b 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -161,6 +161,7 @@ static void ttm_tt_init_fields(struct ttm_tt *ttm,
        ttm->caching = caching;
        ttm->restore = NULL;
        ttm->backup = NULL;
+       ttm->memcg = bo->memcg;
 }
 
 int ttm_tt_init(struct ttm_tt *ttm, struct ttm_buffer_object *bo,
diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h
index 903cd1030110..03e30a056427 100644
--- a/include/drm/ttm/ttm_bo.h
+++ b/include/drm/ttm/ttm_bo.h
@@ -135,6 +135,12 @@ struct ttm_buffer_object {
         * reservation lock.
         */
        struct sg_table *sg;
+
+       /**
+        * @memcg: memory cgroup to charge this to if it ends up using system 
memory.
+        * NULL means don't charge.
+        */
+       struct mem_cgroup *memcg;
 };
 
 #define TTM_BO_MAP_IOMEM_MASK 0x80
@@ -174,6 +180,7 @@ struct ttm_bo_kmap_obj {
  * BOs share the same reservation object.
  * @force_alloc: Don't check the memory account during suspend or CPU page
  * faults. Should only be used by TTM internally.
+ * @account_op: use __GFP_ACCOUNT for this.
  * @resv: Reservation object to allow reserved evictions with.
  * @bytes_moved: Statistics on how many bytes have been moved.
  *
@@ -186,6 +193,7 @@ struct ttm_operation_ctx {
        bool gfp_retry_mayfail;
        bool allow_res_evict;
        bool force_alloc;
+       bool account_op;
        struct dma_resv *resv;
        uint64_t bytes_moved;
 };
diff --git a/include/drm/ttm/ttm_tt.h b/include/drm/ttm/ttm_tt.h
index 13cf47f3322f..23e5bcbaec3a 100644
--- a/include/drm/ttm/ttm_tt.h
+++ b/include/drm/ttm/ttm_tt.h
@@ -101,8 +101,9 @@ struct ttm_tt {
 #define TTM_TT_FLAG_EXTERNAL_MAPPABLE  BIT(3)
 #define TTM_TT_FLAG_DECRYPTED          BIT(4)
 #define TTM_TT_FLAG_BACKED_UP          BIT(5)
+#define TTM_TT_FLAG_ACCOUNTED          BIT(6)
 
-#define TTM_TT_FLAG_PRIV_POPULATED     BIT(6)
+#define TTM_TT_FLAG_PRIV_POPULATED     BIT(7)
        uint32_t page_flags;
        /** @num_pages: Number of pages in the page array. */
        uint32_t num_pages;
@@ -126,6 +127,9 @@ struct ttm_tt {
        enum ttm_caching caching;
        /** @restore: Partial restoration from backup state. TTM private */
        struct ttm_pool_tt_restore *restore;
+
+       /** @memcg: Memory cgroup to account this to */
+       struct mem_cgroup *memcg;
 };
 
 /**
-- 
2.49.0

Reply via email to