Skip to contentSkip to conversation

QEMU/KVM: large page support

PATCH In review Marcelo Tosatti 2 participants 4 messages Feb 23, 2008 KVM

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 QEMU/KVM: large page support

Add an option so the user can specify the hugetlbfs mounted path, with fallback to 4k pages on error.

Align the 4GB+ memslot on large page boundary.

qemu/hw/pc.c +9 -0
Index: kvm-userspace.gitpara/qemu/hw/pc.c
===================================================================
@@ -854,6 +854,15 @@ static void pc_init1(ram_addr_t ram_size
     /* above 4giga memory allocation */
     if (above_4g_mem_size > 0) {
         ram_addr = qemu_ram_alloc(above_4g_mem_size);
+	if (hpagesize) {
+		if (ram_addr & (hpagesize-1)) {
+			unsigned long aligned_addr;
+			aligned_addr = (ram_addr + hpagesize - 1) &
+					 ~(hpagesize-1);
+			qemu_ram_alloc(aligned_addr - ram_addr);
+			ram_addr = aligned_addr;
+		}
+	}
         cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr);
 
 	if (kvm_enabled())
qemu/sysemu.h +1 -0
Index: kvm-userspace.gitpara/qemu/sysemu.h
===================================================================
@@ -99,6 +99,7 @@ extern int no_quit;
 extern int semihosting_enabled;
 extern int autostart;
 extern int old_param;
+extern int hpagesize;
 extern const char *bootp_filename;
 
 
qemu/vl.c +98 -1

141 lines not on this page · raw message

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#1 lore raw

Hi Marcelo,

Quoted 15 lines · Marcelo Tosatti

Add an option so the user can specify the hugetlbfs mounted path, with fallback to 4k pages on error.

Align the 4GB+ memslot on large page boundary.

Index: kvm-userspace.gitpara/qemu/hw/pc.c
===================================================================

qemu/hw/pc.c +0 -0
@@ -854,6 +854,15 @@ static void pc_init1(ram_addr_t ram_size
     /* above 4giga memory allocation */
     if (above_4g_mem_size > 0) {
         ram_addr = qemu_ram_alloc(above_4g_mem_size);

qemu/hw/pc.c static void pc_init1(ram_addr_t ram_size · line 866

Quoted 10 lines
qemu/hw/pc.c +9 -0
+	if (hpagesize) {
+		if (ram_addr & (hpagesize-1)) {
+			unsigned long aligned_addr;
+			aligned_addr = (ram_addr + hpagesize - 1) &
+					 ~(hpagesize-1);
+			qemu_ram_alloc(aligned_addr - ram_addr);
+			ram_addr = aligned_addr;
+		}
+	}
 

In general, I don't think it causes any real harm if we always align the ram address to a large page boundary. If we aren't on Linux (and can't determine what the large page size is), we can just set hpagesize to getpagesize(). I think there's a good reason for this that I'll explain below.

Quoted 12 lines
qemu/hw/pc.c +11 -0
+
+void *alloc_huge_area(unsigned long memory, const char *path)
+{
+	void *area;
+	int fd;
+	char *filename;
+	char *tmpfile = "/kvm.XXXXXX";
+
+	filename = qemu_malloc(4096);
+	if (!filename) 
+		return NULL;

qemu/hw/pc.c static void pc_init1(ram_addr_t ram_size

Quoted 10 lines
qemu/hw/pc.c +10 -0
+
+	memset(filename, 0, 4096);
+	strncpy(filename, path, 4096 - strlen(tmpfile) - 1);
+	strcat(filename, tmpfile);
+	
+	hpagesize = gethugepagesize() * 1024;
+	if (!hpagesize)
+		return NULL;
+
+	mkstemp(filename);

mkstemp returns a file descriptor so the following open is not required.

qemu/hw/pc.c

Quoted 8 lines
qemu/hw/pc.c +7 -0
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		hpagesize = 0;
+		exit(0);
+	}
+	memory = (memory+hpagesize-1) & ~(hpagesize-1);

I'm a little surprised that hugetlbfs doesn't require an ftruncate() before the mmap(). Does an ftruncate() do any harm? If so, it would be better to have one.

qemu/hw/pc.c

Quoted 2 lines
qemu/hw/pc.c +1 -0
+	area = mmap(0, memory, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);

I think a MAP_SHARED may have some advantages in that it then becomes possible to pass this file descriptor around to other processes so they can mmap() the same memory region. I don't know if that works with hugetlbfs but it certainly does with tmpfs. My thinking is that this code can be made generic so it works with either hugetlbfs or tmpfs.

Furthermore, I think it would be interesting if we defaulted to trying to create the memory file in something like /dev/kvm-mem or something more appropriately named. An administrator can then either mount a hugetlbfs or tmpfs mount there. We still probably want to provide an option to override where to create the file and we want to be able to fall back to a normal malloc() of course but at least this makes it possible for the distros to set things up so that it Just Work without the user having to understand things like hugetlbfs and tmpfs.

Maybe we'll even see something that merges the two filesystems in the future so that if a huge page allocation fails, it falls back to creating a normal tmpfs file. Perhaps that's a reasonable mount option to add to hugetlbfs.

qemu/hw/pc.c

Quoted 9 lines
qemu/hw/pc.c +8 -0
+	if (area == MAP_FAILED) {
+		perror("mmap");
+		hpagesize = 0;
+		exit(0);
+	}
+
+	hugetlbfile = filename;
+	atexit(cleanup_hugetlb);

Instead of registering an atexit() handler, I think it would be better to unlink immediately after doing the mkstemp(). This reduces the possibility of leaking the file in the event of catastrophe (like a kill -SIGKILL).

Regards,

Anthony Liguori

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#2 lore raw

Hi Anthony,

Thanks for your comments.

Quoted 5 lines · Anthony Liguori

In general, I don't think it causes any real harm if we always align the ram address to a large page boundary. If we aren't on Linux (and can't determine what the large page size is), we can just set hpagesize to getpagesize(). I think there's a good reason for this that I'll explain below.

I thought about doing that (gets rid of the 4GB+ special casing) but we lose the ability to compact smaller allocations in a single largepage.

Right now the VGA BIOS and the BIOS fit in the same largepage, for example.

Quoted 16 lines
Quoted 16 lines
qemu/vl.c +16 -0
+
+void *alloc_huge_area(unsigned long memory, const char *path)
+{
+	void *area;
+	int fd;
+	char *filename;
+	char *tmpfile = "/kvm.XXXXXX";
+
+	filename = qemu_malloc(4096);
+	if (!filename) 
+		return NULL;
+
+	memset(filename, 0, 4096);
+	strncpy(filename, path, 4096 - strlen(tmpfile) - 1);
+	strcat(filename, tmpfile);
+	
Quoted 8 lines

qemu/vl.c void qemu_get_launch_info(int *argc, cha · line 8624

Quoted 6 lines
qemu/vl.c +5 -0
+	hpagesize = gethugepagesize() * 1024;
+	if (!hpagesize)
+		return NULL;
+
+	mkstemp(filename);

mkstemp returns a file descriptor so the following open is not required.

Right, will fix.

Quoted 4 lines
Quoted 4 lines
qemu/vl.c +4 -0
+	fd = open(filename, O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		hpagesize = 0;
Quoted 8 lines

qemu/vl.c void qemu_get_launch_info(int *argc, cha · line 8631

Quoted 4 lines
qemu/vl.c +3 -0
+		exit(0);
+	}
+	memory = (memory+hpagesize-1) & ~(hpagesize-1);

I'm a little surprised that hugetlbfs doesn't require an ftruncate() before the mmap(). Does an ftruncate() do any harm? If so, it would be better to have one.

Its not needed because hugetlbfs automatically adjusts the inode size on demand.

Don't think it will do any harm and its compliant with normal filesystems.

Quoted 8 lines

qemu/vl.c void qemu_get_launch_info(int *argc, cha · line 8633

Quoted 2 lines
qemu/vl.c +1 -0
+	area = mmap(0, memory, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);

I think a MAP_SHARED may have some advantages in that it then becomes possible to pass this file descriptor around to other processes so they can mmap() the same memory region. I don't know if that works with hugetlbfs but it certainly does with tmpfs. My thinking is that this code can be made generic so it works with either hugetlbfs or tmpfs.

Yes, makes sense.

Quoted 8 lines

Furthermore, I think it would be interesting if we defaulted to trying to create the memory file in something like /dev/kvm-mem or something more appropriately named. An administrator can then either mount a hugetlbfs or tmpfs mount there. We still probably want to provide an option to override where to create the file and we want to be able to fall back to a normal malloc() of course but at least this makes it possible for the distros to set things up so that it Just Work without the user having to understand things like hugetlbfs and tmpfs.

I like the idea. I'll change "-hugetlb-path" to "-mem-path" for now (and test it with tmpfs). Not so fond of hardcoding a path in QEMU though.

Quoted 9 lines

Maybe we'll even see something that merges the two filesystems in the future so that if a huge page allocation fails, it falls back to creating a normal tmpfs file. Perhaps that's a reasonable mount option to add to hugetlbfs.

Instead of registering an atexit() handler, I think it would be better to unlink immediately after doing the mkstemp(). This reduces the possibility of leaking the file in the event of catastrophe (like a kill -SIGKILL).

Right, will fix.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

#3 lore raw
Quoted 6 lines · Marcelo Tosatti

I thought about doing that (gets rid of the 4GB+ special casing) but we lose the ability to compact smaller allocations in a single largepage.

Right now the VGA BIOS and the BIOS fit in the same largepage, for example.

Ah, good point. I was actually talking about doing this adjustment for ram regardless of whether we're using large pages--not necessarily for all memory allocations. I saw no harm in doing this alignment even if we were using tmpfs and just getting 4k pages. Of course, I think we're in agreement here though :-)

Quoted 3 lines

I like the idea. I'll change "-hugetlb-path" to "-mem-path" for now (and test it with tmpfs). Not so fond of hardcoding a path in QEMU though.

If we had a unified tmpfs/hugetlbfs, I think it would make a lot of sense. I think I need to ask around though first and see how reasonable that is.

Regards,

Anthony Liguori

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/