VirtualBox

source: vbox/trunk/src/VBox/Main/include/USBIdDatabase.h@ 58016

Last change on this file since 58016 was 58016, checked in by vboxsync, 9 years ago

USBIdDatabase*: Size optimization reducing VBoxSVC by xxxx bytes on 64-bit Windows (debug) - just for the fun of it. :-)

  • Use parallel arrays instead of structures/classes with alignment padding (4 or 6 bytes on 64-bit hosts).
  • Exchanging the vendor id in the product table for a product table index and length in the vendor entry.
  • Use a string table with 32-bit references that includes the size.
  • The 32-bit references saves relocations.
  • The string table skips the terminator char, saving 1 byte per string.
  • The string table eliminates duplicate strings and duplicate substrings.
  • Very simple compression that replaces the 127 most frequently used words.
  • Replaced lower_bound with handcoded binary lookup (easier for parallel arrays, seems to reduce code size too).

Before:
VBoxSVC.exe w/ db: 10145792 bytes,
VBoxSVC.exe w/o db: 9436672 bytes,
Database cost: 709120 bytes.

After:
VBoxSVC.exe w/ db: 9797120 bytes
VBoxSVC.exe w/o db: 9439232 bytes
Database cost: 357888 bytes

Saving 351232 bytes (49%).

PS. Relocations saving estimated to be around 30987 bytes (a bit uncertain because of string pooling by the compiler / linker).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1/* $Id: USBIdDatabase.h 58016 2015-10-03 18:47:11Z vboxsync $ */
2/** @file
3 * USB device vendor and product ID database.
4 */
5
6/*
7 * Copyright (C) 2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ___USBIdDatabase_h
19#define ___USBIdDatabase_h
20
21#include <iprt/assert.h>
22#include <iprt/stdint.h>
23#include <iprt/cpp/ministring.h>
24
25
26/** Saves a few bytes (~25%) on strings. */
27#define USB_ID_DATABASE_WITH_COMPRESSION
28
29/** Max string length. */
30#define USB_ID_DATABASE_MAX_STRING _1K
31
32
33/**
34 * USB ID database string table reference.
35 */
36typedef struct USBIDDBSTR
37{
38 /** Offset of the string in the string table. */
39 uint32_t off : 22;
40 /** The length of the string. */
41 uint32_t cch : 10;
42} USBIDDBSTR;
43AssertCompileSize(USBIDDBSTR, sizeof(uint32_t));
44
45
46/**
47 * Elements of product table.
48 */
49typedef struct USBIDDBPROD
50{
51 /** Product ID. */
52 uint16_t idProduct;
53} USBIDDBPROD;
54AssertCompileSize(USBIDDBPROD, sizeof(uint16_t));
55
56
57/**
58 * Element of vendor table.
59 */
60typedef struct USBIDDBVENDOR
61{
62 /** Vendor ID. */
63 uint16_t idVendor;
64 /** Index of the first product. */
65 uint16_t iProduct;
66 /** Number of products. */
67 uint16_t cProducts;
68} USBIDDBVENDOR;
69AssertCompileSize(USBIDDBVENDOR, sizeof(uint16_t) * 3);
70
71
72/**
73 * Wrapper for static array of Aliases.
74 */
75class USBIdDatabase
76{
77public: // For assertions and statis in the generator.
78 /** String table. */
79 static const char s_achStrTab[];
80 /** The size of the string table (for bounds checking). */
81 static const size_t s_cchStrTab;
82#ifdef USB_ID_DATABASE_WITH_COMPRESSION
83 /** Dictionary containing the 127 most used substrings (that we managed
84 * to detect without lousy word based searching). */
85 static const USBIDDBSTR s_aCompDict[127];
86#endif
87
88 /** Number of vendors in the two parallel arrays. */
89 static const size_t s_cVendors;
90 /** Vendor IDs lookup table. */
91 static const USBIDDBVENDOR s_aVendors[];
92 /** Vendor names table running parallel to s_aVendors. */
93 static const USBIDDBSTR s_aVendorNames[];
94
95 /** Number of products in the two parallel arrays. */
96 static const size_t s_cProducts;
97 /** Vendor+Product keys for lookup purposes. */
98 static const USBIDDBPROD s_aProducts[];
99 /** Product names table running parallel to s_aProducts. */
100 static const USBIDDBSTR s_aProductNames[];
101
102public:
103 static RTCString returnString(USBIDDBSTR const *pStr)
104 {
105 Assert(pStr->cch < s_cchStrTab);
106 Assert(pStr->off < s_cchStrTab);
107 Assert(pStr->off + pStr->cch < s_cchStrTab);
108
109#ifdef USB_ID_DATABASE_WITH_COMPRESSION
110 char szTmp[USB_ID_DATABASE_MAX_STRING * 2];
111 char *pchDst = &szTmp[0];
112 size_t cchSrc = pStr->cch;
113 const char *pchSrc = &s_achStrTab[pStr->off];
114 Assert(cchSrc <= USB_ID_DATABASE_MAX_STRING);
115 while (cchSrc-- > 0)
116 {
117 unsigned char uch = *pchSrc++;
118 if (!(uch & 0x80))
119 {
120 *pchDst++ = (char)uch;
121 Assert(uch != 0);
122 Assert((uintptr_t)(pchDst - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING);
123 }
124 else if (uch == 0xff)
125 {
126 RTUNICP uc = ' ';
127 int rc = RTStrGetCpNEx(&pchSrc, &cchSrc, &uc);
128 AssertStmt(RT_SUCCESS(rc), (uc = '?', pchSrc++, cchSrc--));
129 pchDst = RTStrPutCp(pchDst, uc);
130 Assert((uintptr_t)(pchDst - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING);
131 }
132 else
133 {
134 /* Dictionary reference. No unescaping necessary here. */
135 const USBIDDBSTR *pStr2 = &s_aCompDict[uch & 0x7f];
136 Assert(pStr2->cch < s_cchStrTab);
137 Assert(pStr2->off < s_cchStrTab);
138 Assert(pStr2->off + pStr->cch < s_cchStrTab);
139 Assert((uintptr_t)(&pchDst[pStr2->cch] - &szTmp[0]) < USB_ID_DATABASE_MAX_STRING);
140 memcpy(pchDst, &s_achStrTab[pStr2->off], pStr2->cch);
141 pchDst += pStr2->cch;
142 }
143 }
144 *pchDst = '\0';
145 return RTCString(szTmp, pchDst - &szTmp[0]);
146#else /* !USB_ID_DATABASE_WITH_COMPRESSION */
147 return RTCString(&s_achStrTab[pStr->off], pStr->cch);
148#endif /* !USB_ID_DATABASE_WITH_COMPRESSION */
149 }
150
151private:
152 /**
153 * Performs a binary lookup of @a idVendor.
154 *
155 * @returns The index in the vendor tables, UINT32_MAX if not found.
156 * @param idVendor The vendor ID.
157 */
158 static uint32_t lookupVendor(uint16_t idVendor)
159 {
160 size_t iStart = 0;
161 size_t iEnd = s_cVendors;
162 for (;;)
163 {
164 size_t idx = iStart + (iEnd - iStart) / 2;
165 if (s_aVendors[idx].idVendor < idVendor)
166 {
167 idx++;
168 if (idx < iEnd)
169 iStart = idx;
170 else
171 return UINT32_MAX;
172 }
173 else if (s_aVendors[idx].idVendor > idVendor)
174 {
175 if (idx != iStart)
176 iEnd = idx;
177 else
178 return UINT32_MAX;
179 }
180 else
181 return (uint32_t)idx;
182 }
183 }
184
185 /**
186 * Performs a binary lookup of @a idProduct.
187 *
188 * @returns The index in the product tables, UINT32_MAX if not found.
189 * @param idProduct The product ID.
190 * @param iStart The index of the first entry for the vendor.
191 * @param iEnd The index of after the last entry.
192 */
193 static uint32_t lookupProduct(uint16_t idProduct, size_t iStart, size_t iEnd)
194 {
195 for (;;)
196 {
197 size_t idx = iStart + (iEnd - iStart) / 2;
198 if (s_aProducts[idx].idProduct < idProduct)
199 {
200 idx++;
201 if (idx < iEnd)
202 iStart = idx;
203 else
204 return UINT32_MAX;
205 }
206 else if (s_aProducts[idx].idProduct > idProduct)
207 {
208 if (idx != iStart)
209 iEnd = idx;
210 else
211 return UINT32_MAX;
212 }
213 else
214 return (uint32_t)idx;
215 }
216 }
217
218
219public:
220 static RTCString findProduct(uint16_t idVendor, uint16_t idProduct)
221 {
222 uint32_t idxVendor = lookupVendor(idVendor);
223 if (idxVendor != UINT32_MAX)
224 {
225 uint32_t idxProduct = lookupProduct(idProduct, s_aVendors[idxVendor].iProduct,
226 s_aVendors[idxVendor].iProduct + s_aVendors[idxVendor].cProducts);
227 if (idxProduct != UINT32_MAX)
228 return returnString(&s_aProductNames[idxProduct]);
229 }
230 return RTCString();
231 }
232
233 static RTCString findVendor(uint16_t idVendor)
234 {
235 uint32_t idxVendor = lookupVendor(idVendor);
236 if (idxVendor != UINT32_MAX)
237 return returnString(&s_aVendorNames[idxVendor]);
238 return RTCString();
239 }
240
241 static RTCString findVendorAndProduct(uint16_t idVendor, uint16_t idProduct, RTCString *pstrProduct)
242 {
243 uint32_t idxVendor = lookupVendor(idVendor);
244 if (idxVendor != UINT32_MAX)
245 {
246 uint32_t idxProduct = lookupProduct(idProduct, s_aVendors[idxVendor].iProduct,
247 s_aVendors[idxVendor].iProduct + s_aVendors[idxVendor].cProducts);
248 if (idxProduct != UINT32_MAX)
249 *pstrProduct = returnString(&s_aProductNames[idxProduct]);
250 else
251 pstrProduct->setNull();
252 return returnString(&s_aVendorNames[idxVendor]);
253 }
254 pstrProduct->setNull();
255 return RTCString();
256 }
257
258};
259
260
261#endif
262
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette