DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] mem: get physical address of any pointer
@ 2013-06-12  7:50 Thomas Monjalon
  2013-06-12 11:54 ` Olivier MATZ
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Monjalon @ 2013-06-12  7:50 UTC (permalink / raw)
  To: dev

From: Damien Millescamps <damien.millescamps@6wind.com>

Extract rte_mem_virt2phy() from find_physaddr().

This function permits to obtain the physical address of any
virtual address mapped to the current process calling this function.
Note that this function is very slow and shouldn't be called
after initialization to avoid a performance bottleneck.

Signed-off-by: Damien Millescamps <damien.millescamps@6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
---
 lib/librte_eal/common/include/rte_memory.h |    7 +++
 lib/librte_eal/linuxapp/eal/eal_memory.c   |   83 +++++++++++++++-------------
 2 files changed, 52 insertions(+), 38 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index bf843dc..eaf4cc9 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -70,6 +70,7 @@ enum rte_page_sizes {
 #ifndef __KERNEL__ /* so we can include this header in kernel modules */
 typedef uint64_t phys_addr_t; /**< Physical address definition. */
 #endif
+#define RTE_BAD_PHYS_ADDR ((phys_addr_t)-1)
 
 /**
  * Physical memory segment descriptor.
@@ -87,6 +88,12 @@ struct rte_memseg {
 	uint32_t nrank;             /**< Number of ranks. */
 } __attribute__((__packed__));
 
+/**
+ * Get physical address of any mapped virtual address in the current process.
+ * It is found by browsing the /proc/self/pagemap special file.
+ * The page won't be swappable anymore.
+ */
+phys_addr_t rte_mem_virt2phy(const void *virt);
 
 /**
  * Get the layout of the available physical memory.
diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c
index 30a955f..f1dd2e9 100644
--- a/lib/librte_eal/linuxapp/eal/eal_memory.c
+++ b/lib/librte_eal/linuxapp/eal/eal_memory.c
@@ -34,6 +34,7 @@
  *  version: DPDK.L.1.2.3-3
  */
 
+#define _FILE_OFFSET_BITS 64
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -266,53 +267,59 @@ unmap_all_hugepages_orig(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
 }
 
 /*
- * For each hugepage in hugepg_tbl, fill the physaddr value. We find
- * it by browsing the /proc/self/pagemap special file.
+ * Get physical address of any mapped virtual address in the current process.
  */
-static int
-find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+phys_addr_t
+rte_mem_virt2phy(const void *virt)
 {
-	int fd;
-	unsigned i;
+	int fdmem;
 	uint64_t page;
-	unsigned long virt_pfn;
-	int page_size;
+	off_t offset;
+	unsigned long virtual = (unsigned long)virt;
+	int page_size = getpagesize();
+	unsigned long aligned = (virtual & ~ (page_size - 1));
+
+	/* allocate page in physical memory and prevent from swapping */
+	mlock((void*)aligned, page_size);
+
+	fdmem = open("/proc/self/pagemap", O_RDONLY);
+	if (fdmem < 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		return RTE_BAD_PHYS_ADDR;
+	}
+	offset = (off_t) (virtual / page_size) * sizeof(uint64_t);
+	if (lseek(fdmem, offset, SEEK_SET) == (off_t) -1) {
+		RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	if (read(fdmem, &page, sizeof(uint64_t)) <= 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	close (fdmem);
 
-	/* standard page size */
-	page_size = getpagesize();
+	/* pfn (page frame number) are bits 0-54 (see pagemap.txt in Linux doc) */
+	return ((page & 0x7fffffffffffffULL) * page_size) + (virtual % page_size);
+}
 
-	fd = open("/proc/self/pagemap", O_RDONLY);
-	if (fd < 0) {
-		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s",
-			__func__, strerror(errno));
-		return -1;
-	}
+/*
+ * For each hugepage in hugepg_tbl, fill the physaddr value.
+ */
+static int
+find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+{
+	unsigned i;
 
 	for (i = 0; i < hpi->num_pages; i++) {
-		off_t offset;
-		virt_pfn = (unsigned long)hugepg_tbl[i].orig_va /
-			page_size;
-		offset = sizeof(uint64_t) * virt_pfn;
-		if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
-			RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
-			return -1;
-		}
-		if (read(fd, &page, sizeof(uint64_t)) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
+		hugepg_tbl[i].physaddr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
+		if (hugepg_tbl[i].physaddr == RTE_BAD_PHYS_ADDR)
 			return -1;
-		}
-
-		/*
-		 * the pfn (page frame number) are bits 0-54 (see
-		 * pagemap.txt in linux Documentation)
-		 */
-		hugepg_tbl[i].physaddr = ((page & 0x7fffffffffffffULL) * page_size);
 	}
-	close(fd);
 	return 0;
 }
 
-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [dpdk-dev] [PATCH] mem: get physical address of any pointer
  2013-06-12  7:50 [dpdk-dev] [PATCH] mem: get physical address of any pointer Thomas Monjalon
@ 2013-06-12 11:54 ` Olivier MATZ
  2013-06-12 15:24   ` Thomas Monjalon
  0 siblings, 1 reply; 5+ messages in thread
From: Olivier MATZ @ 2013-06-12 11:54 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

Please find some comments below.

 > +/**
 > + * Get physical address of any mapped virtual address in the current 
process.
 > + * It is found by browsing the /proc/self/pagemap special file.
 > + * The page won't be swappable anymore.
 > + */
 > +phys_addr_t rte_mem_virt2phy(const void *virt);
 >
 > [...]
 > -static int
 > -find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
 > +phys_addr_t
 > +rte_mem_virt2phy(const void *virt)
 >   {
 > [...]
 > +    /* allocate page in physical memory and prevent from swapping */
 > +    mlock((void*)aligned, page_size);

Should this function really do the mlock() ?

It's a bit confusing to have a function that looks like a "get"
that will change the status of the page.

Another approach that sounds more reasonnable to me is to let the
application does the mlock(), and have the rte_mem_virt2phy() return
RTE_BAD_PHYS_ADDR if the page is not locked in memory. This info
is well known from the /proc/self/pagemap.

Should we also rename virt2phy in virt2phys ?

Regards,
Olivier

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [dpdk-dev] [PATCH] mem: get physical address of any pointer
  2013-06-12 11:54 ` Olivier MATZ
@ 2013-06-12 15:24   ` Thomas Monjalon
  2013-06-12 15:35     ` Olivier MATZ
  0 siblings, 1 reply; 5+ messages in thread
From: Thomas Monjalon @ 2013-06-12 15:24 UTC (permalink / raw)
  To: dev

From: Damien Millescamps <damien.millescamps@6wind.com>

Extract rte_mem_virt2phy() from find_physaddr().

rte_mem_virt2phy() permits to obtain the physical address of any
virtual address mapped to the current process calling this function.
Note that this function is very slow and shouldn't be called
after initialization to avoid a performance bottleneck.

The memory must be locked with mlock(). The function rte_mem_lock_page()
is a mlock() helper that lock the whole page.

A better name would be rte_mem_virt2phys but rte_mem_virt2phy is more
consistent with rte_mempool_virt2phy.

Signed-off-by: Damien Millescamps <damien.millescamps@6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
---
 lib/librte_eal/common/include/rte_memory.h |   22 +++++++
 lib/librte_eal/linuxapp/eal/eal_memory.c   |   89 ++++++++++++++++------------
 2 files changed, 73 insertions(+), 38 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index bf843dc..d9d368b 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -70,6 +70,7 @@ enum rte_page_sizes {
 #ifndef __KERNEL__ /* so we can include this header in kernel modules */
 typedef uint64_t phys_addr_t; /**< Physical address definition. */
 #endif
+#define RTE_BAD_PHYS_ADDR ((phys_addr_t)-1)
 
 /**
  * Physical memory segment descriptor.
@@ -87,6 +88,27 @@ struct rte_memseg {
 	uint32_t nrank;             /**< Number of ranks. */
 } __attribute__((__packed__));
 
+/**
+ * Lock page in physical memory and prevent from swapping.
+ *
+ * @param virt
+ *   The virtual address.
+ * @return
+ *   0 on success, negative on error.
+ */
+int rte_mem_lock_page(const void *virt);
+
+/**
+ * Get physical address of any mapped virtual address in the current process.
+ * It is found by browsing the /proc/self/pagemap special file.
+ * The page must be locked.
+ *
+ * @param virt
+ *   The virtual address.
+ * @return
+ *   The physical address or RTE_BAD_PHYS_ADDR on error.
+ */
+phys_addr_t rte_mem_virt2phy(const void *virt);
 
 /**
  * Get the layout of the available physical memory.
diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c
index 30a955f..82467f3 100644
--- a/lib/librte_eal/linuxapp/eal/eal_memory.c
+++ b/lib/librte_eal/linuxapp/eal/eal_memory.c
@@ -34,6 +34,7 @@
  *  version: DPDK.L.1.2.3-3
  */
 
+#define _FILE_OFFSET_BITS 64
 #include <errno.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -265,54 +266,66 @@ unmap_all_hugepages_orig(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
 	return 0;
 }
 
+/* Lock page in physical memory and prevent from swapping. */
+int
+rte_mem_lock_page(const void *virt)
+{
+	unsigned long virtual = (unsigned long)virt;
+	int page_size = getpagesize();
+	unsigned long aligned = (virtual & ~ (page_size - 1));
+	return mlock((void*)aligned, page_size);
+}
+
 /*
- * For each hugepage in hugepg_tbl, fill the physaddr value. We find
- * it by browsing the /proc/self/pagemap special file.
+ * Get physical address of any mapped virtual address in the current process.
  */
-static int
-find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+phys_addr_t
+rte_mem_virt2phy(const void *virt)
 {
-	int fd;
-	unsigned i;
+	int fdmem;
 	uint64_t page;
-	unsigned long virt_pfn;
-	int page_size;
+	off_t offset;
+	unsigned long virtual = (unsigned long)virt;
+	int page_size = getpagesize();
+
+	fdmem = open("/proc/self/pagemap", O_RDONLY);
+	if (fdmem < 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		return RTE_BAD_PHYS_ADDR;
+	}
+	offset = (off_t) (virtual / page_size) * sizeof(uint64_t);
+	if (lseek(fdmem, offset, SEEK_SET) == (off_t) -1) {
+		RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	if (read(fdmem, &page, sizeof(uint64_t)) <= 0) {
+		RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s\n",
+		                  __func__, strerror(errno));
+		close(fdmem);
+		return RTE_BAD_PHYS_ADDR;
+	}
+	close (fdmem);
 
-	/* standard page size */
-	page_size = getpagesize();
+	/* pfn (page frame number) are bits 0-54 (see pagemap.txt in Linux doc) */
+	return ((page & 0x7fffffffffffffULL) * page_size) + (virtual % page_size);
+}
 
-	fd = open("/proc/self/pagemap", O_RDONLY);
-	if (fd < 0) {
-		RTE_LOG(ERR, EAL, "%s(): cannot open /proc/self/pagemap: %s",
-			__func__, strerror(errno));
-		return -1;
-	}
+/*
+ * For each hugepage in hugepg_tbl, fill the physaddr value.
+ */
+static int
+find_physaddr(struct hugepage *hugepg_tbl, struct hugepage_info *hpi)
+{
+	unsigned i;
 
 	for (i = 0; i < hpi->num_pages; i++) {
-		off_t offset;
-		virt_pfn = (unsigned long)hugepg_tbl[i].orig_va /
-			page_size;
-		offset = sizeof(uint64_t) * virt_pfn;
-		if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
-			RTE_LOG(ERR, EAL, "%s(): seek error in /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
-			return -1;
-		}
-		if (read(fd, &page, sizeof(uint64_t)) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): cannot read /proc/self/pagemap: %s",
-					__func__, strerror(errno));
-			close(fd);
+		hugepg_tbl[i].physaddr = rte_mem_virt2phy(hugepg_tbl[i].orig_va);
+		if (hugepg_tbl[i].physaddr == RTE_BAD_PHYS_ADDR)
 			return -1;
-		}
-
-		/*
-		 * the pfn (page frame number) are bits 0-54 (see
-		 * pagemap.txt in linux Documentation)
-		 */
-		hugepg_tbl[i].physaddr = ((page & 0x7fffffffffffffULL) * page_size);
 	}
-	close(fd);
 	return 0;
 }
 
-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [dpdk-dev] [PATCH] mem: get physical address of any pointer
  2013-06-12 15:24   ` Thomas Monjalon
@ 2013-06-12 15:35     ` Olivier MATZ
  2013-06-12 15:42       ` Thomas Monjalon
  0 siblings, 1 reply; 5+ messages in thread
From: Olivier MATZ @ 2013-06-12 15:35 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

On 06/12/2013 05:24 PM, Thomas Monjalon wrote:
> From: Damien Millescamps<damien.millescamps@6wind.com>
>
> Extract rte_mem_virt2phy() from find_physaddr().

Acked-by: Olivier Matz <olivier.matz@6wind.com>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [dpdk-dev] [PATCH] mem: get physical address of any pointer
  2013-06-12 15:35     ` Olivier MATZ
@ 2013-06-12 15:42       ` Thomas Monjalon
  0 siblings, 0 replies; 5+ messages in thread
From: Thomas Monjalon @ 2013-06-12 15:42 UTC (permalink / raw)
  To: dev

12/06/2013 17:35, Olivier MATZ :
> On 06/12/2013 05:24 PM, Thomas Monjalon wrote:
> > From: Damien Millescamps<damien.millescamps@6wind.com>
> > 
> > Extract rte_mem_virt2phy() from find_physaddr().
> 
> Acked-by: Olivier Matz <olivier.matz@6wind.com>

pushed

-- 
Thomas

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-06-12 15:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-12  7:50 [dpdk-dev] [PATCH] mem: get physical address of any pointer Thomas Monjalon
2013-06-12 11:54 ` Olivier MATZ
2013-06-12 15:24   ` Thomas Monjalon
2013-06-12 15:35     ` Olivier MATZ
2013-06-12 15:42       ` Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).