Skip to content

Commit 4451f6a

Browse files
authored
Implement to_string(uint32_t) without using the locale (#5805)
Using the locale takes a mutex deep in the C++ library. Avoid this on hot compilation paths, e.g. in the validator. Fixed: #5802
1 parent 7c9210c commit 4451f6a

File tree

9 files changed

+113
-13
lines changed

9 files changed

+113
-13
lines changed

Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ SPVTOOLS_SRC_FILES := \
2727
source/table.cpp \
2828
source/text.cpp \
2929
source/text_handler.cpp \
30+
source/to_string.cpp \
3031
source/util/bit_vector.cpp \
3132
source/util/parse_number.cpp \
3233
source/util/string_utils.cpp \

BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ static_library("spvtools") {
475475
"source/text.h",
476476
"source/text_handler.cpp",
477477
"source/text_handler.h",
478+
"source/to_string.cpp",
479+
"source/to_string.h",
478480
"source/util/bit_vector.cpp",
479481
"source/util/bit_vector.h",
480482
"source/util/bitutils.h",
@@ -1416,6 +1418,7 @@ if (build_with_chromium && spvtools_build_executables) {
14161418
"test/text_to_binary.type_declaration_test.cpp",
14171419
"test/text_to_binary_test.cpp",
14181420
"test/text_word_get_test.cpp",
1421+
"test/to_string_test.cpp",
14191422
"test/unit_spirv.cpp",
14201423
"test/unit_spirv.h",
14211424
]

source/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ set(SPIRV_SOURCES
266266
${CMAKE_CURRENT_SOURCE_DIR}/table.h
267267
${CMAKE_CURRENT_SOURCE_DIR}/text.h
268268
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
269+
${CMAKE_CURRENT_SOURCE_DIR}/to_string.h
269270
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.h
270271

271272
${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.cpp
@@ -294,6 +295,7 @@ set(SPIRV_SOURCES
294295
${CMAKE_CURRENT_SOURCE_DIR}/table.cpp
295296
${CMAKE_CURRENT_SOURCE_DIR}/text.cpp
296297
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp
298+
${CMAKE_CURRENT_SOURCE_DIR}/to_string.cpp
297299
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.cpp
298300
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_adjacency.cpp
299301
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_annotation.cpp

source/name_mapper.cpp

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,15 @@
2525
#include "source/binary.h"
2626
#include "source/latest_version_spirv_header.h"
2727
#include "source/parsed_operand.h"
28+
#include "source/to_string.h"
2829
#include "spirv-tools/libspirv.h"
2930

3031
namespace spvtools {
31-
namespace {
3232

33-
// Converts a uint32_t to its string decimal representation.
34-
std::string to_string(uint32_t id) {
35-
// Use stringstream, since some versions of Android compilers lack
36-
// std::to_string.
37-
std::stringstream os;
38-
os << id;
39-
return os.str();
33+
NameMapper GetTrivialNameMapper() {
34+
return [](uint32_t i) { return spvtools::to_string(i); };
4035
}
4136

42-
} // anonymous namespace
43-
44-
NameMapper GetTrivialNameMapper() { return to_string; }
45-
4637
FriendlyNameMapper::FriendlyNameMapper(const spv_const_context context,
4738
const uint32_t* code,
4839
const size_t wordCount)

source/opt/inst_debug_printf_pass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "inst_debug_printf_pass.h"
1818

1919
#include "source/spirv_constant.h"
20+
#include "source/to_string.h"
2021
#include "source/util/string_utils.h"
2122
#include "spirv/unified1/NonSemanticDebugPrintf.h"
2223

@@ -396,7 +397,7 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) {
396397
context()->AddFunction(std::move(output_func));
397398

398399
std::string name("stream_write_");
399-
name += std::to_string(param_cnt);
400+
name += spvtools::to_string(param_cnt);
400401

401402
context()->AddDebug2Inst(
402403
NewGlobalName(param2output_func_id_[param_cnt], name));

source/to_string.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "source/to_string.h"
16+
17+
#include <cassert>
18+
19+
namespace spvtools {
20+
21+
std::string to_string(uint32_t n) {
22+
// This implementation avoids using standard library features that access
23+
// the locale. Using the locale requires taking a mutex which causes
24+
// annoying serialization.
25+
26+
constexpr int max_digits = 10; // max uint has 10 digits
27+
// Contains the resulting digits, with least significant digit in the last
28+
// entry.
29+
char buf[max_digits];
30+
int write_index = max_digits - 1;
31+
if (n == 0) {
32+
buf[write_index] = '0';
33+
} else {
34+
while (n > 0) {
35+
int units = n % 10;
36+
buf[write_index--] = "0123456789"[units];
37+
n = (n - units) / 10;
38+
}
39+
write_index++;
40+
}
41+
assert(write_index >= 0);
42+
return std::string(buf + write_index, max_digits - write_index);
43+
}
44+
} // namespace spvtools

source/to_string.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef SOURCE_TO_STRING_H_
16+
#define SOURCE_TO_STRING_H_
17+
18+
#include <cstdint>
19+
#include <string>
20+
21+
namespace spvtools {
22+
23+
// Returns the decimal representation of a number as a string,
24+
// without using the locale.
25+
std::string to_string(uint32_t n);
26+
27+
} // namespace spvtools
28+
29+
#endif // SOURCE_TO_STRING_H_

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ set(TEST_SOURCES
151151
text_to_binary.subgroup_dispatch_test.cpp
152152
text_to_binary.reserved_sampling_test.cpp
153153
text_word_get_test.cpp
154+
to_string_test.cpp
154155

155156
unit_spirv.cpp
156157
)

test/to_string_test.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "source/to_string.h"
16+
17+
#include "gmock/gmock.h"
18+
19+
namespace {
20+
21+
TEST(ToString, Uint32) {
22+
EXPECT_EQ(spvtools::to_string(0u), "0");
23+
EXPECT_EQ(spvtools::to_string(1u), "1");
24+
EXPECT_EQ(spvtools::to_string(1234567890u), "1234567890");
25+
EXPECT_EQ(spvtools::to_string(0xffffffffu), "4294967295");
26+
}
27+
28+
} // namespace

0 commit comments

Comments
 (0)