Optimize to use decode buffer pool (#1890)
* Optimize to use decode buffer poll * Drop unnecessary logging * Refine * Update app/src/main/cpp/archive.c Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com> --------- Co-authored-by: Dude so hot <djohn@fbi.gov> Co-authored-by: FooIbar <118464521+FooIbar@users.noreply.github.com>
This commit is contained in:
1 file changed
+49
-57
+49
-57
@@ -49,28 +49,21 @@ typedef struct {
|
||||
void *addr;
|
||||
} entry;
|
||||
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static archive_ctx **ctx_pool = NULL;
|
||||
#define CTX_POOL_SIZE 20
|
||||
#define MAX_PARALLEL_DECOMP 4
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static void *mempool = MAP_FAILED;
|
||||
static size_t *mempoolofs = NULL;
|
||||
static int page_size = 0;
|
||||
|
||||
#define PAGE_ALIGN(x) ((x + page_size - 1) & ~(page_size - 1))
|
||||
|
||||
#define MEMPOOL_ADDR_BY_SORTED_IDX(x) (mempool + (index ? mempoolofs[index - 1] : 0))
|
||||
#define MEMPOOL_SIZE (mempoolofs[entryCount - 1])
|
||||
|
||||
#define PROT_RW (PROT_WRITE | PROT_READ)
|
||||
#define MAP_ANON_POOL (MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE)
|
||||
|
||||
static pthread_mutex_t ctx_pool_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static archive_ctx **ctx_pool = NULL;
|
||||
static pthread_mutex_t buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void *decode_buffer[MAX_PARALLEL_DECOMP];
|
||||
static bool need_encrypt = false;
|
||||
static char *passwd = NULL;
|
||||
static void *archiveAddr = MAP_FAILED;
|
||||
static size_t archiveSize = 0;
|
||||
static entry *entries = NULL;
|
||||
static size_t entryCount = 0;
|
||||
static ssize_t max_file_size = 0;
|
||||
|
||||
const char supportExt[10][6] = {
|
||||
"jpeg",
|
||||
@@ -130,7 +123,7 @@ static bool fill_entry_zero_copy(struct archive *arc, entry *entry) {
|
||||
return zero_copy;
|
||||
}
|
||||
|
||||
static bool archive_map_entries_index(archive_ctx *ctx, bool sort) {
|
||||
static void archive_map_entries_index(archive_ctx *ctx, bool sort) {
|
||||
int count = 0;
|
||||
bool zero_copy = true;
|
||||
while (archive_read_next_header(ctx->arc, &ctx->entry) == ARCHIVE_OK) {
|
||||
@@ -138,40 +131,44 @@ static bool archive_map_entries_index(archive_ctx *ctx, bool sort) {
|
||||
if (archive_entry_is_file(ctx->entry) && filename_is_playable_file(name)) {
|
||||
entries[count].filename = strdup(name);
|
||||
entries[count].index = count;
|
||||
entries[count].size = archive_entry_size(ctx->entry);
|
||||
ssize_t size = archive_entry_size(ctx->entry);
|
||||
max_file_size = max(size, max_file_size);
|
||||
entries[count].size = size;
|
||||
// We don't expect zero copy if first content can't do zero copy
|
||||
if (zero_copy) zero_copy = fill_entry_zero_copy(ctx->arc, &entries[count]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (sort) qsort(entries, entryCount, sizeof(entry), compare_entries);
|
||||
return zero_copy;
|
||||
}
|
||||
|
||||
static void archive_prealloc_mempool() {
|
||||
mempoolofs = calloc(entryCount, sizeof(size_t));
|
||||
for (int i = 0; i < entryCount; ++i) {
|
||||
mempoolofs[i] = PAGE_ALIGN(entries[i].size) + (i ? mempoolofs[i - 1] : 0);
|
||||
}
|
||||
mempool = mmap(0, MEMPOOL_SIZE, PROT_RW, MAP_ANON_POOL, -1, 0);
|
||||
if (mempool == MAP_FAILED) {
|
||||
LOGE("%s%s", "mmap failed with error ", strerror(errno));
|
||||
abort();
|
||||
static void *acquire_decode_buffer() {
|
||||
void *addr = NULL;
|
||||
pthread_mutex_lock(&buffer_mutex);
|
||||
for (int i = 0; i < MAX_PARALLEL_DECOMP; ++i) {
|
||||
addr = decode_buffer[i];
|
||||
if (addr) {
|
||||
decode_buffer[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&buffer_mutex);
|
||||
if (!addr) addr = malloc(max_file_size);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void mempool_release_pages(void *addr, size_t size) {
|
||||
size = PAGE_ALIGN(size);
|
||||
madvise_log_if_error(addr, size, MADV_DONTNEED);
|
||||
}
|
||||
|
||||
static bool kernel_can_prefault = true;
|
||||
|
||||
static void mempool_prefault_pages(void *addr, size_t size) {
|
||||
size = PAGE_ALIGN(size);
|
||||
if (kernel_can_prefault) {
|
||||
if (madvise(addr, size, MADV_POPULATE_WRITE)) kernel_can_prefault = false;
|
||||
static void release_decode_buffer(void *buffer) {
|
||||
pthread_mutex_lock(&buffer_mutex);
|
||||
for (int i = 0; i < MAX_PARALLEL_DECOMP; ++i) {
|
||||
void *addr = decode_buffer[i];
|
||||
if (!addr) {
|
||||
decode_buffer[i] = buffer;
|
||||
pthread_mutex_unlock(&buffer_mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&buffer_mutex);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static int archive_list_all_entries(archive_ctx *ctx) {
|
||||
@@ -227,7 +224,7 @@ static int archive_skip_to_index(archive_ctx *ctx, int index) {
|
||||
static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
|
||||
int ret;
|
||||
archive_ctx *ctx = NULL;
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_mutex_lock(&ctx_pool_mutex);
|
||||
for (int i = 0; i < CTX_POOL_SIZE; i++) {
|
||||
if (!ctx_pool[i])
|
||||
continue;
|
||||
@@ -242,14 +239,14 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
|
||||
}
|
||||
if (ctx)
|
||||
ctx->using = 1;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
pthread_mutex_unlock(&ctx_pool_mutex);
|
||||
|
||||
if (!ctx) {
|
||||
archive_ctx *victimCtx = NULL;
|
||||
int victimIdx = 0;
|
||||
int replace = 1;
|
||||
ctx = archive_alloc_ctx();
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_mutex_lock(&ctx_pool_mutex);
|
||||
for (int i = 0; i < CTX_POOL_SIZE; i++) {
|
||||
if (!ctx_pool[i]) {
|
||||
ctx_pool[i] = ctx;
|
||||
@@ -264,7 +261,7 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
|
||||
}
|
||||
}
|
||||
if (replace) ctx_pool[victimIdx] = ctx;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
pthread_mutex_unlock(&ctx_pool_mutex);
|
||||
if (replace) archive_release_ctx(victimCtx);
|
||||
}
|
||||
ret = archive_skip_to_index(ctx, idx);
|
||||
@@ -282,7 +279,6 @@ JNIEXPORT jint JNICALL
|
||||
Java_com_hippo_ehviewer_jni_ArchiveKt_openArchive(JNIEnv *env, jclass thiz, jint fd, jlong size, jboolean sort_entries) {
|
||||
EH_UNUSED(env);
|
||||
EH_UNUSED(thiz);
|
||||
page_size = getpagesize();
|
||||
archive_ctx *ctx = NULL;
|
||||
archiveAddr = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (archiveAddr == MAP_FAILED) {
|
||||
@@ -327,10 +323,8 @@ Java_com_hippo_ehviewer_jni_ArchiveKt_openArchive(JNIEnv *env, jclass thiz, jint
|
||||
|
||||
ctx = archive_alloc_ctx();
|
||||
entries = calloc(entryCount, sizeof(entry));
|
||||
bool fully_zero_copy = archive_map_entries_index(ctx, sort_entries);
|
||||
archive_map_entries_index(ctx, sort_entries);
|
||||
archive_release_ctx(ctx);
|
||||
|
||||
if (!fully_zero_copy) archive_prealloc_mempool();
|
||||
return (int) entryCount;
|
||||
}
|
||||
|
||||
@@ -343,11 +337,9 @@ Java_com_hippo_ehviewer_jni_ArchiveKt_extractToByteBuffer(JNIEnv *env, jclass th
|
||||
if (entry->addr) {
|
||||
return (*env)->NewDirectByteBuffer(env, entry->addr, size);
|
||||
} else {
|
||||
void *addr = MEMPOOL_ADDR_BY_SORTED_IDX(index);
|
||||
index = entry->index;
|
||||
archive_ctx *ctx = NULL;
|
||||
if (!archive_get_ctx(&ctx, index)) {
|
||||
mempool_prefault_pages(addr, size);
|
||||
if (!archive_get_ctx(&ctx, entry->index)) {
|
||||
void *addr = acquire_decode_buffer();
|
||||
ssize_t bytes = archive_read_data(ctx->arc, addr, size);
|
||||
ctx->using = 0;
|
||||
if (bytes == size) {
|
||||
@@ -359,7 +351,7 @@ Java_com_hippo_ehviewer_jni_ArchiveKt_extractToByteBuffer(JNIEnv *env, jclass th
|
||||
LOGE("%s", "No enough data read, WTF?");
|
||||
}
|
||||
}
|
||||
mempool_release_pages(addr, size);
|
||||
release_decode_buffer(addr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -382,12 +374,11 @@ Java_com_hippo_ehviewer_jni_ArchiveKt_closeArchive(JNIEnv *env, jclass thiz) {
|
||||
munmap(archiveAddr, archiveSize);
|
||||
archiveAddr = MAP_FAILED;
|
||||
}
|
||||
if (mempool != MAP_FAILED) {
|
||||
munmap(mempool, MEMPOOL_SIZE);
|
||||
mempool = MAP_FAILED;
|
||||
for (int i = 0; i < MAX_PARALLEL_DECOMP; ++i) {
|
||||
free(decode_buffer[i]);
|
||||
decode_buffer[i] = NULL;
|
||||
}
|
||||
free(mempoolofs);
|
||||
mempoolofs = NULL;
|
||||
max_file_size = 0;
|
||||
if (entries) {
|
||||
for (int i = 0; i < entryCount; ++i) {
|
||||
free((void *) entries[i].filename);
|
||||
@@ -458,8 +449,9 @@ JNIEXPORT void JNICALL
|
||||
Java_com_hippo_ehviewer_jni_ArchiveKt_releaseByteBuffer(JNIEnv *env, jclass thiz, jobject buffer) {
|
||||
EH_UNUSED(thiz);
|
||||
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
|
||||
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
|
||||
if (!ADDR_IN_FILE_MAPPING(addr)) mempool_release_pages(addr, size);
|
||||
if (!ADDR_IN_FILE_MAPPING(addr)) {
|
||||
release_decode_buffer(addr);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
|
||||
Reference in new issue
Block a user