정상적인 CPU 온도에도 불구하고 Kythe 코드 인덱싱 프로세스가 제한됨

정상적인 CPU 온도에도 불구하고 Kythe 코드 인덱싱 프로세스가 제한됨

특정 워크로드를 실행할 때만 발생하는 CPU 제한 문제가 발생했습니다.Kythe 인덱서. 재현을 위한 자세한 단계는 질문 끝에 있습니다. 여기서는 높은 수준의 요약을 제공하겠습니다.

Kythe는 소스 코드에서 인덱스를 추출하는 도구입니다. 저는 LLVM의 각 컴파일 단위에 대해 GNU Parallel에서 Kythe를 실행합니다(병렬은 자동으로 32개의 프로세스를 실행합니다).

다음 워크로드는 10분 이상 모든 코어를 지속적으로 최대화할 수 있었습니다.

  • Ninja를 사용한 Clang 컴파일. 이 워크로드는 유사한 수의 입력 작업을 수행해야 한다는 점에서 인덱싱과 다소 유사합니다. Kythe는 내부적으로 Clang을 사용하여 코드를 인덱싱합니다. CPU온도는 75~80도 정도 됩니다. Kythe 실행과 관련 없는 차이점 중 하나는 Kythe가 약 300MB ~ 2.5GB의 인덱스를 생성할 수 있다는 것입니다.모든따라서 임시 파일을 생성하는 작은 Python 래퍼에서 Kythe를 실행하고 Kythe가 파일에 쓴 다음 파일을 삭제합니다.
  • GNU Parallel은 간단한 바쁜 루프를 실행합니다(5-15초 안에 1K 벡터 요소를 증가시킵니다. 이는 Kythe가 컴파일 단위를 인덱싱하는 데 걸리는 시간과 비슷합니다). 온도는 위와 비슷합니다.

그러나 GNU Parallel에서 Kythe를 실행하면 약간의 제한, CPU 제한 및 작업이 배포되지 않습니다(사용해도 sudo cpupower frequency-set -g performance도움이 되지 않습니다. 따라서 문제는 Kythe 프로세스가 잠시 후에 불이익을 받거나 우선 순위가 낮아지는 것 같습니다). 브라우저 속도 저하를 참조하세요). 온도는 약 60°C까지 떨어집니다.

CPU 조절을 위해 Kythe 사용

위 이미지에서 차트의 전반부는 GNU 병렬/사용 중 주기 작업 부하를 보여줍니다. 그런 다음 이러한 프로세스를 종료하고 GNU Parallel/Kythe 작업 부하를 시작합니다. 어떤 이유로 Kythe 워크로드에는 Clang이나 Busy 루프 워크로드가 겪지 않는 조절 문제가 있습니다. 이 문제의 원인은 무엇입니까? 추가로 디버깅하려면 어떻게 해야 합니까?

단계 복사

  1. (준비) LLVM 저장소에서 CMake 명령을 실행합니다.

    git clone https://github.com/llvm/llvm-project.git --depth=1
    cd llvm-project/llvm
    CC=/usr/bin/clang-14 CXX=/usr/bin/clang++-14 cmake -B ../build -DCMAKE_BUILD_TYPE=Release -G Ninja -DLLVM_ENABLE_PROJECTS=clang
    

    그러면 파일이 준비됩니다 ../build/compile_commands.json.

  2. (준비) Kythe 버전(예: 아래 $HOME/code)을 다운로드하고 Kythe 설명서에 설명된 대로 추출기를 실행합니다.

    wget https://github.com/kythe/kythe/releases/download/v0.0.60/kythe-v0.0.60.tar.gz -o $HOME/code
    tar xzf $HOME/code/kythe-v0.0.60.tar.gz
    cd ../build
    mkdir kythe-v0.0.60-output
    KYTHE_ROOT_DIRECTORY=$PWD KYTHE_OUTPUT_DIRECTORY=$PWD/kythe-v0.0.60-output/ KYTHE_CORPUS=my-llvm $HOME/code/kythe-v0.0.60/tools/runextractor compdb -extractor $HOME/code/kythe-v0.0.60/extractors/cxx_extractor
    
  3. (실제 작업량) Kythe를 병렬로 실행:

    #!/usr/bin/env python3
    # code/timing.py
    
    import sys
    import tempfile
    import time
    import subprocess
    import os
    from datetime import datetime
    
    input_file = sys.argv[1]
    _, output_file = tempfile.mkstemp(prefix="entries-")
    
    start = datetime.now()
    subprocess.run(["/home/varun/code/kythe-v0.0.60/indexers/cxx_indexer", "--ignore_unimplemented", input_file, "-o", output_file])
    end = datetime.now()
    delta = end - start
    
    input_size = os.stat(input_file).st_size
    output_size = os.stat(output_file).st_size
    print("{} bytes to {} bytes in {} sec from {}".format(input_size, output_size, delta.seconds, input_file))
    
    os.remove(output_file)
    
    parallel ~/code/timing.py ::: kythe-v0.0.60-output/*.kzip | tee timings.txt
    

답변1

Kythe 실행과 관련 없는 차이점 중 하나는 Kythe가 컴파일 단위당 약 300MB ~ 2.5GB의 인덱스를 생성할 수 있다는 것입니다. 따라서 Kythe가 쓸 수 있는 임시 파일을 생성한 다음 파일을 삭제하는 작은 Python 래퍼에서 Kythe를 실행합니다.

결과적으로 이것은 매우 관련이 있습니다. Kythe의 높은 디스크 출력을 시뮬레이션하는 더미 스크립트를 생성하고 비슷한 제한이 발생하는지 확인하면 이것이 문제를 일으키는지 쉽게 확인할 수 있습니다. 다음은 예제 스크립트입니다:

#!/usr/bin/env python3

import sys
import tempfile
import time
import os
import random
from datetime import timedelta
from datetime import datetime

output_fd, output_file = tempfile.mkstemp(prefix="entries-")

size_100M = random.randint(5, 15)

start = datetime.now()

# Kythe can end up writing about 500MB - 1.5GB in a span of 5-15s.
# We mimic that workload by writing 1M every 0.01s, and just wasting
# some CPU if we're done writing early.

dummyvec = list(range(1024))

for i in range(size_100M * 100):
    iter_start = datetime.now()
    iter_end = iter_start + timedelta(milliseconds=10)
    os.write(output_fd, os.urandom(1024 * 1024))
    while datetime.now() < iter_end:
        # Waste CPU
        for i in range(len(dummyvec)):
            dummyvec[i] = (dummyvec[i] + 1) % 1024

end = datetime.now()
delta = end - start

output_size = os.stat(output_file).st_size
print("Wrote {} bytes in {} sec".format(output_size, delta.seconds))

os.remove(output_file)

스크립트를 다시 실행할 수 있습니다 parallel.

parallel high_output.py ::: kythe-v0.0.60-output/*.kzip

15초보다 긴 타이밍이 표시되기 시작하면 제한이 발생하고 있음을 확인할 수 있습니다.

parallel명령이 한동안 실행된 후 20~25초보다 긴 시간이 표시되기 시작하는 것으로 나타났습니다 .


CPU 온도뿐만 아니라 다른 온도도 살펴보는 것도 중요합니다. 예를 들어 lm-sensorsUbuntu에서 이 패키지를 사용하여 다양한 센서의 온도를 볼 수 있습니다.

# Re-run sensors from lm-sensors every 2 seconds
watch -n 2 sensors

문제는 NVMe 드라이브의 온도였습니다.

nvme-pci-0400                                                                                                  
Adapter: PCI adapter                                                                                           
Composite:    +55.9°C  (low  = -273.1°C, high = +81.8°C)                                                       
                       (crit = +84.8°C)                                                                        
Sensor 1:     +55.9°C  (low  = -273.1°C, high = +65261.8°C)                                                    
Sensor 2:     +87.8°C  (low  = -273.1°C, high = +65261.8°C)          

최고 속도에서 Kythe는 궁극적으로 컴파일 단위당 100MB/s의 출력을 쓸 수 있습니다. 나쁘지는 않지만 프로세스가 32개 있다는 것은 3.2GB/s의 출력을 의미하는데, 제 경우에는 NVMe를 압도해 과열을 일으키는 것 같았습니다. NVMe 드라이브가 과열되면 Linux는 실행 중인 모든 프로세스를 제한하는 것처럼 보입니다(브라우저 속도 저하를 설명).

특히 Kythe의 경우 이를 기반으로Google 그룹스 주제--experimental_dynamic_claim_cache, Kythe 에는 백그라운드에서 memcached를 활용하여 디스크 출력을 줄이는 데 도움이 될 수 있는 플래그가 있습니다 .

관련 정보