Community코딩 & 개발github.com

magmalake/mojo-data-performance

빠른 Mojo 데이터 코드를 작성하고, 파이프라인의 행 단위 루프부터 리더, 라이터, 코덱까지 시간이 어디에서 소비되는지 찾아내며, 검증 가능한 벤치마크 수치를 얻습니다. Arrow 레코드 배치, Parquet 또는 Iceberg 스캔(arrow-mlake, parquet.mojo, iceberg.mojo, dista, orca)을 순회하는 Mojo 코드를 작성하거나 검토할 때; 파서, 리더, 라이터, 인코더 또는 코덱을 더 빠르게 만들 때; 벤치마크를 작성하거나 pyarrow, parquet-cpp, arrow-rs 또는 Ray와 비교할 때; 수치가 너무 좋아 보이거나 실행 간에 변동할 때; 또는 성능 향상을 주장하기 전에 사용하세요. Modular의 mojo-syntax 스킬과 함께 사용됩니다.

mojo-data-performance란 무엇인가요?

이 스킬은 Mojo 데이터 파이프라인의 성능을 체계적으로 최적화하고 프로파일링하기 위한 종합 가이드를 제공합니다. 디코딩, 행별 작업, 대기(저장소, 락, 스레드)의 세 가지 주요 시간 소비 영역을 식별하고, 스캔 자체를 기준으로 사용하여 병목 지점을 정량화하는 방법을 설명합니다. 특히 행별 루프 최적화를 위한 구체적인 규칙(원시 포인터 접근, 구조체 배열 사용, 분기 없는 필터링, 정수 키에 대한 밀집 배열 활용)과 전체 파이프라인 튜닝 규칙(스레드 간 작업 분산, I/O 중첩, 공유 라이브러리 로드 최적화, 캐싱, 메모리 대역폭 인식)을 측정된 효과와 함께 제시합니다. 또한 리더/라이터/코덱의 하위 수준 최적화, 신뢰할 수 있는 벤치마크 측정 방법, 그리고 성능 향상을 주장하기 전에 반드시 확인해야 할 사항들을 다룹니다. 이 스킬은 Modular의 mojo-syntax 스킬을 보완하며, arrow-mlake, parquet.mojo, iceberg.mojo, dista, orca와 같은 라이브러리를 사용하는 Mojo 데이터 코드에 특히 유용합니다.

지원 대상~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/magmalake/skills/tree/HEAD/mojo-data-performance

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

데이터 파이프라인의 시간은 세 곳으로 갑니다: 데이터 읽기 및 디코딩, 각 행에서 수행되는 작업, 그리고 대기(저장소, 락 또는 하나의 바쁜 스레드에서). 디코딩은 일반적으로 라이브러리에서 이미 튜닝되어 있습니다. 각 행의 작업은 여러분이 작성하는 부분이며, 부주의한 루프가 2~3배의 비용을 초래할 수 있는 곳입니다.

이 파일의 대부분은 스캔의 배치를 소비하는 코드에 관한 것입니다. 그 아래에 있는 리더, 라이터 또는 코덱과 신뢰할 수 있는 수치를 얻는 방법에 대해서는 마지막 두 섹션과 그 참조 자료를 참조하세요.

첫째, 시간이 어디로 가는지 측정하세요

비교할 두 번째 구현(Ray, DuckDB, pyarrow)이 있는 경우는 드뭅니다. 대신 스캔 자체를 기준으로 사용하세요:

  1. 스캔만 시간을 측정합니다. 동일한 스캔, 동일한 열, 필터 및 ScanOptions를 사용하여 배치를 폐기합니다. 이것은 디코딩 전용 기준선입니다: 어떤 파이프라인도 이것보다 빠를 수 없습니다.
  2. 자체 작업만 시간을 측정합니다. 배치별 호출(fold, add, 배치를 소비하는 모든 것)을 perf_counter_ns()로 감싸고 시간을 합산합니다.
  3. 비교합니다. 단일 스레드에서 전체 시간이 디코딩 전용 시간의 약 1.5배 이내이면 작업이 가벼운 것입니다; 그 이상이면 작업이 병목이며 최적화할 가치가 있습니다. 여러 스레드에서는 작업이 하나의 스레드에서 실행되는 반면 디코딩은 여러 스레드에서 실행되는지도 확인하세요.

측정 예: 7700만 건의 여행 데이터에 대한 그룹바이가 단일 스레드에서 4.6초가 걸렸으며, 이 중 2.1초가 행별 작업(45%)이었습니다. 8개 스레드에서는 2.6초가 걸렸으며, 동일한 2.1초가 작업(82%)이었습니다. 하나의 스레드가 모든 배치를 소비했기 때문입니다. references/profiling.md에 레시피와 함정이 있습니다.

행별 루프 규칙

각 규칙은 dista 셔플 벤치마크(7700만 행, 로컬 테이블, 단일 스레드)에서 절약한 시간과 함께 제공됩니다. 코드는 references/hot-loops.md에 있습니다.

규칙측정된 효과
각 열의 원시 포인터를 배치당 한 번 가져온 다음 포인터를 인덱싱합니다. 루프 내부에서 List 또는 Tuple[List, List]를 인덱싱하지 마세요.전체 행별 작업 시간 1.40 → 0.78초
하나의 키가 축적하는 모든 것을 하나의 슬롯에 나란히 유지합니다(구조체 배열). 병렬 배열을 사용하지 마십시오. 그러면 한 번의 업데이트가 하나의 캐시 라인에만 닿습니다.다음 규칙과 함께 2.09 → 1.40초
분기 없이 필터링합니다: 모든 행을 계산하고, kept 인덱스에 쓰고, kept를 Int(keep)만큼 증가시킵니다. 그런 다음 유지된 행을 두 번째의 타이트한 루프에서 추가합니다.위 규칙과 함께 측정됨
키가 작은 정수(zone × zone × hour는 170만)인 경우, Dict 대신 밀집 배열을 키로 인덱싱합니다.단독 측정되지 않음; 두 버전 모두 밀집 배열 사용
최적화하는 동안 부동소수점 덧셈의 순서를 변경하지 마세요. 그러면 결과가 이전 결과와 비트 단위로 일치해야 하며, 이는 무료 정확성 검사입니다.위의 모든 단계가 정확히 일치함

전체 파이프라인 규칙

규칙측정된 효과
여러 스레드가 디코딩하는 것을 하나의 스레드가 소비하도록 하지 마세요. 각 작업자에게 자체 누산기를 제공하고 마지막에 병합합니다(dista의 맵 태스크처럼).16개 스레드는 AWS에서 단일 프로세스 그룹바이를 202초에서 126초로만 줄임
하나의 디코딩 스레드에서도 여러 읽기를 동시에 진행합니다: ScanOptions.files_at_once(및 overlap_io)를 iceberg.mojo에서 사용하세요.S3에서 읽는 단일 스레드에서 6.6–6.9배
공유 C 라이브러리를 프로세스당 한 번 로드하고 핸들을 유지하며, 호출당 로드하지 마세요.zstd가 호출마다 열릴 때 스캔 시간의 52%가 dyld에서 소비됨; 수정 후 2,687 → 262ms
바이트 단위로 반복되는 구문 분석 결과(예: 매니페스트의 Avro 스키마)를 캐시하세요.매니페스트 계획의 고정 비용이 3.6배 감소(113.7 → 31.9µs)
레코드별로 할당하지 마세요: 재사용된 슬롯으로 디코딩하세요.Avro 리더가 커서 전에 레코드당 약 60번 할당함
한계를 인식하세요: 몇 개의 코어를 넘으면 스캔은 메모리 대역폭에 의해 제한되며, 더 많은 스레드가 도움이 되지 않습니다. 대신 더 적은 바이트를 읽으세요.Iceberg 스캔이 단일 코어에서 35.8ms, 4개 코어에서 12.1ms로 약 3배

references/case-studies.md는 각 사례에 대한 이야기와 문제를 알려준 징후를 설명합니다.

리더, 라이터 및 코덱

디코딩 자체가 느린 부분일 때, 규칙은 주로 버려지는 작업을 수행하지 않는 것에 관한 것입니다. 세부 사항과 수치는 references/readers-and-codecs.md에 있습니다.

  • 각 빠른 경로의 게이트가 이를 도달하는 호출자에 의해 충족될 수 있는지 확인하고, 계측을 통해 실행됨을 증명하세요. 게이트를 어떤 리스트 열도 충족할 수 없었던 벡터화된 경로는 9KiB 열을 읽기의 43%로 남겼습니다.
  • 이후 결정이 일반적으로 폐기하는 것을 계산하지 마세요. 일반 인코딩을 선택하기 위해 딕셔너리를 구축하는 것은 int64 열 쓰기의 67%를 차지했습니다; 이를 제거하면 출력이 바이트 단위로 동일하면서 쓰기가 3.3배 빨라졌습니다.
  • 복사 대신 빌리고, 최종 레이아웃으로 직접 디코딩하세요(예: 정의 수준을 유효성 비트맵으로).
  • 데이터에 실행(run)이 있는 경우 실행 단위로 작업하세요: 1% null에서 약 250번의 memmove가 약 25,000번의 슬롯별 분기를 대체합니다.
  • 단계가 이미 메모리 대역폭에 도달했을 때를 인식하세요: 18.3MB를 1.2ms에 입출력하여 약 30GB/s를 이동한 단계는 건너뛸 수밖에 없었습니다.
  • 스레드를 추가하기 전에 가장 느린 항목을 찾으세요. 열 청크로 분할하면 하나의 큰 열이 항상 실행되었기 때문에 한 읽기가 1.39배로 제한되었습니다.

최적화뿐만 아니라 결과도 테스트하세요: 의도적으로 최적화를 깨뜨리고 테스트가 실패하는지 확인하세요 (references/testing-optimizations.md). Mojo 자체의 함정(예: 마지막 사용 시 값이 사라지는 현상, MutUntrackedOrigin)은 references/mojo-hazards.md에 있습니다.

신뢰할 수 있는 수치 얻기

references/measurement.md에 전체 규칙이 있습니다. magmalake에서 결론을 바꾼 규칙은 다음과 같습니다:

  • 중앙값(p50)을 p90과 함께 보고하고, 평균만 보고하지 마세요. 하나의 느린 첫 호출이 평균을 30% 이동시키고 p50은 전혀 이동시키지 않았습니다.
  • 벤치마크를 미리 빌드하고, mojo run으로 시간을 측정하지 마세요. JIT가 한 벤치마크를 1.9배 부풀렸습니다.
  • 머신이 안정적인지 확인하세요. 동일한 벤치마크가 유휴 상태에서 31ms, 16개의 바쁜 스레드 옆에서 89ms가 걸렸습니다.
  • 참조의 API와 스레드 수를 명시하세요. pq.read_table은 pyarrow의 데이터셋 스캐너이지 parquet-cpp의 읽기 경로가 아니며, pyarrow의 스레드 설정이 한 파일의 읽기를 2.9배 이동시켰습니다.
  • 두 수치가 일치하지 않을 때, 차이를 설명하기 전에 동일한 방식으로 생성되었는지 확인하세요.

성능 향상을 주장하기 전에

  • 결과를 비교하세요 전후, 가능한 경우 정확히 동일하게(마지막 루프 규칙 참조). 더 빠른 잘못된 답변은 느린 올바른 답변보다 나쁩니다.
  • 두 수치와 설정을 보고하세요: 행, 스레드, 로컬 디스크 또는 S3, 캐시가 웜 상태였는지 여부.
  • 남은 것을 말하세요. 셔플 수정 후 777ms 중 325ms는 여전히 열 복사에 사용되며, 여러 스레드에서도 작업은 여전히 하나의 스레드에서 수행됩니다.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

magmalake/dista

Write and run distributed Mojo programs with dista, magmalake's Ray-style task framework, where one compiled binary is the driver, the head and every worker. Use when writing or reviewing Mojo code that imports dista or mentions distributed Mojo, a remote task, `Task`/`Task2`/`TaskMany`/`TaskWith`, `ObjectRef`, `rt.remote`, `rt.get`, `Seq`, an actor with methods or checkpoints, a cluster, a head, workers, `DISTA_ROLE`/`DISTA_HEAD`, the `dista` command (status, drain, scale, timeline, stop), draining, autoscaling, or a dista runtime inside an orca pipeline step; and when a dista job hangs, is refused with a registry mismatch, or fails with a lost result. Pairs with Modular's mojo-syntax skill and magmalake's mojo-data-performance skill.

magmalake/magmalake-apps

Build a data application on magmalake as one Mojo project, with pipelines run by orca, a lake of Iceberg tables over S3, and a long-running flare web app reading them, then deploy it to AWS with `orca aws`. Use when starting a new magmalake project or laying one out (pixi, mojoshelf, `bin/`, `pipelines/`, `src/`); when a pipeline step writes Iceberg tables that an app reads; when writing a flare web app, console or dashboard over the lake; when running the project locally with Postgres and a local warehouse; or when deploying to AWS (`orca aws up`, `push`, `register`, `app`, `status`, `down`), setting up its hostnames, secrets, public bucket or costs. Pipelines in depth (partitions, keyed, sensors, dista tasks) are the `orca` skill's.

관련 스킬