1 /* 2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved 3 * 4 * This source code is subject to the terms of the BSD 2 Clause License and 5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License 6 * was not distributed with this source code in the LICENSE file, you can 7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open 8 * Media Patent License 1.0 was not distributed with this source code in the 9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent. 10 */ 11 12 #include <assert.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include "aom/aom_integer.h" 18 #include "av1/decoder/accounting.h" 19 20 static int aom_accounting_hash(const char *str) { 21 uint32_t val; 22 const unsigned char *ustr; 23 val = 0; 24 ustr = (const unsigned char *)str; 25 /* This is about the worst hash one can design, but it should be good enough 26 here. */ 27 while (*ustr) val += *ustr++; 28 return val % AOM_ACCOUNTING_HASH_SIZE; 29 } 30 31 /* Dictionary lookup based on an open-addressing hash table. */ 32 int aom_accounting_dictionary_lookup(Accounting *accounting, const char *str) { 33 int hash; 34 size_t len; 35 AccountingDictionary *dictionary; 36 dictionary = &accounting->syms.dictionary; 37 hash = aom_accounting_hash(str); 38 while (accounting->hash_dictionary[hash] != -1) { 39 if (strcmp(dictionary->strs[accounting->hash_dictionary[hash]], str) == 0) { 40 return accounting->hash_dictionary[hash]; 41 } 42 hash++; 43 if (hash == AOM_ACCOUNTING_HASH_SIZE) hash = 0; 44 } 45 /* No match found. */ 46 assert(dictionary->num_strs + 1 < MAX_SYMBOL_TYPES); 47 accounting->hash_dictionary[hash] = dictionary->num_strs; 48 len = strlen(str); 49 dictionary->strs[dictionary->num_strs] = malloc(len + 1); 50 snprintf(dictionary->strs[dictionary->num_strs], len + 1, "%s", str); 51 dictionary->num_strs++; 52 return dictionary->num_strs - 1; 53 } 54 55 void aom_accounting_init(Accounting *accounting) { 56 int i; 57 accounting->num_syms_allocated = 1000; 58 accounting->syms.syms = 59 malloc(sizeof(AccountingSymbol) * accounting->num_syms_allocated); 60 accounting->syms.dictionary.num_strs = 0; 61 assert(AOM_ACCOUNTING_HASH_SIZE > 2 * MAX_SYMBOL_TYPES); 62 for (i = 0; i < AOM_ACCOUNTING_HASH_SIZE; i++) 63 accounting->hash_dictionary[i] = -1; 64 aom_accounting_reset(accounting); 65 } 66 67 void aom_accounting_reset(Accounting *accounting) { 68 accounting->syms.num_syms = 0; 69 accounting->syms.num_binary_syms = 0; 70 accounting->syms.num_multi_syms = 0; 71 accounting->context.x = -1; 72 accounting->context.y = -1; 73 accounting->last_tell_frac = 0; 74 } 75 76 void aom_accounting_clear(Accounting *accounting) { 77 int i; 78 AccountingDictionary *dictionary; 79 free(accounting->syms.syms); 80 dictionary = &accounting->syms.dictionary; 81 for (i = 0; i < dictionary->num_strs; i++) { 82 free(dictionary->strs[i]); 83 } 84 } 85 86 void aom_accounting_set_context(Accounting *accounting, int16_t x, int16_t y) { 87 accounting->context.x = x; 88 accounting->context.y = y; 89 } 90 91 void aom_accounting_record(Accounting *accounting, const char *str, 92 uint32_t bits) { 93 AccountingSymbol sym; 94 // Reuse previous symbol if it has the same context and symbol id. 95 if (accounting->syms.num_syms) { 96 AccountingSymbol *last_sym; 97 last_sym = &accounting->syms.syms[accounting->syms.num_syms - 1]; 98 if (memcmp(&last_sym->context, &accounting->context, 99 sizeof(AccountingSymbolContext)) == 0) { 100 uint32_t id; 101 id = aom_accounting_dictionary_lookup(accounting, str); 102 if (id == last_sym->id) { 103 last_sym->bits += bits; 104 last_sym->samples++; 105 return; 106 } 107 } 108 } 109 sym.context = accounting->context; 110 sym.samples = 1; 111 sym.bits = bits; 112 sym.id = aom_accounting_dictionary_lookup(accounting, str); 113 assert(sym.id <= 255); 114 if (accounting->syms.num_syms == accounting->num_syms_allocated) { 115 accounting->num_syms_allocated *= 2; 116 accounting->syms.syms = 117 realloc(accounting->syms.syms, 118 sizeof(AccountingSymbol) * accounting->num_syms_allocated); 119 assert(accounting->syms.syms != NULL); 120 } 121 accounting->syms.syms[accounting->syms.num_syms++] = sym; 122 } 123 124 void aom_accounting_dump(Accounting *accounting) { 125 int i; 126 AccountingSymbol *sym; 127 printf("\n----- Number of recorded syntax elements = %d -----\n", 128 accounting->syms.num_syms); 129 printf("----- Total number of symbol calls = %d (%d binary) -----\n", 130 accounting->syms.num_multi_syms + accounting->syms.num_binary_syms, 131 accounting->syms.num_binary_syms); 132 for (i = 0; i < accounting->syms.num_syms; i++) { 133 sym = &accounting->syms.syms[i]; 134 printf("%s x: %d, y: %d bits: %f samples: %d\n", 135 accounting->syms.dictionary.strs[sym->id], sym->context.x, 136 sym->context.y, (float)sym->bits / 8.0, sym->samples); 137 } 138 } 139