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 948  
949 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 953 void dump_exec_info(FILE *f,
952 954 int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
953 955  
... ...
... ... @@ -1887,6 +1887,12 @@ int cpu_physical_memory_get_dirty_tracking(void)
1887 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 1896 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
1891 1897 {
1892 1898 ram_addr_t ram_addr;
... ...
hw/cirrus_vga.c
... ... @@ -31,6 +31,7 @@
31 31 #include "pci.h"
32 32 #include "console.h"
33 33 #include "vga_int.h"
  34 +#include "kvm.h"
34 35  
35 36 /*
36 37 * TODO:
... ... @@ -1228,6 +1229,12 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
1228 1229 }
1229 1230  
1230 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 1238 s->cirrus_bank_base[bank_index] = offset;
1232 1239 s->cirrus_bank_limit[bank_index] = limit;
1233 1240 } else {
... ... @@ -1356,6 +1363,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1356 1363 s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
1357 1364 break;
1358 1365 case 0x07: // Extended Sequencer Mode
  1366 + cirrus_update_memory_access(s);
1359 1367 case 0x08: // EEPROM Control
1360 1368 case 0x09: // Scratch Register 0
1361 1369 case 0x0a: // Scratch Register 1
... ... @@ -1528,6 +1536,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
1528 1536 s->gr[reg_index] = reg_value;
1529 1537 cirrus_update_bank_ptr(s, 0);
1530 1538 cirrus_update_bank_ptr(s, 1);
  1539 + cirrus_update_memory_access(s);
1531 1540 break;
1532 1541 case 0x0B:
1533 1542 s->gr[reg_index] = reg_value;
... ... @@ -2618,6 +2627,52 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
2618 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 2676 /* Compute the memory access functions */
2622 2677 static void cirrus_update_memory_access(CirrusVGAState *s)
2623 2678 {
... ... @@ -2636,11 +2691,13 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
2636 2691  
2637 2692 mode = s->gr[0x05] & 0x7;
2638 2693 if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
  2694 + map_linear_vram(s);
2639 2695 s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
2640 2696 s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
2641 2697 s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
2642 2698 } else {
2643 2699 generic_io:
  2700 + unmap_linear_vram(s);
2644 2701 s->cirrus_linear_write[0] = cirrus_linear_writeb;
2645 2702 s->cirrus_linear_write[1] = cirrus_linear_writew;
2646 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 3159 qemu_get_be32s(f, &s->hw_cursor_x);
3103 3160 qemu_get_be32s(f, &s->hw_cursor_y);
3104 3161  
  3162 + cirrus_update_memory_access(s);
3105 3163 /* force refresh */
3106 3164 s->graphic_mode = -1;
3107 3165 cirrus_update_bank_ptr(s, 0);
... ... @@ -3261,6 +3319,13 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
3261 3319 s->cirrus_linear_io_addr);
3262 3320 cpu_register_physical_memory(addr + 0x1000000, 0x400000,
3263 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 3331 static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
... ...
hw/vga.c
... ... @@ -28,6 +28,7 @@
28 28 #include "vga_int.h"
29 29 #include "pixel_ops.h"
30 30 #include "qemu-timer.h"
  31 +#include "kvm.h"
31 32  
32 33 //#define DEBUG_VGA
33 34 //#define DEBUG_VGA_MEM
... ... @@ -1243,6 +1244,8 @@ static void vga_draw_text(VGAState *s, int full_update)
1243 1244 vga_draw_glyph8_func *vga_draw_glyph8;
1244 1245 vga_draw_glyph9_func *vga_draw_glyph9;
1245 1246  
  1247 + vga_dirty_log_stop(s);
  1248 +
1246 1249 full_update |= update_palette16(s);
1247 1250 palette = s->last_palette;
1248 1251  
... ... @@ -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 1575 * graphic modes
1561 1576 */
... ... @@ -1570,6 +1585,9 @@ static void vga_draw_graphic(VGAState *s, int full_update)
1570 1585  
1571 1586 full_update |= update_basic_params(s);
1572 1587  
  1588 + if (!full_update)
  1589 + vga_sync_dirty_bitmap(s);
  1590 +
1573 1591 s->get_resolution(s, &width, &height);
1574 1592 disp_width = width;
1575 1593  
... ... @@ -1743,6 +1761,8 @@ static void vga_draw_blank(VGAState *s, int full_update)
1743 1761 return;
1744 1762 if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1745 1763 return;
  1764 + vga_dirty_log_stop(s);
  1765 +
1746 1766 if (ds_get_bits_per_pixel(s->ds) == 8)
1747 1767 val = s->rgb_to_pixel(0, 0, 0);
1748 1768 else
... ... @@ -2092,6 +2112,28 @@ typedef struct PCIVGAState {
2092 2112 VGAState vga_state;
2093 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 2137 static void vga_map(PCIDevice *pci_dev, int region_num,
2096 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 2144 } else {
2103 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 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 102 uint8_t *vram_ptr; \
103 103 ram_addr_t vram_offset; \
104 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 110 unsigned long bios_offset; \
106 111 unsigned int bios_size; \
107 112 target_phys_addr_t base_ctrl; \
... ... @@ -189,6 +194,10 @@ static inline int c6_to_8(int v)
189 194 void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
190 195 ram_addr_t vga_ram_offset, int vga_ram_size);
191 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 201 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
193 202 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
194 203 void vga_invalidate_scanlines(VGAState *s, int y1, int y2);
... ...