Skip to content

Commit

Permalink
Implement to_string(uint32_t) without using the locale
Browse files Browse the repository at this point in the history
Using the locale takes a mutex deep in the C++ library.
Avoid this on hot compilation paths, e.g. in the validator.

Fixed: KhronosGroup#5802
  • Loading branch information
dneto0 committed Sep 12, 2024
1 parent 7c9210c commit a3031e6
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 13 deletions.
1 change: 1 addition & 0 deletions Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SPVTOOLS_SRC_FILES := \
source/table.cpp \
source/text.cpp \
source/text_handler.cpp \
source/to_string.cpp \
source/util/bit_vector.cpp \
source/util/parse_number.cpp \
source/util/string_utils.cpp \
Expand Down
3 changes: 3 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ static_library("spvtools") {
"source/text.h",
"source/text_handler.cpp",
"source/text_handler.h",
"source/to_string.cpp",
"source/to_string.h",
"source/util/bit_vector.cpp",
"source/util/bit_vector.h",
"source/util/bitutils.h",
Expand Down Expand Up @@ -1416,6 +1418,7 @@ if (build_with_chromium && spvtools_build_executables) {
"test/text_to_binary.type_declaration_test.cpp",
"test/text_to_binary_test.cpp",
"test/text_word_get_test.cpp",
"test/to_string_test.cpp",
"test/unit_spirv.cpp",
"test/unit_spirv.h",
]
Expand Down
2 changes: 2 additions & 0 deletions source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/table.h
${CMAKE_CURRENT_SOURCE_DIR}/text.h
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h
${CMAKE_CURRENT_SOURCE_DIR}/to_string.h
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.h

${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.cpp
Expand Down Expand Up @@ -294,6 +295,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/table.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text.cpp
${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/to_string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_adjacency.cpp
${CMAKE_CURRENT_SOURCE_DIR}/val/validate_annotation.cpp
Expand Down
15 changes: 3 additions & 12 deletions source/name_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,15 @@
#include "source/binary.h"
#include "source/latest_version_spirv_header.h"
#include "source/parsed_operand.h"
#include "source/to_string.h"
#include "spirv-tools/libspirv.h"

namespace spvtools {
namespace {

// Converts a uint32_t to its string decimal representation.
std::string to_string(uint32_t id) {
// Use stringstream, since some versions of Android compilers lack
// std::to_string.
std::stringstream os;
os << id;
return os.str();
NameMapper GetTrivialNameMapper() {
return [](uint32_t i) { return spvtools::to_string(i); };
}

} // anonymous namespace

NameMapper GetTrivialNameMapper() { return to_string; }

FriendlyNameMapper::FriendlyNameMapper(const spv_const_context context,
const uint32_t* code,
const size_t wordCount)
Expand Down
3 changes: 2 additions & 1 deletion source/opt/inst_debug_printf_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "inst_debug_printf_pass.h"

#include "source/spirv_constant.h"
#include "source/to_string.h"
#include "source/util/string_utils.h"
#include "spirv/unified1/NonSemanticDebugPrintf.h"

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

std::string name("stream_write_");
name += std::to_string(param_cnt);
name += spvtools::to_string(param_cnt);

context()->AddDebug2Inst(
NewGlobalName(param2output_func_id_[param_cnt], name));
Expand Down
44 changes: 44 additions & 0 deletions source/to_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "source/to_string.h"

#include <cassert>

namespace spvtools {

std::string to_string(uint32_t n) {
// This implementation avoids using standard library features that access
// the locale. Using the locale requires taking a mutex which causes
// annoying serialization.

constexpr int max_digits = 10; // max uint has 10 digits
// Contains the resulting digits, with least significant digit in the last
// entry.
char buf[max_digits];
int write_index = max_digits - 1;
if (n == 0) {
buf[write_index] = '0';
} else {
while (n > 0) {
int units = n % 10;
buf[write_index--] = "0123456789"[units];
n = (n - units) / 10;
}
write_index++;
}
assert(write_index >= 0);
return std::string(buf + write_index, max_digits - write_index);
}
} // namespace spvtools
29 changes: 29 additions & 0 deletions source/to_string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SOURCE_TO_STRING_H_
#define SOURCE_TO_STRING_H_

#include <cstdint>
#include <string>

namespace spvtools {

// Returns the decimal representation of a number as a string,
// without using the locale.
std::string to_string(uint32_t n);

} // namespace spvtools

#endif // SOURCE_TO_STRING_H_
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ set(TEST_SOURCES
text_to_binary.subgroup_dispatch_test.cpp
text_to_binary.reserved_sampling_test.cpp
text_word_get_test.cpp
to_string_test.cpp

unit_spirv.cpp
)
Expand Down
28 changes: 28 additions & 0 deletions test/to_string_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "source/to_string.h"

#include "gmock/gmock.h"

namespace {

TEST(ToString, Uint32) {
EXPECT_EQ(spvtools::to_string(0u), "0");
EXPECT_EQ(spvtools::to_string(1u), "1");
EXPECT_EQ(spvtools::to_string(1234567890u), "1234567890");
EXPECT_EQ(spvtools::to_string(0xffffffffu), "4294967295");
}

} // namespace

0 comments on commit a3031e6

Please sign in to comment.