All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jerin Jacob <jerin.jacob@caviumnetworks.com>
To: dev@dpdk.org
Cc: bruce.richardson@intel.com, harry.van.haaren@intel.com,
	hemant.agrawal@nxp.com, gage.eads@intel.com, nipun.gupta@nxp.com,
	narender.vangati@intel.com, nikhil.rao@intel.com,
	gprathyusha@caviumnetworks.com,
	Jerin Jacob <jerin.jacob@caviumnetworks.com>
Subject: [PATCH 25/33] app/testeventdev: perf queue: add worker functions
Date: Mon, 29 May 2017 01:28:46 +0530	[thread overview]
Message-ID: <20170528195854.6064-26-jerin.jacob@caviumnetworks.com> (raw)
In-Reply-To: <20170528195854.6064-1-jerin.jacob@caviumnetworks.com>

Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
---
 app/test-eventdev/test_perf_common.h |  60 +++++++++++++++
 app/test-eventdev/test_perf_queue.c  | 137 +++++++++++++++++++++++++++++++++++
 2 files changed, 197 insertions(+)

diff --git a/app/test-eventdev/test_perf_common.h b/app/test-eventdev/test_perf_common.h
index f8246953a..9888e5078 100644
--- a/app/test-eventdev/test_perf_common.h
+++ b/app/test-eventdev/test_perf_common.h
@@ -86,6 +86,66 @@ struct perf_elt {
 	uint64_t timestamp;
 } __rte_cache_aligned;
 
+#define BURST_SIZE 16
+
+#define PERF_WORKER_INIT\
+	struct worker_data *w  = arg;\
+	struct test_perf *t = w->t;\
+	struct evt_options *opt = t->opt;\
+	const uint8_t dev = w->dev_id;\
+	const uint8_t port = w->port_id;\
+	uint8_t *const sched_type_list = &t->sched_type_list[0];\
+	struct rte_mempool *const pool = t->pool;\
+	const uint8_t nb_stages = t->opt->nb_stages;\
+	const uint8_t laststage = nb_stages - 1;\
+	uint8_t cnt = 0;\
+	void *bufs[16] __rte_cache_aligned;\
+	int const sz = RTE_DIM(bufs);\
+	if (opt->verbose_level > 1)\
+		printf("%s(): lcore %d dev_id %d port=%d\n", __func__,\
+				rte_lcore_id(), dev, port)
+
+static inline __attribute__((always_inline)) int
+perf_process_last_stage(struct rte_mempool *const pool,
+		struct rte_event *const ev, struct worker_data *const w,
+		void *bufs[], int const buf_sz, uint8_t count)
+{
+	bufs[count++] = ev->event_ptr;
+	w->processed_pkts++;
+	rte_smp_wmb();
+
+	if (unlikely(count == buf_sz)) {
+		count = 0;
+		rte_mempool_put_bulk(pool, bufs, buf_sz);
+	}
+	return count;
+}
+
+static inline __attribute__((always_inline)) uint8_t
+perf_process_last_stage_latency(struct rte_mempool *const pool,
+		struct rte_event *const ev, struct worker_data *const w,
+		void *bufs[], int const buf_sz, uint8_t count)
+{
+	uint64_t latency;
+	struct perf_elt *const m = ev->event_ptr;
+
+	bufs[count++] = ev->event_ptr;
+	w->processed_pkts++;
+
+	if (unlikely(count == buf_sz)) {
+		count = 0;
+		latency = rte_get_timer_cycles() - m->timestamp;
+		rte_mempool_put_bulk(pool, bufs, buf_sz);
+	} else {
+		latency = rte_get_timer_cycles() - m->timestamp;
+	}
+
+	w->latency += latency;
+	rte_smp_wmb();
+	return count;
+}
+
+
 static inline int
 perf_nb_event_ports(struct evt_options *opt)
 {
diff --git a/app/test-eventdev/test_perf_queue.c b/app/test-eventdev/test_perf_queue.c
index 352240c7b..811f7f78d 100644
--- a/app/test-eventdev/test_perf_queue.c
+++ b/app/test-eventdev/test_perf_queue.c
@@ -41,6 +41,142 @@ perf_queue_nb_event_queues(struct evt_options *opt)
 	return evt_nr_active_lcores(opt->plcores) * opt->nb_stages;
 }
 
+static inline __attribute__((always_inline)) void
+mark_fwd_latency(struct rte_event *const ev,
+		const uint8_t nb_stages)
+{
+	if (unlikely((ev->queue_id % nb_stages) == 0)) {
+		struct perf_elt *const m = ev->event_ptr;
+
+		m->timestamp = rte_get_timer_cycles();
+	}
+}
+
+static inline __attribute__((always_inline)) void
+fwd_event(struct rte_event *const ev, uint8_t *const sched_type_list,
+		const uint8_t nb_stages)
+{
+	ev->queue_id++;
+	ev->sched_type = sched_type_list[ev->queue_id % nb_stages];
+	ev->op = RTE_EVENT_OP_FORWARD;
+	ev->event_type = RTE_EVENT_TYPE_CPU;
+}
+
+static int
+perf_queue_worker(void *arg, const int enable_fwd_latency)
+{
+	PERF_WORKER_INIT;
+	struct rte_event ev;
+
+	while (t->done == false) {
+		uint16_t event = rte_event_dequeue_burst(dev, port, &ev, 1, 0);
+
+		if (!event) {
+			rte_pause();
+			continue;
+		}
+		if (enable_fwd_latency)
+		/* first q in pipeline, mark timestamp to compute fwd latency */
+			mark_fwd_latency(&ev, nb_stages);
+
+		/* last stage in pipeline */
+		if (unlikely((ev.queue_id % nb_stages) == laststage)) {
+			if (enable_fwd_latency)
+				cnt = perf_process_last_stage_latency(pool,
+					&ev, w, bufs, sz, cnt);
+			else
+				cnt = perf_process_last_stage(pool,
+					&ev, w, bufs, sz, cnt);
+		} else {
+			fwd_event(&ev, sched_type_list, nb_stages);
+			while (rte_event_enqueue_burst(dev, port, &ev, 1) != 1)
+				rte_pause();
+		}
+	}
+	return 0;
+}
+
+static int
+perf_queue_worker_burst(void *arg, const int enable_fwd_latency)
+{
+	PERF_WORKER_INIT;
+	uint16_t i;
+	/* +1 to avoid prefetch out of array check */
+	struct rte_event ev[BURST_SIZE + 1];
+
+	while (t->done == false) {
+		uint16_t const nb_rx = rte_event_dequeue_burst(dev, port, ev,
+				BURST_SIZE, 0);
+
+		if (!nb_rx) {
+			rte_pause();
+			continue;
+		}
+
+		for (i = 0; i < nb_rx; i++) {
+			if (enable_fwd_latency) {
+				rte_prefetch0(ev[i+1].event_ptr);
+				/* first queue in pipeline.
+				 * mark time stamp to compute fwd latency
+				 */
+				mark_fwd_latency(&ev[i], nb_stages);
+			}
+			/* last stage in pipeline */
+			if (unlikely((ev[i].queue_id % nb_stages) ==
+						 laststage)) {
+				if (enable_fwd_latency)
+					cnt = perf_process_last_stage_latency(
+						pool, &ev[i], w, bufs, sz, cnt);
+				else
+					cnt = perf_process_last_stage(pool,
+						&ev[i], w, bufs, sz, cnt);
+
+				ev[i].op = RTE_EVENT_OP_RELEASE;
+			} else {
+				fwd_event(&ev[i], sched_type_list, nb_stages);
+			}
+		}
+
+		uint16_t enq;
+
+		enq = rte_event_enqueue_burst(dev, port, ev, nb_rx);
+		while (enq < nb_rx) {
+			enq += rte_event_enqueue_burst(dev, port,
+							ev + enq, nb_rx - enq);
+		}
+	}
+	return 0;
+}
+
+static int
+worker_wrapper(void *arg)
+{
+	struct worker_data *w  = arg;
+	struct evt_options *opt = w->t->opt;
+
+	/* FIXME: probe through device capability */
+	const int burst = 1;
+	const int fwd_latency = opt->fwd_latency;
+
+	/* allow compiler to optimize */
+	if (!burst && !fwd_latency)
+		return perf_queue_worker(arg, 0);
+	else if (!burst && fwd_latency)
+		return perf_queue_worker(arg, 1);
+	else if (burst && !fwd_latency)
+		return perf_queue_worker_burst(arg, 0);
+	else if (burst && fwd_latency)
+		return perf_queue_worker_burst(arg, 1);
+
+	rte_panic("invalid worker\n");
+}
+
+static int
+perf_queue_launch_lcores(struct evt_test *test, struct evt_options *opt)
+{
+	return perf_launch_lcores(test, opt, worker_wrapper);
+}
+
 static int
 perf_queue_eventdev_setup(struct evt_test *test, struct evt_options *opt)
 {
@@ -143,6 +279,7 @@ static const struct evt_test_ops perf_queue =  {
 	.test_setup         = perf_test_setup,
 	.mempool_setup      = perf_mempool_setup,
 	.eventdev_setup     = perf_queue_eventdev_setup,
+	.launch_lcores      = perf_queue_launch_lcores,
 	.eventdev_destroy   = perf_eventdev_destroy,
 	.mempool_destroy    = perf_mempool_destroy,
 	.test_result        = perf_test_result,
-- 
2.13.0

  parent reply	other threads:[~2017-05-28 20:02 UTC|newest]

Thread overview: 133+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-28 19:58 [PATCH 00/33] introduce generic eventdev test application framework Jerin Jacob
2017-05-28 19:58 ` [PATCH 01/33] app/testeventdev: introduce dpdk-test-eventdev application Jerin Jacob
2017-06-23 12:23   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 02/33] app/testeventdev: define eventdev test ops Jerin Jacob
2017-06-01 20:44   ` Eads, Gage
2017-06-23 12:27   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 03/33] app/testeventdev: add eventdev test registration framework Jerin Jacob
2017-06-23 12:28   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 04/33] app/testeventdev: add string parsing helpers Jerin Jacob
2017-06-23 12:30   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 05/33] app/testeventdev: add common helper functions Jerin Jacob
2017-05-28 19:58 ` [PATCH 06/33] app/testeventdev: define the test options Jerin Jacob
2017-06-23 13:07   ` Van Haaren, Harry
2017-07-03  7:10     ` Jerin Jacob
2017-05-28 19:58 ` [PATCH 07/33] app/testeventdev: add helper functions to check options Jerin Jacob
2017-05-28 19:58 ` [PATCH 08/33] app/testeventdev: add helper functions to dump options Jerin Jacob
2017-05-28 19:58 ` [PATCH 09/33] app/testeventdev: update options through the command line Jerin Jacob
2017-05-28 19:58 ` [PATCH 10/33] app/testeventdev: invoke the test ops Jerin Jacob
2017-05-28 19:58 ` [PATCH 11/33] app/testeventdev: add the signal handler Jerin Jacob
2017-05-28 19:58 ` [PATCH 12/33] app/testeventdev: order: add test setup and destroy Jerin Jacob
2017-05-28 19:58 ` [PATCH 13/33] app/testeventdev: order: add basic functions Jerin Jacob
2017-05-28 19:58 ` [PATCH 14/33] app/testeventdev: order: add eventdev port setup Jerin Jacob
2017-06-23 12:36   ` Van Haaren, Harry
2017-06-23 12:45     ` Jerin Jacob
2017-05-28 19:58 ` [PATCH 15/33] app/testeventdev: order: launch lcores Jerin Jacob
2017-06-01 20:54   ` Eads, Gage
2017-05-28 19:58 ` [PATCH 16/33] app/testeventdev: add order queue test Jerin Jacob
2017-05-28 19:58 ` [PATCH 17/33] app/testeventdev: order queue: add worker functions Jerin Jacob
2017-05-28 19:58 ` [PATCH 18/33] app/testeventdev: add order "all types queue" test Jerin Jacob
2017-05-28 19:58 ` [PATCH 19/33] app/testeventdev: perf: add test setup and destroy Jerin Jacob
2017-05-28 19:58 ` [PATCH 20/33] app/testeventdev: perf: add basic functions Jerin Jacob
2017-05-28 19:58 ` [PATCH 21/33] app/testeventdev: perf: add opt dump and check functions Jerin Jacob
2017-05-28 19:58 ` [PATCH 22/33] app/testeventdev: perf: add eventdev port setup Jerin Jacob
2017-06-23 12:42   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 23/33] app/testeventdev: perf: launch lcores Jerin Jacob
2017-05-28 19:58 ` [PATCH 24/33] app/testeventdev: add perf queue test Jerin Jacob
2017-06-23 12:47   ` Van Haaren, Harry
2017-07-03  8:38     ` Jerin Jacob
2017-05-28 19:58 ` Jerin Jacob [this message]
2017-06-01 21:04   ` [PATCH 25/33] app/testeventdev: perf queue: add worker functions Eads, Gage
2017-06-02 12:21     ` Jerin Jacob
2017-05-28 19:58 ` [PATCH 26/33] app/testeventdev: add perf "all types queue" test Jerin Jacob
2017-05-28 19:58 ` [PATCH 27/33] app/testeventdev: perf: add "all type queue" worker function Jerin Jacob
2017-05-28 19:58 ` [PATCH 28/33] doc: describe the new eventdev test application Jerin Jacob
2017-06-23 12:53   ` Van Haaren, Harry
2017-07-03  9:48     ` Jerin Jacob
2017-06-30 14:09   ` Mcnamara, John
2017-05-28 19:58 ` [PATCH 29/33] doc/testeventdev: add "order queue" test details Jerin Jacob
2017-06-30 14:19   ` Mcnamara, John
2017-05-28 19:58 ` [PATCH 30/33] doc/testeventdev: add "order all types " Jerin Jacob
2017-06-30 14:23   ` Mcnamara, John
2017-06-30 14:28   ` Mcnamara, John
2017-05-28 19:58 ` [PATCH 31/33] doc/testeventdev: add "perf " Jerin Jacob
2017-06-01 21:11   ` Eads, Gage
2017-06-02 12:10     ` Jerin Jacob
2017-06-30 14:31   ` Mcnamara, John
2017-05-28 19:58 ` [PATCH 32/33] doc/testeventdev: add "perf all types " Jerin Jacob
2017-06-23 12:56   ` Van Haaren, Harry
2017-05-28 19:58 ` [PATCH 33/33] maintainers: claim responsibility for the eventdev test app Jerin Jacob
2017-06-23 12:58   ` Van Haaren, Harry
2017-06-23 12:21 ` [PATCH 00/33] introduce generic eventdev test application framework Van Haaren, Harry
2017-07-03 19:13 ` [PATCH v2 00/34] " Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 01/34] app/testeventdev: introduce dpdk-test-eventdev application Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 02/34] app/testeventdev: define eventdev test ops Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 03/34] app/testeventdev: add eventdev test registration framework Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 04/34] app/testeventdev: add string parsing helpers Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 05/34] app/testeventdev: add common helper functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 06/34] app/testeventdev: define the test options Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 07/34] app/testeventdev: add helper functions to check options Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 08/34] app/testeventdev: add helper functions to dump options Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 09/34] app/testeventdev: update options through the command line Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 10/34] app/testeventdev: invoke the test ops Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 11/34] app/testeventdev: add the signal handler Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 12/34] app/testeventdev: order: add test setup and destroy Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 13/34] app/testeventdev: order: add basic functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 14/34] app/testeventdev: order: add eventdev port setup Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 15/34] app/testeventdev: order: launch lcores Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 16/34] app/testeventdev: add order queue test Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 17/34] app/testeventdev: order queue: add worker functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 18/34] app/testeventdev: add order "all types queue" test Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 19/34] app/testeventdev: perf: add test setup and destroy Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 20/34] app/testeventdev: perf: add basic functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 21/34] app/testeventdev: perf: add opt dump and check functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 22/34] app/testeventdev: perf: add eventdev port setup Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 23/34] app/testeventdev: perf: launch lcores Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 24/34] app/testeventdev: add perf queue test Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 25/34] app/testeventdev: perf queue: add worker functions Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 26/34] app/testeventdev: add perf "all types queue" test Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 27/34] app/testeventdev: perf: add "all type queue" worker function Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 28/34] doc: describe the new eventdev test application Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 29/34] doc/testeventdev: add "order queue" test details Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 30/34] doc/testeventdev: add "order all types " Jerin Jacob
2017-07-03 19:13   ` [PATCH v2 31/34] doc/testeventdev: add "perf " Jerin Jacob
2017-07-03 19:14   ` [PATCH v2 32/34] doc/testeventdev: add "perf all types " Jerin Jacob
2017-07-03 19:14   ` [PATCH v2 33/34] maintainers: claim responsibility for the eventdev test app Jerin Jacob
2017-07-03 19:14   ` [PATCH v2 34/34] doc: update release notes for dpdk-test-eventdev application Jerin Jacob
2017-07-04  4:52   ` [PATCH v3 00/34] introduce generic eventdev test application framework Jerin Jacob
2017-07-04  4:52     ` [PATCH v3 01/34] app/testeventdev: introduce dpdk-test-eventdev application Jerin Jacob
2017-07-04  4:52     ` [PATCH v3 02/34] app/testeventdev: define eventdev test ops Jerin Jacob
2017-07-04  4:52     ` [PATCH v3 03/34] app/testeventdev: add eventdev test registration framework Jerin Jacob
2017-07-04  4:52     ` [PATCH v3 04/34] app/testeventdev: add string parsing helpers Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 05/34] app/testeventdev: add common helper functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 06/34] app/testeventdev: define the test options Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 07/34] app/testeventdev: add helper functions to check options Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 08/34] app/testeventdev: add helper functions to dump options Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 09/34] app/testeventdev: update options through the command line Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 10/34] app/testeventdev: invoke the test ops Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 11/34] app/testeventdev: add the signal handler Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 12/34] app/testeventdev: order: add test setup and destroy Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 13/34] app/testeventdev: order: add basic functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 14/34] app/testeventdev: order: add eventdev port setup Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 15/34] app/testeventdev: order: launch lcores Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 16/34] app/testeventdev: add order queue test Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 17/34] app/testeventdev: order queue: add worker functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 18/34] app/testeventdev: add order "all types queue" test Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 19/34] app/testeventdev: perf: add test setup and destroy Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 20/34] app/testeventdev: perf: add basic functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 21/34] app/testeventdev: perf: add opt dump and check functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 22/34] app/testeventdev: perf: add eventdev port setup Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 23/34] app/testeventdev: perf: launch lcores Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 24/34] app/testeventdev: add perf queue test Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 25/34] app/testeventdev: perf queue: add worker functions Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 26/34] app/testeventdev: add perf "all types queue" test Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 27/34] app/testeventdev: perf: add "all type queue" worker function Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 28/34] doc: describe the new eventdev test application Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 29/34] doc/testeventdev: add "order queue" test details Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 30/34] doc/testeventdev: add "order all types " Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 31/34] doc/testeventdev: add "perf " Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 32/34] doc/testeventdev: add "perf all types " Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 33/34] maintainers: claim responsibility for the eventdev test app Jerin Jacob
2017-07-04  4:53     ` [PATCH v3 34/34] doc: update release notes for dpdk-test-eventdev application Jerin Jacob
2017-07-04 11:33       ` Mcnamara, John
2017-07-07  5:48     ` [PATCH v3 00/34] introduce generic eventdev test application framework Jerin Jacob

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=20170528195854.6064-26-jerin.jacob@caviumnetworks.com \
    --to=jerin.jacob@caviumnetworks.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    --cc=gage.eads@intel.com \
    --cc=gprathyusha@caviumnetworks.com \
    --cc=harry.van.haaren@intel.com \
    --cc=hemant.agrawal@nxp.com \
    --cc=narender.vangati@intel.com \
    --cc=nikhil.rao@intel.com \
    --cc=nipun.gupta@nxp.com \
    /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: link
Be 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.