코딩 에이전트가 성능 최적화의 비용을 극적으로 낮추면서, 워크로드별 맞춤 최적화와 더 빠른 소프트웨어가 가능해지고 있다.
얼마 전, LLM이 느리고 비대한 코드를 만든다고 말하는 사람들은 결국 모든 것을 초최적화된 어셈블리로 다시 작성하면 망신당할 것이라는 내용의 바이럴 트윗을 봤다. 아직 모든 것을 어셈블리로 작성하고 싶은 단계는 아니다. 하지만 테스트에 관해 Nolan Lawson이 말한, 이제 원하는 만큼의 버그를 고를 수 있다는 이야기의 어떤 변형, 그리고 내가 여기에서 그보다 덜 우아하게 언급한 내용은 성능에도 점점 더 사실이 되고 있다.
내 지난 글에서, 예전에는 전문성이 필요했던 성능 작업의 비용이 여러 자릿수만큼 떨어졌고, 희귀한 기술 집합을 가진 개인이나 팀이 필요했던 성능 작업을 이제 몇 문장만 입력할 수 있는 사람이면 누구나 할 수 있게 되었다는 의견에 대해1, 즉 과거에는 최대 규모이거나 가장 수익성 높은 프로젝트가 아니면 비용 대비 가치가 없었던 온갖 최적화를 이제 할 수 있게 되었다는 말에 대해, Marc Brooker는 이렇게 답했다
마지막 요점에 전적으로 동의합니다. 워크로드의 한 부류가 아니라 특정 워크로드에 맞춰진 동적 맞춤 소프트웨어는 매우 그럴듯한 결과로 보입니다. 물론 그 자체로 온갖 흥미로운 위험과 기회를 동반합니다. FFTW가 조금 떠오릅니다. 그리고 매우 특정한 문제, 흔히 매우 특정한 하드웨어에서 극도로 빠르고 작아지는 데 집중했던 기묘한 옛 데모신 기법들도 수없이 많습니다. 예를 들어 코드를 텍스처로 재사용해서 훌륭한 캐시 지역성을 얻은 데모를 기억합니다.
그리고 Michael Malis는 다음과 같이 지적했다.
AI가 도움이 되지 않는 이유는 “코드는 결코 어려운 부분이 아니었기 때문”이라는 밈이 돌고 있습니다. 일부 영역에서는 맞는 말이라고 생각하지만, 다른 영역에서는 코드를 작성하는 일이 분명히 어려운 부분이었습니다. JIT 컴파일러가 훌륭한 예입니다. 많은 소프트웨어에서 JIT 컴파일러는 코드 속도를 높이는 데 큰 도움이 됩니다. JIT 컴파일러가 드문 것은, 역사적으로 구현이 가치 있을 정도로는 너무 어려웠다는 뜻이라고 생각합니다. LLM은 진입 장벽을 낮추고 JIT 컴파일러를 훨씬 쉽게 작성하게 했습니다. 이것이 pgrust의 논지입니다. 데이터베이스는 역사적으로 구축하기 가장 어려운 소프트웨어였고 그 때문에 제약을 받았습니다. 이제 AI와 함께라면 우리가 만드는 소프트웨어의 종류에 더 야심차게 접근할 수 있습니다.
지난 글에서 만든 정규식 엔진 FRE로 이를 시도해 보자. 에이전트가 rebar 정규식 벤치마크 모음에 접근할 수 있는 상태에서 한 달 동안 정규식 엔진 성능 개선을 반복하도록 해서 만들었다는 점을 기억하자. 그 결과 FRE는 홀드아웃 벤치마크가 있다고 에이전트에게 경고하기 전까지 rebar에 심하게 과적합되었다. 경고 후 에이전트는 최적화를 충분히 일반화했고, 홀드아웃에서 성능이 그럭저럭 괜찮아졌다. 홀드아웃 벤치마크에서 잘 검증된 정규식 엔진을 이기지 못하는 “소프트웨어 공장” 정규식 엔진을 쓸 특별한 이유는 없다. 하지만 FRE에서 주목할 만했던 점 하나는 네이티브 AOT 컴파일 버전이 더 긴 검색에서 꽤 잘했다는 것이다. ripgrep가 일반 매처를 실행하는 동안 다른 스레드에서 네이티브 코드 컴파일러를 돌리고, 컴파일이 끝나면 네이티브 코드로 전환하면 전반적으로 더 나은 성능을 얻을 수 있다는 것은 당연해 보인다. 물론 컴파일에 스레드 하나를 잃으므로 짧은 질의에서는 대체로 성능이 나빠질 것이다. 하지만 나는 ripgrep가 몇 초 걸릴 때보다 여러 초나 여러 분 실행될 때 얼마나 오래 걸리는지를 훨씬 더 중요하게 생각하므로, 그 절충은 괜찮다.
사람 시간 몇 분으로 정규식 엔진을 만들 수 있었던 것과 마찬가지로, 이 실험도 사람 시간 몇 분으로 그냥 해볼 수 있다. 몇 문장을 입력하자 에이전트가 이를 가능하게 하는 작업을 수행했고(사람에게는 상당한 코드 수술이 될 일이다), 내 codex 이력에서 나온 실제 ripgrep 질의로 벤치마크를 실행했다. 더 긴 질의에서는 아주 단순한 몇몇 질의에서 2x-4x 성능 향상을 볼 수 있다. 하지만 대부분의 질의는 더 복잡하다. 대표적인 홀드아웃 질의에서, AOT를 활성화해야 하는 질의의 경우2, 약 7%의 속도 향상을 얻는다. 세상을 뒤흔들 결과는 아니지만, codex에 몇 분 입력한 대가로는 나쁜 결과도 아니다. 그리고 여전히 더 최적화하고 있으므로, 아마 더 빨라질 것이다.
반복해서 컴퓨터에서 텍스트를 검색한다면, 이를 빠르게 하는 명백한 방법은 정규식 매칭용 네이티브 코드 컴파일러를 작성하는 것이 아니라 인덱스를 만드는 것이므로, 이것은 다소 엉뚱한 일일 수 있다. 하지만 여기서 요점은 예전에는 상당한 시간과 전문성이 필요했던 이런 기술 작업을 이제는 그냥 사소하게 할 수 있다는 것이다. 텍스트 인덱스를 만든다고 하면, 나는 마침 SIGIR에서 최우수 논문상을 받은, 지속적으로 빠른 텍스트 수집에 특화된 Bing 검색 인덱스 BitFunnel을 작업한 적이 있다. 따라서 전체 머신의 빠른 로컬 인덱스를 만든다면 시도할 실험 몇 가지를 생각할 수 있다. 내가 본 프로젝트들은 코드 디렉터리를 인덱싱하려는 듯하지만, 내 머신 성능을 정말 망가뜨리는 것은 codex가 생성 파일이 아주 많은 거대한 임시 디렉터리에 ripgrep를 실행하기로 결정한 뒤, 찾지 못하면 내 전체 머신을 살피도록 확장하는 경우다. 그래서 몇몇 프로젝트의 코드뿐 아니라 전체 디스크의 인덱스를 원할 것이다.
AI 연구소에서 일하면서 Cerebras 칩에서 실행되는 최신 모델이나 tok/s를 크게 늘려 검색의 부하와 수요를 높이는 다른 가속기 같은 것에 접근할 수 있었다면, 기존 인덱서가 충분히 빠른지, 아니면 직접 맞춤형을 만들어야 할지 조사해 볼 수도 있다. BitFunnel의 오픈 소스 버전에는 “단지” 바이트코드 인터프리터와 JIT 하나만 있지만, Bing 버전에는 여러 JIT 컴파일러가 있다. 그런 수준의 최적화를 수행하는 프로젝트는 예전에는 큰 사업이었지만, 이제는 “주말이면 할 수 있겠는데”가 이런 종류의 프로젝트 일부에서는 실제로 사실이다. 보잘것없는 월 $200 계정으로는 조금 더 빠른 ripgrep와 기성 인덱스면 충분하다고 생각한다. 그러니 빠르게 수집하는 전 머신 인덱스 프로젝트는 “독자(중 AI 연구소에서 일하는 사람)를 위한 연습문제”로 남겨둘 수 있겠다.
최적화 비용의 극적인 감소는 2025년 11월부터, 어쩌면 공개 모델로는 그보다 조금 전부터 사실이었다. 물론 AI 연구소 사람들이 접근할 수 있었던 것으로는 그보다 훨씬 전부터였을 것이다. GPT-5.1 또는 5.2 시절의 예로, 게임 AI에 대한 지식이 전혀 없는 상태에서 Azul AI를 만들어 보려 했다. 이는 상당히 큰 차이로 이 게임에서 세계 최강 AI가 되었다. 두 번째로 강한 AI를 설명한 논문을 읽어보면, 내 AI가 “AI” 측면에서는 아마 조금 더 나은 것 같다. 그러나 주된 승리는 최적화에서 온다. 논문을 읽고 그 과정과 내 과정을 비교해 추정하면 아마 두 자릿수 정도 적은 시간을 썼고, 대부분 여러 머신 클러스터 대신 내 노트북에서 작업했다. 이는 실험 실행, 매개변수 조정 등에 쓸 대역폭도 훨씬 적었다는 뜻이다. 예를 들어 다른 AI는 단일 스레드이고 내 AI는 다중 스레드다. 나는 네이티브 코드 버전과 끔찍한 wasm 공유 메모리 + javascript 버전을 모두 갖고 있고, 서로 다른 두 버전을 위한 두 가지 탐색 아키텍처도 있다. 이들은 “필요로 하는” 다중 스레딩 알고리즘이 완전히 다르다. 하나는 매우 작고 빠른 신경망을 위한 minimax이고, 다른 하나는 더 큰 신경망을 위한 MCTS다. 이를 손으로 했다면 꽤 큰 작업이었을 것이다. 그리고 게임 AI용 다중 스레딩 알고리즘을 직접 30분간 읽기 전에 LLM이 자체의 잘못된 추론에 따라 다중 스레딩 알고리즘을 몇 번 고르게 뒀기 때문에, 결국 다중 스레딩 알고리즘을 여러 번 다시 작성했다(codex가 다시 작성하게 했다).
이런 경우 다중 스레딩 알고리즘을 디버그하고 검증하기 위해 하는 표준 작업이 많다. 예를 들어 비결정적인 알고리즘인데도 버그를 재현할 수 있도록 디버그 로그에서 리플레이를 구현하는 일이다. 그것만으로도 손으로 했다면 아마 며칠에서 일주일의 작업이었겠지만, 에이전트가 반복문에서 사소하게 할 수 있는 바로 그런 일이다. 리플레이를 시도하게 하고, 완벽한 리플레이가 나오지 않을 때마다 비결정성을 위한 로깅을 삽입하면 된다. 이런 까다로운 최적화를 작동시키는 데 예전에는 필요했던 지루한 작업의 상당 부분이 사라졌다.
이는 다른 많은 까다로운 최적화에도 적용된다. CPU 마이크로코드를 작성하고, CPU 검증을 하고, 검색 엔진 인덱스 최적화를 해본 경험 등으로, 나는 최적화를 보며 “흠, 이건 성능을 2% 높이겠지만 이 까다로운 최적화가 작동함을 검증하는 데 N 인일이 걸리겠네”라고 생각하고, 최적화를 작동시키는 데 시간을 쓸 가치가 있는지에 따라 진행 여부를 결정한 경험이 많다. 이제 이 N이 엄청난 배수로 떨어졌으므로(사람 시간으로는 가변적이지만 흔히 1000x / 10000x / 1000000x, 검색 인덱스가 사용한 JIT의 컴파일러를 작성한 Bing 엔지니어와 비교해 계량 요금의 토큰 비용을 보면 달러 비용으로는 아마 1000x에 더 가깝다), 수행할 가치가 있는 이런 종류의 최적화 수가 크게 늘어난다. 작동할지 확신할 수 없는 최적화도 마찬가지다. 예전에는 가속될지 확신하지 못하는 최적화를 보고 “성능 영향을 추정할 만큼 충분히 좋은 측정에 이르려면 구현에 M시간이 걸릴 텐데”라고 생각하곤 했다. 이제는 훨씬 더 많은 그런 최적화를 시도할 만하다.
게임 AI 사례로 돌아가면, 적어도 내가 시도한 AI에서는 속도를 두 배로 할 때마다 약 100 Elo를 얻는 듯하다. 아마 무승부가 아주 드물어서 체스보다 더 클 것이다. 다중 스레딩만 추가해도 큰 머신에서는 그 외에 비슷한 AI를 완전히 압도하기에 충분하다. 대부분의 사람이 손으로 하기에는 너무 성가시다고 느낄 만한 최적화 10-20개를 더 쌓으면 강도 차이는 엄청나며, 손으로 작성한 AI가 따라잡으려 하는 것은 사실상 합리적이지 않다3.
게임 AI 사례는 대부분의 소프트웨어보다 조금 더 성가시다. 원하는 최적화 중 많은 것이 실제 결과를 바꾸며, 속도 증가와 결과 변화가 실제로 더 좋은 결과를 주는지 나쁜 결과를 주는지 실전에서 판별하는 싸고 사소한 방법이 없기 때문이다. 또한 전에 언급했듯이, 현재 공개된 최신 모델은 실험 설계에 꽤 취약하다. 그래서 최적화가 좋은지 판단하기 위해 이들이 사용할 틀을 내가 마련해야 했다. 하지만 그것이 갖춰지고 나면 다른 최적화 문제와 같다. LLM 최적화를 하는 사람들도 이런 종류의 문제를 다뤄야 할 것 같지만, 대부분의 최적화 문제는 훨씬 더 간단하다.
다른 예를 들면, 성능 면접을 준비하는 과정에서 Jamie Brandon은 Anthropic의 현재 공개된 성능 과제를 시도했다. 해본 뒤 Claude가 자신이 멈춘 곳부터 이어서 하게 했고, 훨씬 더 좋은 결과를 얻었다. Claude가 자신은 하지 않았던 일을 살펴본 뒤, 많은 최적화는 자신도 생각했지만 아직 해보지 못했던 것들이었고, “[그] 외에는 몇 주 동안 이 일을 하지 않는 한 절대 시도하지 않을 미친 것들”이었다고 말했다4. 그는 합리적인 성능 엔지니어이고 원했던 성능 직무의 제안도 받았지만, 잘 정의된 최적화 문제에서는 괜찮은 모델을 이길 가능성이 없다. 나는 그 문제를 직접 시도하지 않았지만, 비슷한 시간 제약이라면 나 역시 가능성이 없으리라 생각한다.
Marc Brooker의 다음 의견으로 돌아가 보자.
워크로드의 한 부류가 아니라 특정 워크로드에 맞춰진 동적 맞춤 소프트웨어는 매우 그럴듯한 결과로 보입니다.
이는 꽤 불가피해 보인다. 내 글에 대한 또 다른 답변에서 pgrust의 Michael Malis도 비슷한 말을 했다.
[pgrust 최적화에 관한 논의] ... 이런 최적화는 충분히 쉽게 만들 수 있으므로 고객의 워크로드를 보고 필요에 따라 추가할 수 있다고 생각합니다
어떤 프레임워크나 설정도 없이, 이 글을 쓰기 직전에 에이전트가 내 ripgrep 질의를 위한 워크로드별 최적화를 하게 했다. 네이티브 코드 컴파일러 전환이 아니라, 일련의 벤치마크에 근거해 일반 FRE 엔진을 최적화한 것이다. 시작하는 데 내 시간 약 2분이 들었다. 최적화는 질의 집합에서 실행되고, 나중에 홀드아웃 질의 집합을 대상으로 실행한다. 아직 실행 중이지만 초기 결과는 유망해 보인다. 최적화 한 번 후, 워크로드 최적화 버전은 홀드아웃에서 표준 ripgrep보다 2% 빠르고 계속 빨라지고 있다. 내 로컬 ripgrep 사용에서 2%는 큰일이 아니지만, 이것이 몇 분 걸렸고 이 최적화는 내가 이 대목을 입력하기 시작했을 때 시작되어 아직도 개선 중임을 생각하면, 여기서 2%의 이득을 택하겠다. 네이티브 코드 컴파일러와 결합한 것은 아니며, 제대로 결합하면 전체 이득은 더 클 것이다. 그리고 이것이 FRE 정규식 엔진을 활용한다는 점을 기억하자5. FRE는 홀드아웃 벤치마크에서 Rust 정규식 엔진보다 상당히 느렸고, 내가 정규식 워크로드를 전혀 모르며 최신 LLM도 인간의 안내 없이 개방형 자기 개선 반복을 할 만큼 실험 설계를 잘하지 못했기 때문에, 홀드아웃 성능을 개선할 좋은 방법이 없어 홀드아웃에서의 개선도 느렸다. 하지만 내가 관심 있는 것이 내 워크로드에서의 성능이라면, 데이터도 충분하고 계속 더 생성되고 있다. 위에서 Marc Brooker가 언급했듯 과거 데이터에 없는 체제 변화 등이 있을 때 과적합은 조심해야 하지만, 그래도 이전보다 더 나은 상황이다.
더 일반적인 경우 Amazon의 Marc Brooker나 pgrust를 작업하는 Michael Malis 같은 사람이라면, 이것을 일회성으로만 하기보다 고객과 함께 고객 데이터를 사용해 최적화하는 프로그램을 시험 운영하고, 이를 일반 고객에게 확장하는 방법을 알아보는 것이 타당하다. 나는 그것이 내 시간을 가장 잘 쓰는 회사에서 일하지는 않지만6, 더 큰 규모의 대기업에 이런 일이 다가오고 있음을 볼 수 있다는 점은 꽤 놀랍다. 내 개인 작업 흐름을 위해 이런 실험을 실행하는 데는 내 시간이 몇 분밖에 들지 않으므로, 개인 프로젝트에서 이런 일을 해보는 것도 충분히 합리적이다.
Jamie Brandon, Michael Malis, Max Bittker에게 의견, 수정, 토론에 감사한다.
추신. 지난몇 글에서 언급했듯이, 코딩 에이전트와 함께라면 실험을 실행하고 내 호기심을 만족시킬 만큼 결과를 보는 시간은 크게 줄어든 반면, 결과를 정말 엄밀하게 만드는 시간은 변하지 않았거나 늘었다. 따라서 예전 방식으로 글을 쓰면 내가 실험할 수 있는 대역폭에 비해 아주 적은 실험만 실행하게 된다. 그 결과 이 실험들을 실행하고 몇 친구와 결과를 공유해 왔다. 실험으로, 수년 동안 이 실험들이 몇 친구에게만 알려지는 대신 마지막 글처럼 아주 빠르고 비엄밀한 방식으로 이를 적어보려 한다. 마지막 글처럼 이 글을 작성하고 모든 정리를 반 시간 안에 마치는 것을 목표로 했으며 시간을 재지는 않았지만, 조금 넘겼다고 확신한다.
이렇게 해도 이를 적는 시간이 길어서 최근 결과를 공유하는 일이 밀리고 있다. 하지만 LLM이 쓴 글로 전환할 생각은 아직 없고, 데이터를 정리하고 이런 글을 써서 반 시간 이내에 글을 완성할 만큼 시간을 줄이는 일도 현실적으로 가능하다고 생각하지 않는다. 이 글의 길이만 보아도, 이를 입력하는 데는 내가 쓰는 내용을 멈춰 생각하는 시간을 포함해 20-30분 정도가 걸릴 것이다. 그러고 데이터를 보면 때로 무언가 충분히 이상해 보여서 고쳐야 할 문제가 있는지 자세히 살펴봐야 한다. 여기서도 여러 번 그랬고, 훨씬 더 많은 시간을 쓰지 않았으므로 내가 모르는 다른 데이터 문제가 있을 것이라고 예상한다.
어쨌든 이 빠르고, 분명 더 틀릴 수도 있는 글에 의견이 있다면 어떻게 생각하는지 알려 달라(XBskyMastodon)!
나는 X의 개발자들이 느린 코드를 작성해서 나쁘고 나쁘게 느껴야 한다는 일반적 정서에 오랫동안 강하게 반대해 왔다. 프로그래밍 전문성에는 매우 다양한 종류가 있고, 대부분의 프로그래머가 성능 전문성을 갖고 있지 않을 뿐 아니라, 기업이 관심 갖는 것, 고용 시장의 모습 등의 관점에서 그들이 성능 전문성을 개발하는 것이 타당하지 않을 수도 있다. 그러므로 대부분의 프로젝트가 성능 전문가가 달성할 수 있는 수준에 비해 매우 나쁜 성능을 보이는 것은 당연하다.
위 예에서 Jamie Brandon은 Anthropic의 제안을 받았고, OpenAI가 아니라면 아마 그나 그와 같은 사람을 고용할 여유가 없을 것이다. 그러나 한정된 최적화 문제에서 그를 이길 수 있는 코딩 에이전트를 쓰는 것은 감당할 수 있다. 에이전트는 그가 가진 판단력을 갖고 있지 않아 개방형 문제에서는 더 못할 것이다. 최적화된 정규식 엔진을 만들려 하고 과적합하지 말라고만 했을 때, 홀드아웃 벤치마크에서 최고 정규식 엔진들보다 한 자릿수 이상 더 나빴다. 하지만 홀드아웃에서 성능이 나쁘다고 에이전트에게 말한 뒤에는 정규식 엔진 성능을 충분히 높여 대체로 성능 면에서 2군 정규식 엔진들과 맞먹게 했다. 오늘날 대부분 코드의 일반적인 성능 최적화 수준과 비교하면 그것도 여전히 매우 좋다. 하지만 온갖 문제에서 합리적인 성능을 얻기에는 충분히 좋다. 이 글은 대체로 백엔드 성능 문제를 다뤘지만, LCP, INP 같은 일련의 지표를 낮추고 싶다면 에이전트가 프런트엔드 성능에서 더 나빠 보이지도 않는다.
내 머신에서 ripgrep 질의 분포에 관한 몇 가지 정보가 있다. 이것이 다른 곳에서 일어나는 일을 전혀 대표한다고 주장하지 않는다. 검색한 패턴 길이의 분포에는 예상보다 긴 패턴이 훨씬 많다. p50은 유니코드 코드 포인트 55개다. 간단히 문자라고 부르겠다. 이는 이미 내가 손으로 grep하는 것보다 길고, p90은 119다!
정규식의 교대 분기 수를 볼 수도 있는데, 다시 한번 말하지만 내가 손으로 하는 것보다 훨씬 복잡하다.
또 다른 관점은 이들이 어떻게 상관되는지 보는 것이다. 정규식이 길어질수록 정규식의 교대 분기가 더 많아지는가? 그렇다.
그런데 이 정말 긴 정규식은 대체 무엇일까? 살펴보면, 가장 긴 것 대부분은 함수 또는 테스트 이름에 대한 긴 교대다. 다음 정규식처럼, FRE 개발과 관련 있어 보인다.
fn (hot_byte_compiler_is_generic_only_and_anonymous_count_uses_auto_count|
one_pattern_count_spans_uses_the_retained_complete_span_session|
formal_compact_state_byte_visitors_coexist_with_native_count|
fixed_boundary_record_visit_matches_line_relative_reference_and_is_atomic|
unbounded_languages_refuse_finite_extraction_before_allocation|
formal_single_raw_span_sweep_preflight|
assert_exact_fixture_uses_formal_large_continuation_sweep|
url_only_compile_identity_binds_language_and_owner_mode|
url_only_compile_exact_limits_and_runtime_refusals_close|
url_only_compile_post_plan_allocation_faults_close|
url_only_owner_discriminator_is_stable_and_precharged|
url_only_compile_owner_is_strategy_and_operation_scoped|
formal_rebar_url_owner_is_compile_only_and_matches_oracle|
formal_rebar_url_exact_fixture_uses_certified_execution|
formal_fixed_schema_materialization_matches_both_record_oracles_and_controls|
formal_single_count_selects_compact_state_byte_complete_bound_visitors|
authenticated_bound_line_total_lf_free_domain_opportunity_exceeds_five_percent|
prepared_absolute_onepass_fuses_slots_and_preserves_pre_source_fallback|
authenticated_word_boundary_russian_compact_lowering_public_canary|
ordered_nfa_x86_epsilon_edges_bypass_the_assertion_call|
ordered_nfa_aarch64_epsilon_edges_bypass_the_assertion_call|
ordered_edge_dispatch_v2_is_target_neutral_deterministic_and_relocation_free|
ordered_edge_dispatch_v2_copies_canonical_tables_and_cap_falls_back_to_v1|
ordered_nfa_v3_composes_terminal_range_and_dispatch_without_data_relocations|
ordered_nfa_x86_terminal_range_emits_authenticated_reverse_scan|
ordered_nfa_aarch64_terminal_range_emits_authenticated_reverse_scan|
ordered_nfa_x86_boundary_assertion_cache_is_lazy_and_boundary_scoped|
ordered_nfa_aarch64_caches_repeated_assertions_once_per_boundary|
boundary_assertion_cache_requires_dense_exact_kind_reuse|
boundary_assertion_cache_selection_is_compiler_only_and_deterministic)
하지만 다음처럼 재미있는 수치 구성도 있다.
:(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9]|20[0-9]|21[0-9]|22[0-9]|23[0-9]|24[0-9]|25[0-9]|26[0-9]|27[0-9]|28[0-9]|29[0-9]|30[0-9]|31[0-9]|32[0-9]|33[0-9]|34[0-9]|35[0-9]|36[0-9]|37[0-9]|38[0-9]|39[0-9]|40[0-9]|41[0-9]|42[0-9]|43[0-9]|44[0-9]|45[0-9]|46[0-9]|47[0-9]|48[0-9]|49[0-9]|50[0-9]|51[0-9]|52[0-9]|53[0-9]|54[0-9]|55[0-9]|56[0-9]|57[0-9]|58[0-9]|59[0-9]|60[0-9]|61[0-9]|62[0-9]|63[0-9]|64[0-9]|65[0-9]|66[0-9]|67[0-9]|68[0-9]|69[0-9]|70[0-9]|71[0-9]|72[0-9]|73[0-9]|74[0-9]|75[0-9]|76[0-9]|77[0-9]|78[0-9]|79[0-9]|80[0-9]|81[0-9]|82[0-9]|83[0-9]|84[0-9]|85[0-9]|86[0-9]|87[0-9]|88[0-9]|89[0-9]|90[0-9]|91[0-9]|92[0-9]|93[0-9]|94[0-9]|95[0-9]|96[0-9]|97[0-9]|98[0-9]|99[0-9])[0-9]:
이는 :(?:1[3-9]|[2-9][0-9])[0-9]{2}:와 동등하다. 원래 입력에서 ripgrep로 실행하면 대략 같은 성능을 보인다. 이를 위한 전체 파이프라인은 다음과 같았다.
cargo clippy … | rg 'crates/fre-aot-regex/src/module.rs:' | rg NUMBER_REGEX | head -250
사람에게는 이상한 일일 수 있지만, 에이전트는 이런 종류의 일을 항상 하는 듯하다.
다른 주제로, ripgrep 질의가 걸린 시간을 보면 느린 질의가 상당히 많다. 예를 들어 p99는 거의 1분이다! p999는 거의 10분이다! 그리고 이 기간 동안의 최대 질의는 한 노트북에서 약 한 달로, AWS 호스트에서 에이전트를 실행할 때는 질의와 분포가 다를 법하지만 확인하지는 않았다. 거의 2시간에 이른다!
명령줄 옵션으로 보면 다음과 같다. 아마 놀랍지 않게도 codex는 줄 번호를 자주 원하고, 무슨 이유에서인지 아주 가끔 PCRE2 정규식을 사용한다.
이에 대해서는 플롯이나 표를 추가하지 않겠지만, 또 주목할 점은 어떤 패턴을 검색하는지의 지역성이 꽤 낮다는 것이다. 약 94%의 패턴은 한 번만 나타났다. 많은 질의가 아주 길었다는 점을 생각하면 이해된다. 하지만 어떤 파일을 검색하는지에는 꽤 높은 지역성이 있으며, 검색한 파일은 비교적 곧 다시 검색될 가능성이 높다. 이는 충분히 작은 파일의 경우 메모리에서 검색될 가능성이 높다는 뜻이다.
또한 질의의 99%는 정규식 질의였고(1%는 비정규식 문자열 검색이었다), 검색 질의의 99.9%는 ASCII 전용이었다. 그러나 검색한 파일 기준으로는 약 45%가 ASCII 전용이고 55%는 유니코드를 포함했으며, 이는 유니코드에 대해 내가 예상했던 것보다 높은 비율이다.
지난 글 초안에서 Peter Geoghegan은 이렇게 지적했다.
지원 기능을 줄여도 정규식 구현은 더 빨라질 수 있습니다. 일부 구현은 역참조 등을 지원하지 않습니다.
여기에서도 그렇다. 여기서 수행한 워크로드별 최적화는 codex에 짧은 지시 몇 개를 주고 원하는 대로 하게 했기 때문에 꽤 피상적이었다. 일반적으로 그것이 codex를 가장 효과적으로 사용하는 방법은 아니다. 하지만 더 상세한 계획이 있다면, 내 질의의 흔한 사용 사례를 지원하는 더 집중적인 최적화로 더 큰 이득을 기대할 수 있다.