sourcecode

std::string의 컨텍스트에서 약자 SSO의 의미

copyscript 2023. 10. 31. 22:33
반응형

std::string의 컨텍스트에서 약자 SSO의 의미

최적화와 코드 스타일에 대한 C++ 질문에서, 몇몇 답변들은 복사본을 최적화하는 맥락에서 "SSO"를 언급했습니다.std::string 맥락에서 SSO는 그러한 맥락에서 무엇을 의미합니까?

분명히 "싱글 사인 온"은 아닙니다."공유 문자열 최적화"?

배경 / 개요

호출하지 않고 생성하는 변수인 자동 변수("스택에서")에 대한 작업malloc/new)는 일반적으로 다음을 사용하여 생성되는 변수인 free store("heap")와 관련된 것보다 훨씬 빠릅니다.new의 크기는 되어 있지 .) 단, 자동 배열의 크기는 컴파일 타임에 고정되어 있지만, 프리 스토어에서 제공하는 배열의 크기는 고정되어 있지 않습니다.또한 스택 크기는 제한적이며(일반적으로 몇 개의 MiB), 무료 저장소는 시스템의 메모리에 의해서만 제한됩니다.

SSO는 숏/스몰 스트링 최적화입니다 Astd::string일반적으로 문자열을 무료 저장소("heap")의 포인터로 저장합니다. 이는 마치 호출하는 것처럼 유사한 성능 특성을 제공합니다.new char [size]이렇게 매우 큰할 수 가 느려질 수 이렇게 하면 매우 큰 문자열에 대한 스택 오버플로를 방지할 수 있지만, 특히 복사 작업의 경우에는 더 느려질 수 있습니다.최적화를 위해, 많은 구현이std::string작은 자동 배열을 만듭니다.char [20]인 경우가 다양함) 문자열이 20자 이하인 경우(이 예에서는 실제 크기가 다양함) 해당 배열에 직접 저장됩니다.이렇게 하면 전화할 필요가 없습니다.new일이 좀 빨라지는 것 같아요

편집:

저는 이 답변이 그렇게 인기가 있을 줄은 예상하지 못했지만, 실제로 "야생에서" SSO의 구현을 읽어본 적이 없다는 점에 주의하면서, 좀 더 현실적인 구현을 해보겠습니다.

구현내역

, a.std::string다음 정보를 저장해야 합니다.

  • 사이즈를
  • 용량을
  • 데이터 위치

사이즈는 a로 저장할 수 있었습니다.std::string::size_type끝을 가리킬 수도 있습니다.유일한 차이점은 사용자가 호출할 때 두 개의 포인터를 빼야 하는지 여부입니다.size아니면 a를 추가합니다.size_type사용자가 호출할 때 포인터로end할 수 용량은 어느 쪽이든 저장할 수 있습니다.

사용하지 않는 것은 돈을 지불하지 않습니다.

먼저, 위에서 설명한 내용을 바탕으로 순진한 구현을 고려해 보십시오.

class string {
public:
    // all 83 member functions
private:
    std::unique_ptr<char[]> m_data;
    size_type m_size;
    size_type m_capacity;
    std::array<char, 16> m_sso;
};

64비트 시스템의 경우 일반적으로 다음을 의미합니다.std::string는 문자열당 24바이트의 '오버헤드'를 가지며, SSO 버퍼에 대해서는 16바이트를 더합니다(패딩 요구사항으로 인해 20개가 아닌 여기서 16개를 선택함).단순화된 예처럼 세 개의 데이터 멤버와 로컬 문자 배열을 저장한다는 것은 정말 말이 안 될 것입니다.m_size <= 16, 그러면 모든 데이터를 넣을 것입니다.m_sso, 용량은 이미 알고 있고 데이터에 대한 포인터는 필요 없습니다.m_size > 16, 그럼 난 필요 없어요m_sso로 하는 제가 필요로 하는 곳에는 절대 중복이 없습니다.공간을 낭비하지 않는 현명한 솔루션은 다음과 같습니다(검증되지 않은 예제 용도만 해당).

class string {
public:
    // all 83 member functions
private:
    size_type m_size;
    union {
        class {
            // This is probably better designed as an array-like class
            std::unique_ptr<char[]> m_data;
            size_type m_capacity;
        } m_large;
        std::array<char, sizeof(m_large)> m_small;
    };
};

대부분의 구현이 이와 비슷하다고 생각합니다.

SSO는 "Small String Optimization"의 줄임말로, 작은 문자열이 별도로 할당된 버퍼를 사용하지 않고 문자열 클래스 본문에 포함되는 기법입니다.

다른 답변에서 이미 설명한 바와 같이 SSO는 Small/Short String Optimization을 의미합니다.이러한 최적화의 동기는 일반적으로 애플리케이션이 긴 문자열보다 훨씬 짧은 문자열을 더 많이 처리한다는 부인할 수 없는 증거입니다.

데이비드 스톤이 위의 답변에서 설명한 바와 같이,std::stringclass는 내부 버퍼를 사용하여 주어진 길이까지 콘텐츠를 저장하므로 동적으로 메모리를 할당할 필요가 없습니다.이렇게 하면 코드가 더 효율적이고 빨라집니다.

다른 관련 답변은 내부 버퍼의 크기가 다음에 따라 달라진다는 것을 명확하게 보여줍니다.std::string플랫폼마다 다른 구현(아래 벤치마크 결과 참조).

벤치마크

여기 길이가 같은 많은 문자열의 복사 작업을 벤치마크하는 작은 프로그램이 있습니다.길이가 = 1인 1000만 문자열 복사 시간 인쇄를 시작합니다.그런 다음 길이 = 2의 문자열로 반복합니다.길이가 50까지 계속됩니다.

#include <string>
#include <iostream>
#include <vector>
#include <chrono>

static const char CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static const int ARRAY_SIZE = sizeof(CHARS) - 1;

static const int BENCHMARK_SIZE = 10000000;
static const int MAX_STRING_LENGTH = 50;

using time_point = std::chrono::high_resolution_clock::time_point;

void benchmark(std::vector<std::string>& list) {
    std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();

    // force a copy of each string in the loop iteration
    for (const auto s : list) {
        std::cout << s;
    }

    std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
    const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
    std::cerr << list[0].length() << ',' << duration << '\n';
}

void addRandomString(std::vector<std::string>& list, const int length) {
    std::string s(length, 0);
    for (int i = 0; i < length; ++i) {
        s[i] = CHARS[rand() % ARRAY_SIZE];
    }
    list.push_back(s);
}

int main() {
    std::cerr << "length,time\n";

    for (int length = 1; length <= MAX_STRING_LENGTH; length++) {
        std::vector<std::string> list;
        for (int i = 0; i < BENCHMARK_SIZE; i++) {
            addRandomString(list, length);
        }
        benchmark(list);
    }

    return 0;
}

이 프로그램을 실행하려면 다음과 같이 해야 합니다../a.out > /dev/null문자열을 인쇄하는 시간이 계산되지 않도록 해야 합니다.중요한 숫자가 인쇄되어 있습니다.stderr, 콘솔에 나타날 겁니다

MacBook과 Ubuntu 머신의 출력으로 차트를 만들었습니다.길이가 지정된 지점에 도달하면 문자열을 복사하는 시간이 크게 증가합니다.내부 버퍼에 더 이상 문자열이 들어가지 않고 메모리 할당을 사용해야 하는 순간입니다.

또한 리눅스 머신에서는 문자열의 길이가 16에 도달할 때 점프가 발생합니다.맥북에서는 길이가 23이 되면 점프가 일어납니다.이는 SSO가 플랫폼 구현에 따라 다름을 확인해 줍니다.

우분투 SSO benchmark on Ubuntu

맥북 프로 SSO benchmark on Macbook Pro

언급URL : https://stackoverflow.com/questions/10315041/meaning-of-acronym-sso-in-the-context-of-stdstring

반응형