diff mbox series

[RFC] memcg: add charging of already allocated slab objects

Message ID 20240824010139.1293051-1-shakeel.butt@linux.dev (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [RFC] memcg: add charging of already allocated slab objects | expand

Checks

Context Check Description
netdev/tree_selection success Not a local patch

Commit Message

Shakeel Butt Aug. 24, 2024, 1:01 a.m. UTC
At the moment, the slab objects are charged to the memcg at the
allocation time. However there are cases where slab objects are
allocated at the time where the right target memcg to charge it to is
not known. One such case is the network sockets for the incoming
connection which are allocated in the softirq context.

Couple hundred thousand connections are very normal on large loaded
server and almost all of those sockets underlying those connections get
allocated in the softirq context and thus not charged to any memcg.
However later at the accept() time we know the right target memcg to
charge. Let's add new API to charge already allocated objects, so we can
have better accounting of the memory usage.

Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>
---

This is RFC to get early comments and I still have to measure the
performance impact of this charging. Particularly I am planning to test
neper's tcp_crr with this patch.

 include/linux/slab.h            |  1 +
 mm/slub.c                       | 39 +++++++++++++++++++++++++++++++++
 net/ipv4/inet_connection_sock.c |  1 +
 3 files changed, 41 insertions(+)

Comments

Jakub Kicinski Aug. 26, 2024, 9:46 p.m. UTC | #1
On Fri, 23 Aug 2024 18:01:39 -0700 Shakeel Butt wrote:
> +EXPORT_SYMBOL(kmem_cache_post_charge);

FWIW ipv4 can't be a module, but perhaps you're just following local
customs
Shakeel Butt Aug. 26, 2024, 11 p.m. UTC | #2
On Mon, Aug 26, 2024 at 02:46:00PM GMT, Jakub Kicinski wrote:
> On Fri, 23 Aug 2024 18:01:39 -0700 Shakeel Butt wrote:
> > +EXPORT_SYMBOL(kmem_cache_post_charge);
> 
> FWIW ipv4 can't be a module, but perhaps you're just following local
> customs

Yup just following the local customs of that file.
diff mbox series

Patch

diff --git a/include/linux/slab.h b/include/linux/slab.h
index 512e7c844b7f..a8b09b0ca066 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -547,6 +547,7 @@  void *kmem_cache_alloc_lru_noprof(struct kmem_cache *s, struct list_lru *lru,
 			    gfp_t gfpflags) __assume_slab_alignment __malloc;
 #define kmem_cache_alloc_lru(...)	alloc_hooks(kmem_cache_alloc_lru_noprof(__VA_ARGS__))
 
+bool kmem_cache_post_charge(void *objp, gfp_t gfpflags);
 void kmem_cache_free(struct kmem_cache *s, void *objp);
 
 kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
diff --git a/mm/slub.c b/mm/slub.c
index b6b947596e26..574122ad89b8 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2189,6 +2189,16 @@  void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab, void **p,
 
 	__memcg_slab_free_hook(s, slab, p, objects, obj_exts);
 }
+
+static __fastpath_inline
+bool memcg_slab_post_charge(struct kmem_cache *s, void *p, gfp_t flags)
+{
+	if (likely(!memcg_kmem_online()))
+		return true;
+
+	return __memcg_slab_post_alloc_hook(s, NULL, flags, 1, &p);
+}
+
 #else /* CONFIG_MEMCG */
 static inline bool memcg_slab_post_alloc_hook(struct kmem_cache *s,
 					      struct list_lru *lru,
@@ -2202,6 +2212,13 @@  static inline void memcg_slab_free_hook(struct kmem_cache *s, struct slab *slab,
 					void **p, int objects)
 {
 }
+
+static inline bool memcg_slab_post_charge(struct kmem_cache *s,
+					  void *p,
+					  gfp_t flags)
+{
+	return true;
+}
 #endif /* CONFIG_MEMCG */
 
 #ifdef CONFIG_SLUB_RCU_DEBUG
@@ -4110,6 +4127,28 @@  void *kmem_cache_alloc_lru_noprof(struct kmem_cache *s, struct list_lru *lru,
 }
 EXPORT_SYMBOL(kmem_cache_alloc_lru_noprof);
 
+bool kmem_cache_post_charge(void *objp, gfp_t gfpflags)
+{
+	struct folio *folio;
+	struct slab *slab;
+	struct kmem_cache *s;
+
+	folio = virt_to_folio(objp);
+	if (unlikely(!folio_test_slab(folio)))
+		return false;
+
+	slab = folio_slab(folio);
+	s = slab->slab_cache;
+
+	/* Ignore KMALLOC_NORMAL cache */
+	if (s->flags & SLAB_KMALLOC &&
+	    !(s->flags & (SLAB_CACHE_DMA|SLAB_ACCOUNT|SLAB_RECLAIM_ACCOUNT)))
+		return true;
+
+	return memcg_slab_post_charge(s, objp, gfpflags);
+}
+EXPORT_SYMBOL(kmem_cache_post_charge);
+
 /**
  * kmem_cache_alloc_node - Allocate an object on the specified node
  * @s: The cache to allocate from.
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 64d07b842e73..f707bb76e24d 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -733,6 +733,7 @@  struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg)
 		if (amt)
 			mem_cgroup_charge_skmem(newsk->sk_memcg, amt,
 						GFP_KERNEL | __GFP_NOFAIL);
+		kmem_cache_post_charge(newsk, GFP_KERNEL | __GFP_NOFAIL);
 
 		release_sock(newsk);
 	}