[PATCH v2 2/2] lib/uuid.c: eliminate uuid_[bl]e_index arrays

From: George Spelvin
Date: Sat Jun 04 2016 - 01:15:00 EST


Both input and output code is simplified if we use a mapping from binary
UUID index to ASCII UUID position. This lets us combine hyphen-skipping
and endian-swapping into one table.

This significantly simplifies __uuid_to_bin(), which was using *two*
lookup tables.

uuid_[bl]e_index were EXPORT_SYMBOLed for no obvious reason; all users are
compiled unconditionally into the kernel. The replacement uuid_[bl]e_pos
arrays are not exported until a need appears.

Benefits:
* The source code is shorter and simpler,
* it executes faster,
* initialized data is 16 bytes smaller, and
* compiled code is smaller.

Since this is not hot code, the important benchmark is not run time
but code size:

uuid_string() __uuid_to_bin()
Before After Delta Percent Before After Delta Percent
x86-32 199 196 -3 -1.5% 122 90 -32 -26.2%
x86-64 186 162 -24 -12.9% 127 90 -37 -29.1%
arm 264 216 -48 -18.2% 116 92 -24 -20.7%
thumb 160 136 -24 -15.0% 100 50 -50 -50.0%
arm64 244 188 -56 -23.0% 148 116 -32 -21.6%

Signed-off-by: George Spelvin <linux@xxxxxxxxxxx>
---
include/linux/uuid.h | 5 +++--
lib/uuid.c | 24 +++++++++---------------
lib/vsprintf.c | 26 ++++++++++----------------
3 files changed, 22 insertions(+), 33 deletions(-)

diff --git a/include/linux/uuid.h b/include/linux/uuid.h
index 2d095fc6..238f16f7 100644
--- a/include/linux/uuid.h
+++ b/include/linux/uuid.h
@@ -41,8 +41,9 @@ extern void uuid_be_gen(uuid_be *u);

bool __must_check uuid_is_valid(const char *uuid);

-extern const u8 uuid_le_index[16];
-extern const u8 uuid_be_index[16];
+/* For each binary byte, string offset in ASCII UUID where it appears */
+extern const u8 uuid_be_pos[16];
+extern const u8 uuid_le_pos[16];

int uuid_le_to_bin(const char *uuid, uuid_le *u);
int uuid_be_to_bin(const char *uuid, uuid_be *u);
diff --git a/lib/uuid.c b/lib/uuid.c
index e116ae5f..93945915 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -21,11 +21,6 @@
#include <linux/uuid.h>
#include <linux/random.h>

-const u8 uuid_le_index[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15};
-EXPORT_SYMBOL(uuid_le_index);
-const u8 uuid_be_index[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
-EXPORT_SYMBOL(uuid_be_index);
-
/***************************************************************
* Random UUID interface
*
@@ -97,32 +92,31 @@ bool uuid_is_valid(const char *uuid)
}
EXPORT_SYMBOL(uuid_is_valid);

-static int __uuid_to_bin(const char *uuid, __u8 b[16], const u8 ei[16])
+/* For each binary byte, string offset in ASCII UUID where it appears */
+const u8 uuid_be_pos[16] = {0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34};
+const u8 uuid_le_pos[16] = {6,4,2,0,11,9,16,14,19,21,24,26,28,30,32,34};
+
+static int __uuid_to_bin(const char uuid[36], __u8 b[16], const u8 pos[16])
{
- static const u8 si[16] = {0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34};
unsigned int i;

if (!uuid_is_valid(uuid))
return -EINVAL;

- for (i = 0; i < 16; i++) {
- int hi = hex_to_bin(uuid[si[i]] + 0);
- int lo = hex_to_bin(uuid[si[i]] + 1);
-
- b[ei[i]] = (hi << 4) | lo;
- }
+ for (i = 0; i < 16; i++)
+ hex2bin(b + i, uuid + pos[i], 1);

return 0;
}

int uuid_le_to_bin(const char *uuid, uuid_le *u)
{
- return __uuid_to_bin(uuid, u->b, uuid_le_index);
+ return __uuid_to_bin(uuid, u->b, uuid_le_pos);
}
EXPORT_SYMBOL(uuid_le_to_bin);

int uuid_be_to_bin(const char *uuid, uuid_be *u)
{
- return __uuid_to_bin(uuid, u->b, uuid_be_index);
+ return __uuid_to_bin(uuid, u->b, uuid_be_pos);
}
EXPORT_SYMBOL(uuid_be_to_bin);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 4ee07e89..f02cfd9f 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1313,38 +1313,32 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
struct printf_spec spec, const char *fmt)
{
char uuid[UUID_STRING_LEN + 1];
- char *p = uuid;
int i;
- const u8 *index = uuid_be_index;
+ const u8 *pos = uuid_be_pos;
const char *hex = hex_asc;

switch (fmt[1]) {
case 'L':
hex = hex_asc_upper; /* fall-through */
case 'l':
- index = uuid_le_index;
+ pos = uuid_le_pos;
break;
case 'B':
hex = hex_asc_upper;
break;
}

+ /* Format each byte of the raw uuid into the buffer */
for (i = 0; i < 16; i++) {
- u8 byte = addr[index[i]];
+ u8 byte = addr[i];
+ char *p = uuid + pos[i];

- *p++ = hex[byte >> 4];
- *p++ = hex[byte & 0x0f];
- switch (i) {
- case 3:
- case 5:
- case 7:
- case 9:
- *p++ = '-';
- break;
- }
+ p[0] = hex[byte >> 4];
+ p[1] = hex[byte & 0x0f];
}
-
- *p = 0;
+ /* Insert the fixed punctuation */
+ uuid[23] = uuid[18] = uuid[13] = uuid[8] = '-';
+ uuid[UUID_STRING_LEN] = '\0';

return string(buf, end, uuid, spec);
}
--
2.8.1