| /* |
| * 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; |
| } |