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
aom_accounting_hash(const char * str)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. */
aom_accounting_dictionary_lookup(Accounting * accounting,const char * str)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
aom_accounting_init(Accounting * accounting)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
aom_accounting_reset(Accounting * accounting)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
aom_accounting_clear(Accounting * accounting)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
aom_accounting_set_context(Accounting * accounting,int16_t x,int16_t y)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
aom_accounting_record(Accounting * accounting,const char * str,uint32_t bits)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
aom_accounting_dump(Accounting * accounting)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