Michael Bebenita | 6048d05 | 2016-08-25 14:40:54 -0700 | [diff] [blame] | 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 "./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 | int 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; |
Thomas Davies | f7f87ff | 2017-03-01 16:24:56 +0000 | [diff] [blame] | 69 | accounting->syms.num_binary_syms = 0; |
| 70 | accounting->syms.num_multi_syms = 0; |
Michael Bebenita | 6048d05 | 2016-08-25 14:40:54 -0700 | [diff] [blame] | 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; |
Thomas Davies | f7f87ff | 2017-03-01 16:24:56 +0000 | [diff] [blame] | 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); |
Michael Bebenita | 6048d05 | 2016-08-25 14:40:54 -0700 | [diff] [blame] | 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 | } |