Skip to content

Commit 72d1e61

Browse files
jiebinnakpm00
authored andcommitted
ipc/msg: mitigate the lock contention with percpu counter
The msg_bytes and msg_hdrs atomic counters are frequently updated when IPC msg queue is in heavy use, causing heavy cache bounce and overhead. Change them to percpu_counter greatly improve the performance. Since there is one percpu struct per namespace, additional memory cost is minimal. Reading of the count done in msgctl call, which is infrequent. So the need to sum up the counts in each CPU is infrequent. Apply the patch and test the pts/stress-ng-1.4.0 -- system v message passing (160 threads). Score gain: 3.99x CPU: ICX 8380 x 2 sockets Core number: 40 x 2 physical cores Benchmark: pts/stress-ng-1.4.0 -- system v message passing (160 threads) [[email protected]: coding-style cleanups] [[email protected]: avoid negative value by overflow in msginfo] Link: https://lkml.kernel.org/r/[email protected] [[email protected]: fix min() warnings] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Jiebin Sun <[email protected]> Reviewed-by: Tim Chen <[email protected]> Cc: Alexander Mikhalitsyn <[email protected]> Cc: Alexey Gladkov <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: Dennis Zhou <[email protected]> Cc: "Eric W . Biederman" <[email protected]> Cc: Manfred Spraul <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Tejun Heo <[email protected]> Cc: Vasily Averin <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 5d0ce35 commit 72d1e61

File tree

4 files changed

+43
-19
lines changed

4 files changed

+43
-19
lines changed

include/linux/ipc_namespace.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/refcount.h>
1212
#include <linux/rhashtable-types.h>
1313
#include <linux/sysctl.h>
14+
#include <linux/percpu_counter.h>
1415

1516
struct user_namespace;
1617

@@ -36,8 +37,8 @@ struct ipc_namespace {
3637
unsigned int msg_ctlmax;
3738
unsigned int msg_ctlmnb;
3839
unsigned int msg_ctlmni;
39-
atomic_t msg_bytes;
40-
atomic_t msg_hdrs;
40+
struct percpu_counter percpu_msg_bytes;
41+
struct percpu_counter percpu_msg_hdrs;
4142

4243
size_t shm_ctlmax;
4344
size_t shm_ctlall;

ipc/msg.c

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <linux/nsproxy.h>
4040
#include <linux/ipc_namespace.h>
4141
#include <linux/rhashtable.h>
42+
#include <linux/percpu_counter.h>
4243

4344
#include <asm/current.h>
4445
#include <linux/uaccess.h>
@@ -285,10 +286,10 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
285286
rcu_read_unlock();
286287

287288
list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
288-
atomic_dec(&ns->msg_hdrs);
289+
percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1);
289290
free_msg(msg);
290291
}
291-
atomic_sub(msq->q_cbytes, &ns->msg_bytes);
292+
percpu_counter_sub_local(&ns->percpu_msg_bytes, msq->q_cbytes);
292293
ipc_update_pid(&msq->q_lspid, NULL);
293294
ipc_update_pid(&msq->q_lrpid, NULL);
294295
ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
@@ -495,17 +496,22 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
495496
msginfo->msgssz = MSGSSZ;
496497
msginfo->msgseg = MSGSEG;
497498
down_read(&msg_ids(ns).rwsem);
498-
if (cmd == MSG_INFO) {
499+
if (cmd == MSG_INFO)
499500
msginfo->msgpool = msg_ids(ns).in_use;
500-
msginfo->msgmap = atomic_read(&ns->msg_hdrs);
501-
msginfo->msgtql = atomic_read(&ns->msg_bytes);
501+
max_idx = ipc_get_maxidx(&msg_ids(ns));
502+
up_read(&msg_ids(ns).rwsem);
503+
if (cmd == MSG_INFO) {
504+
msginfo->msgmap = min_t(int,
505+
percpu_counter_sum(&ns->percpu_msg_hdrs),
506+
INT_MAX);
507+
msginfo->msgtql = min_t(int,
508+
percpu_counter_sum(&ns->percpu_msg_bytes),
509+
INT_MAX);
502510
} else {
503511
msginfo->msgmap = MSGMAP;
504512
msginfo->msgpool = MSGPOOL;
505513
msginfo->msgtql = MSGTQL;
506514
}
507-
max_idx = ipc_get_maxidx(&msg_ids(ns));
508-
up_read(&msg_ids(ns).rwsem);
509515
return (max_idx < 0) ? 0 : max_idx;
510516
}
511517

@@ -935,8 +941,8 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext,
935941
list_add_tail(&msg->m_list, &msq->q_messages);
936942
msq->q_cbytes += msgsz;
937943
msq->q_qnum++;
938-
atomic_add(msgsz, &ns->msg_bytes);
939-
atomic_inc(&ns->msg_hdrs);
944+
percpu_counter_add_local(&ns->percpu_msg_bytes, msgsz);
945+
percpu_counter_add_local(&ns->percpu_msg_hdrs, 1);
940946
}
941947

942948
err = 0;
@@ -1159,8 +1165,8 @@ static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, in
11591165
msq->q_rtime = ktime_get_real_seconds();
11601166
ipc_update_pid(&msq->q_lrpid, task_tgid(current));
11611167
msq->q_cbytes -= msg->m_ts;
1162-
atomic_sub(msg->m_ts, &ns->msg_bytes);
1163-
atomic_dec(&ns->msg_hdrs);
1168+
percpu_counter_sub_local(&ns->percpu_msg_bytes, msg->m_ts);
1169+
percpu_counter_sub_local(&ns->percpu_msg_hdrs, 1);
11641170
ss_wakeup(msq, &wake_q, false);
11651171

11661172
goto out_unlock0;
@@ -1297,20 +1303,34 @@ COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
12971303
}
12981304
#endif
12991305

1300-
void msg_init_ns(struct ipc_namespace *ns)
1306+
int msg_init_ns(struct ipc_namespace *ns)
13011307
{
1308+
int ret;
1309+
13021310
ns->msg_ctlmax = MSGMAX;
13031311
ns->msg_ctlmnb = MSGMNB;
13041312
ns->msg_ctlmni = MSGMNI;
13051313

1306-
atomic_set(&ns->msg_bytes, 0);
1307-
atomic_set(&ns->msg_hdrs, 0);
1314+
ret = percpu_counter_init(&ns->percpu_msg_bytes, 0, GFP_KERNEL);
1315+
if (ret)
1316+
goto fail_msg_bytes;
1317+
ret = percpu_counter_init(&ns->percpu_msg_hdrs, 0, GFP_KERNEL);
1318+
if (ret)
1319+
goto fail_msg_hdrs;
13081320
ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
1321+
return 0;
1322+
1323+
fail_msg_hdrs:
1324+
percpu_counter_destroy(&ns->percpu_msg_bytes);
1325+
fail_msg_bytes:
1326+
return ret;
13091327
}
13101328

13111329
#ifdef CONFIG_IPC_NS
13121330
void msg_exit_ns(struct ipc_namespace *ns)
13131331
{
1332+
percpu_counter_destroy(&ns->percpu_msg_bytes);
1333+
percpu_counter_destroy(&ns->percpu_msg_hdrs);
13141334
free_ipcs(ns, &msg_ids(ns), freeque);
13151335
idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
13161336
rhashtable_destroy(&ns->ids[IPC_MSG_IDS].key_ht);

ipc/namespace.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,11 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
6666
if (!setup_ipc_sysctls(ns))
6767
goto fail_mq;
6868

69+
err = msg_init_ns(ns);
70+
if (err)
71+
goto fail_put;
72+
6973
sem_init_ns(ns);
70-
msg_init_ns(ns);
7174
shm_init_ns(ns);
7275

7376
return ns;

ipc/util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ static inline void mq_put_mnt(struct ipc_namespace *ns) { }
6464

6565
#ifdef CONFIG_SYSVIPC
6666
void sem_init_ns(struct ipc_namespace *ns);
67-
void msg_init_ns(struct ipc_namespace *ns);
67+
int msg_init_ns(struct ipc_namespace *ns);
6868
void shm_init_ns(struct ipc_namespace *ns);
6969

7070
void sem_exit_ns(struct ipc_namespace *ns);
7171
void msg_exit_ns(struct ipc_namespace *ns);
7272
void shm_exit_ns(struct ipc_namespace *ns);
7373
#else
7474
static inline void sem_init_ns(struct ipc_namespace *ns) { }
75-
static inline void msg_init_ns(struct ipc_namespace *ns) { }
75+
static inline int msg_init_ns(struct ipc_namespace *ns) { return 0; }
7676
static inline void shm_init_ns(struct ipc_namespace *ns) { }
7777

7878
static inline void sem_exit_ns(struct ipc_namespace *ns) { }

0 commit comments

Comments
 (0)