Created
October 25, 2023 01:22
-
-
Save mrocklin/9eca141688d03bbb6c375e53bee35c6d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "id": "ac7b089d-b128-403e-ae72-6aec681aaef7", | |
| "metadata": {}, | |
| "source": [ | |
| "## Setup" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "id": "e840f019-140f-4807-8fe3-a0411beb29a9", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "1\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "!echo $OMP_NUM_THREADS" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "id": "9c8f0c06-3580-4dad-9a6d-b49fefbd4d74", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import os\n", | |
| "os.environ[\"OMP_NUM_THREADS\"] = \"8\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "id": "19a60ae0-2763-437b-8548-2c7ae4ae7682", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import contextlib\n", | |
| "import pyarrow.parquet as pq\n", | |
| "from dask.utils import format_bytes\n", | |
| "import time" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "id": "04731fb7-d84d-4342-afb1-8a1c3060ae4b", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import s3fs\n", | |
| "s3 = s3fs.S3FileSystem()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "id": "3ba34ae5-d3c3-4f87-a77a-c1f317cec64d", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "['coiled-runtime-ci/tpc-h/scale-10/lineitem/lineitem_02c36a39-8df5-493a-9d04-a763fc8d0465.parquet',\n", | |
| " 'coiled-runtime-ci/tpc-h/scale-10/lineitem/lineitem_04136638-fb9b-4a48-a420-02577a9e8880.parquet',\n", | |
| " 'coiled-runtime-ci/tpc-h/scale-10/lineitem/lineitem_049bc3cc-9a29-4605-87f5-22681bb2122e.parquet',\n", | |
| " 'coiled-runtime-ci/tpc-h/scale-10/lineitem/lineitem_04b2c18b-9c53-4d74-af58-71610c6dcd04.parquet',\n", | |
| " 'coiled-runtime-ci/tpc-h/scale-10/lineitem/lineitem_08dd8fe0-39c0-455c-bfe9-524528ed072c.parquet']" | |
| ] | |
| }, | |
| "execution_count": 5, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "filenames = s3.glob(\"coiled-runtime-ci/tpc-h/scale-10/lineitem/*.parquet\")\n", | |
| "filenames[:5]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "id": "8a806cf3-1f32-437e-b123-7f6e870ec7fe", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "'2.87 GiB'" | |
| ] | |
| }, | |
| "execution_count": 6, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "nbytes = s3.du(\"coiled-runtime-ci/tpc-h/scale-10/lineitem/\")\n", | |
| "format_bytes(nbytes )" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "id": "89bed71c-ae93-437a-8359-1404ff6fa20b", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "@contextlib.contextmanager\n", | |
| "def bandwidth():\n", | |
| " start = time.time()\n", | |
| " yield\n", | |
| " stop = time.time()\n", | |
| " print(int(nbytes / (stop - start) // 2**20), \"MiB/s\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 8, | |
| "id": "e44d379e-fbe6-4665-b0c7-db43d6c61dcd", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from concurrent.futures import ThreadPoolExecutor" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "cfccf3f9-d01d-4f41-89c5-a04b55cbbadf", | |
| "metadata": {}, | |
| "source": [ | |
| "## Test general bandwidth onto these machines" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 9, | |
| "id": "aee4b03f-d9d4-43f5-a6f0-ce3bf9e97f2f", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "303 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " def load(fn):\n", | |
| " s3.open(fn).read()\n", | |
| " list(e.map(load, filenames))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 10, | |
| "id": "bdfe6184-b332-4253-a34e-cedc3d6d92c7", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "444 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(6) as e:\n", | |
| " def load(fn):\n", | |
| " s3.open(fn).read()\n", | |
| " list(e.map(load, filenames))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 11, | |
| "id": "5f309e61-83e9-4a54-af90-7d820bd4d96a", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "554 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " def load(fn):\n", | |
| " s3.open(fn).read()\n", | |
| " list(e.map(load, filenames))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "b198d9b5-f2b1-400f-9c4e-b69032d27699", | |
| "metadata": {}, | |
| "source": [ | |
| "## ParquetFile\n", | |
| "\n", | |
| "We have three knobs to play with:\n", | |
| "\n", | |
| "- `pre_buffer`: this is always going to be a good choice\n", | |
| "- `use_threads`: it seems that we want this to be off\n", | |
| "- `filesystem`: s3fs seems to work best with external threads\n", | |
| "\n", | |
| "*maybe these change with large `OMP_NUM_THREADS` but I haven't been able to make this happen." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "516ec3e2-f7fe-4210-9146-3bd34b5f19d6", | |
| "metadata": {}, | |
| "source": [ | |
| "### S3FS" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "id": "734daba8-7160-4b13-b38b-f7c56c36bc5d", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "184 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " def load(fn):\n", | |
| " with s3.open(fn, mode=\"rb\") as f:\n", | |
| " pq.ParquetFile(f, pre_buffer=True).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "id": "20b8f1e1-1b4a-4dec-a7f2-8a1b9b52ed30", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "268 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " def load(fn):\n", | |
| " with s3.open(fn, mode=\"rb\") as f:\n", | |
| " pq.ParquetFile(f, pre_buffer=True).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "id": "1dcb397e-b347-4b89-9754-14d807c9f45a", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "46 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " def load(fn):\n", | |
| " with s3.open(fn, mode=\"rb\") as f:\n", | |
| " pq.ParquetFile(f, pre_buffer=False).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "f6acf24f-3db9-4490-be21-e3811914b7ab", | |
| "metadata": {}, | |
| "source": [ | |
| "### Arrow FS\n", | |
| "\n", | |
| "Less awesome unfortunately. Should try again with OMP_NUM_THREADS" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "id": "e8969a7f-3c2a-4af3-af6c-a5edfadc53e6", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from pyarrow.fs import S3FileSystem\n", | |
| "import boto3\n", | |
| "session = boto3.session.Session()\n", | |
| "credentials = session.get_credentials()\n", | |
| "\n", | |
| "fs = S3FileSystem(\n", | |
| " secret_key=credentials.secret_key,\n", | |
| " access_key=credentials.access_key,\n", | |
| " region=\"us-east-2\",\n", | |
| " session_token=credentials.token,\n", | |
| ")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 16, | |
| "id": "b4036f7b-4532-4404-9d88-a2845185763a", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "136 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " def load(fn):\n", | |
| " pq.ParquetFile(\"s3://\" + fn, pre_buffer=True).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 17, | |
| "id": "2e99023f-f3c5-4eab-b09c-392221921b0e", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "126 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " def load(fn):\n", | |
| " pq.ParquetFile(\"s3://\" + fn, pre_buffer=True).read(\n", | |
| " use_threads=True,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 18, | |
| "id": "2645c274-fbda-4f4a-967c-74c2b6f00af0", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "189 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " def load(fn):\n", | |
| " pq.ParquetFile(\"s3://\" + fn, pre_buffer=True).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| " list(e.map(load, filenames))\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "04a43d98-c921-4e88-868b-69bd0c62307e", | |
| "metadata": {}, | |
| "source": [ | |
| "1. pre_buffer is critical\n", | |
| "2. We shouldn't use the dedicated Arrow thread pool (or maybe this is OMP_NUM_THREADS specific)\n", | |
| "3. We should oversaturate cores" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "63ece358-23f4-4c16-bd69-07b553a70c4d", | |
| "metadata": {}, | |
| "source": [ | |
| "I also tried using the parquet method here, but honestly I couldn't figure out how to invoke it. Emperically I've found that it gives the best results so far." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "344cde23-f7f4-41fc-913e-972cb161c9f4", | |
| "metadata": {}, | |
| "source": [ | |
| "## Dask" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 19, | |
| "id": "d3d65ec7-ef73-4a8e-9bae-1b9e0be48ea6", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import dask\n", | |
| "import dask.dataframe as dd" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 20, | |
| "id": "77b0d19b-e0ca-4209-9fad-ccafe7e086bd", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "168 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "df = dd.read_parquet(\"s3://coiled-runtime-ci/tpc-h/scale-10/lineitem\")\n", | |
| "\n", | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " with dask.config.set(pool=e):\n", | |
| " df.map_partitions(lambda df: df.head(1)).persist(scheduler=\"threads\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 21, | |
| "id": "18028478-ae9f-4029-9764-b61cdca8d67f", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "162 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "df = dd.read_parquet(\n", | |
| " \"s3://coiled-runtime-ci/tpc-h/scale-10/lineitem\",\n", | |
| " open_file_options={\"precache_options\": {\"method\": \"parquet\"}},\n", | |
| ")\n", | |
| "\n", | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(4) as e:\n", | |
| " with dask.config.set(pool=e):\n", | |
| " df.map_partitions(lambda df: df.head(1)).persist(scheduler=\"threads\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 22, | |
| "id": "48d93c01-f5b5-41b7-863a-87b229bdbd10", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "227 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "df = dd.read_parquet(\"s3://coiled-runtime-ci/tpc-h/scale-10/lineitem\")\n", | |
| "\n", | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " with dask.config.set(pool=e):\n", | |
| " df.map_partitions(lambda df: df.head(1)).persist(scheduler=\"threads\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 23, | |
| "id": "0b97a712-ba0e-4e45-9927-27f6b9752275", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "204 MiB/s\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "df = dd.read_parquet(\n", | |
| " \"s3://coiled-runtime-ci/tpc-h/scale-10/lineitem\",\n", | |
| " open_file_options={\"precache_options\": {\"method\": \"parquet\"}},\n", | |
| ")\n", | |
| "\n", | |
| "with bandwidth():\n", | |
| " with ThreadPoolExecutor(8) as e:\n", | |
| " with dask.config.set(pool=e):\n", | |
| " df.map_partitions(lambda df: df.head(1)).persist(scheduler=\"threads\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "6b23c3ae-fd16-4558-8caa-efdda2dae887", | |
| "metadata": {}, | |
| "source": [ | |
| "## Hybrid" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "f10b0023-b1c8-4e88-a96c-d0548a8d6dd6", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "%load_ext snakeviz" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "106c0cdd-45c9-46b4-aefd-a2a8fc04e581", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "%%snakeviz\n", | |
| "\n", | |
| "import io\n", | |
| "from dask.local import synchronous_executor\n", | |
| "with bandwidth():\n", | |
| " with synchronous_executor as e:\n", | |
| " def load(fn):\n", | |
| " bytes = s3.open(fn).read()\n", | |
| " f = io.BytesIO(bytes)\n", | |
| " df = pq.ParquetFile(f, pre_buffer=True).read(\n", | |
| " use_threads=False,\n", | |
| " use_pandas_metadata=True,\n", | |
| " )\n", | |
| "\n", | |
| " list(e.map(load, filenames))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "675abaef-a515-425a-b826-5236ef6b427e", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3 (ipykernel)", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.11.6" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 5 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment