blob: 0062189b5017a18aad8c3da57b6d244914a06622 [file] [log] [blame]
/*
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* aomedia.org/license/patent-license/.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "aom/aom_integer.h"
#include "av1/decoder/accounting.h"
static int accounting_hash(AccountingSymbolInfo *acct_info) {
uint32_t val;
const unsigned char *ustr;
val = 0;
ustr = (const unsigned char *)acct_info->c_file;
/* This is about the worst hash one can design, but it should be good enough
here. */
while (*ustr) val += *ustr++;
for (int i = 0; i < AOM_ACCOUNTING_MAX_TAGS; i++) {
if (acct_info->tags[i] == NULL) break;
ustr = (const unsigned char *)acct_info->tags[i];
while (*ustr) val += *ustr++;
}
val += acct_info->c_line;
return val % AOM_ACCOUNTING_HASH_SIZE;
}
int tags_equal(AccountingSymbolInfo *a, AccountingSymbolInfo *b) {
for (int i = 0; i < AOM_ACCOUNTING_MAX_TAGS; i++) {
if (a->tags[i] == NULL && b->tags[i] != NULL) return 0;
if (a->tags[i] != NULL && b->tags[i] == NULL) return 0;
if (a->tags[i] != b->tags[i]) {
if (strcmp(a->tags[i], b->tags[i]) != 0) {
return 0;
}
}
}
return 1;
}
/* Dictionary lookup based on an open-addressing hash table. */
int aom_accounting_dictionary_lookup(Accounting *accounting,
AccountingSymbolInfo *acct_info) {
int hash;
AccountingDictionary *dictionary;
dictionary = &accounting->syms.dictionary;
hash = accounting_hash(acct_info);
while (accounting->hash_dictionary[hash] != -1) {
if (strcmp(dictionary->acct_infos[accounting->hash_dictionary[hash]].c_file,
acct_info->c_file) == 0 &&
dictionary->acct_infos[accounting->hash_dictionary[hash]].c_line ==
acct_info->c_line &&
tags_equal(&dictionary->acct_infos[accounting->hash_dictionary[hash]],
acct_info)) {
return accounting->hash_dictionary[hash];
}
hash++;
if (hash == AOM_ACCOUNTING_HASH_SIZE) hash = 0;
}
/* No match found. */
assert(dictionary->num_strs + 1 < MAX_SYMBOL_TYPES);
accounting->hash_dictionary[hash] = dictionary->num_strs;
dictionary->acct_infos[dictionary->num_strs] = *acct_info;
dictionary->num_strs++;
return dictionary->num_strs - 1;
}
void aom_accounting_init(Accounting *accounting) {
int i;
accounting->num_syms_allocated = 1000;
accounting->syms.syms =
malloc(sizeof(AccountingSymbol) * accounting->num_syms_allocated);
accounting->syms.dictionary.num_strs = 0;
assert(AOM_ACCOUNTING_HASH_SIZE > 2 * MAX_SYMBOL_TYPES);
for (i = 0; i < AOM_ACCOUNTING_HASH_SIZE; i++)
accounting->hash_dictionary[i] = -1;
aom_accounting_reset(accounting);
}
void aom_accounting_reset(Accounting *accounting) {
accounting->syms.num_syms = 0;
accounting->syms.num_binary_syms = 0;
accounting->syms.num_multi_syms = 0;
accounting->syms.num_bypass_coded = 0;
accounting->syms.num_ctx_coded = 0;
accounting->context.x = -1;
accounting->context.y = -1;
accounting->last_tell_frac = 0;
}
void aom_accounting_clear(Accounting *accounting) {
free(accounting->syms.syms);
}
void aom_accounting_set_context(Accounting *accounting, int16_t x, int16_t y,
TREE_TYPE tree_type) {
accounting->context.x = x;
accounting->context.y = y;
accounting->context.tree_type = tree_type;
}
void aom_accounting_record(Accounting *accounting, int value,
SYMBOL_CODING_MODE coding_mode,
AccountingSymbolInfo acct_info, uint64_t bits) {
AccountingSymbol sym;
sym.context = accounting->context;
sym.value = value;
sym.coding_mode = coding_mode;
sym.bits = bits;
sym.id = aom_accounting_dictionary_lookup(accounting, &acct_info);
assert(sym.id <= 255);
if (accounting->syms.num_syms == accounting->num_syms_allocated) {
accounting->num_syms_allocated *= 2;
accounting->syms.syms =
realloc(accounting->syms.syms,
sizeof(AccountingSymbol) * accounting->num_syms_allocated);
assert(accounting->syms.syms != NULL);
}
accounting->syms.syms[accounting->syms.num_syms++] = sym;
}
void aom_accounting_dump(Accounting *accounting) {
int i;
AccountingSymbol *sym;
printf("\n----- Number of recorded syntax elements = %d -----\n",
accounting->syms.num_syms);
printf("----- Total number of symbol calls = %d (%d binary) -----\n",
accounting->syms.num_multi_syms + accounting->syms.num_binary_syms,
accounting->syms.num_binary_syms);
for (i = 0; i < accounting->syms.num_syms; i++) {
sym = &accounting->syms.syms[i];
printf("%s x: %d, y: %d, tree: %d, bits: %f value: %d\n",
accounting->syms.dictionary.acct_infos[sym->id].c_func,
sym->context.x, sym->context.y, sym->context.tree_type,
(double)sym->bits / (double)(1 << AOM_ACCT_BITRES), 1);
}
}
AccountingSymbolInfo aom_accounting_make_info(
const char *c_func, const char *c_file, int c_line, const char *tag0,
const char *tag1, const char *tag2, const char *tag3) {
AccountingSymbolInfo info = {
.c_func = c_func,
.c_file = c_file,
.c_line = c_line,
.tags = { tag0, tag1, tag2, tag3 },
};
return info;
}