|  | /* | 
|  | * 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.context_switch = 0; | 
|  | accounting->syms.total_hits = 0; | 
|  | accounting->syms.prev_context_id = NULL; | 
|  | accounting->syms.num_ctx_coded = 0; | 
|  | accounting->syms.num_symlen_minus1 = 0; | 
|  | accounting->syms.num_ctx_log2 = 0; | 
|  | accounting->syms.num_bypass_log2 = 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; | 
|  | } |