qcow2: reuse cluster data for adjacent sectors (speed up ~30%)
This commit is contained in:
@@ -37,6 +37,7 @@ struct vdisk_qcow2 {
|
|||||||
size_t l1_size;
|
size_t l1_size;
|
||||||
uint64_t sector_idx_mask;
|
uint64_t sector_idx_mask;
|
||||||
uint64_t *l1;
|
uint64_t *l1;
|
||||||
|
uint64_t prev_cluster_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define QCOW2_MAGIC "QFI\xfb"
|
#define QCOW2_MAGIC "QFI\xfb"
|
||||||
@@ -100,6 +101,14 @@ qcow2_read_guest_sector(struct vdisk_qcow2 *d, uint64_t sector, uint8_t *buf) {
|
|||||||
uint64_t l1_entry = d->l1[l1_index];
|
uint64_t l1_entry = d->l1[l1_index];
|
||||||
uint64_t l2_entry;
|
uint64_t l2_entry;
|
||||||
|
|
||||||
|
if (cluster_index == d->prev_cluster_index) {
|
||||||
|
memcpy(buf,
|
||||||
|
d->cluster + (sector & d->sector_idx_mask) * d->vdisk.sect_size,
|
||||||
|
d->vdisk.sect_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->prev_cluster_index = cluster_index;
|
||||||
|
|
||||||
uint64_t l2_table_offset = l1_entry & L1_ENTRY_OFFSET_MASK;
|
uint64_t l2_table_offset = l1_entry & L1_ENTRY_OFFSET_MASK;
|
||||||
if (!l2_table_offset) {
|
if (!l2_table_offset) {
|
||||||
memset(buf, 0, d->vdisk.sect_size);
|
memset(buf, 0, d->vdisk.sect_size);
|
||||||
@@ -126,9 +135,6 @@ qcow2_read_guest_sector(struct vdisk_qcow2 *d, uint64_t sector, uint8_t *buf) {
|
|||||||
strerror(errno));
|
strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(buf,
|
|
||||||
d->cluster + (sector & d->sector_idx_mask) * d->vdisk.sect_size,
|
|
||||||
d->vdisk.sect_size);
|
|
||||||
} else {
|
} else {
|
||||||
off_t cmp_offset = d->l2_entry_cmp_offset_mask & l2_entry;
|
off_t cmp_offset = d->l2_entry_cmp_offset_mask & l2_entry;
|
||||||
printf("cmp_offset: 0x%" PRIx64 "\n", cmp_offset);
|
printf("cmp_offset: 0x%" PRIx64 "\n", cmp_offset);
|
||||||
@@ -143,11 +149,11 @@ qcow2_read_guest_sector(struct vdisk_qcow2 *d, uint64_t sector, uint8_t *buf) {
|
|||||||
}
|
}
|
||||||
unsigned long dest_size = d->cluster_size;
|
unsigned long dest_size = d->cluster_size;
|
||||||
uncompress(d->cluster, &dest_size, d->cmp_cluster, cmp_size);
|
uncompress(d->cluster, &dest_size, d->cmp_cluster, cmp_size);
|
||||||
|
}
|
||||||
memcpy(buf,
|
memcpy(buf,
|
||||||
d->cluster + (sector & d->sector_idx_mask) * d->vdisk.sect_size,
|
d->cluster + (sector & d->sector_idx_mask) * d->vdisk.sect_size,
|
||||||
d->vdisk.sect_size);
|
d->vdisk.sect_size);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
STDCALL void
|
STDCALL void
|
||||||
vdisk_qcow2_close(void *userdata) {
|
vdisk_qcow2_close(void *userdata) {
|
||||||
@@ -194,18 +200,19 @@ struct vdisk*
|
|||||||
vdisk_init_qcow2(const char *fname, struct umka_io *io) {
|
vdisk_init_qcow2(const char *fname, struct umka_io *io) {
|
||||||
struct vdisk_qcow2 *d =
|
struct vdisk_qcow2 *d =
|
||||||
(struct vdisk_qcow2*)calloc(1, sizeof(struct vdisk_qcow2));
|
(struct vdisk_qcow2*)calloc(1, sizeof(struct vdisk_qcow2));
|
||||||
d->vdisk.diskfunc = (diskfunc_t) {.strucsize = sizeof(diskfunc_t),
|
|
||||||
.close = vdisk_qcow2_close,
|
|
||||||
.read = vdisk_qcow2_read,
|
|
||||||
.write = vdisk_qcow2_write,
|
|
||||||
};
|
|
||||||
d->vdisk.io = io;
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
fprintf(stderr, "[vdisk.qcow2] can't allocate memory: %s\n",
|
fprintf(stderr, "[vdisk.qcow2] can't allocate memory: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->vdisk.diskfunc = (diskfunc_t) {.strucsize = sizeof(diskfunc_t),
|
||||||
|
.close = vdisk_qcow2_close,
|
||||||
|
.read = vdisk_qcow2_read,
|
||||||
|
.write = vdisk_qcow2_write,
|
||||||
|
};
|
||||||
|
d->vdisk.io = io;
|
||||||
|
d->prev_cluster_index = ~(uint64_t)0;
|
||||||
if (!(d->fd = open(fname, O_RDONLY))) {
|
if (!(d->fd = open(fname, O_RDONLY))) {
|
||||||
fprintf(stderr, "[vdisk.qcow2] can't open file '%s': %s\n", fname,
|
fprintf(stderr, "[vdisk.qcow2] can't open file '%s': %s\n", fname,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
Reference in New Issue
Block a user