Commit 2bec46dc97571a3c34b18fe4ca198e7bfbdca41f

Authored by aliguori
1 parent 5832d1f2

vga optimization (Glauber Costa)

Hypervisors like KVM perform badly while doing mmio on
a loop, because it'll generate an exit on each access.
This is the case with VGA, which results in very bad
performance.

In this patch, we map the linear frame buffer as RAM,
make sure it has dirty region tracking enabled, and then
just let the region to be written.

Cleanups suggestions by:
  Stefano Stabellini <stefano.stabellini@eu.citrix.com>

Signed-off-by: Glauber Costa <glommer@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5793 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-all.h
@@ -948,6 +948,8 @@ int cpu_physical_memory_set_dirty_tracking(int enable); @@ -948,6 +948,8 @@ int cpu_physical_memory_set_dirty_tracking(int enable);
948 948
949 int cpu_physical_memory_get_dirty_tracking(void); 949 int cpu_physical_memory_get_dirty_tracking(void);
950 950
  951 +void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr);
  952 +
951 void dump_exec_info(FILE *f, 953 void dump_exec_info(FILE *f,
952 int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); 954 int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
953 955
@@ -1887,6 +1887,12 @@ int cpu_physical_memory_get_dirty_tracking(void) @@ -1887,6 +1887,12 @@ int cpu_physical_memory_get_dirty_tracking(void)
1887 return in_migration; 1887 return in_migration;
1888 } 1888 }
1889 1889
  1890 +void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
  1891 +{
  1892 + if (kvm_enabled())
  1893 + kvm_physical_sync_dirty_bitmap(start_addr, end_addr);
  1894 +}
  1895 +
1890 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) 1896 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1891 { 1897 {
1892 ram_addr_t ram_addr; 1898 ram_addr_t ram_addr;
hw/cirrus_vga.c
@@ -31,6 +31,7 @@ @@ -31,6 +31,7 @@
31 #include "pci.h" 31 #include "pci.h"
32 #include "console.h" 32 #include "console.h"
33 #include "vga_int.h" 33 #include "vga_int.h"
  34 +#include "kvm.h"
34 35
35 /* 36 /*
36 * TODO: 37 * TODO:
@@ -1228,6 +1229,12 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) @@ -1228,6 +1229,12 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
1228 } 1229 }
1229 1230
1230 if (limit > 0) { 1231 if (limit > 0) {
  1232 + /* Thinking about changing bank base? First, drop the dirty bitmap information
  1233 + * on the current location, otherwise we lose this pointer forever */
  1234 + if (s->lfb_vram_mapped) {
  1235 + target_phys_addr_t base_addr = isa_mem_base + 0xa0000 + bank_index * 0x8000;
  1236 + cpu_physical_sync_dirty_bitmap(base_addr, base_addr + 0x8000);
  1237 + }
1231 s->cirrus_bank_base[bank_index] = offset; 1238 s->cirrus_bank_base[bank_index] = offset;
1232 s->cirrus_bank_limit[bank_index] = limit; 1239 s->cirrus_bank_limit[bank_index] = limit;
1233 } else { 1240 } else {
@@ -1356,6 +1363,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) @@ -1356,6 +1363,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1356 s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5); 1363 s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
1357 break; 1364 break;
1358 case 0x07: // Extended Sequencer Mode 1365 case 0x07: // Extended Sequencer Mode
  1366 + cirrus_update_memory_access(s);
1359 case 0x08: // EEPROM Control 1367 case 0x08: // EEPROM Control
1360 case 0x09: // Scratch Register 0 1368 case 0x09: // Scratch Register 0
1361 case 0x0a: // Scratch Register 1 1369 case 0x0a: // Scratch Register 1
@@ -1528,6 +1536,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) @@ -1528,6 +1536,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1528 s->gr[reg_index] = reg_value; 1536 s->gr[reg_index] = reg_value;
1529 cirrus_update_bank_ptr(s, 0); 1537 cirrus_update_bank_ptr(s, 0);
1530 cirrus_update_bank_ptr(s, 1); 1538 cirrus_update_bank_ptr(s, 1);
  1539 + cirrus_update_memory_access(s);
1531 break; 1540 break;
1532 case 0x0B: 1541 case 0x0B:
1533 s->gr[reg_index] = reg_value; 1542 s->gr[reg_index] = reg_value;
@@ -2618,6 +2627,52 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { @@ -2618,6 +2627,52 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
2618 cirrus_linear_bitblt_writel, 2627 cirrus_linear_bitblt_writel,
2619 }; 2628 };
2620 2629
  2630 +static void map_linear_vram(CirrusVGAState *s)
  2631 +{
  2632 +
  2633 + if (!s->map_addr && s->lfb_addr && s->lfb_end) {
  2634 + s->map_addr = s->lfb_addr;
  2635 + s->map_end = s->lfb_end;
  2636 + cpu_register_physical_memory(s->map_addr, s->map_end - s->map_addr, s->vram_offset);
  2637 + vga_dirty_log_start((VGAState *)s);
  2638 + }
  2639 +
  2640 + if (!s->map_addr)
  2641 + return;
  2642 +
  2643 + s->lfb_vram_mapped = 0;
  2644 +
  2645 + if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
  2646 + && !((s->sr[0x07] & 0x01) == 0)
  2647 + && !((s->gr[0x0B] & 0x14) == 0x14)
  2648 + && !(s->gr[0x0B] & 0x02)) {
  2649 +
  2650 + cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
  2651 + (s->vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
  2652 + cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
  2653 + (s->vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
  2654 +
  2655 + s->lfb_vram_mapped = 1;
  2656 + vga_dirty_log_start((VGAState *)s);
  2657 + }
  2658 + else {
  2659 + cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, s->vga_io_memory);
  2660 + cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, s->vga_io_memory);
  2661 + }
  2662 +
  2663 +}
  2664 +
  2665 +static void unmap_linear_vram(CirrusVGAState *s)
  2666 +{
  2667 + if (s->map_addr && s->lfb_addr && s->lfb_end) {
  2668 + vga_dirty_log_stop((VGAState *)s);
  2669 + s->map_addr = s->map_end = 0;
  2670 + }
  2671 +
  2672 + cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
  2673 + s->vga_io_memory);
  2674 +}
  2675 +
2621 /* Compute the memory access functions */ 2676 /* Compute the memory access functions */
2622 static void cirrus_update_memory_access(CirrusVGAState *s) 2677 static void cirrus_update_memory_access(CirrusVGAState *s)
2623 { 2678 {
@@ -2636,11 +2691,13 @@ static void cirrus_update_memory_access(CirrusVGAState *s) @@ -2636,11 +2691,13 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
2636 2691
2637 mode = s->gr[0x05] & 0x7; 2692 mode = s->gr[0x05] & 0x7;
2638 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { 2693 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
  2694 + map_linear_vram(s);
2639 s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; 2695 s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
2640 s->cirrus_linear_write[1] = cirrus_linear_mem_writew; 2696 s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
2641 s->cirrus_linear_write[2] = cirrus_linear_mem_writel; 2697 s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
2642 } else { 2698 } else {
2643 generic_io: 2699 generic_io:
  2700 + unmap_linear_vram(s);
2644 s->cirrus_linear_write[0] = cirrus_linear_writeb; 2701 s->cirrus_linear_write[0] = cirrus_linear_writeb;
2645 s->cirrus_linear_write[1] = cirrus_linear_writew; 2702 s->cirrus_linear_write[1] = cirrus_linear_writew;
2646 s->cirrus_linear_write[2] = cirrus_linear_writel; 2703 s->cirrus_linear_write[2] = cirrus_linear_writel;
@@ -3102,6 +3159,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) @@ -3102,6 +3159,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
3102 qemu_get_be32s(f, &s->hw_cursor_x); 3159 qemu_get_be32s(f, &s->hw_cursor_x);
3103 qemu_get_be32s(f, &s->hw_cursor_y); 3160 qemu_get_be32s(f, &s->hw_cursor_y);
3104 3161
  3162 + cirrus_update_memory_access(s);
3105 /* force refresh */ 3163 /* force refresh */
3106 s->graphic_mode = -1; 3164 s->graphic_mode = -1;
3107 cirrus_update_bank_ptr(s, 0); 3165 cirrus_update_bank_ptr(s, 0);
@@ -3261,6 +3319,13 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num, @@ -3261,6 +3319,13 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
3261 s->cirrus_linear_io_addr); 3319 s->cirrus_linear_io_addr);
3262 cpu_register_physical_memory(addr + 0x1000000, 0x400000, 3320 cpu_register_physical_memory(addr + 0x1000000, 0x400000,
3263 s->cirrus_linear_bitblt_io_addr); 3321 s->cirrus_linear_bitblt_io_addr);
  3322 +
  3323 + s->map_addr = s->map_end = 0;
  3324 + s->lfb_addr = addr & TARGET_PAGE_MASK;
  3325 + s->lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
  3326 + /* account for overflow */
  3327 + if (s->lfb_end < addr + VGA_RAM_SIZE)
  3328 + s->lfb_end = addr + VGA_RAM_SIZE;
3264 } 3329 }
3265 3330
3266 static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, 3331 static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
hw/vga.c
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 #include "vga_int.h" 28 #include "vga_int.h"
29 #include "pixel_ops.h" 29 #include "pixel_ops.h"
30 #include "qemu-timer.h" 30 #include "qemu-timer.h"
  31 +#include "kvm.h"
31 32
32 //#define DEBUG_VGA 33 //#define DEBUG_VGA
33 //#define DEBUG_VGA_MEM 34 //#define DEBUG_VGA_MEM
@@ -1243,6 +1244,8 @@ static void vga_draw_text(VGAState *s, int full_update) @@ -1243,6 +1244,8 @@ static void vga_draw_text(VGAState *s, int full_update)
1243 vga_draw_glyph8_func *vga_draw_glyph8; 1244 vga_draw_glyph8_func *vga_draw_glyph8;
1244 vga_draw_glyph9_func *vga_draw_glyph9; 1245 vga_draw_glyph9_func *vga_draw_glyph9;
1245 1246
  1247 + vga_dirty_log_stop(s);
  1248 +
1246 full_update |= update_palette16(s); 1249 full_update |= update_palette16(s);
1247 palette = s->last_palette; 1250 palette = s->last_palette;
1248 1251
@@ -1556,6 +1559,18 @@ void vga_invalidate_scanlines(VGAState *s, int y1, int y2) @@ -1556,6 +1559,18 @@ void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
1556 } 1559 }
1557 } 1560 }
1558 1561
  1562 +static void vga_sync_dirty_bitmap(VGAState *s)
  1563 +{
  1564 + if (s->map_addr)
  1565 + cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
  1566 +
  1567 + if (s->lfb_vram_mapped) {
  1568 + cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
  1569 + cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
  1570 + }
  1571 + vga_dirty_log_start(s);
  1572 +}
  1573 +
1559 /* 1574 /*
1560 * graphic modes 1575 * graphic modes
1561 */ 1576 */
@@ -1570,6 +1585,9 @@ static void vga_draw_graphic(VGAState *s, int full_update) @@ -1570,6 +1585,9 @@ static void vga_draw_graphic(VGAState *s, int full_update)
1570 1585
1571 full_update |= update_basic_params(s); 1586 full_update |= update_basic_params(s);
1572 1587
  1588 + if (!full_update)
  1589 + vga_sync_dirty_bitmap(s);
  1590 +
1573 s->get_resolution(s, &width, &height); 1591 s->get_resolution(s, &width, &height);
1574 disp_width = width; 1592 disp_width = width;
1575 1593
@@ -1743,6 +1761,8 @@ static void vga_draw_blank(VGAState *s, int full_update) @@ -1743,6 +1761,8 @@ static void vga_draw_blank(VGAState *s, int full_update)
1743 return; 1761 return;
1744 if (s->last_scr_width <= 0 || s->last_scr_height <= 0) 1762 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1745 return; 1763 return;
  1764 + vga_dirty_log_stop(s);
  1765 +
1746 if (ds_get_bits_per_pixel(s->ds) == 8) 1766 if (ds_get_bits_per_pixel(s->ds) == 8)
1747 val = s->rgb_to_pixel(0, 0, 0); 1767 val = s->rgb_to_pixel(0, 0, 0);
1748 else 1768 else
@@ -2092,6 +2112,28 @@ typedef struct PCIVGAState { @@ -2092,6 +2112,28 @@ typedef struct PCIVGAState {
2092 VGAState vga_state; 2112 VGAState vga_state;
2093 } PCIVGAState; 2113 } PCIVGAState;
2094 2114
  2115 +void vga_dirty_log_start(VGAState *s)
  2116 +{
  2117 + if (kvm_enabled() && s->map_addr)
  2118 + kvm_log_start(s->map_addr, s->map_end - s->map_addr);
  2119 +
  2120 + if (kvm_enabled() && s->lfb_vram_mapped) {
  2121 + kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
  2122 + kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
  2123 + }
  2124 +}
  2125 +
  2126 +void vga_dirty_log_stop(VGAState *s)
  2127 +{
  2128 + if (kvm_enabled() && s->map_addr)
  2129 + kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
  2130 +
  2131 + if (kvm_enabled() && s->lfb_vram_mapped) {
  2132 + kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
  2133 + kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
  2134 + }
  2135 +}
  2136 +
2095 static void vga_map(PCIDevice *pci_dev, int region_num, 2137 static void vga_map(PCIDevice *pci_dev, int region_num,
2096 uint32_t addr, uint32_t size, int type) 2138 uint32_t addr, uint32_t size, int type)
2097 { 2139 {
@@ -2102,6 +2144,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num, @@ -2102,6 +2144,11 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
2102 } else { 2144 } else {
2103 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); 2145 cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
2104 } 2146 }
  2147 +
  2148 + s->map_addr = addr;
  2149 + s->map_end = addr + VGA_RAM_SIZE;
  2150 +
  2151 + vga_dirty_log_start(s);
2105 } 2152 }
2106 2153
2107 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 2154 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
hw/vga_int.h
@@ -102,6 +102,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s); @@ -102,6 +102,11 @@ typedef void (* vga_update_retrace_info_fn)(struct VGAState *s);
102 uint8_t *vram_ptr; \ 102 uint8_t *vram_ptr; \
103 ram_addr_t vram_offset; \ 103 ram_addr_t vram_offset; \
104 unsigned int vram_size; \ 104 unsigned int vram_size; \
  105 + uint32_t lfb_addr; \
  106 + uint32_t lfb_end; \
  107 + uint32_t map_addr; \
  108 + uint32_t map_end; \
  109 + uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */ \
105 unsigned long bios_offset; \ 110 unsigned long bios_offset; \
106 unsigned int bios_size; \ 111 unsigned int bios_size; \
107 target_phys_addr_t base_ctrl; \ 112 target_phys_addr_t base_ctrl; \
@@ -189,6 +194,10 @@ static inline int c6_to_8(int v) @@ -189,6 +194,10 @@ static inline int c6_to_8(int v)
189 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 194 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
190 ram_addr_t vga_ram_offset, int vga_ram_size); 195 ram_addr_t vga_ram_offset, int vga_ram_size);
191 void vga_init(VGAState *s); 196 void vga_init(VGAState *s);
  197 +
  198 +void vga_dirty_log_start(VGAState *s);
  199 +void vga_dirty_log_stop(VGAState *s);
  200 +
192 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); 201 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
193 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); 202 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
194 void vga_invalidate_scanlines(VGAState *s, int y1, int y2); 203 void vga_invalidate_scanlines(VGAState *s, int y1, int y2);