lib/vsprintf.c: Further simplify uuid_string()
Subsystems (3)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 1 line · On Mon, 30 May 2016 at 10:45:39 Andy Shevchenko wrote:
You have to send this to public mailing list,
Okay. lkml and commenters on recent patches added to Cc:.
To those just joining, I had a couple of local patches I had made to lib/vsprintf.c:uuid_string() which had been sitting around ignored due to not knowing who to submit them to.
Then I noticed (merge conflicts while rebasing my local patches) that Andy was working on the area and sent them to him.
[Aside: Ted, I agree that whoever decided to make UUIDs non-universal by introducing an ambiguous parse is richly deserving of scorn.]
Quoted 5 lines
but looking briefly to the code it looks like trade bad for worse, on other words I don't see much beneficial from it. You are decreasing code size by increasing data size. Speed is not a bottleneck here anyway, since
*printf()is slow by definition. Table should be shared viauuid.hheader and code if you wish it look generic.
Wow, I didn't expect that! I thought the improvement was obvious in pretty much every possible way, which is why I didn't include much explanation. I'll explain my thinking in more detail here; could you tell me where you disagree?
I agree with you that such "support" code shouldn't try to micro-optimize its own performance at the expense of static resources (code size, large tables), because CPU resources like L1 cache, TLB, and branch predictor slots should be reserved for the hot code.
It's not that we don't care about speed, but given its infrequent use we care even more about slowing down the *rest* of the kernel.
That's exactly why I headlined the space savings rather than the performance gains.
As an example of a less useful "optimization", it's possible to unroll the loop twice and print 16 bits per iteration. You could even shrink the tables to 8 bytes each, since since odd entries can be derived from even entries by complementing the low-order bit:
for (i = 0; i < 8; i++) {
p = hex_byte_pack(p, addr[index[i]]);
p = hex_byte_pack(p, addr[index[i]^1]);
if ((unsigned)i - 1 < 4)
*p++ = '-';
}There are two optimzations here:
1) Replacing the "uc" boolean with a pointer.
lib/vsprintf.c +7 -7
@@ -1316,24 +1316,24 @@ char *uuid_string(char *buf, char *end, const u8 *addr,char *p = uuid;int i;const u8 *index = uuid_be_index; -bool uc = false; +const char *hex = hex_asc;switch (*(++fmt)) {case 'L' : - uc = true;/* fall-through */ + hex = hex_asc_upper;/* fall-through */ case 'l' : index = uuid_le_index;break ;case 'B' : - uc = true; + hex = hex_asc_upper;break ; }for (i =0 ; i <16 ; i++) { -if (uc) - p =hex_byte_pack_upper (p, addr[index[i]]); -else - p =hex_byte_pack (p, addr[index[i]]); +u8 byte = addr[index[i]]; + + *p++ = hex[byte >>4 ]; + *p++ = hex[byte &0x0f ];switch (i) {case 3 :case 5 :
This seems like an obvious win. It's performing exactly the same data memory accesses as the conditional form (the tables it uses are the tables which the hex_byte_pack() macros use internally), while reducing the code size both statically and dynamically.
Dynamically, it eliminates 16 conditional branches. The only extra reesource consumed is the "hex" pointer variable which is larger than the "uc" boolean, but as it's one register either way, that's nothing.
So it's saving L1I space and a branch predictor entry as well as being faster, all without making the code any harder to understand.
I really don't see any downside at all.
2) Inverting the order of formatting.
This is a more complex change. Rather than format the UUID in output order, and use a table to get the permuted input byte order, I invert the table to list the output position for each input byte.
Thus, the input is read in order and the output is written out of order.
lib/vsprintf.c +13 -16
@@ -1313,38 +1313,35 @@ 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; +/* Offset in uuid[] where each byte is printed, two cases. */ +static const u8 be[16 ] = {0 ,2 ,4 ,6 ,9 ,11 ,14 ,16 ,19 ,21 ,24 ,26 ,28 ,30 ,32 ,34 }; +static const u8 le[16 ] = {6 ,4 ,2 ,0 ,11 ,9 ,16 ,14 ,19 ,21 ,24 ,26 ,28 ,30 ,32 ,34 }; +const u8 *index = be;const char *hex = hex_asc;switch (*(++fmt)) {case 'L' : hex = hex_asc_upper;/* fall-through */ case 'l' : - index = uuid_le_index; + index = le;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 + index[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); }
When I first wrote it, it didn't increase table size at all, since it was just swapping one set of tables for another.
Now that you're sharing the tables, it's possible to *reduce* table size. My be[] table is identical to your si[] table in __uuid_to_bin(), and using my le[] table there would let you eliminate uuid_le_index[] and uuid_be_index[] completely, for a net 16 byte saving.
More significantly, it decreases both static and dynamic code size by trading the switch() for the four explicit stores of the '-' punctuation.
Most of the work done by the switch() is folded into the table showing which output positions to reserve for punctuation.
Again, the change is not only a speed boost, but speeds up the rest of the kernel by reducing cache and branch predictor use.
I agree it's harder to understand, precisely because the table does two things at once, but not hugely so; the comments resolve any questions the reader might have. In general, subtlety is a problem when it affects a large area of code (RCU being the poster child); this is a self-contained micro-optimization which doesn't affect the understandability or maintainability of the kernel as a whole, and someone who does care about this particular fucntion doesn't have to read very much to figure it out.
PATCH 1/1 lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 1 line
From
a0d084b1225f2efcf4b5c81871c9c446155b9b13Mon Sep 17 00:00:00 2001
From: George Spelvin <[email protected]>
Date: Tue, 31 May 2016 16:00:22 -0400
Subject: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Both input and output code is simplified if we instead use a mapping from binary UUID index to ASCII UUID position. This lets us combine hyphen-skipping and endian-swapping into one table.
uuid_[bl]e_index were EXPORT_SYMBOLed for no obvious reason; there are no users outside of lib/. The replacement uuid_[bl]e_pos arrays are not exported pending finding a need.
The arrays are combined in one contiguous uuid_byte_pos[2][16] array as a micro-optimization for uuid_string(). Choosing between the two can be done by adding 16 rather than loading a second full-word address.
x86-64 code size reductions:uuid_string: was 228 bytes, now 134__uuid_to_bin: was 119 bytes, now 85
Initialized data is also reduced by 16 bytes.
---
Here's a patch implementing the suggestion I made earlier. This reduces code size, data size, and run time for input and output of UUIDs.
This patch is on top of the upper/lower case hex optimization for lib/vsprintf.c I sent earlier. If you don't have it, just ignore the merge conflicts in uuid_string() and take the "after" version.
include/linux/uuid.h | 6 ++++-- lib/uuid.c | 24 ++++++++++-------------- lib/vsprintf.c | 32 +++++++++++++------------------- 3 files changed, 27 insertions(+), 35 deletions(-)
include/linux/uuid.h +4 -2
@@ -41,8 +41,10 @@ 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_byte_pos[2 ][16 ]; +#define uuid_be_pos (uuid_byte_pos[0]) +#define uuid_le_pos (uuid_byte_pos[1])int uuid_le_to_bin (const char *uuid,uuid_le *u);int uuid_be_to_bin (const char *uuid,uuid_be *u);
lib/uuid.c +10 -14
@@ -21,10 +21,10 @@#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); +const u8 uuid_byte_pos[2 ][16 ] = { + {0 ,2 ,4 ,6 ,9 ,11 ,14 ,16 ,19 ,21 ,24 ,26 ,28 ,30 ,32 ,34 },/* uuid_be_pos */ + {6 ,4 ,2 ,0 ,11 ,9 ,16 ,14 ,19 ,21 ,24 ,26 ,28 ,30 ,32 ,34 }/* uuid_le_pos */ +};/*************************************************************** * Random UUID interface
@@ -97,32 +97,28 @@ 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 ]) +static int __uuid_to_bin (const char uuid[36 ],__u8 b[16 ],const u8 si[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++) +if (hex2bin (b + i, uuid + si[i],1 ) <0 ) +return -EINVAL ;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);
lib/vsprintf.c +13 -19
@@ -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' : + pos = uuid_le_pos; +break ;case 'L' : - hex = hex_asc_upper;/* fall-through */ -case 'l' : - index = uuid_le_index; -break ; + pos = uuid_le_pos;/* Fall-through */ 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); }
Signature · 1 line
2.8.1
Re: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 2 lines · George Spelvin
Here's a patch implementing the suggestion I made earlier. This reduces code size, data size, and run time for input and output of UUIDs.
[]
lib/uuid.c
Quoted 1 line
lib/uuid.c +0
-0
[]
lib/uuid.c bool uuid_is_valid(const char *uuid) · line 100
Quoted 6 lines
lib/uuid.c +0
-0@@ -97,32 +97,28 @@ bool uuid_is_valid(const char *uuid) } EXPORT_SYMBOL(uuid_is_valid);lib/uuid.c +1
-1-static int __uuid_to_bin (const char *uuid,__u8 b[16 ],const u8 ei[16 ]) +static int __uuid_to_bin (const char uuid[36 ],__u8 b[16 ],const u8 si[16 ])
Functions with sized array arguments are generally undesired.
Linus once wrote: (http://comments.gmane.org/gmane.linux.kernel/2031400)
array arguments in C don't
actually exist. Sadly, compilers accept it for various bad historical reasons, and silently turn it into just a pointer argument. There are arguments for them, but they are from weak minds.
Perhaps this would be better using simple pointers and without the __
static int __uuid_to_bin(const char *uuid, u8 *b, const u8 *si)
Re: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 4 lines
Functions with sized array arguments are generally undesired.
Linus once wrote: (http://comments.gmane.org/gmane.linux.kernel/2031400)
Quoted 8 lines
array arguments in C don't
actually exist. Sadly, compilers accept it for various bad historical reasons, and silently turn it into just a pointer argument. There are arguments for them, but they are from weak minds.Perhaps this would be better using simple pointers and without the __
static int
__uuid_to_bin(const char *uuid, u8 *b, const u8 *si)
I haven't looked up the full original discussion to see if this is a point on which I disagree with Linus, but I find it useful for documentation:
this is not just a pointer to "some" bytes, this is a pointer to [LENGTH] bytes. It's a reminder to the caller that they'd better pass in a buffer of the required size.
Obviosuly, it makes no actual difference to the compiler.
C99 actually has a way to say this explicitly to the compiler, but the syntax is ugly:
static int __uuid_to_bin(const char uuid[static 36], __u8 b[static 16],
const u8 si[static 16])
(This includes the effect of __attribute__((nonnull)).)
Further discussion at
https://hamberg.no/erlend/posts/2013-02-18-static-array-indices.html
https://stackoverflow.com/questions/3430315/what-is-the-purpose-of-static-keyword-in-array-parameter-of-function-like-char
(FWIW, another two style points which I disagre with Linus about are that I don't mind "sizeof variable" without parens, and that I don't mind using a bare "0" for a null pointer. More substantially, I like "bool" a lot more than Linus does.)
Andy Shevchenko
reviewerRe: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
In reply to Joe PerchesQuoted 7 lines · Joe Perches
Quoted 3 lines · George Spelvin
Here's a patch implementing the suggestion I made earlier. This reduces
code size, data size, and run time for input and output of UUIDs.[]
lib/uuid.c
Quoted 1 line
lib/uuid.c +0
-0[]
Quoted 10 lines
Quoted 8 lines
lib/uuid.c +0
-0@@ -97,32 +97,28 @@ 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])
+static int__uuid_to_bin(const char uuid[36], __u8 b[16], const u8 si[16])Functions with sized array arguments are generally undesired.
That function follows existing UUID API. Since we have now it consolidated in one place someone may fix it eventually.
Refer to this discussion as well:
http://www.spinics.net/lists/linux-efi/msg08105.html
Quoted 15 lines
Linus once wrote: (http://comments.gmane.org/gmane.linux.kernel/203140
0)array arguments in C don't
actually exist. Sadly, compilers accept it for various bad historical
reasons, and silently turn it into just a pointer argument. There are
arguments for them, but they are from weak minds.Perhaps this would be better using simple pointers and without the __
static int
__uuid_to_bin(const char *uuid, u8 *b, const u8 *si)
Signature · 2 lines
Andy Shevchenko <[email protected]> Intel Finland Oy
Re: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 11 lines · Andy Shevchenko
Quoted 7 lines · Joe Perches
Quoted 4 lines · George Spelvin
-static int
__uuid_to_bin(const char *uuid, __u8 b[16], const u8 ei[16])
+static int__uuid_to_bin(const char uuid[36], __u8 b[16], const u8 si[16])Functions with sized array arguments are generally undesired.
That function follows existing UUID API. Since we have now it consolidated in one place someone may fix it eventually.
Just to clarify:
int foo(char *);
int foo(char *floccinaucinihilipilifcation);
int foo(char *p);
int foo(char p[]);
int foo(char []);
int foo(char p[1]);
int foo(char p[999999999]);
are all the exact same declaration. There is no API change; the only difference is stylistic. (Try it! Copy them to a .c file and compile it. Observe the lack of conflicting declaration warnings.)
Although the compiler doesn't care, I happen to prefer to include parameter names for the benefit of someone reading the header files.
For the same reason, if the pointer is to the start of an array with definite length (that's not 1), I prefer to use the array form showing that length.
But it's a matter of style, not substance, either way.
Re: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 24 lines · George Spelvin
Quoted 9 lines · Andy Shevchenko
Quoted 6 lines · Joe Perches
Quoted 4 lines · George Spelvin
-static int
__uuid_to_bin(const char *uuid, __u8 b[16], const u8 ei[16])
+static int__uuid_to_bin(const char uuid[36], __u8 b[16], const u8 si[16])Functions with sized array arguments are generally undesired.
That function follows existing UUID API. Since we have now it consolidated in one place someone may fix it eventually.
Just to clarify:
int
foo(char *);
intfoo(char *floccinaucinihilipilifcation);
intfoo(char *p);
intfoo(char p[]);
intfoo(char []);
intfoo(char p[1]);
intfoo(char p[999999999]);are all the exact same declaration. There is no API change; the only difference is stylistic. (Try it! Copy them to a .c file and compile it. Observe the lack of conflicting declaration warnings.)
Quoted 8 lines
Although the compiler doesn't care, I happen to prefer to include parameter names for the benefit of someone reading the header files.
For the same reason, if the pointer is to the start of an array with definite length (that's not 1), I prefer to use the array form showing that length.
But it's a matter of style, not substance, either way.
I believe the substantive bit of the argument is the ability to misunderstand that sizeof(argument with size char[999]) is not 999 but is sizeof(*).
Andrew Morton
maintainerRe: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
In reply to George SpelvinQuoted 2 lines · On 31 May 2016 16:31:22 -0400 "George Spelvin" <[email protected]>…
This patch is on top of the upper/lower case hex optimization for
lib/vsprintf.cI sent earlier.
I can't find it. Please take more care when referring to patches, to prevent mistakes from being made.
Andy Shevchenko
reviewerRe: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
Quoted 8 lines · Andrew Morton
Quoted 2 lines · On 31 May 2016 16:31:22 -0400 "George Spelvin" <linux@sciencehorizons. net>…
This patch is on top of the upper/lower case hex optimization for
lib/vsprintf.cI sent earlier.I can't find it. Please take more care when referring to patches, to prevent mistakes from being made.
In any case I would to hear from people before going with them. Rasmus, perhaps you can comment on the subject?
Signature · 2 lines
Andy Shevchenko <[email protected]> Intel Finland Oy
Andy Shevchenko
reviewerRe: [PATCH] lib/uuid.c: eliminate uuid_[bl]e_index arrays
In reply to George SpelvinQuoted 4 lines · George Spelvin
From
a0d084b1225f2efcf4b5c81871c9c446155b9b13Mon Sep 17 00:00:00 2001
From: George Spelvin <[email protected]>
Date: Tue, 31 May 2016 16:00:22 -0400
Subject: [PATCH]lib/uuid.c: eliminate uuid_[bl]e_index arrays
There is a tool called git send-email. It would be better to use it directly.
Also, please fix Cc list (I got bounce response) and add some key people like Rasmus.
Quoted 11 lines
Both input and output code is simplified if we instead use a mapping from binary UUID index to ASCII UUID position. This lets us combine hyphen-skipping and endian-swapping into one table.
uuid_[bl]e_index were
EXPORT_SYMBOLedfor no obvious reason; there are no users outside of lib/. The replacement uuid_[bl]e_pos arrays are not exported pending finding a need.The arrays are combined in one contiguous uuid_byte_pos[2][16] array as a micro-optimization for
uuid_string().
Oh, it makes readability worse.
Quoted 7 lines
Choosing between
the two can be done by adding 16 rather than loading a second full-word address.x86-64 code size reductions:
uuid_string: was 228 bytes, now 134__uuid_to_bin: was 119 bytes, now 85
x86_32? arm?
Quoted 10 lines
Initialized data is also reduced by 16 bytes.
Here's a patch implementing the suggestion I made earlier. This reduces
code size, data size, and run time for input and output of UUIDs.This patch is on top of the upper/lower case hex optimization for
lib/vsprintf.cI sent earlier. If you don't have it, just ignore the merge conflicts inuuid_string()and take the "after" version.
--- a/include/linux/uuid.h
Quoted 31 lines
+++
b/include/linux/uuid.h(quoted diff) +0
-0@@ -41,8 +41,10 @@ extern void uuid_be_gen(uuid_be *u);
bool__must_checkuuid_is_valid(const char *uuid);include/linux/uuid.h +1
-2-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 */
include/linux/uuid.h +3
-0+extern const u8 uuid_byte_pos[2 ][16 ]; +#define uuid_be_pos (uuid_byte_pos[0]) +#define uuid_le_pos (uuid_byte_pos[1])
intuuid_le_to_bin(const char *uuid, uuid_le *u); intuuid_be_to_bin(const char *uuid, uuid_be *u);lib/uuid.c +0
-0@@ -21,10 +21,10 @@ #include <linux/uuid.h> #include <linux/random.h>lib/uuid.c +2
-4-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); +const u8 uuid_byte_pos[2 ][16 ] = { + {0 ,2 ,4 ,6 ,9 ,11 ,14 ,16 ,19 ,21 ,24 ,26 ,28 ,30 ,32 ,34 },/*
uuid_be_pos*/lib/uuid.c +1
-0+ {6,4,2,0,11,9,16,14,19,21,24,26,28,30,32,34} /*
Quoted 2 lines
uuid_le_pos*/
+};
And what prevent you to use two arrays? Above looks not good for reading and error prone for users.
Quoted 11 lines
/***************************************************************
* Random UUID interfacelib/uuid.c +0
-0@@ -97,32 +97,28 @@ 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])
+static int__uuid_to_bin(const char uuid[36], __u8 b[16], const u8 si[16])
This one... Let's keep a prototype as is for now.
Quoted 10 lines
{
lib/uuid.c +0
-1- 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;
lib/uuid.c bool uuid_is_valid(const char *uuid) · line 109
Quoted 9 lines
lib/uuid.c +3
-6-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++) +if (hex2bin (b + i, uuid + si[i],1 ) <0 ) +return -EINVAL ;
How hex2bin is better here? We have validation done, no need to repeat. So, I suggest not to touch this piece of code.
Quoted 38 lines
lib/vsprintf.c +1
-2@@ -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]) {lib/vsprintf.c +3
-0+case 'l' : + pos = uuid_le_pos; +break ;case 'L':
lib/vsprintf.c +1
-4- hex = hex_asc_upper;/* fall-through */ -case 'l' : - index = uuid_le_index; -break ; + pos = uuid_le_pos;/* Fall-through */ case 'B':
hex =hex_asc_upper;
break;
}lib/vsprintf.c +1
-0+/* Format each byte of the raw uuid into the buffer */ for (i = 0; i < 16; i++) {
lib/vsprintf.c +2
-1-u8 byte = addr[index[i]]; +u8 byte = addr[i]; +char *p = uuid + pos[i];lib/vsprintf.c +0
-4- *p++ = hex[byte >>4 ]; - *p++ = hex[byte &0x0f ]; -switch (i) { -case 3 :
lib/vsprintf.c char *uuid_string(char *buf, char *end, const u8 *addr,
Quoted 10 lines
lib/vsprintf.c +2
-6-case 5 : -case 7 : -case 9 : - *p++ ='-' ; -break ; - } + p[0 ] = hex[byte >>4 ]; + p[1 ] = hex[byte &0x0f ];
If you wish you may convert this to hex_byte_pack{,upper}().
Signature · 2 lines
Andy Shevchenko <[email protected]> Intel Finland Oy