From: Mel Gorman <mgorman@suse.de> To: Peter Zijlstra <a.p.zijlstra@chello.nl>, Ingo Molnar <mingo@kernel.org> Cc: Andrea Arcangeli <aarcange@redhat.com>, Johannes Weiner <hannes@cmpxchg.org>, Linux-MM <linux-mm@kvack.org>, LKML <linux-kernel@vger.kernel.org>, Mel Gorman <mgorman@suse.de> Subject: [PATCH 8/8] sched: Increase NUMA PTE scanning when a new preferred node is selected Date: Wed, 26 Jun 2013 15:38:07 +0100 [thread overview] Message-ID: <1372257487-9749-9-git-send-email-mgorman@suse.de> (raw) In-Reply-To: <1372257487-9749-1-git-send-email-mgorman@suse.de> The NUMA PTE scan is reset every sysctl_numa_balancing_scan_period_reset in case of phase changes. This is crude and it is clearly visible in graphs when the PTE scanner resets even if the workload is already balanced. This patch increases the scan rate if the preferred node is updated and the task is currently running on the node to recheck if the placement decision is correct. In the optimistic expectation that the placement decisions will be correct, the maximum period between scans is also increased to reduce overhead due to automatic NUMA balancing. Signed-off-by: Mel Gorman <mgorman@suse.de> --- Documentation/sysctl/kernel.txt | 11 +++-------- include/linux/mm_types.h | 3 --- include/linux/sched/sysctl.h | 1 - kernel/sched/core.c | 1 - kernel/sched/fair.c | 26 +++++++++++--------------- kernel/sysctl.c | 7 ------- 6 files changed, 14 insertions(+), 35 deletions(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 246b128..a275042 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -373,15 +373,13 @@ guarantee. If the target workload is already bound to NUMA nodes then this feature should be disabled. Otherwise, if the system overhead from the feature is too high then the rate the kernel samples for NUMA hinting faults may be controlled by the numa_balancing_scan_period_min_ms, -numa_balancing_scan_delay_ms, numa_balancing_scan_period_reset, -numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb and -numa_balancing_settle_count sysctls. +numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms, +numa_balancing_scan_size_mb and numa_balancing_settle_count sysctls. ============================================================== numa_balancing_scan_period_min_ms, numa_balancing_scan_delay_ms, -numa_balancing_scan_period_max_ms, numa_balancing_scan_period_reset, -numa_balancing_scan_size_mb +numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb Automatic NUMA balancing scans tasks address space and unmaps pages to detect if pages are properly placed or if the data should be migrated to a @@ -416,9 +414,6 @@ effectively controls the minimum scanning rate for each task. numa_balancing_scan_size_mb is how many megabytes worth of pages are scanned for a given scan. -numa_balancing_scan_period_reset is a blunt instrument that controls how -often a tasks scan delay is reset to detect sudden changes in task behaviour. - numa_balancing_settle_count is how many scan periods must complete before the schedule balancer stops pushing the task towards a preferred node. This gives the scheduler a chance to place the task on an alternative node if the diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index ace9a5f..de70964 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -421,9 +421,6 @@ struct mm_struct { */ unsigned long numa_next_scan; - /* numa_next_reset is when the PTE scanner period will be reset */ - unsigned long numa_next_reset; - /* Restart point for scanning and setting pte_numa */ unsigned long numa_scan_offset; diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index bf8086b..10d16c4f 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -47,7 +47,6 @@ extern enum sched_tunable_scaling sysctl_sched_tunable_scaling; extern unsigned int sysctl_numa_balancing_scan_delay; extern unsigned int sysctl_numa_balancing_scan_period_min; extern unsigned int sysctl_numa_balancing_scan_period_max; -extern unsigned int sysctl_numa_balancing_scan_period_reset; extern unsigned int sysctl_numa_balancing_scan_size; extern unsigned int sysctl_numa_balancing_settle_count; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b4722d6..2d1fd93 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1585,7 +1585,6 @@ static void __sched_fork(struct task_struct *p) #ifdef CONFIG_NUMA_BALANCING if (p->mm && atomic_read(&p->mm->mm_users) == 1) { p->mm->numa_next_scan = jiffies; - p->mm->numa_next_reset = jiffies; p->mm->numa_scan_seq = 0; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 490e601..e9bbb70 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -782,8 +782,7 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se) * numa task sample period in ms */ unsigned int sysctl_numa_balancing_scan_period_min = 100; -unsigned int sysctl_numa_balancing_scan_period_max = 100*50; -unsigned int sysctl_numa_balancing_scan_period_reset = 100*600; +unsigned int sysctl_numa_balancing_scan_period_max = 100*600; /* Portion of address space to scan in MB */ unsigned int sysctl_numa_balancing_scan_size = 256; @@ -881,6 +880,7 @@ static void task_numa_placement(struct task_struct *p) */ if (max_faults && max_nid != p->numa_preferred_nid) { int preferred_cpu; + int old_migrate_seq = p->numa_migrate_seq; /* * If the task is not on the preferred node then find the most @@ -892,6 +892,15 @@ static void task_numa_placement(struct task_struct *p) max_nid); sched_setnuma(p, max_nid, preferred_cpu); + + /* + * If preferred nodes changes frequently then the scan rate + * will be continually high. Mitigate this by increaseing the + * scan rate only if the task was settled. + */ + if (old_migrate_seq >= sysctl_numa_balancing_settle_count) + p->numa_scan_period = max(p->numa_scan_period >> 1, + sysctl_numa_balancing_scan_period_min); } } @@ -985,19 +994,6 @@ void task_numa_work(struct callback_head *work) } /* - * Reset the scan period if enough time has gone by. Objective is that - * scanning will be reduced if pages are properly placed. As tasks - * can enter different phases this needs to be re-examined. Lacking - * proper tracking of reference behaviour, this blunt hammer is used. - */ - migrate = mm->numa_next_reset; - if (time_after(now, migrate)) { - p->numa_scan_period = sysctl_numa_balancing_scan_period_min; - next_scan = now + msecs_to_jiffies(sysctl_numa_balancing_scan_period_reset); - xchg(&mm->numa_next_reset, next_scan); - } - - /* * Enforce maximal scan/migration frequency.. */ migrate = mm->numa_next_scan; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 263486f..1fcbc68 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -373,13 +373,6 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, { - .procname = "numa_balancing_scan_period_reset", - .data = &sysctl_numa_balancing_scan_period_reset, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { .procname = "numa_balancing_scan_period_max_ms", .data = &sysctl_numa_balancing_scan_period_max, .maxlen = sizeof(unsigned int), -- 1.8.1.4
WARNING: multiple messages have this Message-ID (diff)
From: Mel Gorman <mgorman@suse.de> To: Peter Zijlstra <a.p.zijlstra@chello.nl>, Ingo Molnar <mingo@kernel.org> Cc: Andrea Arcangeli <aarcange@redhat.com>, Johannes Weiner <hannes@cmpxchg.org>, Linux-MM <linux-mm@kvack.org>, LKML <linux-kernel@vger.kernel.org>, Mel Gorman <mgorman@suse.de> Subject: [PATCH 8/8] sched: Increase NUMA PTE scanning when a new preferred node is selected Date: Wed, 26 Jun 2013 15:38:07 +0100 [thread overview] Message-ID: <1372257487-9749-9-git-send-email-mgorman@suse.de> (raw) In-Reply-To: <1372257487-9749-1-git-send-email-mgorman@suse.de> The NUMA PTE scan is reset every sysctl_numa_balancing_scan_period_reset in case of phase changes. This is crude and it is clearly visible in graphs when the PTE scanner resets even if the workload is already balanced. This patch increases the scan rate if the preferred node is updated and the task is currently running on the node to recheck if the placement decision is correct. In the optimistic expectation that the placement decisions will be correct, the maximum period between scans is also increased to reduce overhead due to automatic NUMA balancing. Signed-off-by: Mel Gorman <mgorman@suse.de> --- Documentation/sysctl/kernel.txt | 11 +++-------- include/linux/mm_types.h | 3 --- include/linux/sched/sysctl.h | 1 - kernel/sched/core.c | 1 - kernel/sched/fair.c | 26 +++++++++++--------------- kernel/sysctl.c | 7 ------- 6 files changed, 14 insertions(+), 35 deletions(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 246b128..a275042 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -373,15 +373,13 @@ guarantee. If the target workload is already bound to NUMA nodes then this feature should be disabled. Otherwise, if the system overhead from the feature is too high then the rate the kernel samples for NUMA hinting faults may be controlled by the numa_balancing_scan_period_min_ms, -numa_balancing_scan_delay_ms, numa_balancing_scan_period_reset, -numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb and -numa_balancing_settle_count sysctls. +numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms, +numa_balancing_scan_size_mb and numa_balancing_settle_count sysctls. ============================================================== numa_balancing_scan_period_min_ms, numa_balancing_scan_delay_ms, -numa_balancing_scan_period_max_ms, numa_balancing_scan_period_reset, -numa_balancing_scan_size_mb +numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb Automatic NUMA balancing scans tasks address space and unmaps pages to detect if pages are properly placed or if the data should be migrated to a @@ -416,9 +414,6 @@ effectively controls the minimum scanning rate for each task. numa_balancing_scan_size_mb is how many megabytes worth of pages are scanned for a given scan. -numa_balancing_scan_period_reset is a blunt instrument that controls how -often a tasks scan delay is reset to detect sudden changes in task behaviour. - numa_balancing_settle_count is how many scan periods must complete before the schedule balancer stops pushing the task towards a preferred node. This gives the scheduler a chance to place the task on an alternative node if the diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index ace9a5f..de70964 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -421,9 +421,6 @@ struct mm_struct { */ unsigned long numa_next_scan; - /* numa_next_reset is when the PTE scanner period will be reset */ - unsigned long numa_next_reset; - /* Restart point for scanning and setting pte_numa */ unsigned long numa_scan_offset; diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index bf8086b..10d16c4f 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -47,7 +47,6 @@ extern enum sched_tunable_scaling sysctl_sched_tunable_scaling; extern unsigned int sysctl_numa_balancing_scan_delay; extern unsigned int sysctl_numa_balancing_scan_period_min; extern unsigned int sysctl_numa_balancing_scan_period_max; -extern unsigned int sysctl_numa_balancing_scan_period_reset; extern unsigned int sysctl_numa_balancing_scan_size; extern unsigned int sysctl_numa_balancing_settle_count; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b4722d6..2d1fd93 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1585,7 +1585,6 @@ static void __sched_fork(struct task_struct *p) #ifdef CONFIG_NUMA_BALANCING if (p->mm && atomic_read(&p->mm->mm_users) == 1) { p->mm->numa_next_scan = jiffies; - p->mm->numa_next_reset = jiffies; p->mm->numa_scan_seq = 0; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 490e601..e9bbb70 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -782,8 +782,7 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se) * numa task sample period in ms */ unsigned int sysctl_numa_balancing_scan_period_min = 100; -unsigned int sysctl_numa_balancing_scan_period_max = 100*50; -unsigned int sysctl_numa_balancing_scan_period_reset = 100*600; +unsigned int sysctl_numa_balancing_scan_period_max = 100*600; /* Portion of address space to scan in MB */ unsigned int sysctl_numa_balancing_scan_size = 256; @@ -881,6 +880,7 @@ static void task_numa_placement(struct task_struct *p) */ if (max_faults && max_nid != p->numa_preferred_nid) { int preferred_cpu; + int old_migrate_seq = p->numa_migrate_seq; /* * If the task is not on the preferred node then find the most @@ -892,6 +892,15 @@ static void task_numa_placement(struct task_struct *p) max_nid); sched_setnuma(p, max_nid, preferred_cpu); + + /* + * If preferred nodes changes frequently then the scan rate + * will be continually high. Mitigate this by increaseing the + * scan rate only if the task was settled. + */ + if (old_migrate_seq >= sysctl_numa_balancing_settle_count) + p->numa_scan_period = max(p->numa_scan_period >> 1, + sysctl_numa_balancing_scan_period_min); } } @@ -985,19 +994,6 @@ void task_numa_work(struct callback_head *work) } /* - * Reset the scan period if enough time has gone by. Objective is that - * scanning will be reduced if pages are properly placed. As tasks - * can enter different phases this needs to be re-examined. Lacking - * proper tracking of reference behaviour, this blunt hammer is used. - */ - migrate = mm->numa_next_reset; - if (time_after(now, migrate)) { - p->numa_scan_period = sysctl_numa_balancing_scan_period_min; - next_scan = now + msecs_to_jiffies(sysctl_numa_balancing_scan_period_reset); - xchg(&mm->numa_next_reset, next_scan); - } - - /* * Enforce maximal scan/migration frequency.. */ migrate = mm->numa_next_scan; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 263486f..1fcbc68 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -373,13 +373,6 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, { - .procname = "numa_balancing_scan_period_reset", - .data = &sysctl_numa_balancing_scan_period_reset, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { .procname = "numa_balancing_scan_period_max_ms", .data = &sysctl_numa_balancing_scan_period_max, .maxlen = sizeof(unsigned int), -- 1.8.1.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2013-06-26 14:38 UTC|newest] Thread overview: 124+ messages / expand[flat|nested] mbox.gz Atom feed top 2013-06-26 14:37 [PATCH 0/6] Basic scheduler support for automatic NUMA balancing Mel Gorman 2013-06-26 14:37 ` Mel Gorman 2013-06-26 14:38 ` [PATCH 1/8] mm: numa: Document automatic NUMA balancing sysctls Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-26 14:38 ` [PATCH 2/8] sched: Track NUMA hinting faults on per-node basis Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-27 15:57 ` Peter Zijlstra 2013-06-27 15:57 ` Peter Zijlstra 2013-06-28 12:22 ` Mel Gorman 2013-06-28 12:22 ` Mel Gorman 2013-06-28 6:08 ` Srikar Dronamraju 2013-06-28 6:08 ` Srikar Dronamraju 2013-06-28 8:56 ` Peter Zijlstra 2013-06-28 8:56 ` Peter Zijlstra 2013-06-28 12:30 ` Mel Gorman 2013-06-28 12:30 ` Mel Gorman 2013-06-26 14:38 ` [PATCH 3/8] sched: Select a preferred node with the most numa hinting faults Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-28 6:14 ` Srikar Dronamraju 2013-06-28 6:14 ` Srikar Dronamraju 2013-06-28 8:59 ` Peter Zijlstra 2013-06-28 8:59 ` Peter Zijlstra 2013-06-28 10:24 ` Srikar Dronamraju 2013-06-28 10:24 ` Srikar Dronamraju 2013-06-28 12:33 ` Mel Gorman 2013-06-28 12:33 ` Mel Gorman 2013-06-26 14:38 ` [PATCH 4/8] sched: Update NUMA hinting faults once per scan Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-28 6:32 ` Srikar Dronamraju 2013-06-28 6:32 ` Srikar Dronamraju 2013-06-28 9:01 ` Peter Zijlstra 2013-06-28 9:01 ` Peter Zijlstra 2013-06-26 14:38 ` [PATCH 5/8] sched: Favour moving tasks towards the preferred node Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-27 14:52 ` Peter Zijlstra 2013-06-27 14:52 ` Peter Zijlstra 2013-06-27 14:53 ` Peter Zijlstra 2013-06-27 14:53 ` Peter Zijlstra 2013-06-28 13:00 ` Mel Gorman 2013-06-28 13:00 ` Mel Gorman 2013-06-27 16:01 ` Peter Zijlstra 2013-06-27 16:01 ` Peter Zijlstra 2013-06-28 13:01 ` Mel Gorman 2013-06-28 13:01 ` Mel Gorman 2013-06-27 16:11 ` Peter Zijlstra 2013-06-27 16:11 ` Peter Zijlstra 2013-06-28 13:45 ` Mel Gorman 2013-06-28 13:45 ` Mel Gorman 2013-06-28 15:10 ` Peter Zijlstra 2013-06-28 15:10 ` Peter Zijlstra 2013-06-28 8:11 ` Srikar Dronamraju 2013-06-28 8:11 ` Srikar Dronamraju 2013-06-28 9:04 ` Peter Zijlstra 2013-06-28 9:04 ` Peter Zijlstra 2013-06-28 10:07 ` Srikar Dronamraju 2013-06-28 10:07 ` Srikar Dronamraju 2013-06-28 10:24 ` Peter Zijlstra 2013-06-28 10:24 ` Peter Zijlstra 2013-06-28 13:51 ` Mel Gorman 2013-06-28 13:51 ` Mel Gorman 2013-06-28 17:14 ` Srikar Dronamraju 2013-06-28 17:14 ` Srikar Dronamraju 2013-06-28 17:34 ` Mel Gorman 2013-06-28 17:34 ` Mel Gorman 2013-06-28 17:44 ` Srikar Dronamraju 2013-06-28 17:44 ` Srikar Dronamraju 2013-06-26 14:38 ` [PATCH 6/8] sched: Reschedule task on preferred NUMA node once selected Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-27 14:54 ` Peter Zijlstra 2013-06-27 14:54 ` Peter Zijlstra 2013-06-28 13:54 ` Mel Gorman 2013-06-28 13:54 ` Mel Gorman 2013-07-02 12:06 ` Srikar Dronamraju 2013-07-02 12:06 ` Srikar Dronamraju 2013-07-02 16:29 ` Mel Gorman 2013-07-02 16:29 ` Mel Gorman 2013-07-02 18:17 ` Peter Zijlstra 2013-07-02 18:17 ` Peter Zijlstra 2013-07-06 6:44 ` Srikar Dronamraju 2013-07-06 6:44 ` Srikar Dronamraju 2013-07-06 10:47 ` Peter Zijlstra 2013-07-06 10:47 ` Peter Zijlstra 2013-07-02 18:15 ` Peter Zijlstra 2013-07-02 18:15 ` Peter Zijlstra 2013-07-03 9:50 ` Peter Zijlstra 2013-07-03 9:50 ` Peter Zijlstra 2013-07-03 15:28 ` Mel Gorman 2013-07-03 15:28 ` Mel Gorman 2013-07-03 18:46 ` Peter Zijlstra 2013-07-03 18:46 ` Peter Zijlstra 2013-06-26 14:38 ` [PATCH 7/8] sched: Split accounting of NUMA hinting faults that pass two-stage filter Mel Gorman 2013-06-26 14:38 ` Mel Gorman 2013-06-27 14:56 ` Peter Zijlstra 2013-06-27 14:56 ` Peter Zijlstra 2013-06-28 14:00 ` Mel Gorman 2013-06-28 14:00 ` Mel Gorman 2013-06-28 7:00 ` Srikar Dronamraju 2013-06-28 7:00 ` Srikar Dronamraju 2013-06-28 9:36 ` Peter Zijlstra 2013-06-28 9:36 ` Peter Zijlstra 2013-06-28 10:12 ` Srikar Dronamraju 2013-06-28 10:12 ` Srikar Dronamraju 2013-06-28 10:33 ` Peter Zijlstra 2013-06-28 10:33 ` Peter Zijlstra 2013-06-28 14:29 ` Mel Gorman 2013-06-28 14:29 ` Mel Gorman 2013-06-28 15:12 ` Peter Zijlstra 2013-06-28 15:12 ` Peter Zijlstra 2013-06-26 14:38 ` Mel Gorman [this message] 2013-06-26 14:38 ` [PATCH 8/8] sched: Increase NUMA PTE scanning when a new preferred node is selected Mel Gorman 2013-06-27 14:59 ` [PATCH 0/6] Basic scheduler support for automatic NUMA balancing Peter Zijlstra 2013-06-27 14:59 ` Peter Zijlstra 2013-06-28 13:54 ` Srikar Dronamraju 2013-06-28 13:54 ` Srikar Dronamraju 2013-07-01 5:39 ` Srikar Dronamraju 2013-07-01 5:39 ` Srikar Dronamraju 2013-07-01 8:43 ` Mel Gorman 2013-07-01 8:43 ` Mel Gorman 2013-07-02 5:28 ` Srikar Dronamraju 2013-07-02 5:28 ` Srikar Dronamraju 2013-07-02 7:46 ` Peter Zijlstra 2013-07-02 7:46 ` Peter Zijlstra 2013-07-02 8:55 ` Peter Zijlstra 2013-07-02 8:55 ` Peter Zijlstra
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1372257487-9749-9-git-send-email-mgorman@suse.de \ --to=mgorman@suse.de \ --cc=a.p.zijlstra@chello.nl \ --cc=aarcange@redhat.com \ --cc=hannes@cmpxchg.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-mm@kvack.org \ --cc=mingo@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.