From 1413593fb49cc544927a1c10c9b5f5d73663cde7 Mon Sep 17 00:00:00 2001 From: Sajad Karm Date: Tue, 2 Aug 2022 11:50:37 +0200 Subject: [PATCH 01/81] Add a few changes to run zip-tiered and tiered1 benchmarks. --- run.sh | 82 +++++++++++++++++++++++++++++++++++------------------ src/lib.rs | 2 +- src/main.rs | 2 +- src/zip.rs | 6 ++-- 4 files changed, 60 insertions(+), 32 deletions(-) diff --git a/run.sh b/run.sh index 9670bc5..16b1167 100755 --- a/run.sh +++ b/run.sh @@ -1,33 +1,35 @@ #!/usr/bin/env bash function run { - local name="$1" - local mode="$2" - shift 2 + local vdev_type="$1" + local name="$2" + local mode="$3" + shift 3 - local out_path="results/$(date -I)/${name}_$(date +%s)" + local out_path="results/$(date -I)_${vdev_type}/${name}_$(date +%s)" + #local out_path="results/$(date -I)/${name}_$(date +%s)" mkdir -p "$out_path" pushd "$out_path" - echo "wiping ssd" - blkdiscard /dev/disk/by-id/nvme-CT500P5SSD8_20512BF90C84 +# echo "wiping ssd" +# blkdiscard /dev/disk/by-id/nvme-CT500P5SSD8_20512BF90C84 - sleep 10 +# sleep 10 echo "running $mode with these settings:" env | grep BETREE__ env > "env" - bectl config print-active > "config" - betree-perf "$mode" "$@" + /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/bectl config print-active > "config" + /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/betree-perf "$mode" "$@" echo "merging results into $out_path/out.jsonl" - json-merge \ + /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/json-merge \ --timestamp-key epoch_ms \ ./betree-metrics.jsonl \ ./proc.jsonl \ ./sysinfo.jsonl \ - | json-flatten > "out.jsonl" + | /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/json-flatten > "out.jsonl" popd @@ -40,19 +42,34 @@ export RUST_LOG=warn export BETREE_CONFIG="$PWD/perf-config.json" function tiered() { + #export PMEM_NO_CLWB=1 + #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) + #export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ], [ \"/vol2/datafile1\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ \"/vol2/datafile1\" ], [ \"/vol1/datafile1\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/vol1/datafile1\", direct = false } ], [ { path = \"/vol2/datafile1\", direct = false } ] ]" + #export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/haura/datafile\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/haura/datafile\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/datafile1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/datafile1\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { mem = $((100 * 1024 * 1024 * 1024)) } ], [ { mem = $((100 * 1024 * 1024 * 1024)) } ] ]" + + #local vdev_type="dram" + local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" + ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - run tiered1_all0_alloc tiered + run "$vdev_type" tiered1_all0_alloc tiered1 ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run tiered1_id_alloc tiered + run "$vdev_type" tiered1_id_alloc tiered1 ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - run tiered1_all1_alloc tiered + run "$vdev_type" tiered1_all1_alloc tiered1 ) } @@ -62,7 +79,7 @@ function zip_cache() { for cache_mib in 32 64 128 256 512 1024 2048 4096 8192; do ( export BETREE__CACHE_SIZE=$(($cache_mib * 1024 * 1024)) - run "zip_cache_$cache_mb" zip 4 100 10 "$F" "$F_CD_START" + run "default" "zip_cache_$cache_mb" zip 4 100 10 "$F" "$F_CD_START" ) done } @@ -82,7 +99,7 @@ function zip_mt() { local per_worker=$(($total / $num_workers)) local per_run=$(($per_worker / 10)) - run "zip_mt_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "default" "zip_mt_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" done ) done @@ -90,7 +107,7 @@ function zip_mt() { function zip_tiered() { local F="$PWD/data/linux-5.12.13.zip" - local F_CD_START=1040032667 + local F_CD_START=1 #242415017 #1040032667 # for cache_mib in 256 512 1024; do for cache_mib in 32 64; do echo "using $cache_mib MiB of cache" @@ -99,6 +116,11 @@ function zip_tiered() { local total=10000 + #local vdev_type="dram" + local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" + for num_workers in 1 2 3 4 5 6 7 8 9 10; do echo "running with $num_workers workers" local per_worker=$(($total / $num_workers)) @@ -106,23 +128,26 @@ function zip_tiered() { ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - run "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ] ]" + run "$vdev_type" "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + run "$vdev_type" "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - run "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + run "$vdev_type" "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__STORAGE__TIERS="[ [ { mem = $((4 * 1024 * 1024 * 1024)) } ] ]" export BETREE__ALLOC_STRATEGY="[[0], [0], [], []]" - run "zip_tiered_mem_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "$vdev_type" "zip_tiered_mem_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) done ) @@ -141,26 +166,27 @@ function ingest() { ( export BETREE__COMPRESSION="None" - run ingest_hdd_none ingest "$F" + run "default" ingest_hdd_none ingest "$F" ) for level in $(seq 1 16); do ( export BETREE__COMPRESSION="{ Zstd = { level = $level } }" - run "ingest_hdd_zstd_$level" ingest "$F" + run "default" "ingest_hdd_zstd_$level" ingest "$F" ) done ) } function switchover() { - run switchover_tiny switchover 32 "$((32 * 1024 * 1024))" - run switchover_small switchover 8 "$((128 * 1024 * 1024))" - run switchover_medium switchover 4 "$((2 * 1024 * 1024 * 1024))" - run switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" + run "default" switchover_tiny switchover 32 "$((32 * 1024 * 1024))" + run "default" switchover_small switchover 8 "$((128 * 1024 * 1024))" + run "default" switchover_medium switchover 4 "$((2 * 1024 * 1024 * 1024))" + run "default" switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" } -zip_tiered +#zip_tiered +tiered #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' #export RUST_LOG=info diff --git a/src/lib.rs b/src/lib.rs index cd50701..5fed193 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,7 @@ pub fn with_random_bytes( mut callback: impl FnMut(&[u8]) -> Result<(), E>, ) -> Result<(), E> { let mut buf = vec![0; buf_size]; - +//println!("\n..............................................bufsize{:?}", buf_size); while n_bytes > 0 { rng.fill(&mut buf[..]); if let Err(e) = callback(&buf[..buf_size.min(n_bytes as usize)]) { diff --git a/src/main.rs b/src/main.rs index 958eaec..71c7184 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,7 @@ enum Mode { fn run_all(mode: Mode) -> Result<(), Box> { thread::spawn(|| betree_perf::log_process_info("proc.jsonl", 250)); - let mut sysinfo = process::Command::new("sysinfo-log") + let mut sysinfo = process::Command::new("/home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/sysinfo-log") .args(&["--output", "sysinfo.jsonl", "--interval-ms", "250"]) .spawn()?; diff --git a/src/zip.rs b/src/zip.rs index 183bbcb..4c3b687 100644 --- a/src/zip.rs +++ b/src/zip.rs @@ -36,11 +36,11 @@ pub fn prepare( // let is_metadata = idx < 1024 * 1024 || idx + n_read as u64 + 1024 * 1024 >= start_of_eocr; let is_metadata = idx + n_read as u64 >= start_of_eocr; - cursor.set_storage_preference(if is_metadata { + /*cursor.set_storage_preference(if is_metadata { StoragePreference::FASTEST } else { StoragePreference::FAST - }); + });*/ cursor.write_all(&buf[..n_read])?; idx += n_read as u64; @@ -87,6 +87,8 @@ pub fn read( for _ in 0..files_per_run { let file_name = &file_names.choose(&mut rng).expect("Empty file name list"); + println!("\n...................................{}", file_name); + let mut file = archive .by_name(file_name) .expect("Couldn't access file by name"); From b854960d4bd836f8cffaea6d7e65435be4f04820 Mon Sep 17 00:00:00 2001 From: Sajad Karm Date: Tue, 2 Aug 2022 11:56:19 +0200 Subject: [PATCH 02/81] Add a few changes to run zip-tiered and tiered1 benchmarks. --- src/lib.rs | 1 - src/zip.rs | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5fed193..a71eb89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,6 @@ pub fn with_random_bytes( mut callback: impl FnMut(&[u8]) -> Result<(), E>, ) -> Result<(), E> { let mut buf = vec![0; buf_size]; -//println!("\n..............................................bufsize{:?}", buf_size); while n_bytes > 0 { rng.fill(&mut buf[..]); if let Err(e) = callback(&buf[..buf_size.min(n_bytes as usize)]) { diff --git a/src/zip.rs b/src/zip.rs index 4c3b687..183bbcb 100644 --- a/src/zip.rs +++ b/src/zip.rs @@ -36,11 +36,11 @@ pub fn prepare( // let is_metadata = idx < 1024 * 1024 || idx + n_read as u64 + 1024 * 1024 >= start_of_eocr; let is_metadata = idx + n_read as u64 >= start_of_eocr; - /*cursor.set_storage_preference(if is_metadata { + cursor.set_storage_preference(if is_metadata { StoragePreference::FASTEST } else { StoragePreference::FAST - });*/ + }); cursor.write_all(&buf[..n_read])?; idx += n_read as u64; @@ -87,8 +87,6 @@ pub fn read( for _ in 0..files_per_run { let file_name = &file_names.choose(&mut rng).expect("Empty file name list"); - println!("\n...................................{}", file_name); - let mut file = archive .by_name(file_name) .expect("Couldn't access file by name"); From c081a11a9ca314c5e0222928d4ef1b939b0a27e3 Mon Sep 17 00:00:00 2001 From: Sajad Karm Date: Tue, 2 Aug 2022 14:13:34 +0200 Subject: [PATCH 03/81] Add jupyter compatible py script to generate plots for betree-metrics.jsonl file. --- jupyter/betree_metrics.ipynb | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 jupyter/betree_metrics.ipynb diff --git a/jupyter/betree_metrics.ipynb b/jupyter/betree_metrics.ipynb new file mode 100644 index 0000000..e701eb6 --- /dev/null +++ b/jupyter/betree_metrics.ipynb @@ -0,0 +1,64 @@ +{ + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "python", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8" + }, + "kernelspec": { + "name": "python", + "display_name": "Python (Pyodide)", + "language": "python" + } + }, + "nbformat_minor": 4, + "nbformat": 4, + "cells": [ + { + "cell_type": "code", + "source": "import json\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom matplotlib import pyplot as plt\nplt.figure(figsize=(15,5))\n\ndef subtract_last_index(array):\n last_val = 0\n for index, value in enumerate(array):\n array[index] = value - last_val\n last_val = value\n array[0] = 0\n\ndef subtract_first_index(array):\n first_val = array[0]\n for index, value in enumerate(array):\n array[index] = value -first_val\n\ndata = []\n\nfs = open('betree-metrics.jsonl', 'r')\nline_number = 0\n \nwhile True:\n line_number += 1\n \n # Get next line from file\n line = fs.readline()\n \n # if line is empty\n # end of file is reached\n if not line:\n break\n \n json_object = json.loads(line)\n\n data.append(json_object);\n \n# print(\"{}\".format(data))\n \nfs.close()\n\ndf = pd.DataFrame(data)\n\nepoch = [temp['epoch_ms'] for temp in data]\n\nsubtract_first_index(epoch)\nepoch = np.divide(epoch, 60)\nepoch = epoch.astype(int)\n\nfor x in range(4):\n for y in range(4):\n writes = np.array([])\n reads = np.array([])\n for temp in data:\n if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']):\n continue\n\n writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written'])\n reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read'])\n\n if len(writes) > 0:\n subtract_last_index(writes)\n subtract_last_index(reads)\n\n writes = np.divide(writes, 1024)\n reads = np.divide(reads, 1024)\n \n plt.plot(epoch, writes, label = \"Writes {}/{}\".format(x,y))\n plt.plot(epoch, reads, label = \"Reads {}/{}\".format(x,y))\nplt.legend()\nplt.xlabel(\"epochs\") # add X-axis label\nplt.ylabel(\"MB (I/0)\") # add Y-axis label\nplt.title(\"HAURA\") # add title\n#plt.xticks(epoch, rotation = 90)\nplt.show()\n#plt.savefig('pmem.png')", + "metadata": { + "trusted": true + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "", + "image/png": "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3aUT/0065quNf0tfU+VUK1SWSle9IhVNrr3OWudD7r9+IaXnOifBI850tq9b/4bXV1kqPT1XKlnqBBXR2xcMlbYurg0sKnbUv296rlMNM+279U+iw2GpbJvznMWerzLpy385J+3bP64fIkRl93baMfx0aclfnOfy1B85j1W5W3rkZCcYue5ftSd54bD0zj3Sh/c7QcPQU5ztGD67+ZOwil2Rip+3nG/ggw3M2BM9toafIQ07XVr/pvTBbyVZp2qk/ySnK9TmhVLpqoYfJyPfqTwacaY09LS6gYm10v5NTriz4S3nGLGhyH3OcO5TU+kcu+UlzjF12p1OYBYVCkjbP3Luv2GBc/zl9pdOvk069qq6gdeWD6X5tzth4NivSbN/KuUPaPp5irYzVFN3mTu981aVWOu8tv71S6l0tXTaXdLJ/9427Q2HpdUvSe/e64RifcdL4y6S3vu181q+/Dmpz9j67Tmax17+vDMWUahGGhD/Xje66fU297ihoHO8xd9+38ba43H7x3WvlySXxwmKT/6Plh07baE9jr8j2SdBf/1lbV01EQ45FX3RasQdnzvL+x8beX+c7bxnvHuvdGCzU0HW/zjp00elE2+WZt/T8Drj/4dJzn50dXA1cShQ9/3fuJr+33sk6m2raXno3wUZY5Zaa6ckuh1oGQIONKozBxy7ynw64Vfv6JcXjtdl0wYmujlAp+MLhHTMf83X76aV6fwvvi998zVp8EznyrJiaefyundwp0tFU+p/y96YsmKni8OGBc6JfDggebtJw05zPjiOmO10jyhZGjlxfU/a/okUOuyDrXFJU74tnfYjp8ok3sHtToBQeFz9D9D7NklPXuSchHq7SdNvkE74vpTRrQVtL5Ee/4rT9eWqvzsn16GA9OrN0rK/Ot/gZeQ721Ze4tznmHOdNsafcO1Z57Shco804wZp5xfOCXowboyQrB5ORcLgk5xxUGLbbaTCKVJOr+bb25BD+53nNhSou7xbf6nvhNpvH4M10t9vlJY/I028zPkgv/ML6dp3pD5j6q9380JpzatOAHFwa+va1H2wc+IwaIbkjjtZsSFpx7JIdVDccTf2wkgwcNh7eNVe52QkfttqKp3wZMMCqaq06Xb0nRAJms50Tlriqz4CPiece/9/G1+PJ9PpIjT4JGnta07okTfQCYgGnyi9fY+0+mWpW5E06mzp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" + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": "", + "metadata": {}, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": "", + "metadata": {}, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file From bb4678132f31035d0602628df15def209cab36bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 2 Aug 2022 13:47:15 +0200 Subject: [PATCH 04/81] fix shellcheck lints --- run.sh | 68 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/run.sh b/run.sh index 16b1167..b49b1fa 100755 --- a/run.sh +++ b/run.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC2030,SC2031 # we exploit this characteristic to start several test scenarios - merging them would lead to pollution function run { local vdev_type="$1" @@ -6,11 +7,12 @@ function run { local mode="$3" shift 3 - local out_path="results/$(date -I)_${vdev_type}/${name}_$(date +%s)" + local out_path + out_path="results/$(date -I)_${vdev_type}/${name}_$(date +%s)" #local out_path="results/$(date -I)/${name}_$(date +%s)" mkdir -p "$out_path" - pushd "$out_path" + pushd "$out_path" || return # echo "wiping ssd" # blkdiscard /dev/disk/by-id/nvme-CT500P5SSD8_20512BF90C84 @@ -20,18 +22,18 @@ function run { echo "running $mode with these settings:" env | grep BETREE__ env > "env" - /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/bectl config print-active > "config" - /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/betree-perf "$mode" "$@" + ./target/release/bectl config print-active > "config" + ./target/release/betree-perf "$mode" "$@" echo "merging results into $out_path/out.jsonl" - /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/json-merge \ + ./target/release/json-merge \ --timestamp-key epoch_ms \ ./betree-metrics.jsonl \ ./proc.jsonl \ ./sysinfo.jsonl \ - | /home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/json-flatten > "out.jsonl" + | ./target/release/json-flatten > "out.jsonl" - popd + popd || return sleep 60 } @@ -42,20 +44,20 @@ export RUST_LOG=warn export BETREE_CONFIG="$PWD/perf-config.json" function tiered() { - #export PMEM_NO_CLWB=1 - #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) - #export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ], [ \"/vol2/datafile1\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ \"/vol2/datafile1\" ], [ \"/vol1/datafile1\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/vol1/datafile1\", direct = false } ], [ { path = \"/vol2/datafile1\", direct = false } ] ]" - #export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" - export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/haura/datafile\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/haura/datafile\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/datafile1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/datafile1\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { mem = $((100 * 1024 * 1024 * 1024)) } ], [ { mem = $((100 * 1024 * 1024 * 1024)) } ] ]" - - #local vdev_type="dram" - local vdev_type="pmem" - #local vdev_type="ssd" - #local vdev_type="pmem_fs" + #export PMEM_NO_CLWB=1 + #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) + #export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ], [ \"/vol2/datafile1\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ \"/vol2/datafile1\" ], [ \"/vol1/datafile1\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/vol1/datafile1\", direct = false } ], [ { path = \"/vol2/datafile1\", direct = false } ] ]" + #export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/haura/datafile\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/haura/datafile\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/datafile1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/datafile1\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { mem = $((100 * 1024 * 1024 * 1024)) } ], [ { mem = $((100 * 1024 * 1024 * 1024)) } ] ]" + + #local vdev_type="dram" + local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' @@ -78,8 +80,8 @@ function zip_cache() { local F_CD_START=1040032667 for cache_mib in 32 64 128 256 512 1024 2048 4096 8192; do ( - export BETREE__CACHE_SIZE=$(($cache_mib * 1024 * 1024)) - run "default" "zip_cache_$cache_mb" zip 4 100 10 "$F" "$F_CD_START" + export BETREE__CACHE_SIZE=$((cache_mib * 1024 * 1024)) + run "default" "zip_cache_$cache_mib" zip 4 100 10 "$F" "$F_CD_START" ) done } @@ -90,14 +92,14 @@ function zip_mt() { for cache_mib in 256 512 1024 2048; do echo "using $cache_mib MiB of cache" ( - export BETREE__CACHE_SIZE=$(($cache_mib * 1024 * 1024)) + export BETREE__CACHE_SIZE=$((cache_mib * 1024 * 1024)) local total=10000 for num_workers in 1 2 3 4 5 6 7 8 9 10; do echo "running with $num_workers workers" - local per_worker=$(($total / $num_workers)) - local per_run=$(($per_worker / 10)) + local per_worker=$((total / num_workers)) + local per_run=$((per_worker / 10)) run "default" "zip_mt_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" done @@ -112,7 +114,7 @@ function zip_tiered() { for cache_mib in 32 64; do echo "using $cache_mib MiB of cache" ( - export BETREE__CACHE_SIZE=$(($cache_mib * 1024 * 1024)) + export BETREE__CACHE_SIZE=$((cache_mib * 1024 * 1024)) local total=10000 @@ -123,30 +125,30 @@ function zip_tiered() { for num_workers in 1 2 3 4 5 6 7 8 9 10; do echo "running with $num_workers workers" - local per_worker=$(($total / $num_workers)) - local per_run=$(($per_worker / 10)) + local per_worker=$((total / num_workers)) + local per_run=$((per_worker / 10)) ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ] ]" + export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" + export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( - export BETREE__STORAGE__TIERS="[ [ { mem = $((4 * 1024 * 1024 * 1024)) } ] ]" export BETREE__ALLOC_STRATEGY="[[0], [0], [], []]" + export BETREE__STORAGE__TIERS="[ [ { mem = $((4 * 1024 * 1024 * 1024)) } ] ]" run "$vdev_type" "zip_tiered_mem_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) done From 61ed5a699bc278ffaff080845526379d99fcbae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 2 Aug 2022 14:18:05 +0200 Subject: [PATCH 05/81] add gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54c98ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +results +data From f7adb717dc3083445a1c6a2c941e55ea08c2aab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 2 Aug 2022 14:18:28 +0200 Subject: [PATCH 06/81] add fetching of bench data if not present --- run.sh | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/run.sh b/run.sh index b49b1fa..94bb86f 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,25 @@ #!/usr/bin/env bash # shellcheck disable=SC2030,SC2031 # we exploit this characteristic to start several test scenarios - merging them would lead to pollution +function ensure_prepared { + local url + url="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.58.tar.xz" + + if [ ! -e "$PWD/data/linux.zip" ] + then + mkdir data + pushd data || exit + + curl "$url" -o linux.tar.xz + tar xf linux.tar.xz + rm linux.tar.xz + zip -0 -r linux.zip linux-* + rm -r linux-* + + popd || exit + fi +} + function run { local vdev_type="$1" local name="$2" @@ -76,8 +95,11 @@ function tiered() { } function zip_cache() { - local F="$PWD/data/linux-5.12.13.zip" + local F="$PWD/data/linux.zip" local F_CD_START=1040032667 + + ensure_prepared + for cache_mib in 32 64 128 256 512 1024 2048 4096 8192; do ( export BETREE__CACHE_SIZE=$((cache_mib * 1024 * 1024)) @@ -87,8 +109,11 @@ function zip_cache() { } function zip_mt() { - local F="$PWD/data/linux-5.12.13.zip" + local F="$PWD/data/linux.zip" local F_CD_START=1040032667 + + ensure_prepared + for cache_mib in 256 512 1024 2048; do echo "using $cache_mib MiB of cache" ( @@ -108,8 +133,9 @@ function zip_mt() { } function zip_tiered() { - local F="$PWD/data/linux-5.12.13.zip" + local F="$PWD/data/linux.zip" local F_CD_START=1 #242415017 #1040032667 + ensure_prepared # for cache_mib in 256 512 1024; do for cache_mib in 32 64; do echo "using $cache_mib MiB of cache" @@ -159,9 +185,11 @@ function zip_tiered() { function ingest() { - local F="$PWD/data/linux-5.12.13.zip" + local F="$PWD/data/linux.zip" local DISK=/dev/disk/by-id/ata-WDC_WD30EFRX-68EUZN0_WD-WMC4N2195306 + ensure_prepared + ( export BETREE__STORAGE__TIERS="[ [ { file = \"$DISK\" } ] ]" export BETREE__DEFAULT_STORAGE_CLASS=0 @@ -187,8 +215,8 @@ function switchover() { run "default" switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" } -#zip_tiered -tiered +zip_tiered +#tiered #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' #export RUST_LOG=info From 0a22114c3a6c101d99b465108077e29f49121ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 12:24:50 +0200 Subject: [PATCH 07/81] fetch repository root from environment --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 71c7184..0389aaf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,7 +37,9 @@ enum Mode { fn run_all(mode: Mode) -> Result<(), Box> { thread::spawn(|| betree_perf::log_process_info("proc.jsonl", 250)); - let mut sysinfo = process::Command::new("/home/skarim/myrepo/haura/betree/haura-benchmarks/target/release/sysinfo-log") + + let root = std::env::var("ROOT").expect("Didn't provide a repository ROOT"); + let mut sysinfo = process::Command::new(format!("{root}/target/release/sysinfo-log")) .args(&["--output", "sysinfo.jsonl", "--interval-ms", "250"]) .spawn()?; From e26c515947e5e10149f0ea3fa8959b94fcf67066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 12:26:04 +0200 Subject: [PATCH 08/81] define root in run script --- run.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/run.sh b/run.sh index 94bb86f..a83f0c2 100755 --- a/run.sh +++ b/run.sh @@ -41,11 +41,11 @@ function run { echo "running $mode with these settings:" env | grep BETREE__ env > "env" - ./target/release/bectl config print-active > "config" - ./target/release/betree-perf "$mode" "$@" + bectl config print-active > "config" + "$ROOT/target/release/betree-perf" "$mode" "$@" echo "merging results into $out_path/out.jsonl" - ./target/release/json-merge \ + "$ROOT/target/release/json-merge" \ --timestamp-key epoch_ms \ ./betree-metrics.jsonl \ ./proc.jsonl \ @@ -61,6 +61,7 @@ cargo build --release export RUST_LOG=warn export BETREE_CONFIG="$PWD/perf-config.json" +export ROOT="$PWD" function tiered() { #export PMEM_NO_CLWB=1 From 46ffb7a451c5dcc91e6a5c479d064645a4663c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 13:21:40 +0200 Subject: [PATCH 09/81] move plot notebook to plot script This simply allows for better editability with non-jupyter notebook users. --- jupyter/plot.py | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 jupyter/plot.py diff --git a/jupyter/plot.py b/jupyter/plot.py new file mode 100644 index 0000000..84c4c86 --- /dev/null +++ b/jupyter/plot.py @@ -0,0 +1,85 @@ +import json +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +# %matplotlib inline + +from matplotlib import pyplot as plt +plt.figure(figsize=(15,5)) + +def subtract_last_index(array): + last_val = 0 + for index, value in enumerate(array): + array[index] = value - last_val + last_val = value + array[0] = 0 + +def subtract_first_index(array): + first_val = array[0] + for index, value in enumerate(array): + array[index] = value -first_val + +data = [] + +if len(sys.argv) < 2: + print("Please specify an input json file. If you already completed benchmarks they can be found under `results/*`.") + exit(1) + +fs = open(sys.argv[1], 'r') +line_number = 0 + +while True: + line_number += 1 + + # Get next line from file + line = fs.readline() + + # if line is empty + # end of file is reached + if not line: + break + + json_object = json.loads(line) + + data.append(json_object); + +# print("{}".format(data)) + +fs.close() + +df = pd.DataFrame(data) + +epoch = [temp['epoch_ms'] for temp in data] + +subtract_first_index(epoch) +epoch = np.divide(epoch, 60) +epoch = epoch.astype(int) + +for x in range(4): + for y in range(4): + writes = np.array([]) + reads = np.array([]) + for temp in data: + if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): + continue + + writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written']) + reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read']) + + if len(writes) > 0: + subtract_last_index(writes) + subtract_last_index(reads) + + writes = np.divide(writes, 1024) + reads = np.divide(reads, 1024) + + plt.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) + plt.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) +plt.legend() +plt.xlabel("epochs") # add X-axis label +plt.ylabel("MB (I/0)") # add Y-axis label +plt.title("HAURA") # add title +#plt.xticks(epoch, rotation = 90) +plt.show() +#plt.savefig('pmem.png') From 2c247bed9c53d50779c3edbae504aac4fead1070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 14:51:35 +0200 Subject: [PATCH 10/81] add meta plot script --- jupyter/plot.py | 6 +++--- plot.sh | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100755 plot.sh diff --git a/jupyter/plot.py b/jupyter/plot.py index 84c4c86..32a6fef 100644 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -23,10 +23,10 @@ def subtract_first_index(array): data = [] if len(sys.argv) < 2: - print("Please specify an input json file. If you already completed benchmarks they can be found under `results/*`.") + print("Please specify an input run directory. If you already completed benchmarks they can be found under `results/*`.") exit(1) -fs = open(sys.argv[1], 'r') +fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') line_number = 0 while True: @@ -82,4 +82,4 @@ def subtract_first_index(array): plt.title("HAURA") # add title #plt.xticks(epoch, rotation = 90) plt.show() -#plt.savefig('pmem.png') +plt.savefig(f"{sys.argv[1]}/plot.png") diff --git a/plot.sh b/plot.sh new file mode 100755 index 0000000..f229a50 --- /dev/null +++ b/plot.sh @@ -0,0 +1,15 @@ +#!/bin/env bash + +function plot { + local run=$1 + shift 1 + + docker run -v "$PWD":/usr/src/bench -w /usr/src/bench amancevice/pandas:1.4.3-alpine python jupyter/plot.py "$run" +} + +export ROOT=$PWD + +for run in "$1"/* +do + plot "$run" +done From 578dfd7a0492fc21e09031d62bea58b92db3c0b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 15:37:41 +0200 Subject: [PATCH 11/81] build plots in container and build if required --- Dockerfile | 6 ++++++ plot.sh | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a8dac05 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM python + +RUN pip3 install pandas matplotlib numpy + +# This dockerfile solely exists because there does not seem to be a nice official matplolib+pandas+numpy container. +# diff --git a/plot.sh b/plot.sh index f229a50..2d4c98a 100755 --- a/plot.sh +++ b/plot.sh @@ -1,14 +1,25 @@ #!/bin/env bash +function prepare { + if docker image inspect haura_plots + then + return + else + docker build -t haura_plots . + fi +} + function plot { local run=$1 shift 1 - docker run -v "$PWD":/usr/src/bench -w /usr/src/bench amancevice/pandas:1.4.3-alpine python jupyter/plot.py "$run" + docker run -v "$PWD":/usr/src/bench -w /usr/src/bench haura_plots python jupyter/plot.py "$run" } export ROOT=$PWD +prepare + for run in "$1"/* do plot "$run" From 786e7624d07908af8848d39ad47c64b29f131239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 15:42:04 +0200 Subject: [PATCH 12/81] use memory by default Most users will likely want to change that, though for initial affirmation of functionality this is a nice to have. --- run.sh | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/run.sh b/run.sh index a83f0c2..3368e80 100755 --- a/run.sh +++ b/run.sh @@ -66,13 +66,10 @@ export ROOT="$PWD" function tiered() { #export PMEM_NO_CLWB=1 #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) - #export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ], [ \"/vol2/datafile1\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ \"/vol2/datafile1\" ], [ \"/vol1/datafile1\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/vol1/datafile1\", direct = false } ], [ { path = \"/vol2/datafile1\", direct = false } ] ]" - #export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" - export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/haura/datafile\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/haura/datafile\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/mnt/pmemfs0/datafile1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/mnt/pmemfs1/datafile1\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { mem = $((100 * 1024 * 1024 * 1024)) } ], [ { mem = $((100 * 1024 * 1024 * 1024)) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" #local vdev_type="dram" local vdev_type="pmem" @@ -146,9 +143,10 @@ function zip_tiered() { local total=10000 #local vdev_type="dram" - local vdev_type="pmem" + #local vdev_type="pmem" #local vdev_type="ssd" #local vdev_type="pmem_fs" + export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" for num_workers in 1 2 3 4 5 6 7 8 9 10; do echo "running with $num_workers workers" @@ -157,27 +155,19 @@ function zip_tiered() { ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/vol1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - export BETREE__STORAGE__TIERS="[ [ \"/mnt/pmemfs0/datafile1\" ], [ \"/mnt/pmemfs1/datafile1\" ] ]" run "$vdev_type" "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" ) - ( - export BETREE__ALLOC_STRATEGY="[[0], [0], [], []]" - export BETREE__STORAGE__TIERS="[ [ { mem = $((4 * 1024 * 1024 * 1024)) } ] ]" - run "$vdev_type" "zip_tiered_mem_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" - ) done ) done From b7f454f66049f5f61aa05ab343978e6206287a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 15:51:19 +0200 Subject: [PATCH 13/81] fix path json-flatten --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 3368e80..aab3a58 100755 --- a/run.sh +++ b/run.sh @@ -50,7 +50,7 @@ function run { ./betree-metrics.jsonl \ ./proc.jsonl \ ./sysinfo.jsonl \ - | ./target/release/json-flatten > "out.jsonl" + | "$ROOT/target/release/json-flatten" > "out.jsonl" popd || return From 08e105ec0dd04227ce0799e5518769fd7e299fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 20:01:51 +0200 Subject: [PATCH 14/81] add gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 54c98ee..b7f53e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ +**/target +**/*.rs.bk +**/*.swp +heaptrack* +Cargo.lock + results data From e84260fe8c3bf0dc456512cf53860a9849b20684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 20:03:36 +0200 Subject: [PATCH 15/81] remove lock file As we need to build the code with old versions of betree anyway, this changes depending on the version used. Adding it here brings no stability. --- Cargo.lock | 1347 ---------------------------------------------------- 1 file changed, 1347 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 6c81339..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,1347 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "async-trait" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" -dependencies = [ - "autocfg", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "backtrace" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "betree-perf" -version = "0.1.0" -dependencies = [ - "betree_storage_stack", - "crossbeam", - "figment", - "jemallocator", - "libmedium", - "log", - "parking_lot", - "procfs", - "rand", - "rand_xoshiro", - "serde_json", - "structopt", - "zip", -] - -[[package]] -name = "betree_storage_stack" -version = "0.2.0" -dependencies = [ - "async-trait", - "bincode", - "bitvec", - "byteorder", - "core_affinity", - "enum_dispatch", - "env_logger", - "error-chain", - "figment", - "futures", - "indexmap", - "itertools", - "libc", - "lock_api", - "log", - "lz4-sys", - "owning_ref", - "parking_lot", - "seqlock", - "serde", - "serde_json", - "speedy", - "stable_deref_trait", - "thiserror", - "twox-hash", - "zstd", - "zstd-safe", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bzip2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" -dependencies = [ - "jobserver", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi 0.3.9", -] - -[[package]] -name = "clap" -version = "2.33.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "core_affinity" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8a03115cc34fb0d7c321dd154a3914b3ca082ccc5c11d91bf7117dbbe7171f" -dependencies = [ - "kernel32-sys", - "libc", - "num_cpus", - "winapi 0.2.8", -] - -[[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "enum_dispatch" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "env_logger" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "error-chain" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "backtrace", - "version_check", -] - -[[package]] -name = "figment" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df" -dependencies = [ - "atomic", - "pear", - "serde", - "serde_json", - "uncased", - "version_check", -] - -[[package]] -name = "flate2" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide", -] - -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - -[[package]] -name = "funty" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" - -[[package]] -name = "futures" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" - -[[package]] -name = "futures-executor" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" - -[[package]] -name = "futures-macro" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" -dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" - -[[package]] -name = "futures-task" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" - -[[package]] -name = "futures-util" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" -dependencies = [ - "autocfg", - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "inlinable_string" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" - -[[package]] -name = "instant" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "jemalloc-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45" -dependencies = [ - "cc", - "fs_extra", - "libc", -] - -[[package]] -name = "jemallocator" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69" -dependencies = [ - "jemalloc-sys", - "libc", -] - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" - -[[package]] -name = "libmedium" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f6a8f301ebe547c6a400419521eda51c650687b5877540de8dadbf491921c1" - -[[package]] -name = "lock_api" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" -dependencies = [ - "owning_ref", - "scopeguard", - "serde", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lz4-sys" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca79aa95d8b3226213ad454d328369853be3a1382d89532a854f4d69640acae" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "memoffset" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "pear" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" - -[[package]] -name = "ppv-lite86" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "version_check", - "yansi", -] - -[[package]] -name = "procfs" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8809e0c18450a2db0f236d2a44ec0b4c1412d0eb936233579f0990faa5d5cd" -dependencies = [ - "bitflags", - "byteorder", - "chrono", - "flate2", - "hex", - "lazy_static", - "libc", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - -[[package]] -name = "rand" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_xoshiro" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "seqlock" -version = "0.1.1" -dependencies = [ - "parking_lot", -] - -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" - -[[package]] -name = "smallvec" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" - -[[package]] -name = "speedy" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a94ba2dac24da474e3339dfe17709e5c103172bb4a350e5660eb5277305764" -dependencies = [ - "speedy-derive", -] - -[[package]] -name = "speedy-derive" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c359205f2cf241a00e3fcb62ac2dcd4094df137ea19541dad43a404416470141" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "twox-hash" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e" -dependencies = [ - "cfg-if", - "rand", - "serde", - "static_assertions", -] - -[[package]] -name = "uncased" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wyz" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" - -[[package]] -name = "zip" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" -dependencies = [ - "byteorder", - "bzip2", - "crc32fast", - "flate2", - "thiserror", - "time", -] - -[[package]] -name = "zstd" -version = "0.9.0+zstd.1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" -dependencies = [ - "cc", - "libc", -] From 9ba8cbb32a95ecc483424555954aaedbde1dff73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 3 Aug 2022 20:13:04 +0200 Subject: [PATCH 16/81] fix path bectl Let's assume for now that we clone this into the betree repository. I would like to move this to general haura workspace later on, the paths need to be fixed for this case again. --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index aab3a58..461b7e9 100755 --- a/run.sh +++ b/run.sh @@ -41,7 +41,7 @@ function run { echo "running $mode with these settings:" env | grep BETREE__ env > "env" - bectl config print-active > "config" + "$ROOT/../../target/release/bectl" config print-active > "config" "$ROOT/target/release/betree-perf" "$mode" "$@" echo "merging results into $out_path/out.jsonl" From d1ece9e32d58e98afe66780d50784b3bb32056f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 9 Aug 2022 13:19:15 +0200 Subject: [PATCH 17/81] save plots as svg --- jupyter/plot.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 32a6fef..b7173bd 100644 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -1,8 +1,7 @@ import json import sys import numpy as np -import pandas as pd -import matplotlib.pyplot as plt +import pandas as pd import matplotlib.pyplot as plt # %matplotlib inline from matplotlib import pyplot as plt @@ -81,5 +80,5 @@ def subtract_first_index(array): plt.ylabel("MB (I/0)") # add Y-axis label plt.title("HAURA") # add title #plt.xticks(epoch, rotation = 90) -plt.show() -plt.savefig(f"{sys.argv[1]}/plot.png") +#plt.show() +plt.savefig(f"{sys.argv[1]}/plot.svg") From 5785f8cee158264c43db088689382605d8925b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 9 Aug 2022 13:24:31 +0200 Subject: [PATCH 18/81] fix labels --- jupyter/plot.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index b7173bd..abf5ed5 100644 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -1,7 +1,8 @@ import json import sys import numpy as np -import pandas as pd import matplotlib.pyplot as plt +import pandas as pd +import matplotlib.pyplot as plt # %matplotlib inline from matplotlib import pyplot as plt @@ -77,8 +78,9 @@ def subtract_first_index(array): plt.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) plt.legend() plt.xlabel("epochs") # add X-axis label -plt.ylabel("MB (I/0)") # add Y-axis label -plt.title("HAURA") # add title +plt.ylabel("MiB/s (I/0)") # add Y-axis label +label=' | '.join(sys.argv[1].split('/')[-2:]) +plt.title(f"Haura - {label}") # add title #plt.xticks(epoch, rotation = 90) #plt.show() plt.savefig(f"{sys.argv[1]}/plot.svg") From f194af59e51fd6fa6bfadcf589e0b6a30e3e3afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 10 Aug 2022 10:08:33 +0200 Subject: [PATCH 19/81] suppress docker output --- plot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plot.sh b/plot.sh index 2d4c98a..aec5384 100755 --- a/plot.sh +++ b/plot.sh @@ -1,7 +1,7 @@ #!/bin/env bash function prepare { - if docker image inspect haura_plots + if docker image inspect haura_plots > /dev/null 2>&1 then return else From 7e848ea629aa45e36e62291f6925f80f783fe313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 11 Aug 2022 13:05:47 +0200 Subject: [PATCH 20/81] fix preferences in "tiered" --- src/tiered1.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tiered1.rs b/src/tiered1.rs index 406bf96..663df55 100644 --- a/src/tiered1.rs +++ b/src/tiered1.rs @@ -3,7 +3,7 @@ use betree_storage_stack::StoragePreference; use std::{error::Error, io::Write}; pub fn run(mut client: Client) -> Result<(), Box> { - const N_OBJECTS: u64 = 5; + const N_OBJECTS: u64 = 1; const OBJECT_SIZE: u64 = 5 * 1024 * 1024 * 1024; println!("running tiered1"); @@ -17,8 +17,8 @@ pub fn run(mut client: Client) -> Result<(), Box> { objects.push(name.clone()); let (obj, _info) = - os.open_or_create_object_with_pref(name.as_bytes(), StoragePreference::FAST)?; - let mut cursor = obj.cursor(); + os.open_or_create_object_with_pref(name.as_bytes(), StoragePreference::FASTEST)?; + let mut cursor = obj.cursor_with_pref(StoragePreference::FAST); with_random_bytes(&mut client.rng, OBJECT_SIZE / 2, 8 * 1024 * 1024, |b| { cursor.write_all(b) From 54a397b6bbb6260989fea5e5fe956d2c170721af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 11 Aug 2022 15:19:42 +0200 Subject: [PATCH 21/81] add scientific workflow like benchmark case --- run.sh | 31 ++++++++++++++++++++- src/main.rs | 12 ++++++++ src/scientific_evaluation.rs | 53 ++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/scientific_evaluation.rs diff --git a/run.sh b/run.sh index 461b7e9..9b89fc3 100755 --- a/run.sh +++ b/run.sh @@ -59,7 +59,6 @@ function run { cargo build --release -export RUST_LOG=warn export BETREE_CONFIG="$PWD/perf-config.json" export ROOT="$PWD" @@ -92,6 +91,35 @@ function tiered() { ) } +function scientific_evaluation() { + #export PMEM_NO_CLWB=1 + #export BETREE__CACHE_SIZE=$((4 * 1024 * 1024 * 1024)) + #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" + + #local vdev_type="dram" + #local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" + + ( + export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' + run "$vdev_type" scientific_evaluation_all0_alloc evaluation + ) + + ( + export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' + run "$vdev_type" scientific_evaluation_id_alloc evaluation + ) + + ( + export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' + run "$vdev_type" scientific_evaluation_all1_alloc evaluation + ) +} + function zip_cache() { local F="$PWD/data/linux.zip" local F_CD_START=1040032667 @@ -208,6 +236,7 @@ function switchover() { zip_tiered #tiered +#scientific_evaluation #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' #export RUST_LOG=info diff --git a/src/main.rs b/src/main.rs index 0389aaf..f9b5709 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use structopt::StructOpt; mod ingest; mod rewrite; +mod scientific_evaluation; mod switchover; mod tiered1; mod zip; @@ -15,6 +16,10 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; #[derive(StructOpt)] enum Mode { Tiered1, + Evaluation{ + #[structopt(default_value = "120")] + runtime: u64, + }, Zip { n_clients: u32, runs_per_client: u32, @@ -51,6 +56,13 @@ fn run_all(mode: Mode) -> Result<(), Box> { tiered1::run(client)?; control.database.write().sync()?; } + Mode::Evaluation { + runtime, + } => { + let client = control.client(0, b"scientific_evaluation"); + scientific_evaluation::run(client, runtime)?; + control.database.write().sync()?; + } Mode::Zip { path, start_of_eocr, diff --git a/src/scientific_evaluation.rs b/src/scientific_evaluation.rs new file mode 100644 index 0000000..45162a2 --- /dev/null +++ b/src/scientific_evaluation.rs @@ -0,0 +1,53 @@ +///! This file implements a scientific workflow style writing first serial data +///! onto a storage layer and then reading this data from storage in a somewhat +///! random but repeating pattern. +use betree_perf::*; +use betree_storage_stack::StoragePreference; +use rand::RngCore; +use std::{error::Error, io::Write}; + +pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { + const OBJECT_SIZE: u64 = 10 * 1024 * 1024 * 1024; + const N_POSITIONS: u64 = 1024; + println!("running scientific_evaluation"); + + let (obj, _info) = client + .object_store + .open_or_create_object_with_pref(b"important_research", StoragePreference::FAST)?; + let mut cursor = obj.cursor_with_pref(StoragePreference::FAST); + + with_random_bytes(&mut client.rng, OBJECT_SIZE, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + client.sync().expect("Failed to sync database"); + // Generate positions to read + let mut positions = vec![]; + for _ in 0..N_POSITIONS { + let start = client.rng.next_u64() % (OBJECT_SIZE - 1); + let length = client.rng.next_u64(); + positions.push(( + start, + length + .clamp(0, (OBJECT_SIZE as f64 * 0.1) as u64) + .clamp(0, OBJECT_SIZE.saturating_sub(start)), + )); + } + + let (obj, _info) = client + .object_store + .open_object_with_info(b"important_research")? + .expect("Object was just created, but can't be opened!"); + + let start = std::time::Instant::now(); + for (pos, len) in positions.iter().cycle() { + let mut buf = vec![0; *len as usize]; + obj.read_at(&mut buf, *pos).unwrap(); + // simulate some work done on the data + std::thread::sleep(std::time::Duration::from_millis(10)); + if start.elapsed().as_secs() > runtime { + break; + } + } + + Ok(()) +} From f59078714745b702dcb26583abe3c5c143adbe98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 13 Aug 2022 12:26:49 +0200 Subject: [PATCH 22/81] build database with additional threads if configured --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a71eb89..628da1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,10 +56,10 @@ impl Control { log::info!("using {:?}", cfg); - let database = Database::build(cfg).expect("Failed to open database"); + let database = Database::build_threaded(cfg).expect("Failed to open database"); Control { - database: Arc::new(RwLock::new(database)), + database, } } From 58f37983435d2dc727f599a5ac567873d36086ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 13 Aug 2022 13:22:32 +0200 Subject: [PATCH 23/81] shorten fetched data in evaluation case --- src/scientific_evaluation.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scientific_evaluation.rs b/src/scientific_evaluation.rs index 45162a2..9bef70c 100644 --- a/src/scientific_evaluation.rs +++ b/src/scientific_evaluation.rs @@ -27,8 +27,7 @@ pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { let length = client.rng.next_u64(); positions.push(( start, - length - .clamp(0, (OBJECT_SIZE as f64 * 0.1) as u64) + (length % (OBJECT_SIZE as f64 * 0.006) as u64) .clamp(0, OBJECT_SIZE.saturating_sub(start)), )); } From 8a1f53acb43e51286bb8c38c9ce74566cf1659da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 13 Aug 2022 14:49:08 +0200 Subject: [PATCH 24/81] fetch smaller range in evaluation case --- src/scientific_evaluation.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scientific_evaluation.rs b/src/scientific_evaluation.rs index 9bef70c..be1320d 100644 --- a/src/scientific_evaluation.rs +++ b/src/scientific_evaluation.rs @@ -8,7 +8,8 @@ use std::{error::Error, io::Write}; pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { const OBJECT_SIZE: u64 = 10 * 1024 * 1024 * 1024; - const N_POSITIONS: u64 = 1024; + const FETCH_SIZE: u64 = 12 * 1024 * 1024; + const N_POSITIONS: u64 = 256; println!("running scientific_evaluation"); let (obj, _info) = client @@ -27,7 +28,7 @@ pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { let length = client.rng.next_u64(); positions.push(( start, - (length % (OBJECT_SIZE as f64 * 0.006) as u64) + (length % FETCH_SIZE as u64) .clamp(0, OBJECT_SIZE.saturating_sub(start)), )); } From 91e621aa9f7a10f15f365d9a0bb508ea7b48f7f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 20 Aug 2022 15:22:51 +0200 Subject: [PATCH 25/81] fix labels - throughput plot --- jupyter/plot.py | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) mode change 100644 => 100755 jupyter/plot.py diff --git a/jupyter/plot.py b/jupyter/plot.py old mode 100644 new mode 100755 index abf5ed5..44d14a1 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -3,8 +3,12 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt +import matplotlib.ticker as ticker # %matplotlib inline +# Constants +BLOCK_SIZE = 4096 + from matplotlib import pyplot as plt plt.figure(figsize=(15,5)) @@ -27,21 +31,17 @@ def subtract_first_index(array): exit(1) fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') + line_number = 0 - while True: line_number += 1 - # Get next line from file line = fs.readline() - # if line is empty # end of file is reached if not line: break - json_object = json.loads(line) - data.append(json_object); # print("{}".format(data)) @@ -53,8 +53,8 @@ def subtract_first_index(array): epoch = [temp['epoch_ms'] for temp in data] subtract_first_index(epoch) -epoch = np.divide(epoch, 60) -epoch = epoch.astype(int) + +fig, ax = plt.subplots(figsize=(15,5)) for x in range(4): for y in range(4): @@ -71,16 +71,27 @@ def subtract_first_index(array): subtract_last_index(writes) subtract_last_index(reads) - writes = np.divide(writes, 1024) - reads = np.divide(reads, 1024) - - plt.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) - plt.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) -plt.legend() -plt.xlabel("epochs") # add X-axis label -plt.ylabel("MiB/s (I/0)") # add Y-axis label + # convert to MiB from Blocks + # NOTE: We assume here a block size of 4096 bytes as this is the default haura block size + # if you change this you'll need to modify this here too. + writes = writes * BLOCK_SIZE / 1024 / 1024 + reads = reads * BLOCK_SIZE / 1024 / 1024 + + ax.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) + ax.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) +fig.legend() +# Epoch in seconds +ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" +epoch_formatted = list(map(ms_to_string, epoch)) +ax.set_xlabel("runtime (minute:seconds)") # add X-axis label +ax.set_xticks(epoch, epoch_formatted) +ax.locator_params(tight=True, nbins=10) +# tenth = ticker.MultipleLocator(base=10.0) +#pl.axis()[1].set_major_locator(tenth) + +ax.set_ylabel("MiB/s (I/0)") # add Y-axis label label=' | '.join(sys.argv[1].split('/')[-2:]) -plt.title(f"Haura - {label}") # add title +ax.set_title(f"Haura - {label}") # add title #plt.xticks(epoch, rotation = 90) #plt.show() -plt.savefig(f"{sys.argv[1]}/plot.svg") +fig.savefig(f"{sys.argv[1]}/plot.svg") From 5101a5283611eb7e12aa611aef5b3e124ac9af8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 22 Aug 2022 13:27:05 +0200 Subject: [PATCH 26/81] speed up scientific evaluation benchmark case --- src/scientific_evaluation.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/scientific_evaluation.rs b/src/scientific_evaluation.rs index be1320d..2930e88 100644 --- a/src/scientific_evaluation.rs +++ b/src/scientific_evaluation.rs @@ -12,6 +12,7 @@ pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { const N_POSITIONS: u64 = 256; println!("running scientific_evaluation"); + let start = std::time::Instant::now(); let (obj, _info) = client .object_store .open_or_create_object_with_pref(b"important_research", StoragePreference::FAST)?; @@ -20,6 +21,7 @@ pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { with_random_bytes(&mut client.rng, OBJECT_SIZE, 8 * 1024 * 1024, |b| { cursor.write_all(b) })?; + println!("Initial write took {}s", start.elapsed().as_secs()); client.sync().expect("Failed to sync database"); // Generate positions to read let mut positions = vec![]; @@ -39,15 +41,14 @@ pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { .expect("Object was just created, but can't be opened!"); let start = std::time::Instant::now(); + let mut buf = vec![0; FETCH_SIZE as usize]; for (pos, len) in positions.iter().cycle() { - let mut buf = vec![0; *len as usize]; - obj.read_at(&mut buf, *pos).unwrap(); - // simulate some work done on the data - std::thread::sleep(std::time::Duration::from_millis(10)); - if start.elapsed().as_secs() > runtime { + // Read data as may be done in some evaluation where only parts of a + // database file are read in. + obj.read_at(&mut buf[..*len as usize], *pos).unwrap(); + if start.elapsed().as_secs() >= runtime { break; } } - Ok(()) } From 73ab5e4ba9491b36e74ddaaa904e5e1e9a52dd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 6 Sep 2022 10:15:22 +0200 Subject: [PATCH 27/81] ensure bectl is present --- run.sh | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/run.sh b/run.sh index 9b89fc3..ec1ddf9 100755 --- a/run.sh +++ b/run.sh @@ -20,6 +20,11 @@ function ensure_prepared { fi } +function ensure_bectl { + cd ../../bectl || exit + cargo build --release +} + function run { local vdev_type="$1" local name="$2" @@ -64,15 +69,15 @@ export ROOT="$PWD" function tiered() { #export PMEM_NO_CLWB=1 - #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) + #export BETREE__CACHE_SIZE=$((4 * 1024 * 1024 * 1024)) #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" + #export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" #local vdev_type="dram" - local vdev_type="pmem" - #local vdev_type="ssd" + #local vdev_type="pmem" + #local vdev_type="dram_nvme" #local vdev_type="pmem_fs" ( @@ -93,7 +98,7 @@ function tiered() { function scientific_evaluation() { #export PMEM_NO_CLWB=1 - #export BETREE__CACHE_SIZE=$((4 * 1024 * 1024 * 1024)) + #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" @@ -103,21 +108,8 @@ function scientific_evaluation() { #local vdev_type="pmem" #local vdev_type="ssd" #local vdev_type="pmem_fs" - - ( - export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - run "$vdev_type" scientific_evaluation_all0_alloc evaluation - ) - - ( - export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" scientific_evaluation_id_alloc evaluation - ) - - ( - export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - run "$vdev_type" scientific_evaluation_all1_alloc evaluation - ) + export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' + run "$vdev_type" scientific_evaluation_id_alloc evaluation 30 } function zip_cache() { @@ -234,9 +226,11 @@ function switchover() { run "default" switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" } -zip_tiered +ensure_bectl + +#zip_tiered #tiered -#scientific_evaluation +scientific_evaluation #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' #export RUST_LOG=info From 366a2f242148e1be1dc528abc6f0136f36c123d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 6 Sep 2022 10:16:49 +0200 Subject: [PATCH 28/81] plot latency metrics --- jupyter/plot.py | 120 +++++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 44d14a1..a62236e 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -10,7 +10,6 @@ BLOCK_SIZE = 4096 from matplotlib import pyplot as plt -plt.figure(figsize=(15,5)) def subtract_last_index(array): last_val = 0 @@ -24,6 +23,78 @@ def subtract_first_index(array): for index, value in enumerate(array): array[index] = value -first_val +def plot_throughput(data): + epoch = [temp['epoch_ms'] for temp in data] + subtract_first_index(epoch) + fig, ax = plt.subplots(figsize=(15,5)) + for x in range(4): + for y in range(4): + writes = np.array([]) + reads = np.array([]) + for temp in data: + if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): + continue + + writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written']) + reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read']) + + if len(writes) > 0: + subtract_last_index(writes) + subtract_last_index(reads) + + # convert to MiB from Blocks + # NOTE: We assume here a block size of 4096 bytes as this is the default haura block size + # if you change this you'll need to modify this here too. + writes = writes * BLOCK_SIZE / 1024 / 1024 + reads = reads * BLOCK_SIZE / 1024 / 1024 + + ax.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) + ax.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) + fig.legend() + # Epoch in seconds + ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" + epoch_formatted = list(map(ms_to_string, epoch)) + ax.set_xlabel("runtime (minute:seconds)") # add X-axis label + ax.set_xticks(epoch, epoch_formatted) + ax.locator_params(tight=True, nbins=10) + + ax.set_ylabel("MiB/s (I/0)") # add Y-axis label + label=' | '.join(sys.argv[1].split('/')[-2:]) + ax.set_title(f"Haura - {label}") # add title + fig.savefig(f"{sys.argv[1]}/plot.svg") + +def plot_latency(data): + epoch = [temp['epoch_ms'] for temp in data] + subtract_first_index(epoch) + fig, ax = plt.subplots(figsize=(15,5)) + for x in range(4): + for y in range(4): + lat = np.array([]) + for temp in data: + if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): + continue + + lat = np.append(lat, temp['storage']['tiers'][x]['vdevs'][y]['read_latency']) + + if len(lat) > 0: + lat = lat / 100000 + lat.astype(int) + lat = np.array([np.nan if elem == 0 else elem for elem in lat]) + + + ax.plot(epoch, lat, label = "Average Latency {}/{}".format(x,y)) + fig.legend() + # Epoch in seconds + ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" + epoch_formatted = list(map(ms_to_string, epoch)) + ax.set_xlabel("runtime (minute:seconds)") # add X-axis label + ax.set_xticks(epoch, epoch_formatted) + ax.locator_params(tight=True, nbins=10) + ax.set_ylabel("Read Latency in ms") # add Y-axis label + label=' | '.join(sys.argv[1].split('/')[-2:]) + ax.set_title(f"Haura - {label}") # add title + fig.savefig(f"{sys.argv[1]}/plot_latency.svg") + data = [] if len(sys.argv) < 2: @@ -50,48 +121,5 @@ def subtract_first_index(array): df = pd.DataFrame(data) -epoch = [temp['epoch_ms'] for temp in data] - -subtract_first_index(epoch) - -fig, ax = plt.subplots(figsize=(15,5)) - -for x in range(4): - for y in range(4): - writes = np.array([]) - reads = np.array([]) - for temp in data: - if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): - continue - - writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written']) - reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read']) - - if len(writes) > 0: - subtract_last_index(writes) - subtract_last_index(reads) - - # convert to MiB from Blocks - # NOTE: We assume here a block size of 4096 bytes as this is the default haura block size - # if you change this you'll need to modify this here too. - writes = writes * BLOCK_SIZE / 1024 / 1024 - reads = reads * BLOCK_SIZE / 1024 / 1024 - - ax.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) - ax.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) -fig.legend() -# Epoch in seconds -ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" -epoch_formatted = list(map(ms_to_string, epoch)) -ax.set_xlabel("runtime (minute:seconds)") # add X-axis label -ax.set_xticks(epoch, epoch_formatted) -ax.locator_params(tight=True, nbins=10) -# tenth = ticker.MultipleLocator(base=10.0) -#pl.axis()[1].set_major_locator(tenth) - -ax.set_ylabel("MiB/s (I/0)") # add Y-axis label -label=' | '.join(sys.argv[1].split('/')[-2:]) -ax.set_title(f"Haura - {label}") # add title -#plt.xticks(epoch, rotation = 90) -#plt.show() -fig.savefig(f"{sys.argv[1]}/plot.svg") +plot_throughput(data) +plot_latency(data) From 53c6e51e045beb90b09218dc931a4a085d96cc10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 6 Sep 2022 20:32:32 +0200 Subject: [PATCH 29/81] add naive checkpoints case --- src/checkpoints.rs | 35 +++++++++++++++++++++++++++++++++++ src/main.rs | 7 +++++++ 2 files changed, 42 insertions(+) create mode 100644 src/checkpoints.rs diff --git a/src/checkpoints.rs b/src/checkpoints.rs new file mode 100644 index 0000000..64470e3 --- /dev/null +++ b/src/checkpoints.rs @@ -0,0 +1,35 @@ +///! This case implements a checkpoint like writing test in which multiple +///! objects are created on the preferred fastest speed and later migrated +///! downwards once they are no longer needed. +///! +///! A sync is performed after each object batch to ensure that data is safe +///! before continuing. +use betree_perf::*; +use betree_storage_stack::StoragePreference; +use rand::RngCore; +use std::{error::Error, io::Write}; + +pub fn run(mut client: Client) -> Result<(), Box> { + const N_OBJECTS: usize = 5; + const OBJECT_SIZE_MIB: [u64; N_OBJECTS] = [256, 256, 1, 384, 128]; + const N_GENERATIONS: usize = 20; + println!("running checkpoints"); + + for gen in 0..N_GENERATIONS { + for obj_id in 0..N_OBJECTS { + let key = format!("{gen}_{obj_id}"); + let (obj, _info) = client + .object_store + .open_or_create_object_with_pref(key.as_bytes(), StoragePreference::FASTEST)?; + // We definitely want to write on the fastest layer to minimize + // waiting inbetween computation. + let mut cursor = obj.cursor_with_pref(StoragePreference::FASTEST); + with_random_bytes(&mut client.rng, OBJECT_SIZE_MIB[obj_id] * 1024 * 1024, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + } + client.sync().expect("Failed to sync database"); + } + client.sync().expect("Failed to sync database"); + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index f9b5709..0cc18d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use std::{error::Error, path::PathBuf, process, thread, time::Duration}; use betree_perf::Control; use structopt::StructOpt; +mod checkpoints; mod ingest; mod rewrite; mod scientific_evaluation; @@ -16,6 +17,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; #[derive(StructOpt)] enum Mode { Tiered1, + Checkpoints, Evaluation{ #[structopt(default_value = "120")] runtime: u64, @@ -56,6 +58,11 @@ fn run_all(mode: Mode) -> Result<(), Box> { tiered1::run(client)?; control.database.write().sync()?; } + Mode::Checkpoints => { + let client = control.client(0, b"tiered1"); + checkpoints::run(client)?; + control.database.write().sync()?; + } Mode::Evaluation { runtime, } => { From 5740933de79277547c12f03f4ff7caf6b5df9e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 8 Sep 2022 10:20:56 +0200 Subject: [PATCH 30/81] add semi random wait at the end of each generation --- src/checkpoints.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/checkpoints.rs b/src/checkpoints.rs index 64470e3..578d533 100644 --- a/src/checkpoints.rs +++ b/src/checkpoints.rs @@ -13,6 +13,8 @@ pub fn run(mut client: Client) -> Result<(), Box> { const N_OBJECTS: usize = 5; const OBJECT_SIZE_MIB: [u64; N_OBJECTS] = [256, 256, 1, 384, 128]; const N_GENERATIONS: usize = 20; + const MIN_WAIT_MS: u64 = 1500; + const WAIT_RAND_RANGE: u64 = 400; println!("running checkpoints"); for gen in 0..N_GENERATIONS { @@ -28,6 +30,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { cursor.write_all(b) })?; } + std::thread::sleep(std::time::Duration::from_millis(client.rng.next_u64() % WAIT_RAND_RANGE + MIN_WAIT_MS)); client.sync().expect("Failed to sync database"); } client.sync().expect("Failed to sync database"); From 6506f2a4474445caafa41fd618279f073bb3a984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 8 Sep 2022 10:35:11 +0200 Subject: [PATCH 31/81] add checkpoints run fun --- run.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/run.sh b/run.sh index ec1ddf9..39995dd 100755 --- a/run.sh +++ b/run.sh @@ -21,8 +21,9 @@ function ensure_prepared { } function ensure_bectl { - cd ../../bectl || exit + pushd ../../bectl || exit cargo build --release + popd || return } function run { @@ -112,6 +113,15 @@ function scientific_evaluation() { run "$vdev_type" scientific_evaluation_id_alloc evaluation 30 } +function checkpoints() { + #local vdev_type="dram" + #local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" + export BETREE__ALLOC_STRATEGY='[[0, 1],[1],[],[]]' + run "$vdev_type" checkpoints_fastest checkpoints +} + function zip_cache() { local F="$PWD/data/linux.zip" local F_CD_START=1040032667 @@ -231,6 +241,7 @@ ensure_bectl #zip_tiered #tiered scientific_evaluation +#checkpoints #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' #export RUST_LOG=info From bc9e12c4ccbe10f293fae3adbe3ee9e7781bfac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 8 Sep 2022 10:39:48 +0200 Subject: [PATCH 32/81] add some example configs --- example_config/new-config-w-lfu.json | 63 +++++++++++++++++++++ example_config/new-config-w-rl.json | 60 ++++++++++++++++++++ example_config/new-config-wo-migration.json | 47 +++++++++++++++ example_config/v0.2.0-config.json | 33 +++++++++++ 4 files changed, 203 insertions(+) create mode 100644 example_config/new-config-w-lfu.json create mode 100644 example_config/new-config-w-rl.json create mode 100644 example_config/new-config-wo-migration.json create mode 100644 example_config/v0.2.0-config.json diff --git a/example_config/new-config-w-lfu.json b/example_config/new-config-w-lfu.json new file mode 100644 index 0000000..af9b92e --- /dev/null +++ b/example_config/new-config-w-lfu.json @@ -0,0 +1,63 @@ +{ + "storage": { + "tiers": [ + { + "top_level_vdevs": [ + { + "mem": 16106127360 + } + ], + "preferred_access_type": "Unknown" + }, + { + "top_level_vdevs": [ + { + "path": "/tmp/disk_a", + "direct": true + } + ], + "preferred_access_type": "Unknown" + } + ], + "queue_depth_factor": 20, + "thread_pool_size": null, + "thread_pool_pinned": false + }, + "alloc_strategy": [ + [ + 0 + ], + [ + 1 + ], + [ + 2 + ], + [ + 3 + ] + ], + "default_storage_class": 0, + "compression": "None", + "cache_size": 4294967296, + "access_mode": "AlwaysCreateNew", + "sync_interval_ms": 1000, + "migration_policy": { + "Lfu": { + "grace_period": { + "secs": 0, + "nanos": 0 + }, + "migration_threshold": 0.9, + "update_period": { + "secs": 1, + "nanos": 0 + }, + "policy_config": { + "promote_num": 99999, + "promote_size": 128 + } + } + }, + "metrics": null +} diff --git a/example_config/new-config-w-rl.json b/example_config/new-config-w-rl.json new file mode 100644 index 0000000..e1f65a2 --- /dev/null +++ b/example_config/new-config-w-rl.json @@ -0,0 +1,60 @@ +{ + "storage": { + "tiers": [ + { + "top_level_vdevs": [ + { + "mem": 16106127360 + } + ], + "preferred_access_type": "Unknown" + }, + { + "top_level_vdevs": [ + { + "path": "/tmp/disk_a", + "direct": true + } + ], + "preferred_access_type": "Unknown" + } + ], + "queue_depth_factor": 20, + "thread_pool_size": null, + "thread_pool_pinned": false + }, + "alloc_strategy": [ + [ + 0 + ], + [ + 1 + ], + [ + 2 + ], + [ + 3 + ] + ], + "default_storage_class": 0, + "compression": "None", + "cache_size": 4294967296, + "access_mode": "AlwaysCreateNew", + "sync_interval_ms": 1000, + "migration_policy": { + "ReinforcementLearning": { + "grace_period": { + "secs": 0, + "nanos": 0 + }, + "migration_threshold": 0.8, + "update_period": { + "secs": 1, + "nanos": 0 + }, + "policy_config": null + } + }, + "metrics": null +} diff --git a/example_config/new-config-wo-migration.json b/example_config/new-config-wo-migration.json new file mode 100644 index 0000000..f3954f7 --- /dev/null +++ b/example_config/new-config-wo-migration.json @@ -0,0 +1,47 @@ +{ + "storage": { + "tiers": [ + { + "top_level_vdevs": [ + { + "mem": 16106127360 + } + ], + "preferred_access_type": "Unknown" + }, + { + "top_level_vdevs": [ + { + "path": "/tmp/disk_a", + "direct": true + } + ], + "preferred_access_type": "Unknown" + } + ], + "queue_depth_factor": 20, + "thread_pool_size": null, + "thread_pool_pinned": false + }, + "alloc_strategy": [ + [ + 0 + ], + [ + 1 + ], + [ + 2 + ], + [ + 3 + ] + ], + "default_storage_class": 0, + "compression": "None", + "cache_size": 4294967296, + "access_mode": "AlwaysCreateNew", + "sync_interval_ms": 1000, + "migration_policy": null, + "metrics": null +} diff --git a/example_config/v0.2.0-config.json b/example_config/v0.2.0-config.json new file mode 100644 index 0000000..6006a7e --- /dev/null +++ b/example_config/v0.2.0-config.json @@ -0,0 +1,33 @@ +{ + "storage": { + "tiers": [ + [{ + "mem": 85899345920 + }], + ["/tmp/disk_a"] + ], + "queue_depth_factor": 20, + "thread_pool_size": null, + "thread_pool_pinned": false + }, + "alloc_strategy": [ + [ + 0 + ], + [ + 1 + ], + [ + 2 + ], + [ + 3 + ] + ], + "default_storage_class": 0, + "compression": "None", + "cache_size": 268435456, + "access_mode": "AlwaysCreateNew", + "sync_interval_ms": 1000, + "metrics": null +} From 7e7b644bff5fd811e6e94c5b14fac0f2f3d6e900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 8 Sep 2022 14:41:44 +0200 Subject: [PATCH 33/81] fix epoch throughput computation --- jupyter/plot.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index a62236e..08b8990 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -8,6 +8,8 @@ # Constants BLOCK_SIZE = 4096 +EPOCH_MS=500 +SEC_MS=1000 from matplotlib import pyplot as plt @@ -45,8 +47,8 @@ def plot_throughput(data): # convert to MiB from Blocks # NOTE: We assume here a block size of 4096 bytes as this is the default haura block size # if you change this you'll need to modify this here too. - writes = writes * BLOCK_SIZE / 1024 / 1024 - reads = reads * BLOCK_SIZE / 1024 / 1024 + writes = writes * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) + reads = reads * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) ax.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) ax.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) From 7d4047d6bea7c706b2f227a5fba6a77b11f781a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 8 Sep 2022 21:58:24 +0200 Subject: [PATCH 34/81] increase generations checkpoints benchmark --- src/checkpoints.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/checkpoints.rs b/src/checkpoints.rs index 578d533..7939bb3 100644 --- a/src/checkpoints.rs +++ b/src/checkpoints.rs @@ -12,7 +12,7 @@ use std::{error::Error, io::Write}; pub fn run(mut client: Client) -> Result<(), Box> { const N_OBJECTS: usize = 5; const OBJECT_SIZE_MIB: [u64; N_OBJECTS] = [256, 256, 1, 384, 128]; - const N_GENERATIONS: usize = 20; + const N_GENERATIONS: usize = 70; const MIN_WAIT_MS: u64 = 1500; const WAIT_RAND_RANGE: u64 = 400; println!("running checkpoints"); @@ -20,6 +20,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { for gen in 0..N_GENERATIONS { for obj_id in 0..N_OBJECTS { let key = format!("{gen}_{obj_id}"); + println!("Creating {key}"); let (obj, _info) = client .object_store .open_or_create_object_with_pref(key.as_bytes(), StoragePreference::FASTEST)?; From 20f14920420bf5320914338120209d2f462d565a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 9 Sep 2022 16:25:13 +0200 Subject: [PATCH 35/81] add filesystem case --- src/filesystem.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 15 +++++--- 2 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 src/filesystem.rs diff --git a/src/filesystem.rs b/src/filesystem.rs new file mode 100644 index 0000000..cd41fec --- /dev/null +++ b/src/filesystem.rs @@ -0,0 +1,89 @@ +///! +use betree_perf::*; +use betree_storage_stack::StoragePreference; +use rand::{Rng, RngCore, distributions::{Slice, DistIter}, thread_rng}; +use std::{error::Error, io::Write, ops::Range}; + +fn pref(foo: u8, space: &mut Vec, size: u64) -> StoragePreference { + match foo { + 0 if space[0] > size => { + space[0] -= size; + StoragePreference::FASTEST + } + 1 if space[1] > size => { + space[1] -= size; + StoragePreference::FAST + } + 2 if space[2] > size => { + space[2] -= size; + StoragePreference::SLOW + } + _ => panic!(), + } +} + +pub fn run(mut client: Client) -> Result<(), Box> { + const SMALL: Range = (1 * 1024)..(256 * 1024); + const MEDIUM: Range = (1 * 1024 * 1024)..(200 * 1024 * 1024); + const LARGE: Range = (200 * 1024 * 1024)..(2 * 1024 * 1024 * 1024); + const SIZES: [Range; 3] = [SMALL, MEDIUM, LARGE]; + // barely, seldom, often + const AMOUNT: [usize; 3] = [2000, 300, 20]; + const PROBS: [f64; 3] = [0.01, 0.1, 0.6]; + + // small, medium, large + const DISTRIBUTION: [f32; 3] = [0.9, 0.09, 0.01]; + const TIERS: Range = 0..3; + + let mut space = client + .database + .read() + .free_space_tier() + .iter() + .map(|tier| tier.free.to_bytes()) + .collect::>(); + + println!("running filesystem"); + println!("initialize state"); + + let mut groups = vec![]; + let mut counter: u64 = 1; + for num_objs in AMOUNT.iter() { + groups.push(vec![]); + let objs = groups.last_mut().unwrap(); + for size_grp in 0..3 { + for _ in 0..(*num_objs as f32 * DISTRIBUTION[size_grp]) as usize { + let size = client.rng.gen_range(SIZES[size_grp].clone()); + let pref = pref(client.rng.gen_range(TIERS), &mut space, size); + let (obj, _info) = client + .object_store + .open_or_create_object_with_pref(&counter.to_le_bytes(), pref)?; + objs.push(counter.to_le_bytes()); + counter += 1; + let mut cursor = obj.cursor_with_pref(pref); + with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + } + } + } + + println!("sync db"); + client.sync().expect("Failed to sync database"); + + println!("start reading"); + let mut samplers: Vec> = groups.iter().map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())).collect(); + for _ in 0..10000 { + for (id, prob) in PROBS.iter().enumerate() { + if client.rng.gen_bool(*prob) { + let obj = samplers[id].next().unwrap(); + let obj = client + .object_store + .open_object(obj)?.unwrap(); + for _ in obj.read_all_chunks()? {} + } + } + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 0cc18d6..4364300 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use betree_perf::Control; use structopt::StructOpt; mod checkpoints; +mod filesystem; mod ingest; mod rewrite; mod scientific_evaluation; @@ -18,7 +19,8 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; enum Mode { Tiered1, Checkpoints, - Evaluation{ + Filesystem, + Evaluation { #[structopt(default_value = "120")] runtime: u64, }, @@ -59,13 +61,16 @@ fn run_all(mode: Mode) -> Result<(), Box> { control.database.write().sync()?; } Mode::Checkpoints => { - let client = control.client(0, b"tiered1"); + let client = control.client(0, b"checkpoints"); checkpoints::run(client)?; control.database.write().sync()?; } - Mode::Evaluation { - runtime, - } => { + Mode::Filesystem => { + let client = control.client(0, b"filesystem"); + filesystem::run(client)?; + control.database.write().sync()?; + } + Mode::Evaluation { runtime } => { let client = control.client(0, b"scientific_evaluation"); scientific_evaluation::run(client, runtime)?; control.database.write().sync()?; From 5ce520c2beb7e8e36575ae290e59d362ce04bc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 9 Sep 2022 16:27:09 +0200 Subject: [PATCH 36/81] add filesystem run --- run.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/run.sh b/run.sh index 39995dd..b84dc9a 100755 --- a/run.sh +++ b/run.sh @@ -122,6 +122,15 @@ function checkpoints() { run "$vdev_type" checkpoints_fastest checkpoints } +function filesystem() { + #local vdev_type="dram" + #local vdev_type="pmem" + #local vdev_type="ssd" + #local vdev_type="pmem_fs" + export BETREE__ALLOC_STRATEGY='[[0],[1],[2],[]]' + run "$vdev_type" file_system_three filesystem +} + function zip_cache() { local F="$PWD/data/linux.zip" local F_CD_START=1040032667 @@ -241,6 +250,7 @@ ensure_bectl #zip_tiered #tiered scientific_evaluation +#filesystem #checkpoints #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' From b612aaa40bdc2de8ea6402ffa6272708e9d2664b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 9 Sep 2022 17:09:11 +0200 Subject: [PATCH 37/81] decrease pref on failure --- src/filesystem.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index cd41fec..37cf5e2 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -18,7 +18,8 @@ fn pref(foo: u8, space: &mut Vec, size: u64) -> StoragePreference { space[2] -= size; StoragePreference::SLOW } - _ => panic!(), + 3.. => panic!(), + _ => pref(foo + 1, space, size) } } From fbac232574df81751c8b786edea6c268bdc0c1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 9 Sep 2022 17:15:58 +0200 Subject: [PATCH 38/81] use formatted key --- src/filesystem.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 37cf5e2..c56290d 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -56,10 +56,11 @@ pub fn run(mut client: Client) -> Result<(), Box> { for _ in 0..(*num_objs as f32 * DISTRIBUTION[size_grp]) as usize { let size = client.rng.gen_range(SIZES[size_grp].clone()); let pref = pref(client.rng.gen_range(TIERS), &mut space, size); + let key = format!("key{counter}").into_bytes(); let (obj, _info) = client .object_store - .open_or_create_object_with_pref(&counter.to_le_bytes(), pref)?; - objs.push(counter.to_le_bytes()); + .open_or_create_object_with_pref(&key, pref)?; + objs.push(key); counter += 1; let mut cursor = obj.cursor_with_pref(pref); with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { From 58dde1061c8e889987ce4e79b6d568c882a7bab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sun, 11 Sep 2022 17:14:19 +0200 Subject: [PATCH 39/81] plot object grid with timesteps --- jupyter/plot.py | 119 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 23 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 08b8990..f46dc0a 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -1,18 +1,20 @@ +#! /bin/env python import json import sys import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as ticker -# %matplotlib inline - +from mpl_toolkits.axes_grid1 import make_axes_locatable +import matplotlib.cm as cm +import matplotlib.colors as mat_col +import matplotlib + # Constants BLOCK_SIZE = 4096 EPOCH_MS=500 SEC_MS=1000 -from matplotlib import pyplot as plt - def subtract_last_index(array): last_val = 0 for index, value in enumerate(array): @@ -97,31 +99,102 @@ def plot_latency(data): ax.set_title(f"Haura - {label}") # add title fig.savefig(f"{sys.argv[1]}/plot_latency.svg") -data = [] +# Access string subslice and first tuple member +def sort_by_o_id(key): + return int(key[0][2:]) + +def plot_object_distribution(): + print("reading in data") + fs = open(f"{sys.argv[1]}/tier_state.jsonl", 'r') + data = read_jsonl(fs) + fs.close() + + colors = { + 0: "white", + 1: "#009E73", + 2: "#F0E442", + 3: "#0072B2", + } + cmap = mat_col.ListedColormap([colors[x] for x in colors.keys()]) + labels = np.array(["Not present", "Fastest", "Fast", "Slow"]) + + num_ts = 0 + for current_timestep in data: + # Read all names and order + # Iterate over each tier and add keys to known keys + keys = [] # Vec<(key, num_tier)> + num_tier = 1 + print("fetching keys") + for tier in current_timestep: + for object in tier["files"]: + keys.append((object, num_tier)) + num_tier += 1 + + print("sorting keys") + keys.sort(key=sort_by_o_id) + + # old boundaries update when needed + # seldom accessed 1-2000 (45x45) + # barely accessed 2001-2300 (18x18) + # often accessed 2301-2320 (5x5) + group_1 = [n[1] for n in keys[:2000]] + group_2 = [n[1] for n in keys[2000:2300]] + group_3 = [n[1] for n in keys[2300:2320]] + + # Reshape to matrix and fill with zeros if necessary + print("shaping data") + group_1 = np.concatenate((np.array(group_1), np.zeros(2025 - len(group_1)))).reshape((45,45)) + group_2 = np.concatenate((np.array(group_2), np.zeros(324 - len(group_2)))).reshape((18,18)) + group_3 = np.concatenate((np.array(group_3), np.zeros(25 - len(group_3)))).reshape((5,5)) + + num_group = 0 + fig, axs = plt.subplots(1, 3, figsize=(20,5)) + for group in [group_1, group_2, group_3]: + subax = axs[num_group] + match num_group: + case 0: + subax.set_title("Seldomly Accessed (1%)") + case 1: + subax.set_title("Occassionally Accessed (10%)") + case 2: + subax.set_title("Often Accessed (60%)") + num_group += 1 + subax.imshow(group, cmap=cmap) + #divider = make_axes_locatable(subax) + #cax = divider.append_axes("right", size="5%", pad=0.05) + #fig.colorbar(im, cax=cax) + fmt = matplotlib.ticker.FuncFormatter(lambda x, pos: labels[x]) + norm = matplotlib.colors.BoundaryNorm(np.array([0,1,2,3]), len(labels), clip=True) + ticks = [0, 1, 2, 3] + fig.colorbar(cm.ScalarMappable(cmap=cmap, norm=mat_col.NoNorm()), format=fmt, ticks=ticks) + fig.savefig(f"{sys.argv[1]}/plot_timestep_{num_ts:0>3}.png") + num_ts += 1 + +def read_jsonl(file): + data = [] + while True: + # Get next line from file + line = file.readline() + # if line is empty + # end of file is reached + if not line: + break + json_object = json.loads(line) + data.append(json_object); + return data if len(sys.argv) < 2: print("Please specify an input run directory. If you already completed benchmarks they can be found under `results/*`.") exit(1) -fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') -line_number = 0 -while True: - line_number += 1 - # Get next line from file - line = fs.readline() - # if line is empty - # end of file is reached - if not line: - break - json_object = json.loads(line) - data.append(json_object); - +print("reading intiital data") +fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') # print("{}".format(data)) - +data = read_jsonl(fs) fs.close() -df = pd.DataFrame(data) - -plot_throughput(data) -plot_latency(data) +# Plot actions +#plot_throughput(data) +#plot_latency(data) +plot_object_distribution() From 5ea187b49f32f2a23d9ffa9dfc1335f028b8807e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sun, 11 Sep 2022 20:04:06 +0200 Subject: [PATCH 40/81] render timestep video with ffmpeg --- plot.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plot.sh b/plot.sh index aec5384..2a68ca9 100755 --- a/plot.sh +++ b/plot.sh @@ -14,6 +14,12 @@ function plot { shift 1 docker run -v "$PWD":/usr/src/bench -w /usr/src/bench haura_plots python jupyter/plot.py "$run" + pushd "$run" + if -e plot_timestep_000.png + then + ffmpeg -framerate 2 -i plot_timestep_%03d.png -c:v libx264 -pix_fmt yuv420p plot_timestep.mp4 + fi + popd } export ROOT=$PWD From f6b2d1abcfeb5e2b9acc6f4943a58f27129074d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 13 Sep 2022 15:21:24 +0200 Subject: [PATCH 41/81] use sync interface for reading in --- src/filesystem.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index c56290d..70ca6ba 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -74,6 +74,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { client.sync().expect("Failed to sync database"); println!("start reading"); + let mut buf = vec![0; 2 * 1024 * 1024 * 1024]; let mut samplers: Vec> = groups.iter().map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())).collect(); for _ in 0..10000 { for (id, prob) in PROBS.iter().enumerate() { @@ -82,7 +83,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { let obj = client .object_store .open_object(obj)?.unwrap(); - for _ in obj.read_all_chunks()? {} + obj.read_at(&mut buf, 0).map_err(|e| e.1)?; } } } From 01042b37026fc62f33b7c366c75f5bdf5dbd12fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 13 Sep 2022 15:23:04 +0200 Subject: [PATCH 42/81] fix test call --- plot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plot.sh b/plot.sh index 2a68ca9..73dd920 100755 --- a/plot.sh +++ b/plot.sh @@ -15,7 +15,7 @@ function plot { docker run -v "$PWD":/usr/src/bench -w /usr/src/bench haura_plots python jupyter/plot.py "$run" pushd "$run" - if -e plot_timestep_000.png + if [ -e plot_timestep_000.png ] then ffmpeg -framerate 2 -i plot_timestep_%03d.png -c:v libx264 -pix_fmt yuv420p plot_timestep.mp4 fi From f80398ba04e1ec800762d6f3894f5e47179283e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 14 Sep 2022 14:15:51 +0200 Subject: [PATCH 43/81] fix space accounting usage filesystem case --- src/filesystem.rs | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 70ca6ba..4ff8ad5 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,25 +1,30 @@ ///! use betree_perf::*; use betree_storage_stack::StoragePreference; -use rand::{Rng, RngCore, distributions::{Slice, DistIter}, thread_rng}; +use rand::{Rng, distributions::{Slice, DistIter}, thread_rng}; use std::{error::Error, io::Write, ops::Range}; -fn pref(foo: u8, space: &mut Vec, size: u64) -> StoragePreference { +fn pref(foo: u8, size: u64, client: &Client) -> StoragePreference { + let space = client + .database + .read() + .free_space_tier() + .iter() + .map(|tier| tier.free.to_bytes()) + .collect::>(); + match foo { 0 if space[0] > size => { - space[0] -= size; StoragePreference::FASTEST } 1 if space[1] > size => { - space[1] -= size; StoragePreference::FAST } 2 if space[2] > size => { - space[2] -= size; StoragePreference::SLOW } 3.. => panic!(), - _ => pref(foo + 1, space, size) + _ => pref(foo + 1, size, client) } } @@ -36,14 +41,6 @@ pub fn run(mut client: Client) -> Result<(), Box> { const DISTRIBUTION: [f32; 3] = [0.9, 0.09, 0.01]; const TIERS: Range = 0..3; - let mut space = client - .database - .read() - .free_space_tier() - .iter() - .map(|tier| tier.free.to_bytes()) - .collect::>(); - println!("running filesystem"); println!("initialize state"); @@ -55,7 +52,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { for size_grp in 0..3 { for _ in 0..(*num_objs as f32 * DISTRIBUTION[size_grp]) as usize { let size = client.rng.gen_range(SIZES[size_grp].clone()); - let pref = pref(client.rng.gen_range(TIERS), &mut space, size); + let pref = pref(client.rng.gen_range(TIERS), size, &client); let key = format!("key{counter}").into_bytes(); let (obj, _info) = client .object_store @@ -66,6 +63,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { cursor.write_all(b) })?; + client.sync().expect("Could not write object to disk completely. Check policy or benchmark disk utilization."); } } } From cad30f8d521566a20ac97d061c5034157b2528ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 14 Sep 2022 17:29:35 +0200 Subject: [PATCH 44/81] refine filesystem case --- src/filesystem.rs | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 4ff8ad5..d3aa86b 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,31 +1,25 @@ ///! use betree_perf::*; use betree_storage_stack::StoragePreference; +use betree_storage_stack::vdev::Block; use rand::{Rng, distributions::{Slice, DistIter}, thread_rng}; use std::{error::Error, io::Write, ops::Range}; -fn pref(foo: u8, size: u64, client: &Client) -> StoragePreference { - let space = client - .database - .read() - .free_space_tier() - .iter() - .map(|tier| tier.free.to_bytes()) - .collect::>(); - - match foo { - 0 if space[0] > size => { - StoragePreference::FASTEST - } - 1 if space[1] > size => { - StoragePreference::FAST - } - 2 if space[2] > size => { - StoragePreference::SLOW - } - 3.. => panic!(), - _ => pref(foo + 1, size, client) - } +fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { + let space = client.database.read().free_space_tier(); + match foo { + 0 if Block(space[0].free.0 - size.0) > Block((space[0].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FASTEST + } + 1 if Block(space[1].free.0 - size.0) > Block((space[1].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FAST + } + 2 if Block(space[2].free.0 - size.0) > Block((space[2].total.0 as f64 * 0.2) as u64) => { + StoragePreference::SLOW + } + 3.. => panic!(), + _ => pref(foo + 1, size, client) + } } pub fn run(mut client: Client) -> Result<(), Box> { @@ -35,7 +29,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { const SIZES: [Range; 3] = [SMALL, MEDIUM, LARGE]; // barely, seldom, often const AMOUNT: [usize; 3] = [2000, 300, 20]; - const PROBS: [f64; 3] = [0.01, 0.1, 0.6]; + const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; // small, medium, large const DISTRIBUTION: [f32; 3] = [0.9, 0.09, 0.01]; @@ -43,7 +37,6 @@ pub fn run(mut client: Client) -> Result<(), Box> { println!("running filesystem"); println!("initialize state"); - let mut groups = vec![]; let mut counter: u64 = 1; for num_objs in AMOUNT.iter() { @@ -52,7 +45,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { for size_grp in 0..3 { for _ in 0..(*num_objs as f32 * DISTRIBUTION[size_grp]) as usize { let size = client.rng.gen_range(SIZES[size_grp].clone()); - let pref = pref(client.rng.gen_range(TIERS), size, &client); + let pref = pref(client.rng.gen_range(TIERS), Block::from_bytes(size), &client); let key = format!("key{counter}").into_bytes(); let (obj, _info) = client .object_store @@ -63,7 +56,6 @@ pub fn run(mut client: Client) -> Result<(), Box> { with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { cursor.write_all(b) })?; - client.sync().expect("Could not write object to disk completely. Check policy or benchmark disk utilization."); } } } From c77a87096a74783405266b24a42ea90ffa6babd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 16 Sep 2022 14:57:55 +0200 Subject: [PATCH 45/81] plot ms per byte --- jupyter/plot.py | 52 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index f46dc0a..8c58709 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -104,11 +104,9 @@ def sort_by_o_id(key): return int(key[0][2:]) def plot_object_distribution(): - print("reading in data") fs = open(f"{sys.argv[1]}/tier_state.jsonl", 'r') data = read_jsonl(fs) fs.close() - colors = { 0: "white", 1: "#009E73", @@ -117,20 +115,17 @@ def plot_object_distribution(): } cmap = mat_col.ListedColormap([colors[x] for x in colors.keys()]) labels = np.array(["Not present", "Fastest", "Fast", "Slow"]) - num_ts = 0 for current_timestep in data: # Read all names and order # Iterate over each tier and add keys to known keys keys = [] # Vec<(key, num_tier)> num_tier = 1 - print("fetching keys") for tier in current_timestep: for object in tier["files"]: keys.append((object, num_tier)) num_tier += 1 - print("sorting keys") keys.sort(key=sort_by_o_id) # old boundaries update when needed @@ -142,34 +137,57 @@ def plot_object_distribution(): group_3 = [n[1] for n in keys[2300:2320]] # Reshape to matrix and fill with zeros if necessary - print("shaping data") group_1 = np.concatenate((np.array(group_1), np.zeros(2025 - len(group_1)))).reshape((45,45)) group_2 = np.concatenate((np.array(group_2), np.zeros(324 - len(group_2)))).reshape((18,18)) group_3 = np.concatenate((np.array(group_3), np.zeros(25 - len(group_3)))).reshape((5,5)) num_group = 0 - fig, axs = plt.subplots(1, 3, figsize=(20,5)) + fig, axs = plt.subplots(1, 4, figsize=(20,5)) for group in [group_1, group_2, group_3]: subax = axs[num_group] - match num_group: - case 0: - subax.set_title("Seldomly Accessed (1%)") - case 1: - subax.set_title("Occassionally Accessed (10%)") - case 2: - subax.set_title("Often Accessed (60%)") + mean = group[group > 0].mean() + subax.set_title(f"Object mean level: {mean}") + subax.tick_params(color="white") num_group += 1 - subax.imshow(group, cmap=cmap) + im = subax.imshow(group, cmap=cmap) + im.set_clim(0, num_tier) #divider = make_axes_locatable(subax) #cax = divider.append_axes("right", size="5%", pad=0.05) #fig.colorbar(im, cax=cax) fmt = matplotlib.ticker.FuncFormatter(lambda x, pos: labels[x]) - norm = matplotlib.colors.BoundaryNorm(np.array([0,1,2,3]), len(labels), clip=True) ticks = [0, 1, 2, 3] fig.colorbar(cm.ScalarMappable(cmap=cmap, norm=mat_col.NoNorm()), format=fmt, ticks=ticks) + + times = [] + num_tiers = 0 + for tier in current_timestep: + num_tiers += 1 + resp_times = 0; + total = 0; + for o_id in tier["reqs"]: + resps = tier["reqs"][f"{o_id}"] + size = tier["files"][f"{o_id}"][1] + for resp in resps: + total += 1 + resp_times += resp["response_time"]["nanos"] / size + if total != 0: + times.append(resp_times / total) + else: + times.append(0) + x_ticks = np.arange(0, num_tiers) + width = 0.35 + # convert from nanos to millis + axs[3].bar(x_ticks, np.array(times) / 1000000, width, label='Access latency', hatch=['.', '+', '/'], color='white', edgecolor='black') + axs[3].set_title('Mean access latency for timestep') + axs[3].set_ylabel('Mean latency in ms') + #axs[3].set_ylim(0, 100) + axs[3].set_xticks(x_ticks, labels=["Fastest", "Fast", "Slow"]) + fig.savefig(f"{sys.argv[1]}/plot_timestep_{num_ts:0>3}.png") + matplotlib.pyplot.close(fig) num_ts += 1 + def read_jsonl(file): data = [] while True: @@ -195,6 +213,6 @@ def read_jsonl(file): fs.close() # Plot actions -#plot_throughput(data) +plot_throughput(data) #plot_latency(data) plot_object_distribution() From 6c202cb62e8e11eb5ea9f1c64d6bc3de4779e4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 16 Sep 2022 18:28:58 +0200 Subject: [PATCH 46/81] plot group means over time --- jupyter/plot.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/jupyter/plot.py b/jupyter/plot.py index 8c58709..3649879 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -116,6 +116,8 @@ def plot_object_distribution(): cmap = mat_col.ListedColormap([colors[x] for x in colors.keys()]) labels = np.array(["Not present", "Fastest", "Fast", "Slow"]) num_ts = 0 + # three groups fixed + mean_group_vals = [[], [], []] for current_timestep in data: # Read all names and order # Iterate over each tier and add keys to known keys @@ -146,6 +148,7 @@ def plot_object_distribution(): for group in [group_1, group_2, group_3]: subax = axs[num_group] mean = group[group > 0].mean() + mean_group_vals[num_group].append(mean) subax.set_title(f"Object mean level: {mean}") subax.tick_params(color="white") num_group += 1 @@ -187,6 +190,16 @@ def plot_object_distribution(): matplotlib.pyplot.close(fig) num_ts += 1 + fig, ax = plt.subplots(figsize=(10,5)) + ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group"); + ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed"); + ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed"); + # we might want to pick the actual timestamps for this + ax.set_xlabel("Timestep") + ax.set_ylabel("Mean object tier") + ax.set_title("Mean tier of all object groups over time") + pls_no_cut_off = ax.legend(bbox_to_anchor=(1.0,1.0), loc="upper left") + fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') def read_jsonl(file): data = [] From c386ff743aa863260f19a8b60d0ef2d505f99b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 16 Sep 2022 20:40:07 +0200 Subject: [PATCH 47/81] clamp distribution plot for comparability --- jupyter/plot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jupyter/plot.py b/jupyter/plot.py index 3649879..fcc2680 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -154,6 +154,8 @@ def plot_object_distribution(): num_group += 1 im = subax.imshow(group, cmap=cmap) im.set_clim(0, num_tier) + subax.yaxis.set_ticks([]) + subax.xaxis.set_ticks([]) #divider = make_axes_locatable(subax) #cax = divider.append_axes("right", size="5%", pad=0.05) #fig.colorbar(im, cax=cax) @@ -198,6 +200,7 @@ def plot_object_distribution(): ax.set_xlabel("Timestep") ax.set_ylabel("Mean object tier") ax.set_title("Mean tier of all object groups over time") + ax.set_ylim((1,3)) pls_no_cut_off = ax.legend(bbox_to_anchor=(1.0,1.0), loc="upper left") fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') From 88e27cdcab39afcfee55b99c7819e044765bf1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 11:34:19 +0200 Subject: [PATCH 48/81] filesystem: adjust sizes to fit more to real example --- src/filesystem.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index d3aa86b..2594b29 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -23,29 +23,37 @@ fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { } pub fn run(mut client: Client) -> Result<(), Box> { - const SMALL: Range = (1 * 1024)..(256 * 1024); - const MEDIUM: Range = (1 * 1024 * 1024)..(200 * 1024 * 1024); - const LARGE: Range = (200 * 1024 * 1024)..(2 * 1024 * 1024 * 1024); - const SIZES: [Range; 3] = [SMALL, MEDIUM, LARGE]; // barely, seldom, often - const AMOUNT: [usize; 3] = [2000, 300, 20]; + const AMOUNT: [usize; 3] = [2015, 324, 25]; const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; - // small, medium, large - const DISTRIBUTION: [f32; 3] = [0.9, 0.09, 0.01]; + // LNAL size reference + const SIZES: [u64; 5] = [ + 64 * 1000, + 256 * 1000, + 1 * 1000 * 1000, + 4 * 1000 * 1000, + 1 * 1000 * 1000 * 1000, + ]; + // Tuple describing the file distribution + const TIERS_SPEC: [[usize; 5]; 3] = [ + [511, 128, 682, 682, 12], + [82, 20, 110, 110, 2], + [6, 2, 8, 8, 1], + ]; + const TIERS: Range = 0..3; println!("running filesystem"); println!("initialize state"); let mut groups = vec![]; let mut counter: u64 = 1; - for num_objs in AMOUNT.iter() { + for t_id in 0..3 { groups.push(vec![]); let objs = groups.last_mut().unwrap(); - for size_grp in 0..3 { - for _ in 0..(*num_objs as f32 * DISTRIBUTION[size_grp]) as usize { - let size = client.rng.gen_range(SIZES[size_grp].clone()); - let pref = pref(client.rng.gen_range(TIERS), Block::from_bytes(size), &client); + for (count, size) in TIERS_SPEC[t_id].iter().zip(SIZES.iter()) { + for _ in 0..*count { + let pref = pref(client.rng.gen_range(TIERS), Block::from_bytes(*size), &client); let key = format!("key{counter}").into_bytes(); let (obj, _info) = client .object_store @@ -53,7 +61,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { objs.push(key); counter += 1; let mut cursor = obj.cursor_with_pref(pref); - with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { + with_random_bytes(&mut client.rng, *size, 8 * 1024 * 1024, |b| { cursor.write_all(b) })?; } From 180fec5111e0a917143414642ff67afd74cd03db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 11:55:56 +0200 Subject: [PATCH 49/81] plot.py: adjust group sizes to new case --- jupyter/plot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index fcc2680..10d38e0 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -134,9 +134,9 @@ def plot_object_distribution(): # seldom accessed 1-2000 (45x45) # barely accessed 2001-2300 (18x18) # often accessed 2301-2320 (5x5) - group_1 = [n[1] for n in keys[:2000]] - group_2 = [n[1] for n in keys[2000:2300]] - group_3 = [n[1] for n in keys[2300:2320]] + group_1 = [n[1] for n in keys[:2015]] + group_2 = [n[1] for n in keys[2015:2339]] + group_3 = [n[1] for n in keys[2339:2364]] # Reshape to matrix and fill with zeros if necessary group_1 = np.concatenate((np.array(group_1), np.zeros(2025 - len(group_1)))).reshape((45,45)) From 8c3a2e6762e0435268318c6ba470d3fa7905705b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 14:03:57 +0200 Subject: [PATCH 50/81] filesystem: double object number --- src/filesystem.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 2594b29..8529258 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -24,10 +24,9 @@ fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { pub fn run(mut client: Client) -> Result<(), Box> { // barely, seldom, often - const AMOUNT: [usize; 3] = [2015, 324, 25]; const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; - // LNAL size reference + // LANL size reference const SIZES: [u64; 5] = [ 64 * 1000, 256 * 1000, @@ -37,9 +36,9 @@ pub fn run(mut client: Client) -> Result<(), Box> { ]; // Tuple describing the file distribution const TIERS_SPEC: [[usize; 5]; 3] = [ - [511, 128, 682, 682, 12], - [82, 20, 110, 110, 2], - [6, 2, 8, 8, 1], + [1022, 256, 1364, 1364, 24], + [164, 40, 220, 220, 4], + [12, 4, 16, 16, 2], ]; const TIERS: Range = 0..3; @@ -74,7 +73,9 @@ pub fn run(mut client: Client) -> Result<(), Box> { println!("start reading"); let mut buf = vec![0; 2 * 1024 * 1024 * 1024]; let mut samplers: Vec> = groups.iter().map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())).collect(); - for _ in 0..10000 { + const RUNS: usize = 10000; + for run in 0..RUNS { + println!("Reading generation {run} of {RUNS}"); for (id, prob) in PROBS.iter().enumerate() { if client.rng.gen_bool(*prob) { let obj = samplers[id].next().unwrap(); From 9c63706f53074a059385eb2a7a11becfb57db986 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 15:53:07 +0200 Subject: [PATCH 51/81] filesystem: measure base comparison after 20 min --- src/filesystem.rs | 86 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 8529258..48d3ce2 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -22,31 +22,32 @@ fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { } } -pub fn run(mut client: Client) -> Result<(), Box> { - // barely, seldom, often - const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; +// barely, seldom, often +const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; - // LANL size reference - const SIZES: [u64; 5] = [ - 64 * 1000, - 256 * 1000, - 1 * 1000 * 1000, - 4 * 1000 * 1000, - 1 * 1000 * 1000 * 1000, - ]; - // Tuple describing the file distribution - const TIERS_SPEC: [[usize; 5]; 3] = [ - [1022, 256, 1364, 1364, 24], - [164, 40, 220, 220, 4], - [12, 4, 16, 16, 2], - ]; +// LANL size reference +const SIZES: [u64; 5] = [ + 64 * 1000, + 256 * 1000, + 1 * 1000 * 1000, + 4 * 1000 * 1000, + 1 * 1000 * 1000 * 1000, +]; +// Tuple describing the file distribution +const TIERS_SPEC: [[usize; 5]; 3] = [ + [1022, 256, 1364, 1364, 24], + [164, 40, 220, 220, 4], + [12, 4, 16, 16, 2], +]; - const TIERS: Range = 0..3; +const TIERS: Range = 0..3; +pub fn run(mut client: Client) -> Result<(), Box> { println!("running filesystem"); println!("initialize state"); let mut groups = vec![]; let mut counter: u64 = 1; + let start = std::time::Instant::now(); for t_id in 0..3 { groups.push(vec![]); let objs = groups.last_mut().unwrap(); @@ -70,12 +71,11 @@ pub fn run(mut client: Client) -> Result<(), Box> { println!("sync db"); client.sync().expect("Failed to sync database"); - println!("start reading"); + println!("start conditioning"); let mut buf = vec![0; 2 * 1024 * 1024 * 1024]; let mut samplers: Vec> = groups.iter().map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())).collect(); - const RUNS: usize = 10000; - for run in 0..RUNS { - println!("Reading generation {run} of {RUNS}"); + while start.elapsed().as_secs() < 1200 { + // println!("Reading generation {run} of {RUNS}"); for (id, prob) in PROBS.iter().enumerate() { if client.rng.gen_bool(*prob) { let obj = samplers[id].next().unwrap(); @@ -86,6 +86,48 @@ pub fn run(mut client: Client) -> Result<(), Box> { } } } + println!("sync db"); + client.sync().expect("Failed to sync database"); + println!("start measuring"); + // pick certain files which we know are in range, here we pick 3x64KB, 3x256KB, 3x1MB, 3x4MB, 1x1GB + // Read individual files multiple times to see the cache working? + const SELECTION: [usize; 5] = [3,3,3,3,1]; + let f = std::fs::OpenOptions::new().write(true).create(true).open("filesystem_measurements.csv")?; + let mut w = std::io::BufWriter::new(f); + w.write_all(b"key,size,read_latency_ms,write_latency_ms\n")?; + + for tier in TIERS { + for (idx, sel_num) in SELECTION.iter().enumerate() { + let obj_num = TIERS_SPEC[tier as usize][idx]; + let okstart = obj_key_start(tier as usize, idx); + let okend = okstart + obj_num; + for _ in 0..*sel_num { + let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); + let obj = client.object_store.open_object(obj_key.as_bytes())?.expect("Known object could not be opened"); + let start = std::time::Instant::now(); + obj.read_at(&mut buf, 0).map_err(|e| e.1)?; + let read_time = start.elapsed(); + let size = SIZES[idx]; + let mut cursor = obj.cursor(); + let start = std::time::Instant::now(); + with_random_bytes(&mut client.rng, size, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + let write_time = start.elapsed(); + w.write_all(format!("{obj_key},{size},{},{}\n", read_time.as_millis(), write_time.as_millis()).as_bytes())?; + } + } + } + w.flush()?; Ok(()) } + +fn obj_key_start(tier: usize, group: usize) -> usize { + let mut tier_offset = 0; + for idx in 0..tier { + tier_offset += TIERS_SPEC[idx].iter().sum::(); + } + let group_offset = TIERS_SPEC[tier].iter().take(group).sum::(); + tier_offset + group_offset +} From 7282ace951e01211b1250bd3d1c46cd51f4f8b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 20:14:54 +0200 Subject: [PATCH 52/81] filesystem: cool down before measuring --- src/filesystem.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/filesystem.rs b/src/filesystem.rs index 48d3ce2..a57ad09 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -86,6 +86,8 @@ pub fn run(mut client: Client) -> Result<(), Box> { } } } + // Allow for some cooldown and migration ending... + std::thread::sleep(std::time::Duration::from_secs(30)); println!("sync db"); client.sync().expect("Failed to sync database"); println!("start measuring"); From c495e6a77393f9abd5ff2a209f4cafec9f662210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sat, 17 Sep 2022 20:29:35 +0200 Subject: [PATCH 53/81] filesystem: destroy cache before measuring --- src/filesystem.rs | 95 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index a57ad09..bba6483 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,25 +1,28 @@ ///! use betree_perf::*; -use betree_storage_stack::StoragePreference; use betree_storage_stack::vdev::Block; -use rand::{Rng, distributions::{Slice, DistIter}, thread_rng}; +use betree_storage_stack::StoragePreference; +use rand::{ + distributions::{DistIter, Slice}, + thread_rng, Rng, +}; use std::{error::Error, io::Write, ops::Range}; fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { - let space = client.database.read().free_space_tier(); - match foo { - 0 if Block(space[0].free.0 - size.0) > Block((space[0].total.0 as f64 * 0.2) as u64) => { - StoragePreference::FASTEST - } - 1 if Block(space[1].free.0 - size.0) > Block((space[1].total.0 as f64 * 0.2) as u64) => { - StoragePreference::FAST - } - 2 if Block(space[2].free.0 - size.0) > Block((space[2].total.0 as f64 * 0.2) as u64) => { - StoragePreference::SLOW - } - 3.. => panic!(), - _ => pref(foo + 1, size, client) - } + let space = client.database.read().free_space_tier(); + match foo { + 0 if Block(space[0].free.0 - size.0) > Block((space[0].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FASTEST + } + 1 if Block(space[1].free.0 - size.0) > Block((space[1].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FAST + } + 2 if Block(space[2].free.0 - size.0) > Block((space[2].total.0 as f64 * 0.2) as u64) => { + StoragePreference::SLOW + } + 3.. => panic!(), + _ => pref(foo + 1, size, client), + } } // barely, seldom, often @@ -53,7 +56,11 @@ pub fn run(mut client: Client) -> Result<(), Box> { let objs = groups.last_mut().unwrap(); for (count, size) in TIERS_SPEC[t_id].iter().zip(SIZES.iter()) { for _ in 0..*count { - let pref = pref(client.rng.gen_range(TIERS), Block::from_bytes(*size), &client); + let pref = pref( + client.rng.gen_range(TIERS), + Block::from_bytes(*size), + &client, + ); let key = format!("key{counter}").into_bytes(); let (obj, _info) = client .object_store @@ -73,15 +80,16 @@ pub fn run(mut client: Client) -> Result<(), Box> { println!("start conditioning"); let mut buf = vec![0; 2 * 1024 * 1024 * 1024]; - let mut samplers: Vec> = groups.iter().map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())).collect(); + let mut samplers: Vec> = groups + .iter() + .map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())) + .collect(); while start.elapsed().as_secs() < 1200 { // println!("Reading generation {run} of {RUNS}"); for (id, prob) in PROBS.iter().enumerate() { if client.rng.gen_bool(*prob) { let obj = samplers[id].next().unwrap(); - let obj = client - .object_store - .open_object(obj)?.unwrap(); + let obj = client.object_store.open_object(obj)?.unwrap(); obj.read_at(&mut buf, 0).map_err(|e| e.1)?; } } @@ -90,14 +98,37 @@ pub fn run(mut client: Client) -> Result<(), Box> { std::thread::sleep(std::time::Duration::from_secs(30)); println!("sync db"); client.sync().expect("Failed to sync database"); - println!("start measuring"); // pick certain files which we know are in range, here we pick 3x64KB, 3x256KB, 3x1MB, 3x4MB, 1x1GB // Read individual files multiple times to see the cache working? - const SELECTION: [usize; 5] = [3,3,3,3,1]; + const SELECTION: [usize; 5] = [3, 3, 3, 3, 1]; - let f = std::fs::OpenOptions::new().write(true).create(true).open("filesystem_measurements.csv")?; + { + // Thrash Cache by writing random data into slow with a different object store + println!("destroying cache"); + let os = client + .database + .write() + .open_named_object_store(b"destroycache", StoragePreference::SLOW)?; + let obj = os.create_object(b"foo")?; + let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); + with_random_bytes( + &mut client.rng, + 1 * 1024 * 1024 * 1024, + 8 * 1024 * 1024, + |b| cursor.write_all(b), + )?; + println!("sync db"); + client.sync().expect("Failed to sync database"); + // Cooldown + std::thread::sleep(std::time::Duration::from_secs(30)); + } + println!("start measuring"); + let f = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open("filesystem_measurements.csv")?; let mut w = std::io::BufWriter::new(f); - w.write_all(b"key,size,read_latency_ms,write_latency_ms\n")?; + w.write_all(b"key,size,read_latency_ns,write_latency_ns\n")?; for tier in TIERS { for (idx, sel_num) in SELECTION.iter().enumerate() { @@ -106,7 +137,10 @@ pub fn run(mut client: Client) -> Result<(), Box> { let okend = okstart + obj_num; for _ in 0..*sel_num { let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); - let obj = client.object_store.open_object(obj_key.as_bytes())?.expect("Known object could not be opened"); + let obj = client + .object_store + .open_object(obj_key.as_bytes())? + .expect("Known object could not be opened"); let start = std::time::Instant::now(); obj.read_at(&mut buf, 0).map_err(|e| e.1)?; let read_time = start.elapsed(); @@ -117,7 +151,14 @@ pub fn run(mut client: Client) -> Result<(), Box> { cursor.write_all(b) })?; let write_time = start.elapsed(); - w.write_all(format!("{obj_key},{size},{},{}\n", read_time.as_millis(), write_time.as_millis()).as_bytes())?; + w.write_all( + format!( + "{obj_key},{size},{},{}\n", + read_time.as_nanos(), + write_time.as_nanos() + ) + .as_bytes(), + )?; } } } From 7927055ee285c06503c7b0f70ae99ee7679932c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sun, 18 Sep 2022 21:47:47 +0200 Subject: [PATCH 54/81] plots: plot tier usage & make reqs plots optional --- jupyter/plot.py | 108 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 10d38e0..22c56f4 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -134,14 +134,14 @@ def plot_object_distribution(): # seldom accessed 1-2000 (45x45) # barely accessed 2001-2300 (18x18) # often accessed 2301-2320 (5x5) - group_1 = [n[1] for n in keys[:2015]] - group_2 = [n[1] for n in keys[2015:2339]] - group_3 = [n[1] for n in keys[2339:2364]] - + group_1 = [n[1] for n in keys[:4030]] + group_2 = [n[1] for n in keys[4030:4678]] + group_3 = [n[1] for n in keys[4678:4728]] + # Reshape to matrix and fill with zeros if necessary - group_1 = np.concatenate((np.array(group_1), np.zeros(2025 - len(group_1)))).reshape((45,45)) - group_2 = np.concatenate((np.array(group_2), np.zeros(324 - len(group_2)))).reshape((18,18)) - group_3 = np.concatenate((np.array(group_3), np.zeros(25 - len(group_3)))).reshape((5,5)) + group_1 = np.concatenate((np.array(group_1), np.zeros(4096 - len(group_1)))).reshape((64,64)) + group_2 = np.concatenate((np.array(group_2), np.zeros(676 - len(group_2)))).reshape((26,26)) + group_3 = np.concatenate((np.array(group_3), np.zeros(64 - len(group_3)))).reshape((8,8)) num_group = 0 fig, axs = plt.subplots(1, 4, figsize=(20,5)) @@ -153,7 +153,7 @@ def plot_object_distribution(): subax.tick_params(color="white") num_group += 1 im = subax.imshow(group, cmap=cmap) - im.set_clim(0, num_tier) + im.set_clim(0, 3) subax.yaxis.set_ticks([]) subax.xaxis.set_ticks([]) #divider = make_axes_locatable(subax) @@ -163,39 +163,41 @@ def plot_object_distribution(): ticks = [0, 1, 2, 3] fig.colorbar(cm.ScalarMappable(cmap=cmap, norm=mat_col.NoNorm()), format=fmt, ticks=ticks) - times = [] - num_tiers = 0 - for tier in current_timestep: - num_tiers += 1 - resp_times = 0; - total = 0; - for o_id in tier["reqs"]: - resps = tier["reqs"][f"{o_id}"] - size = tier["files"][f"{o_id}"][1] - for resp in resps: - total += 1 - resp_times += resp["response_time"]["nanos"] / size - if total != 0: - times.append(resp_times / total) - else: - times.append(0) - x_ticks = np.arange(0, num_tiers) - width = 0.35 - # convert from nanos to millis - axs[3].bar(x_ticks, np.array(times) / 1000000, width, label='Access latency', hatch=['.', '+', '/'], color='white', edgecolor='black') - axs[3].set_title('Mean access latency for timestep') - axs[3].set_ylabel('Mean latency in ms') - #axs[3].set_ylim(0, 100) - axs[3].set_xticks(x_ticks, labels=["Fastest", "Fast", "Slow"]) + # Plot response times if available + if 'reqs' in current_timestep[0]: + times = [] + num_tiers = 0 + for tier in current_timestep: + num_tiers += 1 + resp_times = 0; + total = 0; + for o_id in tier["reqs"]: + resps = tier["reqs"][f"{o_id}"] + size = tier["files"][f"{o_id}"][1] + for resp in resps: + total += 1 + resp_times += resp["response_time"]["nanos"] / size + if total != 0: + times.append(resp_times / total) + else: + times.append(0) + x_ticks = np.arange(0, num_tiers) + width = 0.35 + # convert from nanos to millis + axs[3].bar(x_ticks, np.array(times) / 1000000, width, label='Access latency', hatch=['.', '+', '/'], color='white', edgecolor='black') + axs[3].set_title('Mean access latency for timestep') + axs[3].set_ylabel('Mean latency in ms') + #axs[3].set_ylim(0, 100) + axs[3].set_xticks(x_ticks, labels=["Fastest", "Fast", "Slow"]) fig.savefig(f"{sys.argv[1]}/plot_timestep_{num_ts:0>3}.png") matplotlib.pyplot.close(fig) num_ts += 1 fig, ax = plt.subplots(figsize=(10,5)) - ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group"); - ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed"); - ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed"); + ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group", marker="o", markevery=20); + ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed", marker="s", markevery=20); + ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed", marker="^", markevery=20); # we might want to pick the actual timestamps for this ax.set_xlabel("Timestep") ax.set_ylabel("Mean object tier") @@ -204,6 +206,40 @@ def plot_object_distribution(): pls_no_cut_off = ax.legend(bbox_to_anchor=(1.0,1.0), loc="upper left") fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') +def plot_tier_usage(data): + fig, axs = plt.subplots(4, 1, figsize=(9,13)) + + # 0 - 3; Fastest - Slowest + free = [[], [], [], []] + total = [[], [], [], []] + # Map each timestep to an individual + for ts in data: + tier = 0 + for stat in ts["usage"]: + free[tier].append(stat["free"]) + total[tier].append(stat["total"]) + tier += 1 + + tier = 0 + for fr in free: + match tier: + case 0: + axs[tier].set_title("Storage Utilization: Fastest") + case 1: + axs[tier].set_title("Storage Utilization: Fast") + case 2: + axs[tier].set_title("Storage Utilization: Slow") + case 3: + axs[tier].set_title("Storage Utilization: Slowest") + axs[tier].plot(np.array(fr) * 4096 / 1024 / 1024 / 1024, label="Free", marker="o", markevery=200) + axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200) + axs[tier].set_ylim(bottom=0) + axs[tier].legend(loc="lower center") + axs[tier].set_ylabel("Capacity in GiB") + tier += 1 + + fig.savefig(f"{sys.argv[1]}/tier_usage.svg") + def read_jsonl(file): data = [] while True: @@ -222,7 +258,6 @@ def read_jsonl(file): exit(1) -print("reading intiital data") fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') # print("{}".format(data)) data = read_jsonl(fs) @@ -230,5 +265,6 @@ def read_jsonl(file): # Plot actions plot_throughput(data) +plot_tier_usage(data) #plot_latency(data) plot_object_distribution() From 44456f2215f5674248d291298d0ab81cc711822b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 19 Sep 2022 13:50:10 +0200 Subject: [PATCH 55/81] filesystem: add group id to csv --- src/filesystem.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index bba6483..5d85bec 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -37,7 +37,7 @@ const SIZES: [u64; 5] = [ 1 * 1000 * 1000 * 1000, ]; // Tuple describing the file distribution -const TIERS_SPEC: [[usize; 5]; 3] = [ +const GROUPS_SPEC: [[usize; 5]; 3] = [ [1022, 256, 1364, 1364, 24], [164, 40, 220, 220, 4], [12, 4, 16, 16, 2], @@ -54,7 +54,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { for t_id in 0..3 { groups.push(vec![]); let objs = groups.last_mut().unwrap(); - for (count, size) in TIERS_SPEC[t_id].iter().zip(SIZES.iter()) { + for (count, size) in GROUPS_SPEC[t_id].iter().zip(SIZES.iter()) { for _ in 0..*count { let pref = pref( client.rng.gen_range(TIERS), @@ -128,12 +128,12 @@ pub fn run(mut client: Client) -> Result<(), Box> { .create(true) .open("filesystem_measurements.csv")?; let mut w = std::io::BufWriter::new(f); - w.write_all(b"key,size,read_latency_ns,write_latency_ns\n")?; + w.write_all(b"key,size,read_latency_ns,write_latency_ns,group\n")?; - for tier in TIERS { + for (n, _) in GROUPS_SPEC.iter().enumerate() { for (idx, sel_num) in SELECTION.iter().enumerate() { - let obj_num = TIERS_SPEC[tier as usize][idx]; - let okstart = obj_key_start(tier as usize, idx); + let obj_num = GROUPS_SPEC[n][idx]; + let okstart = obj_key_start(n, idx); let okend = okstart + obj_num; for _ in 0..*sel_num { let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); @@ -153,7 +153,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { let write_time = start.elapsed(); w.write_all( format!( - "{obj_key},{size},{},{}\n", + "{obj_key},{size},{},{},{n}\n", read_time.as_nanos(), write_time.as_nanos() ) @@ -169,8 +169,8 @@ pub fn run(mut client: Client) -> Result<(), Box> { fn obj_key_start(tier: usize, group: usize) -> usize { let mut tier_offset = 0; for idx in 0..tier { - tier_offset += TIERS_SPEC[idx].iter().sum::(); + tier_offset += GROUPS_SPEC[idx].iter().sum::(); } - let group_offset = TIERS_SPEC[tier].iter().take(group).sum::(); + let group_offset = GROUPS_SPEC[tier].iter().take(group).sum::(); tier_offset + group_offset } From 4fd10a31ce30a9e1ad7ba5a02d5dbb4f2316bc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 19 Sep 2022 13:51:46 +0200 Subject: [PATCH 56/81] filesystem_zip: add case --- src/filesystem_zip.rs | 160 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/filesystem_zip.rs diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs new file mode 100644 index 0000000..a27c106 --- /dev/null +++ b/src/filesystem_zip.rs @@ -0,0 +1,160 @@ +///! +use betree_perf::*; +use betree_storage_stack::vdev::Block; +use betree_storage_stack::StoragePreference; +use rand::{ + distributions::{DistIter, Slice}, + thread_rng, Rng, seq::{IteratorRandom, SliceRandom}, +}; +use std::{error::Error, io::{Write, Read}, ops::Range, path::Path}; + +fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { + let space = client.database.read().free_space_tier(); + match foo { + 0 if Block(space[0].free.0 - size.0) > Block((space[0].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FASTEST + } + 1 if Block(space[1].free.0 - size.0) > Block((space[1].total.0 as f64 * 0.2) as u64) => { + StoragePreference::FAST + } + 2 if Block(space[2].free.0 - size.0) > Block((space[2].total.0 as f64 * 0.2) as u64) => { + StoragePreference::SLOW + } + 3.. => panic!(), + _ => pref(foo + 1, size, client), + } +} + +// barely, seldom, often +const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; + +const TIERS: Range = 0..3; + +const GROUPS: [f32; 3] = [0.8, 0.15, 0.05]; +const NUM_SAMPLE: usize = 20; + +pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box> { + println!("running filesystem"); + println!("initialize state"); + + let file = std::fs::OpenOptions::new().read(true).open(zip_path)?; + let mut zip = zip::ZipArchive::new(file).unwrap(); + + // Create objects + let start = std::time::Instant::now(); + + // use expandable vector + let mut buf = Vec::new(); + let file_names = zip.file_names().map(|n| n.to_string()).collect::>(); + let mut file_name_with_size = vec![]; + let file_num = file_names.len(); + for file in file_names.into_iter() { + // Read each file and insert randomly as new object into the object store + let mut zfile = zip.by_name(&file).unwrap(); + zfile.read_to_end(&mut buf)?; + let size = zfile.compressed_size(); + let pref = pref( + client.rng.gen_range(TIERS), + Block::from_bytes(size), + &client, + ); + let (obj, _) = client.object_store.open_or_create_object_with_pref(file.as_bytes(), pref)?; + obj.write_at_with_pref(&buf, 0, pref).map_err(|e| e.1)?; + file_name_with_size.push((file,size)); + buf.clear(); + } + + // Create groups + let mut groups: [Vec<(String, u64)>; 3] = [0;3].map(|_| vec![]); + let mut distributed = 0usize; + for (id, part) in GROUPS.iter().enumerate() { + file_name_with_size.shuffle(&mut client.rng); + let num = (part * file_num as f32) as usize; + groups[id] = file_name_with_size[distributed..(distributed+num)].to_vec(); + distributed += num; + } + + println!("sync db"); + client.sync().expect("Failed to sync database"); + + println!("start conditioning"); + let mut buf = vec![0; 5 * 1024 * 1024 * 1024]; + let mut samplers: Vec> = groups + .iter() + .map(|ob| thread_rng().sample_iter(Slice::new(&ob).unwrap())) + .collect(); + while start.elapsed().as_secs() < 1200 { + // println!("Reading generation {run} of {RUNS}"); + for (id, prob) in PROBS.iter().enumerate() { + if client.rng.gen_bool(*prob) { + let obj = samplers[id].next().unwrap(); + let obj = client.object_store.open_object(obj.0.as_bytes())?.unwrap(); + obj.read_at(&mut buf, 0).map_err(|e| e.1)?; + } + } + } + // Allow for some cooldown and migration ending... + std::thread::sleep(std::time::Duration::from_secs(30)); + println!("sync db"); + client.sync().expect("Failed to sync database"); + // // pick certain files which we know are in range, here we pick 3x64KB, 3x256KB, 3x1MB, 3x4MB, 1x1GB + // // Read individual files multiple times to see the cache working? + // const SELECTION: [usize; 5] = [3, 3, 3, 3, 1]; + + { + // Thrash Cache by writing random data into slow with a different object store + println!("destroying cache"); + let os = client + .database + .write() + .open_named_object_store(b"destroycache", StoragePreference::SLOW)?; + let obj = os.create_object(b"foo")?; + let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); + with_random_bytes( + &mut client.rng, + 1 * 1024 * 1024 * 1024, + 8 * 1024 * 1024, + |b| cursor.write_all(b), + )?; + println!("sync db"); + client.sync().expect("Failed to sync database"); + // Cooldown + std::thread::sleep(std::time::Duration::from_secs(30)); + } + println!("start measuring"); + let f = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open("filesystem_zip_measurements.csv")?; + let mut w = std::io::BufWriter::new(f); + w.write_all(b"key,size,read_latency_ns,write_latency_ns,group\n")?; + + for (idx, sampler) in groups.iter().enumerate() { + for _ in 0..NUM_SAMPLE { + let (obj_key, size) = sampler.choose(&mut client.rng).unwrap(); + let obj = client + .object_store + .open_object(obj_key.as_bytes())? + .expect("Known object could not be opened"); + let start = std::time::Instant::now(); + obj.read_at(&mut buf, 0).map_err(|e| e.1)?; + let read_time = start.elapsed(); + let mut cursor = obj.cursor(); + let start = std::time::Instant::now(); + with_random_bytes(&mut client.rng, *size, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + let write_time = start.elapsed(); + w.write_all( + format!( + "{obj_key},{size},{},{},{idx}\n", + read_time.as_nanos(), + write_time.as_nanos() + ) + .as_bytes(), + )?; + } + } + w.flush()?; + Ok(()) +} From 2d52af9d953e0f970715c072ca5f0167c98bf434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 19 Sep 2022 17:30:30 +0200 Subject: [PATCH 57/81] plot: split throughput in four axes --- jupyter/plot.py | 51 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 22c56f4..48540f3 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -27,10 +27,25 @@ def subtract_first_index(array): for index, value in enumerate(array): array[index] = value -first_val +def num_to_name(tier): + match tier: + case 0: + return 'Fastest' + case 1: + return 'Fast' + case 2: + return 'Slow' + case 3: + return 'Slowest' + case _: + return '???' + def plot_throughput(data): epoch = [temp['epoch_ms'] for temp in data] subtract_first_index(epoch) - fig, ax = plt.subplots(figsize=(15,5)) + fig, axs = plt.subplots(4, 1, figsize=(16,8)) + colors=['#009E73', '#F0E442', '#0072B2', '#D55E00'] + markers=['o', '^', ''] for x in range(4): for y in range(4): writes = np.array([]) @@ -51,20 +66,20 @@ def plot_throughput(data): # if you change this you'll need to modify this here too. writes = writes * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) reads = reads * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) + write_line = axs[x].plot(epoch, writes, label = 'Written', color="#F0E442") + read_line = axs[x].plot(epoch, reads, label = 'Read', linestyle='dotted', color="#009E73") - ax.plot(epoch, writes, label = "Writes {}/{}".format(x,y)) - ax.plot(epoch, reads, label = "Reads {}/{}".format(x,y)) - fig.legend() - # Epoch in seconds - ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" - epoch_formatted = list(map(ms_to_string, epoch)) - ax.set_xlabel("runtime (minute:seconds)") # add X-axis label - ax.set_xticks(epoch, epoch_formatted) - ax.locator_params(tight=True, nbins=10) + ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" + epoch_formatted = list(map(ms_to_string, epoch)) + axs[x].set_xlabel("runtime (minute:seconds)") # add X-axis label + axs[x].set_xticks(epoch, epoch_formatted) + axs[x].locator_params(tight=True, nbins=10) - ax.set_ylabel("MiB/s (I/0)") # add Y-axis label - label=' | '.join(sys.argv[1].split('/')[-2:]) - ax.set_title(f"Haura - {label}") # add title + axs[x].set_ylabel(f"{num_to_name(x)}\nMiB/s (I/0)") # add Y-axis label + label=' | '.join(sys.argv[1].split('/')[-2:]) + fig.legend(loc="center right") + # Epoch in seconds + fig.suptitle(f"Haura - {label}", y=0.98) # add title fig.savefig(f"{sys.argv[1]}/plot.svg") def plot_latency(data): @@ -195,9 +210,9 @@ def plot_object_distribution(): num_ts += 1 fig, ax = plt.subplots(figsize=(10,5)) - ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group", marker="o", markevery=20); - ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed", marker="s", markevery=20); - ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed", marker="^", markevery=20); + ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group", marker="o", markevery=10); + ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed", marker="s", markevery=10); + ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed", marker="^", markevery=10); # we might want to pick the actual timestamps for this ax.set_xlabel("Timestep") ax.set_ylabel("Mean object tier") @@ -231,10 +246,10 @@ def plot_tier_usage(data): axs[tier].set_title("Storage Utilization: Slow") case 3: axs[tier].set_title("Storage Utilization: Slowest") - axs[tier].plot(np.array(fr) * 4096 / 1024 / 1024 / 1024, label="Free", marker="o", markevery=200) + axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200) axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200) axs[tier].set_ylim(bottom=0) - axs[tier].legend(loc="lower center") + axs[tier].legend(loc="upper center") axs[tier].set_ylabel("Capacity in GiB") tier += 1 From 7b8c9fba4c9c35c3cd25df2c6657f4cf6b5538b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 19 Sep 2022 17:34:03 +0200 Subject: [PATCH 58/81] plot/usage: display name on y axis --- jupyter/plot.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 48540f3..394b0eb 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -237,20 +237,11 @@ def plot_tier_usage(data): tier = 0 for fr in free: - match tier: - case 0: - axs[tier].set_title("Storage Utilization: Fastest") - case 1: - axs[tier].set_title("Storage Utilization: Fast") - case 2: - axs[tier].set_title("Storage Utilization: Slow") - case 3: - axs[tier].set_title("Storage Utilization: Slowest") axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200) axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200) axs[tier].set_ylim(bottom=0) axs[tier].legend(loc="upper center") - axs[tier].set_ylabel("Capacity in GiB") + axs[tier].set_ylabel(f"{num_to_name(tier)}\nCapacity in GiB") tier += 1 fig.savefig(f"{sys.argv[1]}/tier_usage.svg") From 8ca19973a3478e60fd3e2fba387ebe866ab6ce1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 20 Sep 2022 12:35:37 +0200 Subject: [PATCH 59/81] plot: add latency sampled boxplots --- jupyter/plot.py | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/jupyter/plot.py b/jupyter/plot.py index 394b0eb..7da4e1f 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -246,6 +246,83 @@ def plot_tier_usage(data): fig.savefig(f"{sys.argv[1]}/tier_usage.svg") +# TODO: Adjust bucket sizes +def size_buckets(byte): + if byte <= 64000: + return 64000 + elif byte <= 256000: + return 256000 + elif byte <= 1000000: + return 1000000 + elif byte <= 4000000: + return 4000000 + else: + return 1000000000 + +def bytes_to_lexical(byte): + if byte >= 1000000: + return f"{byte/1000/1000}MB" + return f"{byte/1000}KB" + +def plot_filesystem_test(): + dat = pd.read_csv(f"{sys.argv[1]}/filesystem_measurements.csv") + # groups + fig, axs = plt.subplots(2,3, figsize=(15,5)) + min_read = 99999999999999999 + min_write = 99999999999999999 + max_read = 0 + max_write = 0 + for n in range(3): + sizes = dat[dat['group'] == n]['size'].to_numpy() + reads = {} + reads_raw = dat[dat['group'] == n]['read_latency_ns'].to_numpy() + writes = {} + writes_raw = dat[dat['group'] == n]['write_latency_ns'].to_numpy() + for (idx, size) in enumerate(sizes): + if size_buckets(size) not in reads: + reads[size_buckets(size)] = [] + reads[size_buckets(size)].append(reads_raw[idx]) + if size_buckets(size) not in writes: + writes[size_buckets(size)] = [] + writes[size_buckets(size)].append(writes_raw[idx]) + + sorted_sizes = list(reads) + sorted_sizes.sort() + labels = [] + reads_plot = [] + writes_plot = [] + for size in sorted_sizes: + labels.append(bytes_to_lexical(size)) + a = np.array(reads[size]) / 1000 + min_read = min(min_read, a.min()) + max_read = max(max_read, a.max()) + reads_plot.append(a) + b = np.array(writes[size]) / 1000 + min_write = min(min_write, b.min()) + max_write = max(max_write, b.max()) + writes_plot.append(b) + axs[0][n].boxplot(reads_plot, vert=True, labels=labels) + axs[0][n].set_yscale('log') + match n: + case 0: + axs[0][n].set_title("Seldomly Accessed") + case 1: + axs[0][n].set_title("Occassionally Accessed") + case 2: + axs[0][n].set_title("Often Accessed") + axs[0][n].set_ylabel("Read latency (μs)") + axs[1][n].boxplot(writes_plot, vert=True, labels=labels) + axs[1][n].set_yscale('log') + axs[1][n].set_ylabel("Write latency (μs)") + + for n in range(3): + print(min(min_read, min_write)) + axs[0][n].set_ylim(min(min_read, min_write),max_read + 10000000) + axs[1][n].set_ylim(min(min_read, min_write),max_write + 10000000) + + fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") + + def read_jsonl(file): data = [] while True: @@ -270,6 +347,7 @@ def read_jsonl(file): fs.close() # Plot actions +plot_filesystem_test() plot_throughput(data) plot_tier_usage(data) #plot_latency(data) From 6382cc2a330ce4381265ad74c6f3578f99c9af40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Tue, 20 Sep 2022 13:29:49 +0200 Subject: [PATCH 60/81] filesystem: destroy cache before each measurement --- src/filesystem.rs | 45 +++++++++++++++++++++++-------------------- src/filesystem_zip.rs | 25 +++--------------------- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 5d85bec..c7a4f0e 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -101,27 +101,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { // pick certain files which we know are in range, here we pick 3x64KB, 3x256KB, 3x1MB, 3x4MB, 1x1GB // Read individual files multiple times to see the cache working? const SELECTION: [usize; 5] = [3, 3, 3, 3, 1]; - - { - // Thrash Cache by writing random data into slow with a different object store - println!("destroying cache"); - let os = client - .database - .write() - .open_named_object_store(b"destroycache", StoragePreference::SLOW)?; - let obj = os.create_object(b"foo")?; - let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); - with_random_bytes( - &mut client.rng, - 1 * 1024 * 1024 * 1024, - 8 * 1024 * 1024, - |b| cursor.write_all(b), - )?; - println!("sync db"); - client.sync().expect("Failed to sync database"); - // Cooldown - std::thread::sleep(std::time::Duration::from_secs(30)); - } + thrash_cache(&mut client)?; println!("start measuring"); let f = std::fs::OpenOptions::new() .write(true) @@ -159,6 +139,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { ) .as_bytes(), )?; + thrash_cache(&mut client)?; } } } @@ -174,3 +155,25 @@ fn obj_key_start(tier: usize, group: usize) -> usize { let group_offset = GROUPS_SPEC[tier].iter().take(group).sum::(); tier_offset + group_offset } + +pub(crate) fn thrash_cache(client: &mut Client) -> Result<(), Box> { + // Thrash Cache by writing random data into slow with a different object store + println!("destroying cache"); + let os = client + .database + .write() + .open_named_object_store(b"destroycache", StoragePreference::SLOW)?; + let obj = os.open_or_create_object(b"foo")?; + let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); + with_random_bytes( + &mut client.rng, + 1 * 1024 * 1024 * 1024, + 8 * 1024 * 1024, + |b| cursor.write_all(b), + )?; + println!("sync db"); + client.sync().expect("Failed to sync database"); + // Cooldown + std::thread::sleep(std::time::Duration::from_secs(30)); + Ok(()) +} diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs index a27c106..e0b77c8 100644 --- a/src/filesystem_zip.rs +++ b/src/filesystem_zip.rs @@ -7,6 +7,7 @@ use rand::{ thread_rng, Rng, seq::{IteratorRandom, SliceRandom}, }; use std::{error::Error, io::{Write, Read}, ops::Range, path::Path}; +use crate::filesystem::thrash_cache; fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { let space = client.database.read().free_space_tier(); @@ -31,7 +32,7 @@ const PROBS: [f64; 3] = [0.01, 0.2, 0.9]; const TIERS: Range = 0..3; const GROUPS: [f32; 3] = [0.8, 0.15, 0.05]; -const NUM_SAMPLE: usize = 20; +const NUM_SAMPLE: usize = 50; pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box> { println!("running filesystem"); @@ -100,27 +101,6 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box) -> Result<(), Box Date: Tue, 20 Sep 2022 22:07:53 +0200 Subject: [PATCH 61/81] plot: split up plot throughput --- jupyter/plot.py | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 7da4e1f..92fb416 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -15,6 +15,16 @@ EPOCH_MS=500 SEC_MS=1000 + +# For color reference of "Wong" color scheme see: +# https://davidmathlogic.com/colorblind/#%23000000-%23E69F00-%2356B4E9-%23009E73-%23F0E442-%230072B2-%23D55E00-%23CC79A7 +GREEN='#009E73' +YELLOW='#F0E442' +BLUE='#0072B2' +LIGHT_BLUE='#56B4E9' +RED='#D55E00' +ORANGE='#E69F00' + def subtract_last_index(array): last_val = 0 for index, value in enumerate(array): @@ -44,7 +54,7 @@ def plot_throughput(data): epoch = [temp['epoch_ms'] for temp in data] subtract_first_index(epoch) fig, axs = plt.subplots(4, 1, figsize=(16,8)) - colors=['#009E73', '#F0E442', '#0072B2', '#D55E00'] + colors=[GREEN, YELLOW, BLUE, RED] markers=['o', '^', ''] for x in range(4): for y in range(4): @@ -66,8 +76,8 @@ def plot_throughput(data): # if you change this you'll need to modify this here too. writes = writes * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) reads = reads * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) - write_line = axs[x].plot(epoch, writes, label = 'Written', color="#F0E442") - read_line = axs[x].plot(epoch, reads, label = 'Read', linestyle='dotted', color="#009E73") + axs[x].plot(epoch, reads, label = 'Read', linestyle='dotted', color=GREEN) + axs[x].plot(epoch, writes, label = 'Written', color=BLUE) ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" epoch_formatted = list(map(ms_to_string, epoch)) @@ -80,7 +90,16 @@ def plot_throughput(data): fig.legend(loc="center right") # Epoch in seconds fig.suptitle(f"Haura - {label}", y=0.98) # add title - fig.savefig(f"{sys.argv[1]}/plot.svg") + fig.savefig(f"{sys.argv[1]}/plot_write.svg") + for x in range(4): + lines = axs[x].get_lines() + if len(lines) > 0: + lines[0].set_linestyle('solid') + lines[0].zorder = 2.0 + lines[1].set_linestyle('dotted') + lines[1].zorder = 2.1 + fig.legend(loc="center right") + fig.savefig(f"{sys.argv[1]}/plot_read.svg") def plot_latency(data): epoch = [temp['epoch_ms'] for temp in data] @@ -124,9 +143,9 @@ def plot_object_distribution(): fs.close() colors = { 0: "white", - 1: "#009E73", - 2: "#F0E442", - 3: "#0072B2", + 1: GREEN, + 2: YELLOW, + 3: BLUE, } cmap = mat_col.ListedColormap([colors[x] for x in colors.keys()]) labels = np.array(["Not present", "Fastest", "Fast", "Slow"]) @@ -210,9 +229,9 @@ def plot_object_distribution(): num_ts += 1 fig, ax = plt.subplots(figsize=(10,5)) - ax.plot(mean_group_vals[0], color='#E69F00', label="Seldomly Accessed Group", marker="o", markevery=10); - ax.plot(mean_group_vals[1], color='#56B4E9', label="Occassionally Accessed", marker="s", markevery=10); - ax.plot(mean_group_vals[2], color='#D55E00', label="Often Accessed", marker="^", markevery=10); + ax.plot(mean_group_vals[0], color=ORANGE, label="Seldomly Accessed Group", marker="o", markevery=10); + ax.plot(mean_group_vals[1], color=LIGHT_BLUE, label="Occassionally Accessed", marker="s", markevery=10); + ax.plot(mean_group_vals[2], color=RED, label="Often Accessed", marker="^", markevery=10); # we might want to pick the actual timestamps for this ax.set_xlabel("Timestep") ax.set_ylabel("Mean object tier") @@ -237,8 +256,8 @@ def plot_tier_usage(data): tier = 0 for fr in free: - axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200) - axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200) + axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200, color=BLUE) + axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200, color=GREEN) axs[tier].set_ylim(bottom=0) axs[tier].legend(loc="upper center") axs[tier].set_ylabel(f"{num_to_name(tier)}\nCapacity in GiB") @@ -316,7 +335,6 @@ def plot_filesystem_test(): axs[1][n].set_ylabel("Write latency (μs)") for n in range(3): - print(min(min_read, min_write)) axs[0][n].set_ylim(min(min_read, min_write),max_read + 10000000) axs[1][n].set_ylim(min(min_read, min_write),max_write + 10000000) @@ -347,8 +365,8 @@ def read_jsonl(file): fs.close() # Plot actions -plot_filesystem_test() plot_throughput(data) plot_tier_usage(data) #plot_latency(data) plot_object_distribution() +plot_filesystem_test() From 6832f7b52830828b4de46d45221504f4bf66ac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 21 Sep 2022 09:16:44 +0200 Subject: [PATCH 62/81] filesystem: close object store --- src/filesystem.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/filesystem.rs b/src/filesystem.rs index c7a4f0e..a51c842 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -174,6 +174,7 @@ pub(crate) fn thrash_cache(client: &mut Client) -> Result<(), Box> { println!("sync db"); client.sync().expect("Failed to sync database"); // Cooldown + client.database.write().close_object_store(os); std::thread::sleep(std::time::Duration::from_secs(30)); Ok(()) } From 12cf457d3f93c196534d6bba6a49e22feab1f837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 21 Sep 2022 14:44:59 +0200 Subject: [PATCH 63/81] filesystem: close object store early --- src/filesystem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index a51c842..8abc472 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -171,10 +171,10 @@ pub(crate) fn thrash_cache(client: &mut Client) -> Result<(), Box> { 8 * 1024 * 1024, |b| cursor.write_all(b), )?; + client.database.write().close_object_store(os); println!("sync db"); client.sync().expect("Failed to sync database"); // Cooldown - client.database.write().close_object_store(os); std::thread::sleep(std::time::Duration::from_secs(30)); Ok(()) } From 9cb9d4743ed41c717c48302b0786704f742f8139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 21 Sep 2022 23:23:14 +0200 Subject: [PATCH 64/81] filesystem: use experimental clear cache --- Cargo.toml | 2 +- src/filesystem.rs | 3 +-- src/filesystem_zip.rs | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc42366..4546433 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" members = ["."] [dependencies] -betree_storage_stack = { path = ".." } +betree_storage_stack = { path = "/home/fred/Uni/ParCIO/Pre-MA-project/bepsi/betree", features = ["experimental-api"]} structopt = "0.3" figment = { version = "0.10", features = [ "json" ] } diff --git a/src/filesystem.rs b/src/filesystem.rs index 8abc472..9831db5 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -101,7 +101,6 @@ pub fn run(mut client: Client) -> Result<(), Box> { // pick certain files which we know are in range, here we pick 3x64KB, 3x256KB, 3x1MB, 3x4MB, 1x1GB // Read individual files multiple times to see the cache working? const SELECTION: [usize; 5] = [3, 3, 3, 3, 1]; - thrash_cache(&mut client)?; println!("start measuring"); let f = std::fs::OpenOptions::new() .write(true) @@ -116,6 +115,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { let okstart = obj_key_start(n, idx); let okend = okstart + obj_num; for _ in 0..*sel_num { + client.database.read().clear_cache(); let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); let obj = client .object_store @@ -139,7 +139,6 @@ pub fn run(mut client: Client) -> Result<(), Box> { ) .as_bytes(), )?; - thrash_cache(&mut client)?; } } } diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs index e0b77c8..bd1477f 100644 --- a/src/filesystem_zip.rs +++ b/src/filesystem_zip.rs @@ -4,10 +4,9 @@ use betree_storage_stack::vdev::Block; use betree_storage_stack::StoragePreference; use rand::{ distributions::{DistIter, Slice}, - thread_rng, Rng, seq::{IteratorRandom, SliceRandom}, + thread_rng, Rng, seq::SliceRandom, }; use std::{error::Error, io::{Write, Read}, ops::Range, path::Path}; -use crate::filesystem::thrash_cache; fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { let space = client.database.read().free_space_tier(); @@ -111,7 +110,7 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box Date: Thu, 22 Sep 2022 17:46:31 +0200 Subject: [PATCH 65/81] filesystem: sync after measure --- src/filesystem.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/filesystem.rs b/src/filesystem.rs index 9831db5..1188b13 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -139,6 +139,9 @@ pub fn run(mut client: Client) -> Result<(), Box> { ) .as_bytes(), )?; + client.sync(); + client.database.read().clear_cache(); + std::thread::sleep(std::time::Duration::from_secs(20)); } } } From 62ea089e84e4c657c82214199508185ac66b3044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 22 Sep 2022 22:26:05 +0200 Subject: [PATCH 66/81] fix betree path --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4546433..0dec5a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" members = ["."] [dependencies] -betree_storage_stack = { path = "/home/fred/Uni/ParCIO/Pre-MA-project/bepsi/betree", features = ["experimental-api"]} +betree_storage_stack = { path = "..", features = ["experimental-api"]} structopt = "0.3" figment = { version = "0.10", features = [ "json" ] } From f5948ddd41e64c61efe0f487f523abe6b62f15e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 22 Sep 2022 22:26:51 +0200 Subject: [PATCH 67/81] evaluation-rw: add case --- src/checkpoints.rs | 22 +++++-- src/lib.rs | 4 +- src/main.rs | 24 +++++++- src/scientific_evaluation.rs | 108 +++++++++++++++++++++++++++-------- 4 files changed, 125 insertions(+), 33 deletions(-) diff --git a/src/checkpoints.rs b/src/checkpoints.rs index 7939bb3..5ef493b 100644 --- a/src/checkpoints.rs +++ b/src/checkpoints.rs @@ -8,6 +8,7 @@ use betree_perf::*; use betree_storage_stack::StoragePreference; use rand::RngCore; use std::{error::Error, io::Write}; +use std::io::BufWriter; pub fn run(mut client: Client) -> Result<(), Box> { const N_OBJECTS: usize = 5; @@ -17,7 +18,12 @@ pub fn run(mut client: Client) -> Result<(), Box> { const WAIT_RAND_RANGE: u64 = 400; println!("running checkpoints"); + + let mut stats = BufWriter::new(std::fs::OpenOptions::new().create(true).write(true).open("checkpoints.csv")?); + stats.write_all(b"generation,size_mib,object_num,time_ms\n")?; for gen in 0..N_GENERATIONS { + let start = std::time::Instant::now(); + let mut accumulated_size = 0; for obj_id in 0..N_OBJECTS { let key = format!("{gen}_{obj_id}"); println!("Creating {key}"); @@ -27,13 +33,21 @@ pub fn run(mut client: Client) -> Result<(), Box> { // We definitely want to write on the fastest layer to minimize // waiting inbetween computation. let mut cursor = obj.cursor_with_pref(StoragePreference::FASTEST); - with_random_bytes(&mut client.rng, OBJECT_SIZE_MIB[obj_id] * 1024 * 1024, 8 * 1024 * 1024, |b| { - cursor.write_all(b) - })?; + accumulated_size+= OBJECT_SIZE_MIB[obj_id]; + with_random_bytes( + &mut client.rng, + OBJECT_SIZE_MIB[obj_id] * 1024 * 1024, + 8 * 1024 * 1024, + |b| cursor.write_all(b), + )?; } - std::thread::sleep(std::time::Duration::from_millis(client.rng.next_u64() % WAIT_RAND_RANGE + MIN_WAIT_MS)); + stats.write_all(format!("{gen},{accumulated_size},{N_OBJECTS},{}", start.elapsed().as_millis()).as_bytes())?; + std::thread::sleep(std::time::Duration::from_millis( + client.rng.next_u64() % WAIT_RAND_RANGE + MIN_WAIT_MS, + )); client.sync().expect("Failed to sync database"); } client.sync().expect("Failed to sync database"); + stats.flush()?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 628da1b..1110289 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,9 +58,7 @@ impl Control { let database = Database::build_threaded(cfg).expect("Failed to open database"); - Control { - database, - } + Control { database } } pub fn new() -> Self { diff --git a/src/main.rs b/src/main.rs index 4364300..c270599 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use structopt::StructOpt; mod checkpoints; mod filesystem; +mod filesystem_zip; mod ingest; mod rewrite; mod scientific_evaluation; @@ -20,7 +21,14 @@ enum Mode { Tiered1, Checkpoints, Filesystem, - Evaluation { + FilesystemZip { + path: PathBuf + }, + EvaluationRead { + #[structopt(default_value = "120")] + runtime: u64, + }, + EvaluationRW { #[structopt(default_value = "120")] runtime: u64, }, @@ -70,9 +78,19 @@ fn run_all(mode: Mode) -> Result<(), Box> { filesystem::run(client)?; control.database.write().sync()?; } - Mode::Evaluation { runtime } => { + Mode::FilesystemZip { path } => { + let client = control.client(0, b"filesystem_zip"); + filesystem_zip::run(client, path)?; + control.database.write().sync()?; + } + Mode::EvaluationRead { runtime } => { + let client = control.client(0, b"scientific_evaluation"); + scientific_evaluation::run_read(client, runtime)?; + control.database.write().sync()?; + } + Mode::EvaluationRW { runtime } => { let client = control.client(0, b"scientific_evaluation"); - scientific_evaluation::run(client, runtime)?; + scientific_evaluation::run_read_write(client, runtime)?; control.database.write().sync()?; } Mode::Zip { diff --git a/src/scientific_evaluation.rs b/src/scientific_evaluation.rs index 2930e88..be75b32 100644 --- a/src/scientific_evaluation.rs +++ b/src/scientific_evaluation.rs @@ -1,54 +1,116 @@ -///! This file implements a scientific workflow style writing first serial data -///! onto a storage layer and then reading this data from storage in a somewhat +///! This file implements a scientific workflow style writing first serial data onto a storage layer and then reading this data from storage in a somewhat ///! random but repeating pattern. use betree_perf::*; use betree_storage_stack::StoragePreference; -use rand::RngCore; -use std::{error::Error, io::Write}; +use rand::Rng; +use std::{error::Error, io::{Write, Seek}}; -pub fn run(mut client: Client, runtime: u64) -> Result<(), Box> { - const OBJECT_SIZE: u64 = 10 * 1024 * 1024 * 1024; - const FETCH_SIZE: u64 = 12 * 1024 * 1024; - const N_POSITIONS: u64 = 256; - println!("running scientific_evaluation"); +const OBJECT_SIZE: u64 = 25 * 1024 * 1024 * 1024; +const MIN_FETCH_SIZE: u64 = 1 * 1024; +const MAX_FETCH_SIZE: u64 = 12 * 1024 * 1024; +const N_POSITIONS: u64 = 1024; // E(sum N_POSITIONS_size) = 3GiB +const OBJ_NAME: &[u8] = b"important_research"; + +fn gen_positions(client: &mut Client) -> Vec<(u64, u64)> { + let mut positions = vec![]; + for _ in 0..N_POSITIONS { + let start = client.rng.gen_range(0..OBJECT_SIZE); + let length = client.rng.gen_range(MIN_FETCH_SIZE..MAX_FETCH_SIZE); + positions.push(( + start, + length.clamp(0, OBJECT_SIZE.saturating_sub(start)), + )); + } + positions +} +fn prepare_store(client: &mut Client) -> Result<(), Box> { let start = std::time::Instant::now(); let (obj, _info) = client .object_store - .open_or_create_object_with_pref(b"important_research", StoragePreference::FAST)?; - let mut cursor = obj.cursor_with_pref(StoragePreference::FAST); + .open_or_create_object_with_pref(b"important_research", StoragePreference::SLOW)?; + let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); with_random_bytes(&mut client.rng, OBJECT_SIZE, 8 * 1024 * 1024, |b| { cursor.write_all(b) })?; println!("Initial write took {}s", start.elapsed().as_secs()); client.sync().expect("Failed to sync database"); + Ok(()) +} + +pub fn run_read(mut client: Client, runtime: u64) -> Result<(), Box> { + println!("running scientific_evaluation"); // Generate positions to read - let mut positions = vec![]; - for _ in 0..N_POSITIONS { - let start = client.rng.next_u64() % (OBJECT_SIZE - 1); - let length = client.rng.next_u64(); - positions.push(( - start, - (length % FETCH_SIZE as u64) - .clamp(0, OBJECT_SIZE.saturating_sub(start)), - )); - } + let positions = gen_positions(&mut client); + prepare_store(&mut client)?; let (obj, _info) = client .object_store - .open_object_with_info(b"important_research")? + .open_object_with_info(OBJ_NAME)? .expect("Object was just created, but can't be opened!"); let start = std::time::Instant::now(); - let mut buf = vec![0; FETCH_SIZE as usize]; + let mut buf = vec![0; MAX_FETCH_SIZE as usize]; + let f = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open("evaluation_read.csv")?; + let mut w = std::io::BufWriter::new(f); + w.write_all(b"offset,size,latency_ns\n")?; for (pos, len) in positions.iter().cycle() { // Read data as may be done in some evaluation where only parts of a // database file are read in. + let t = std::time::Instant::now(); obj.read_at(&mut buf[..*len as usize], *pos).unwrap(); + w.write_fmt(format_args!("{pos},{len},{}", t.elapsed().as_nanos()))?; + if start.elapsed().as_secs() >= runtime { + break; + } + } + w.flush()?; + Ok(()) +} + +pub fn run_read_write(mut client: Client, runtime: u64) -> Result<(), Box> { + println!("running scientific_evaluation"); + // Generate positions to read + let positions = gen_positions(&mut client); + prepare_store(&mut client)?; + + let (obj, _info) = client + .object_store + .open_object_with_info(OBJ_NAME)? + .expect("Object was just created, but can't be opened!"); + let mut cursor = obj.cursor(); + + let start = std::time::Instant::now(); + let mut buf = vec![0; MAX_FETCH_SIZE as usize]; + let f = std::fs::OpenOptions::new() + .write(true) + .create(true) + .open("evaluation_read_write.csv")?; + let mut w = std::io::BufWriter::new(f); + w.write_all(b"offset,size,latency_ns,op\n")?; + for (pos, len) in positions.iter().cycle() { + // Read data as may be done in some evaluation where only parts of a + // database file are read in. + if client.rng.gen_bool(0.5) { + let t = std::time::Instant::now(); + obj.read_at(&mut buf[..*len as usize], *pos).unwrap(); + w.write_fmt(format_args!("{pos},{len},{},r", t.elapsed().as_nanos()))?; + } else { + cursor.seek(std::io::SeekFrom::Start(*pos))?; + let t = std::time::Instant::now(); + with_random_bytes(&mut client.rng, *len, 8 * 1024 * 1024, |b| { + cursor.write_all(b) + })?; + w.write_fmt(format_args!("{pos},{len},{},w", t.elapsed().as_nanos()))?; + } if start.elapsed().as_secs() >= runtime { break; } } + w.flush()?; Ok(()) } From 8c0b454145ff4d4d92817050272d5fefd87b5931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Thu, 22 Sep 2022 22:27:20 +0200 Subject: [PATCH 68/81] plot: draw single legend for multiline plots --- jupyter/plot.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jupyter/plot.py b/jupyter/plot.py index 92fb416..d314621 100755 --- a/jupyter/plot.py +++ b/jupyter/plot.py @@ -87,7 +87,7 @@ def plot_throughput(data): axs[x].set_ylabel(f"{num_to_name(x)}\nMiB/s (I/0)") # add Y-axis label label=' | '.join(sys.argv[1].split('/')[-2:]) - fig.legend(loc="center right") + fig.legend(loc="center right",handles=axs[0].get_lines()) # Epoch in seconds fig.suptitle(f"Haura - {label}", y=0.98) # add title fig.savefig(f"{sys.argv[1]}/plot_write.svg") @@ -95,10 +95,10 @@ def plot_throughput(data): lines = axs[x].get_lines() if len(lines) > 0: lines[0].set_linestyle('solid') - lines[0].zorder = 2.0 + lines[0].zorder = 2.1 lines[1].set_linestyle('dotted') - lines[1].zorder = 2.1 - fig.legend(loc="center right") + lines[1].zorder = 2.0 + fig.legend(loc="center right",handles=axs[0].get_lines()) fig.savefig(f"{sys.argv[1]}/plot_read.svg") def plot_latency(data): @@ -241,7 +241,7 @@ def plot_object_distribution(): fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') def plot_tier_usage(data): - fig, axs = plt.subplots(4, 1, figsize=(9,13)) + fig, axs = plt.subplots(4, 1, figsize=(10,13)) # 0 - 3; Fastest - Slowest free = [[], [], [], []] @@ -259,10 +259,10 @@ def plot_tier_usage(data): axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200, color=BLUE) axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200, color=GREEN) axs[tier].set_ylim(bottom=0) - axs[tier].legend(loc="upper center") axs[tier].set_ylabel(f"{num_to_name(tier)}\nCapacity in GiB") tier += 1 + fig.legend(loc='center right',handles=axs[0].get_lines()) fig.savefig(f"{sys.argv[1]}/tier_usage.svg") # TODO: Adjust bucket sizes From 587f6bebaddc4f477857e46e2d295c3046f65313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Sun, 25 Sep 2022 14:49:38 +0200 Subject: [PATCH 69/81] filesystem: add wait --- src/filesystem.rs | 6 +++--- src/filesystem_zip.rs | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 1188b13..6e14215 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -115,7 +115,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { let okstart = obj_key_start(n, idx); let okend = okstart + obj_num; for _ in 0..*sel_num { - client.database.read().clear_cache(); + client.database.read().clear_cache()?; let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); let obj = client .object_store @@ -139,8 +139,8 @@ pub fn run(mut client: Client) -> Result<(), Box> { ) .as_bytes(), )?; - client.sync(); - client.database.read().clear_cache(); + client.sync()?; + client.database.read().clear_cache()?; std::thread::sleep(std::time::Duration::from_secs(20)); } } diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs index bd1477f..e49457f 100644 --- a/src/filesystem_zip.rs +++ b/src/filesystem_zip.rs @@ -110,7 +110,7 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box) -> Result<(), Box Date: Sun, 25 Sep 2022 15:51:49 +0200 Subject: [PATCH 70/81] run: add case functions --- run.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/run.sh b/run.sh index b84dc9a..ae2c3b1 100755 --- a/run.sh +++ b/run.sh @@ -110,7 +110,17 @@ function scientific_evaluation() { #local vdev_type="ssd" #local vdev_type="pmem_fs" export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" scientific_evaluation_id_alloc evaluation 30 + run "$vdev_type" scientific_evaluation_id_alloc evaluation-read 30 +} + +function evaluation_rw() { + export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' + run "$vdev_type" file_system_three evaluation-rw +} + +function filesystem_zip() { + export BETREE__ALLOC_STRATEGY='[[0],[1],[2],[]]' + run "$vdev_type" file_system_three filesystem-zip data/archive.zip } function checkpoints() { From bcabe2419cb78e9b15641abcd3ef2f80332a20b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Mon, 26 Sep 2022 08:24:43 +0200 Subject: [PATCH 71/81] filesystem_zip: fix shuffling --- src/filesystem_zip.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs index e49457f..f0616c6 100644 --- a/src/filesystem_zip.rs +++ b/src/filesystem_zip.rs @@ -67,8 +67,8 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box; 3] = [0;3].map(|_| vec![]); let mut distributed = 0usize; + file_name_with_size.shuffle(&mut client.rng); for (id, part) in GROUPS.iter().enumerate() { - file_name_with_size.shuffle(&mut client.rng); let num = (part * file_num as f32) as usize; groups[id] = file_name_with_size[distributed..(distributed+num)].to_vec(); distributed += num; @@ -135,7 +135,7 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box Date: Mon, 26 Sep 2022 08:29:32 +0200 Subject: [PATCH 72/81] run: fix zip path --- run.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/run.sh b/run.sh index ae2c3b1..0d97bdb 100755 --- a/run.sh +++ b/run.sh @@ -119,8 +119,9 @@ function evaluation_rw() { } function filesystem_zip() { + local path="$PWD/data/archive.zip" export BETREE__ALLOC_STRATEGY='[[0],[1],[2],[]]' - run "$vdev_type" file_system_three filesystem-zip data/archive.zip + run "$vdev_type" file_system_three "$path" } function checkpoints() { @@ -259,8 +260,9 @@ ensure_bectl #zip_tiered #tiered -scientific_evaluation +#scientific_evaluation #filesystem +filesystem_zip #checkpoints #( # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' From 8940bf33f99449365b71863ce147ace3dc9c9838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 20 Jan 2023 16:40:37 +0100 Subject: [PATCH 73/81] plots: reorganize plotting scripts --- .../haura_plots/__init__.py | 254 +++------ .../__pycache__/util.cpython-311.pyc | Bin 0 -> 2236 bytes haura-plots/haura_plots/metrics_plots.py | 59 ++ haura-plots/haura_plots/util.py | 72 +++ haura-plots/poetry.lock | 535 ++++++++++++++++++ haura-plots/pyproject.toml | 18 + jupyter/betree_metrics.ipynb | 64 --- 7 files changed, 767 insertions(+), 235 deletions(-) rename jupyter/plot.py => haura-plots/haura_plots/__init__.py (55%) create mode 100644 haura-plots/haura_plots/__pycache__/util.cpython-311.pyc create mode 100644 haura-plots/haura_plots/metrics_plots.py create mode 100644 haura-plots/haura_plots/util.py create mode 100644 haura-plots/poetry.lock create mode 100644 haura-plots/pyproject.toml delete mode 100644 jupyter/betree_metrics.ipynb diff --git a/jupyter/plot.py b/haura-plots/haura_plots/__init__.py similarity index 55% rename from jupyter/plot.py rename to haura-plots/haura_plots/__init__.py index d314621..5bbbb34 100755 --- a/jupyter/plot.py +++ b/haura-plots/haura_plots/__init__.py @@ -1,4 +1,4 @@ -#! /bin/env python +#!/bin/env python import json import sys import numpy as np @@ -9,145 +9,62 @@ import matplotlib.cm as cm import matplotlib.colors as mat_col import matplotlib - -# Constants -BLOCK_SIZE = 4096 -EPOCH_MS=500 -SEC_MS=1000 +import util +import metrics_plots + +# def plot_latency(data): +# epoch = [temp['epoch_ms'] for temp in data] +# util.subtract_first_index(epoch) +# fig, ax = plt.subplots(figsize=(15,5)) +# for x in range(4): +# for y in range(4): +# lat = np.array([]) +# for temp in data: +# if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): +# continue +# +# lat = np.append(lat, temp['storage']['tiers'][x]['vdevs'][y]['read_latency']) +# +# if len(lat) > 0: +# lat = lat / 100000 +# lat.astype(int) +# lat = np.array([np.nan if elem == 0 else elem for elem in lat]) +# +# +# ax.plot(epoch, lat, label = "Average Latency {}/{}".format(x,y)) +# fig.legend() +# # Epoch in seconds +# ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" +# epoch_formatted = list(map(ms_to_string, epoch)) +# ax.set_xlabel("runtime (minute:seconds)") # add X-axis label +# ax.set_xticks(epoch, epoch_formatted) +# ax.locator_params(tight=True, nbins=10) +# ax.set_ylabel("Read Latency in ms") # add Y-axis label +# label=' | '.join(sys.argv[1].split('/')[-2:]) +# ax.set_title(f"Haura - {label}") # add title +# fig.savefig(f"{sys.argv[1]}/plot_latency.svg") -# For color reference of "Wong" color scheme see: -# https://davidmathlogic.com/colorblind/#%23000000-%23E69F00-%2356B4E9-%23009E73-%23F0E442-%230072B2-%23D55E00-%23CC79A7 -GREEN='#009E73' -YELLOW='#F0E442' -BLUE='#0072B2' -LIGHT_BLUE='#56B4E9' -RED='#D55E00' -ORANGE='#E69F00' - -def subtract_last_index(array): - last_val = 0 - for index, value in enumerate(array): - array[index] = value - last_val - last_val = value - array[0] = 0 - -def subtract_first_index(array): - first_val = array[0] - for index, value in enumerate(array): - array[index] = value -first_val - -def num_to_name(tier): - match tier: - case 0: - return 'Fastest' - case 1: - return 'Fast' - case 2: - return 'Slow' - case 3: - return 'Slowest' - case _: - return '???' - -def plot_throughput(data): - epoch = [temp['epoch_ms'] for temp in data] - subtract_first_index(epoch) - fig, axs = plt.subplots(4, 1, figsize=(16,8)) - colors=[GREEN, YELLOW, BLUE, RED] - markers=['o', '^', ''] - for x in range(4): - for y in range(4): - writes = np.array([]) - reads = np.array([]) - for temp in data: - if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): - continue - - writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written']) - reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read']) - - if len(writes) > 0: - subtract_last_index(writes) - subtract_last_index(reads) - - # convert to MiB from Blocks - # NOTE: We assume here a block size of 4096 bytes as this is the default haura block size - # if you change this you'll need to modify this here too. - writes = writes * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) - reads = reads * BLOCK_SIZE / 1024 / 1024 * (SEC_MS / EPOCH_MS) - axs[x].plot(epoch, reads, label = 'Read', linestyle='dotted', color=GREEN) - axs[x].plot(epoch, writes, label = 'Written', color=BLUE) - - ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" - epoch_formatted = list(map(ms_to_string, epoch)) - axs[x].set_xlabel("runtime (minute:seconds)") # add X-axis label - axs[x].set_xticks(epoch, epoch_formatted) - axs[x].locator_params(tight=True, nbins=10) - - axs[x].set_ylabel(f"{num_to_name(x)}\nMiB/s (I/0)") # add Y-axis label - label=' | '.join(sys.argv[1].split('/')[-2:]) - fig.legend(loc="center right",handles=axs[0].get_lines()) - # Epoch in seconds - fig.suptitle(f"Haura - {label}", y=0.98) # add title - fig.savefig(f"{sys.argv[1]}/plot_write.svg") - for x in range(4): - lines = axs[x].get_lines() - if len(lines) > 0: - lines[0].set_linestyle('solid') - lines[0].zorder = 2.1 - lines[1].set_linestyle('dotted') - lines[1].zorder = 2.0 - fig.legend(loc="center right",handles=axs[0].get_lines()) - fig.savefig(f"{sys.argv[1]}/plot_read.svg") - -def plot_latency(data): - epoch = [temp['epoch_ms'] for temp in data] - subtract_first_index(epoch) - fig, ax = plt.subplots(figsize=(15,5)) - for x in range(4): - for y in range(4): - lat = np.array([]) - for temp in data: - if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): - continue - - lat = np.append(lat, temp['storage']['tiers'][x]['vdevs'][y]['read_latency']) - - if len(lat) > 0: - lat = lat / 100000 - lat.astype(int) - lat = np.array([np.nan if elem == 0 else elem for elem in lat]) - - - ax.plot(epoch, lat, label = "Average Latency {}/{}".format(x,y)) - fig.legend() - # Epoch in seconds - ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" - epoch_formatted = list(map(ms_to_string, epoch)) - ax.set_xlabel("runtime (minute:seconds)") # add X-axis label - ax.set_xticks(epoch, epoch_formatted) - ax.locator_params(tight=True, nbins=10) - ax.set_ylabel("Read Latency in ms") # add Y-axis label - label=' | '.join(sys.argv[1].split('/')[-2:]) - ax.set_title(f"Haura - {label}") # add title - fig.savefig(f"{sys.argv[1]}/plot_latency.svg") - -# Access string subslice and first tuple member def sort_by_o_id(key): + """ + Access string subslice and first tuple member + """ return int(key[0][2:]) def plot_object_distribution(): - fs = open(f"{sys.argv[1]}/tier_state.jsonl", 'r') - data = read_jsonl(fs) - fs.close() + """ + Plot colorcoded grids to show object distribution + """ + data = [] + with open(f"{sys.argv[1]}/tier_state.jsonl", 'r', encoding='UTF-8') as state_file: + data = util.read_jsonl(state_file) colors = { - 0: "white", - 1: GREEN, - 2: YELLOW, - 3: BLUE, - } - cmap = mat_col.ListedColormap([colors[x] for x in colors.keys()]) + 0: util.WHITE, + 1: util.GREEN, + 2: util.YELLOW, + 3: util.BLUE, + } + cmap = mat_col.ListedColormap([x[1] for x in colors.items()]) labels = np.array(["Not present", "Fastest", "Fast", "Slow"]) num_ts = 0 # three groups fixed @@ -158,12 +75,12 @@ def plot_object_distribution(): keys = [] # Vec<(key, num_tier)> num_tier = 1 for tier in current_timestep: - for object in tier["files"]: - keys.append((object, num_tier)) + for obj in tier["files"]: + keys.append((obj, num_tier)) num_tier += 1 - + keys.sort(key=sort_by_o_id) - + # old boundaries update when needed # seldom accessed 1-2000 (45x45) # barely accessed 2001-2300 (18x18) @@ -176,7 +93,7 @@ def plot_object_distribution(): group_1 = np.concatenate((np.array(group_1), np.zeros(4096 - len(group_1)))).reshape((64,64)) group_2 = np.concatenate((np.array(group_2), np.zeros(676 - len(group_2)))).reshape((26,26)) group_3 = np.concatenate((np.array(group_3), np.zeros(64 - len(group_3)))).reshape((8,8)) - + num_group = 0 fig, axs = plt.subplots(1, 4, figsize=(20,5)) for group in [group_1, group_2, group_3]: @@ -191,7 +108,7 @@ def plot_object_distribution(): subax.yaxis.set_ticks([]) subax.xaxis.set_ticks([]) #divider = make_axes_locatable(subax) - #cax = divider.append_axes("right", size="5%", pad=0.05) + #cax = divider.append_axes("right", size="5%", pad=0.05) #fig.colorbar(im, cax=cax) fmt = matplotlib.ticker.FuncFormatter(lambda x, pos: labels[x]) ticks = [0, 1, 2, 3] @@ -203,8 +120,8 @@ def plot_object_distribution(): num_tiers = 0 for tier in current_timestep: num_tiers += 1 - resp_times = 0; - total = 0; + resp_times = 0 + total = 0 for o_id in tier["reqs"]: resps = tier["reqs"][f"{o_id}"] size = tier["files"][f"{o_id}"][1] @@ -229,9 +146,9 @@ def plot_object_distribution(): num_ts += 1 fig, ax = plt.subplots(figsize=(10,5)) - ax.plot(mean_group_vals[0], color=ORANGE, label="Seldomly Accessed Group", marker="o", markevery=10); - ax.plot(mean_group_vals[1], color=LIGHT_BLUE, label="Occassionally Accessed", marker="s", markevery=10); - ax.plot(mean_group_vals[2], color=RED, label="Often Accessed", marker="^", markevery=10); + ax.plot(mean_group_vals[0], color=util.ORANGE, label="Seldomly Accessed Group", marker="o", markevery=10); + ax.plot(mean_group_vals[1], color=util.LIGHT_BLUE, label="Occassionally Accessed", marker="s", markevery=10); + ax.plot(mean_group_vals[2], color=util.RED, label="Often Accessed", marker="^", markevery=10); # we might want to pick the actual timestamps for this ax.set_xlabel("Timestep") ax.set_ylabel("Mean object tier") @@ -241,6 +158,9 @@ def plot_object_distribution(): fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') def plot_tier_usage(data): + """ + Plot the utilized space of each storage tier. + """ fig, axs = plt.subplots(4, 1, figsize=(10,13)) # 0 - 3; Fastest - Slowest @@ -341,32 +261,24 @@ def plot_filesystem_test(): fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") -def read_jsonl(file): - data = [] - while True: - # Get next line from file - line = file.readline() - # if line is empty - # end of file is reached - if not line: - break - json_object = json.loads(line) - data.append(json_object); - return data - -if len(sys.argv) < 2: - print("Please specify an input run directory. If you already completed benchmarks they can be found under `results/*`.") - exit(1) +USAGE_HELP="""Please specify an input run directory. If you already completed\ +benchmarks they can be found under `results/*`. +Usage: + haura-plots +""" -fs = open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r') -# print("{}".format(data)) -data = read_jsonl(fs) -fs.close() - -# Plot actions -plot_throughput(data) -plot_tier_usage(data) -#plot_latency(data) -plot_object_distribution() -plot_filesystem_test() +if __name__ == "__main__": + if len(sys.argv) < 2: + print(USAGE_HELP) + sys.exit(2) + data = [] + with open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r', encoding="UTF-8") as metrics: + data = util.read_jsonl(metrics) + + # Plot actions + metrics_plots.plot_throughput(data) + plot_tier_usage(data) + #plot_latency(data) + plot_object_distribution() + plot_filesystem_test() diff --git a/haura-plots/haura_plots/__pycache__/util.cpython-311.pyc b/haura-plots/haura_plots/__pycache__/util.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be0c5a525744b43aa17694919ef5ed78a123b9e8 GIT binary patch literal 2236 zcma)7&1)M+6rYiHrPY@uf7EeG4wJM^jSZT)5+N)hL zyGm>!5fyq+f@xd`q(`4p()TA`wNOQ1YO6y*@bG+^Nzromi*D!Cw4a|#XRR2t5O zsFn-UNKT{CT!hAQQ5ydicOL) z7;RmxW55m9)}sX43Nt8K zy{}NiGkirl#)M=3Admu=5}{syo-R3MmR@s8hHW!9eaGSJ>5@_9#<>Esi>0!`*WGmY z5^i@QFBo^zRmhWx%BCL`N6Cxe7EeIfcc8nsK{Qb(isA#!*-k)HPyU`9e%yG}c=%xJ zK}+d`P->)uaAc?*AAB|X?vu5hk=@bLFGo+eVr?z{IQA&Ey|Am1mm2v^Bb`B5-x)&j zRC8e;0;3~&A+93W+FtU zr6{gL6fu@>B3N@I>T_LM1vLa{v8&|*<1TTl1&~{#oM|cUA%s6{)@cS zgDd*1A6j0yx^zvKB~!jkE>cBagr5?ccvvK;V840SbKz7|ZG#B4)q$qcj*Y;)l4u5{t)nDys)PFC ZR0I!pP+yFOF{Ec-3?(pBi8qBj^4}H1HMjr( literal 0 HcmV?d00001 diff --git a/haura-plots/haura_plots/metrics_plots.py b/haura-plots/haura_plots/metrics_plots.py new file mode 100644 index 0000000..d4d5472 --- /dev/null +++ b/haura-plots/haura_plots/metrics_plots.py @@ -0,0 +1,59 @@ +""" +Plots visualizing the metrics produced by Haura. +""" +import util +import numpy as np +import matplotlib.pyplot as plt + +def plot_throughput(data, path): + """ + Print a four row throughput plot with focussed read or write throughput. + """ + epoch = [temp['epoch_ms'] for temp in data] + util.subtract_first_index(epoch) + num_tiers = len(data[0]['storage']['tiers']) + fig, axs = plt.subplots(num_tiers, 1, figsize=(16,8)) + for tier_id in range(num_tiers): + for disk_id in range(len(data[0]['storage']['tiers'][tier_id]['vdevs'])): + writes = np.array([]) + reads = np.array([]) + for point in data: + writes = np.append(writes, point['storage']['tiers'][tier_id]['vdevs'][disk_id]['written']) + reads = np.append(reads, point['storage']['tiers'][tier_id]['vdevs'][disk_id]['read']) + + if len(writes) > 0: + util.subtract_last_index(writes) + util.subtract_last_index(reads) + + # convert to MiB from Blocks + # NOTE: We assume here a block size of 4096 bytes as this is the + # default haura block size if you change this you'll need to modify + # this here too. + writes = writes * util.BLOCK_SIZE / 1024 / 1024 * (util.SEC_MS / util.EPOCH_MS) + reads = reads * util.BLOCK_SIZE / 1024 / 1024 * (util.SEC_MS / util.EPOCH_MS) + axs[tier_id].plot(epoch, reads, label = 'Read', linestyle='dotted', color=util.GREEN) + axs[tier_id].plot(epoch, writes, label = 'Written', color=util.BLUE) + + # Formatting + def ms_to_string(time): + time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" + + epoch_formatted = list(map(ms_to_string, epoch)) + axs[tier_id].set_xlabel("runtime (minute:seconds)") + axs[tier_id].set_xticks(epoch, epoch_formatted) + axs[tier_id].locator_params(tight=True, nbins=10) + axs[tier_id].set_ylabel(f"{util.num_to_name(x)}\nMiB/s (I/0)") + label=' | '.join(path.split('/')[-2:]) + fig.legend(loc="center right",handles=axs[0].get_lines()) + # Epoch in seconds + fig.suptitle(f"Haura - {label}", y=0.98) # add title + fig.savefig(f"{path[1]}/plot_write.svg") + for tier_id in range(num_tiers): + lines = axs[tier_id].get_lines() + if len(lines) > 0: + lines[0].set_linestyle('solid') + lines[0].zorder = 2.1 + lines[1].set_linestyle('dotted') + lines[1].zorder = 2.0 + fig.legend(loc="center right",handles=axs[0].get_lines()) + fig.savefig(f"{path[1]}/plot_read.svg") diff --git a/haura-plots/haura_plots/util.py b/haura-plots/haura_plots/util.py new file mode 100644 index 0000000..65fea94 --- /dev/null +++ b/haura-plots/haura_plots/util.py @@ -0,0 +1,72 @@ +""" +Utility functions which may be used in multiple plotting types. +""" + +import json + +# Constants +BLOCK_SIZE=4096 +EPOCH_MS=500 +SEC_MS=1000 + +# For color reference of "Wong" color scheme see: +# https://davidmathlogic.com/colorblind/#%23000000-%23E69F00-%2356B4E9-%23009E73-%23F0E442-%230072B2-%23D55E00-%23CC79A7 +WHITE='#FFFFFF' +GREEN='#009E73' +YELLOW='#F0E442' +BLUE='#0072B2' +LIGHT_BLUE='#56B4E9' +RED='#D55E00' +ORANGE='#E69F00' + +def read_jsonl(file): + """ + Read from a file descriptor line by line a json, parse it, and return a list + of read objects. + """ + data = [] + while True: + # Get next line from file + line = file.readline() + # if line is empty + # end of file is reached + if not line: + break + json_object = json.loads(line) + data.append(json_object) + return data + +def subtract_last_index(array): + """ + From a list of numbers subtract the value of the previous entry from the + next. Operates in-place. + """ + last_val = 0 + for index, value in enumerate(array): + array[index] = value - last_val + last_val = value + array[0] = 0 + +def subtract_first_index(array): + """ + From a list of numbers subtract the first entry from all entries. Operates + in-place. + """ + first_val = array[0] + for index, value in enumerate(array): + array[index] = value -first_val + +def num_to_name(tier): + """Convert a number to the corresponding tier name in the storage + hierarchy.""" + match tier: + case 0: + return 'Fastest' + case 1: + return 'Fast' + case 2: + return 'Slow' + case 3: + return 'Slowest' + case _: + return '???' diff --git a/haura-plots/poetry.lock b/haura-plots/poetry.lock new file mode 100644 index 0000000..a30aadf --- /dev/null +++ b/haura-plots/poetry.lock @@ -0,0 +1,535 @@ +[[package]] +name = "contourpy" +version = "1.0.7" +description = "Python library for calculating contours of 2D quadrilateral grids" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "chromedriver", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy", "docutils-stubs", "mypy (==0.991)", "types-pillow"] +test = ["matplotlib", "pillow", "pytest"] +test-no-images = ["pytest"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "fonttools" +version = "4.38.0" +description = "Tools to manipulate font files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["scipy", "munkres"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=14.0.0)"] +woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "matplotlib" +version = "3.6.3" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.19" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + +[[package]] +name = "numpy" +version = "1.24.1" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pandas" +version = "1.5.3" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = [ + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + +[[package]] +name = "pillow" +version = "9.4.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +category = "main" +optional = false +python-versions = ">=3.6.8" + +[package.extras] +diagrams = ["railroad-diagrams", "jinja2"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2022.7.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "setuptools-scm" +version = "7.1.0" +description = "the blessed package to manage your versions by scm tags" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = ">=20.0" +typing-extensions = "*" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" + +[metadata] +lock-version = "1.1" +python-versions = "^3.11" +content-hash = "ad21fe3a0cafb75646bdb963f624e74adb0aa1c7ab99fa522f0b64c6da3c2be6" + +[metadata.files] +contourpy = [ + {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:95c3acddf921944f241b6773b767f1cbce71d03307270e2d769fd584d5d1092d"}, + {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc1464c97579da9f3ab16763c32e5c5d5bb5fa1ec7ce509a4ca6108b61b84fab"}, + {file = "contourpy-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8acf74b5d383414401926c1598ed77825cd530ac7b463ebc2e4f46638f56cce6"}, + {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c71fdd8f1c0f84ffd58fca37d00ca4ebaa9e502fb49825484da075ac0b0b803"}, + {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f99e9486bf1bb979d95d5cffed40689cb595abb2b841f2991fc894b3452290e8"}, + {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f4d8941a9564cda3f7fa6a6cd9b32ec575830780677932abdec7bcb61717b0"}, + {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9e20e5a1908e18aaa60d9077a6d8753090e3f85ca25da6e25d30dc0a9e84c2c6"}, + {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a877ada905f7d69b2a31796c4b66e31a8068b37aa9b78832d41c82fc3e056ddd"}, + {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6381fa66866b0ea35e15d197fc06ac3840a9b2643a6475c8fff267db8b9f1e69"}, + {file = "contourpy-1.0.7-cp310-cp310-win32.whl", hash = "sha256:3c184ad2433635f216645fdf0493011a4667e8d46b34082f5a3de702b6ec42e3"}, + {file = "contourpy-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:3caea6365b13119626ee996711ab63e0c9d7496f65641f4459c60a009a1f3e80"}, + {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed33433fc3820263a6368e532f19ddb4c5990855e4886088ad84fd7c4e561c71"}, + {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38e2e577f0f092b8e6774459317c05a69935a1755ecfb621c0a98f0e3c09c9a5"}, + {file = "contourpy-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae90d5a8590e5310c32a7630b4b8618cef7563cebf649011da80874d0aa8f414"}, + {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130230b7e49825c98edf0b428b7aa1125503d91732735ef897786fe5452b1ec2"}, + {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58569c491e7f7e874f11519ef46737cea1d6eda1b514e4eb5ac7dab6aa864d02"}, + {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d43960d809c4c12508a60b66cb936e7ed57d51fb5e30b513934a4a23874fae"}, + {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:152fd8f730c31fd67fe0ffebe1df38ab6a669403da93df218801a893645c6ccc"}, + {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9056c5310eb1daa33fc234ef39ebfb8c8e2533f088bbf0bc7350f70a29bde1ac"}, + {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a9d7587d2fdc820cc9177139b56795c39fb8560f540bba9ceea215f1f66e1566"}, + {file = "contourpy-1.0.7-cp311-cp311-win32.whl", hash = "sha256:4ee3ee247f795a69e53cd91d927146fb16c4e803c7ac86c84104940c7d2cabf0"}, + {file = "contourpy-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:5caeacc68642e5f19d707471890f037a13007feba8427eb7f2a60811a1fc1350"}, + {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd7dc0e6812b799a34f6d12fcb1000539098c249c8da54f3566c6a6461d0dbad"}, + {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0f9d350b639db6c2c233d92c7f213d94d2e444d8e8fc5ca44c9706cf72193772"}, + {file = "contourpy-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e96a08b62bb8de960d3a6afbc5ed8421bf1a2d9c85cc4ea73f4bc81b4910500f"}, + {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:031154ed61f7328ad7f97662e48660a150ef84ee1bc8876b6472af88bf5a9b98"}, + {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e9ebb4425fc1b658e13bace354c48a933b842d53c458f02c86f371cecbedecc"}, + {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efb8f6d08ca7998cf59eaf50c9d60717f29a1a0a09caa46460d33b2924839dbd"}, + {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6c180d89a28787e4b73b07e9b0e2dac7741261dbdca95f2b489c4f8f887dd810"}, + {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b8d587cc39057d0afd4166083d289bdeff221ac6d3ee5046aef2d480dc4b503c"}, + {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:769eef00437edf115e24d87f8926955f00f7704bede656ce605097584f9966dc"}, + {file = "contourpy-1.0.7-cp38-cp38-win32.whl", hash = "sha256:62398c80ef57589bdbe1eb8537127321c1abcfdf8c5f14f479dbbe27d0322e66"}, + {file = "contourpy-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:57119b0116e3f408acbdccf9eb6ef19d7fe7baf0d1e9aaa5381489bc1aa56556"}, + {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30676ca45084ee61e9c3da589042c24a57592e375d4b138bd84d8709893a1ba4"}, + {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e927b3868bd1e12acee7cc8f3747d815b4ab3e445a28d2e5373a7f4a6e76ba1"}, + {file = "contourpy-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:366a0cf0fc079af5204801786ad7a1c007714ee3909e364dbac1729f5b0849e5"}, + {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ba9bb365446a22411f0673abf6ee1fea3b2cf47b37533b970904880ceb72f3"}, + {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b0bf0c30d432278793d2141362ac853859e87de0a7dee24a1cea35231f0d50"}, + {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2"}, + {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6d0f9e1d39dbfb3977f9dd79f156c86eb03e57a7face96f199e02b18e58d32a"}, + {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7f6979d20ee5693a1057ab53e043adffa1e7418d734c1532e2d9e915b08d8ec2"}, + {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5dd34c1ae752515318224cba7fc62b53130c45ac6a1040c8b7c1a223c46e8967"}, + {file = "contourpy-1.0.7-cp39-cp39-win32.whl", hash = "sha256:c5210e5d5117e9aec8c47d9156d1d3835570dd909a899171b9535cb4a3f32693"}, + {file = "contourpy-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:60835badb5ed5f4e194a6f21c09283dd6e007664a86101431bf870d9e86266c4"}, + {file = "contourpy-1.0.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce41676b3d0dd16dbcfabcc1dc46090aaf4688fd6e819ef343dbda5a57ef0161"}, + {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a011cf354107b47c58ea932d13b04d93c6d1d69b8b6dce885e642531f847566"}, + {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31a55dccc8426e71817e3fe09b37d6d48ae40aae4ecbc8c7ad59d6893569c436"}, + {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69f8ff4db108815addd900a74df665e135dbbd6547a8a69333a68e1f6e368ac2"}, + {file = "contourpy-1.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efe99298ba37e37787f6a2ea868265465410822f7bea163edcc1bd3903354ea9"}, + {file = "contourpy-1.0.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a1e97b86f73715e8670ef45292d7cc033548266f07d54e2183ecb3c87598888f"}, + {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc331c13902d0f50845099434cd936d49d7a2ca76cb654b39691974cb1e4812d"}, + {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24847601071f740837aefb730e01bd169fbcaa610209779a78db7ebb6e6a7051"}, + {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abf298af1e7ad44eeb93501e40eb5a67abbf93b5d90e468d01fc0c4451971afa"}, + {file = "contourpy-1.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:64757f6460fc55d7e16ed4f1de193f362104285c667c112b50a804d482777edd"}, + {file = "contourpy-1.0.7.tar.gz", hash = "sha256:d8165a088d31798b59e91117d1f5fc3df8168d8b48c4acc10fc0df0d0bdbcc5e"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] +fonttools = [ + {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, + {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"}, +] +kiwisolver = [ + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, + {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, +] +matplotlib = [ + {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:80c166a0e28512e26755f69040e6bf2f946a02ffdb7c00bf6158cca3d2b146e6"}, + {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eb9421c403ffd387fbe729de6d9a03005bf42faba5e8432f4e51e703215b49fc"}, + {file = "matplotlib-3.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5223affa21050fb6118353c1380c15e23aedfb436bf3e162c26dc950617a7519"}, + {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00c248ab6b92bea3f8148714837937053a083ff03b4c5e30ed37e28fc0e7e56"}, + {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca94f0362f6b6f424b555b956971dcb94b12d0368a6c3e07dc7a40d32d6d873d"}, + {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59400cc9451094b7f08cc3f321972e6e1db4cd37a978d4e8a12824bf7fd2f03b"}, + {file = "matplotlib-3.6.3-cp310-cp310-win32.whl", hash = "sha256:57ad1aee29043163374bfa8990e1a2a10ff72c9a1bfaa92e9c46f6ea59269121"}, + {file = "matplotlib-3.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:1fcc4cad498533d3c393a160975acc9b36ffa224d15a6b90ae579eacee5d8579"}, + {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:d2cfaa7fd62294d945b8843ea24228a27c8e7c5b48fa634f3c168153b825a21b"}, + {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c3f08df2ac4636249b8bc7a85b8b82c983bef1441595936f62c2918370ca7e1d"}, + {file = "matplotlib-3.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff2aa84e74f80891e6bcf292ebb1dd57714ffbe13177642d65fee25384a30894"}, + {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11011c97d62c1db7bc20509572557842dbb8c2a2ddd3dd7f20501aa1cde3e54e"}, + {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c235bf9be052347373f589e018988cad177abb3f997ab1a2e2210c41562cc0c"}, + {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bebcff4c3ed02c6399d47329f3554193abd824d3d53b5ca02cf583bcd94470e2"}, + {file = "matplotlib-3.6.3-cp311-cp311-win32.whl", hash = "sha256:d5f18430f5cfa5571ab8f4c72c89af52aa0618e864c60028f11a857d62200cba"}, + {file = "matplotlib-3.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:dfba7057609ca9567b9704626756f0142e97ec8c5ba2c70c6e7bd1c25ef99f06"}, + {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9fb8fb19d03abf3c5dab89a8677e62c4023632f919a62b6dd1d6d2dbf42cd9f5"}, + {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:bbf269e1d24bc25247095d71c7a969813f7080e2a7c6fa28931a603f747ab012"}, + {file = "matplotlib-3.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:994637e2995b0342699b396a320698b07cd148bbcf2dd2fa2daba73f34dd19f2"}, + {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77b384cee7ab8cf75ffccbfea351a09b97564fc62d149827a5e864bec81526e5"}, + {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:73b93af33634ed919e72811c9703e1105185cd3fb46d76f30b7f4cfbbd063f89"}, + {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:debeab8e2ab07e5e3dac33e12456da79c7e104270d2b2d1df92b9e40347cca75"}, + {file = "matplotlib-3.6.3-cp38-cp38-win32.whl", hash = "sha256:acc3b1a4bddbf56fe461e36fb9ef94c2cb607fc90d24ccc650040bfcc7610de4"}, + {file = "matplotlib-3.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:1183877d008c752d7d535396096c910f4663e4b74a18313adee1213328388e1e"}, + {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6adc441b5b2098a4b904bbf9d9e92fb816fef50c55aa2ea6a823fc89b94bb838"}, + {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6d81b11ede69e3a751424b98dc869c96c10256b2206bfdf41f9c720eee86844c"}, + {file = "matplotlib-3.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:29f17b7f2e068dc346687cbdf80b430580bab42346625821c2d3abf3a1ec5417"}, + {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f56a7252eee8f3438447f75f5e1148a1896a2756a92285fe5d73bed6deebff4"}, + {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbddfeb1495484351fb5b30cf5bdf06b3de0bc4626a707d29e43dfd61af2a780"}, + {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:809119d1cba3ece3c9742eb01827fe7a0e781ea3c5d89534655a75e07979344f"}, + {file = "matplotlib-3.6.3-cp39-cp39-win32.whl", hash = "sha256:e0a64d7cc336b52e90f59e6d638ae847b966f68582a7af041e063d568e814740"}, + {file = "matplotlib-3.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:79e501eb847f4a489eb7065bb8d3187117f65a4c02d12ea3a19d6c5bef173bcc"}, + {file = "matplotlib-3.6.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2787a16df07370dcba385fe20cdd0cc3cfaabd3c873ddabca78c10514c799721"}, + {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68d94a436f62b8a861bf3ace82067a71bafb724b4e4f9133521e4d8012420dd7"}, + {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b409b2790cf8d7c1ef35920f01676d2ae7afa8241844e7aa5484fdf493a9a0"}, + {file = "matplotlib-3.6.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:faff486b36530a836a6b4395850322e74211cd81fc17f28b4904e1bd53668e3e"}, + {file = "matplotlib-3.6.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:38d38cb1ea1d80ee0f6351b65c6f76cad6060bbbead015720ba001348ae90f0c"}, + {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f999661589981e74d793ee2f41b924b3b87d65fd929f6153bf0f30675c59b1"}, + {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01b7f521a9a73c383825813af255f8c4485d1706e4f3e2ed5ae771e4403a40ab"}, + {file = "matplotlib-3.6.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9ceebaf73f1a3444fa11014f38b9da37ff7ea328d6efa1652241fe3777bfdab9"}, + {file = "matplotlib-3.6.3.tar.gz", hash = "sha256:1f4d69707b1677560cd952544ee4962f68ff07952fb9069ff8c12b56353cb8c9"}, +] +numpy = [ + {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, + {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, + {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, + {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, + {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, + {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, + {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, + {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, + {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, + {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, + {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, + {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, + {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, + {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, + {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, + {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, + {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, + {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, + {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, +] +packaging = [ + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, +] +pandas = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] +pillow = [ + {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, + {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, + {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, + {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, + {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, + {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, + {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, + {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, + {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, + {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, + {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, + {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, + {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, + {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, + {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, + {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, + {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, + {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, + {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, + {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, + {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, + {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, + {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, + {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, + {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, + {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, + {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, + {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, + {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, + {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, + {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, + {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, + {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, + {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, + {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, + {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, + {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, + {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, + {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, + {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, + {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, + {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, +] +pyparsing = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, + {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, +] +setuptools-scm = [ + {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, + {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] diff --git a/haura-plots/pyproject.toml b/haura-plots/pyproject.toml new file mode 100644 index 0000000..544e72f --- /dev/null +++ b/haura-plots/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "haura-plots" +version = "0.1.0" +description = "Plotting haura benchmarks." +authors = ["Johannes Wünsche "] +license = "AGPL-3.0" + +[tool.poetry.dependencies] +python = "^3.11" +matplotlib = "^3.6.3" +numpy = "^1.24.1" +pandas = "^1.5.3" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/jupyter/betree_metrics.ipynb b/jupyter/betree_metrics.ipynb deleted file mode 100644 index e701eb6..0000000 --- a/jupyter/betree_metrics.ipynb +++ /dev/null @@ -1,64 +0,0 @@ -{ - "metadata": { - "language_info": { - "codemirror_mode": { - "name": "python", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8" - }, - "kernelspec": { - "name": "python", - "display_name": "Python (Pyodide)", - "language": "python" - } - }, - "nbformat_minor": 4, - "nbformat": 4, - "cells": [ - { - "cell_type": "code", - "source": "import json\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom matplotlib import pyplot as plt\nplt.figure(figsize=(15,5))\n\ndef subtract_last_index(array):\n last_val = 0\n for index, value in enumerate(array):\n array[index] = value - last_val\n last_val = value\n array[0] = 0\n\ndef subtract_first_index(array):\n first_val = array[0]\n for index, value in enumerate(array):\n array[index] = value -first_val\n\ndata = []\n\nfs = open('betree-metrics.jsonl', 'r')\nline_number = 0\n \nwhile True:\n line_number += 1\n \n # Get next line from file\n line = fs.readline()\n \n # if line is empty\n # end of file is reached\n if not line:\n break\n \n json_object = json.loads(line)\n\n data.append(json_object);\n \n# print(\"{}\".format(data))\n \nfs.close()\n\ndf = pd.DataFrame(data)\n\nepoch = [temp['epoch_ms'] for temp in data]\n\nsubtract_first_index(epoch)\nepoch = np.divide(epoch, 60)\nepoch = epoch.astype(int)\n\nfor x in range(4):\n for y in range(4):\n writes = np.array([])\n reads = np.array([])\n for temp in data:\n if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']):\n continue\n\n writes = np.append(writes, temp['storage']['tiers'][x]['vdevs'][y]['written'])\n reads = np.append(reads, temp['storage']['tiers'][x]['vdevs'][y]['read'])\n\n if len(writes) > 0:\n subtract_last_index(writes)\n subtract_last_index(reads)\n\n writes = np.divide(writes, 1024)\n reads = np.divide(reads, 1024)\n \n plt.plot(epoch, writes, label = \"Writes {}/{}\".format(x,y))\n plt.plot(epoch, reads, label = \"Reads {}/{}\".format(x,y))\nplt.legend()\nplt.xlabel(\"epochs\") # add X-axis label\nplt.ylabel(\"MB (I/0)\") # add Y-axis label\nplt.title(\"HAURA\") # add title\n#plt.xticks(epoch, rotation = 90)\nplt.show()\n#plt.savefig('pmem.png')", - "metadata": { - "trusted": true - }, - "execution_count": 6, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": "", - "image/png": "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3aUT/0065quNf0tfU+VUK1SWSle9IhVNrr3OWudD7r9+IaXnOifBI850tq9b/4bXV1kqPT1XKlnqBBXR2xcMlbYurg0sKnbUv296rlMNM+279U+iw2GpbJvznMWerzLpy385J+3bP64fIkRl93baMfx0aclfnOfy1B85j1W5W3rkZCcYue5ftSd54bD0zj3Sh/c7QcPQU5ztGD67+ZOwil2Rip+3nG/ggw3M2BM9toafIQ07XVr/pvTBbyVZp2qk/ySnK9TmhVLpqoYfJyPfqTwacaY09LS6gYm10v5NTriz4S3nGLGhyH3OcO5TU+kcu+UlzjF12p1OYBYVCkjbP3Luv2GBc/zl9pdOvk069qq6gdeWD6X5tzth4NivSbN/KuUPaPp5irYzVFN3mTu981aVWOu8tv71S6l0tXTaXdLJ/9427Q2HpdUvSe/e64RifcdL4y6S3vu181q+/Dmpz9j67Tmax17+vDMWUahGGhD/Xje66fU297ihoHO8xd9+38ba43H7x3WvlySXxwmKT/6Plh07baE9jr8j2SdBf/1lbV01EQ45FX3RasQdnzvL+x8beX+c7bxnvHuvdGCzU0HW/zjp00elE2+WZt/T8Drj/4dJzn50dXA1cShQ9/3fuJr+33sk6m2raXno3wUZY5Zaa6ckuh1oGQIONKozBxy7ynw64Vfv6JcXjtdl0wYmujlAp+MLhHTMf83X76aV6fwvvi998zVp8EznyrJiaefyundwp0tFU+p/y96YsmKni8OGBc6JfDggebtJw05zPjiOmO10jyhZGjlxfU/a/okUOuyDrXFJU74tnfYjp8ok3sHtToBQeFz9D9D7NklPXuSchHq7SdNvkE74vpTRrQVtL5Ee/4rT9eWqvzsn16GA9OrN0rK/Ot/gZeQ721Ze4tznmHOdNsafcO1Z57Shco804wZp5xfOCXowboyQrB5ORcLgk5xxUGLbbaTCKVJOr+bb25BD+53nNhSou7xbf6nvhNpvH4M10t9vlJY/I028zPkgv/ML6dp3pD5j6q9380JpzatOAHFwa+va1H2wc+IwaIbkjjtZsSFpx7JIdVDccTf2wkgwcNh7eNVe52QkfttqKp3wZMMCqaq06Xb0nRAJms50Tlriqz4CPiece/9/G1+PJ9PpIjT4JGnta07okTfQCYgGnyi9fY+0+mWpW5E06mzp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" - }, - "metadata": {} - }, - { - "output_type": "display_data", - "data": { - "text/plain": "
" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "source": "", - "metadata": {}, - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file From 91d2098e9f5308eaae0afd52e4d9237df1ca6c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 25 Jan 2023 14:04:55 +0100 Subject: [PATCH 74/81] plots: Add README --- haura-plots/.gitignore | 1 + haura-plots/README.md | 36 ++++++++++++++++++ haura-plots/haura_plots/__init__.py | 11 ++++-- .../__pycache__/util.cpython-311.pyc | Bin 2236 -> 0 bytes haura-plots/haura_plots/metrics_plots.py | 2 +- haura-plots/pyproject.toml | 3 ++ 6 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 haura-plots/.gitignore create mode 100644 haura-plots/README.md delete mode 100644 haura-plots/haura_plots/__pycache__/util.cpython-311.pyc diff --git a/haura-plots/.gitignore b/haura-plots/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/haura-plots/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/haura-plots/README.md b/haura-plots/README.md new file mode 100644 index 0000000..f444a53 --- /dev/null +++ b/haura-plots/README.md @@ -0,0 +1,36 @@ +# haura-plots + +This directory contains some python scripts to visualize the benchmark results +of the provided scenarios. + +## Install + +You require `python3` and `poetry` (https://python-poetry.org/docs/) to run +these scripts. + +Install poetry if not already present: + +``` sh +# Fedora, RHEL, ... +$ sudo dnf install poetry +# Ubuntu +$ sudo apt update +$ sudo apt install python3-poetry +# Alpine +$ apk update +$ apk add poetry +# Or checkout their webpage https://python-poetry.org/docs/#installation +``` + +If poetry is up and running install the required depedencies: + +``` sh +$ poetry install +``` + +## Usage + +``` sh +$ poetry run plots +``` + diff --git a/haura-plots/haura_plots/__init__.py b/haura-plots/haura_plots/__init__.py index 5bbbb34..d7cf62e 100755 --- a/haura-plots/haura_plots/__init__.py +++ b/haura-plots/haura_plots/__init__.py @@ -10,8 +10,8 @@ import matplotlib.colors as mat_col import matplotlib -import util -import metrics_plots +from . import util +from . import metrics_plots # def plot_latency(data): # epoch = [temp['epoch_ms'] for temp in data] @@ -261,14 +261,14 @@ def plot_filesystem_test(): fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") -USAGE_HELP="""Please specify an input run directory. If you already completed\ +USAGE_HELP="""Please specify an input run directory. If you already completed \ benchmarks they can be found under `results/*`. Usage: haura-plots """ -if __name__ == "__main__": +def main(): if len(sys.argv) < 2: print(USAGE_HELP) sys.exit(2) @@ -282,3 +282,6 @@ def plot_filesystem_test(): #plot_latency(data) plot_object_distribution() plot_filesystem_test() + +if __name__ == "__main__": + main() diff --git a/haura-plots/haura_plots/__pycache__/util.cpython-311.pyc b/haura-plots/haura_plots/__pycache__/util.cpython-311.pyc deleted file mode 100644 index be0c5a525744b43aa17694919ef5ed78a123b9e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2236 zcma)7&1)M+6rYiHrPY@uf7EeG4wJM^jSZT)5+N)hL zyGm>!5fyq+f@xd`q(`4p()TA`wNOQ1YO6y*@bG+^Nzromi*D!Cw4a|#XRR2t5O zsFn-UNKT{CT!hAQQ5ydicOL) z7;RmxW55m9)}sX43Nt8K zy{}NiGkirl#)M=3Admu=5}{syo-R3MmR@s8hHW!9eaGSJ>5@_9#<>Esi>0!`*WGmY z5^i@QFBo^zRmhWx%BCL`N6Cxe7EeIfcc8nsK{Qb(isA#!*-k)HPyU`9e%yG}c=%xJ zK}+d`P->)uaAc?*AAB|X?vu5hk=@bLFGo+eVr?z{IQA&Ey|Am1mm2v^Bb`B5-x)&j zRC8e;0;3~&A+93W+FtU zr6{gL6fu@>B3N@I>T_LM1vLa{v8&|*<1TTl1&~{#oM|cUA%s6{)@cS zgDd*1A6j0yx^zvKB~!jkE>cBagr5?ccvvK;V840SbKz7|ZG#B4)q$qcj*Y;)l4u5{t)nDys)PFC ZR0I!pP+yFOF{Ec-3?(pBi8qBj^4}H1HMjr( diff --git a/haura-plots/haura_plots/metrics_plots.py b/haura-plots/haura_plots/metrics_plots.py index d4d5472..11a2323 100644 --- a/haura-plots/haura_plots/metrics_plots.py +++ b/haura-plots/haura_plots/metrics_plots.py @@ -1,7 +1,7 @@ """ Plots visualizing the metrics produced by Haura. """ -import util +from . import util import numpy as np import matplotlib.pyplot as plt diff --git a/haura-plots/pyproject.toml b/haura-plots/pyproject.toml index 544e72f..962096f 100644 --- a/haura-plots/pyproject.toml +++ b/haura-plots/pyproject.toml @@ -13,6 +13,9 @@ pandas = "^1.5.3" [tool.poetry.dev-dependencies] +[tool.poetry.scripts] +plots = "haura_plots:main" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" From b9a47a2362dfca501f0f967e41a9651d6fe0a403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 16 Aug 2023 14:39:41 +0200 Subject: [PATCH 75/81] fix haura struct generic use --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1110289..a9ec0fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,9 +21,9 @@ use rand_xoshiro::Xoshiro256Plus; pub mod bufreader; -pub type Database = database::Database; -pub type Dataset = database::Dataset; -pub type ObjectStore = object::ObjectStore; +pub type Database = database::Database; +pub type Dataset = database::Dataset; +pub type ObjectStore = object::ObjectStore; pub struct Control { pub database: Arc>, From eb3a48e8c75e7e9b2d099d56640d40258eea28c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 16 Aug 2023 14:40:02 +0200 Subject: [PATCH 76/81] fix drop cache call --- src/filesystem.rs | 27 ++------------- src/filesystem_zip.rs | 81 ++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/filesystem.rs b/src/filesystem.rs index 6e14215..92af4e2 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -115,7 +115,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { let okstart = obj_key_start(n, idx); let okend = okstart + obj_num; for _ in 0..*sel_num { - client.database.read().clear_cache()?; + client.database.read().drop_cache()?; let obj_key = format!("key{}", client.rng.gen_range(okstart..=okend)); let obj = client .object_store @@ -140,7 +140,7 @@ pub fn run(mut client: Client) -> Result<(), Box> { .as_bytes(), )?; client.sync()?; - client.database.read().clear_cache()?; + client.database.read().drop_cache()?; std::thread::sleep(std::time::Duration::from_secs(20)); } } @@ -157,26 +157,3 @@ fn obj_key_start(tier: usize, group: usize) -> usize { let group_offset = GROUPS_SPEC[tier].iter().take(group).sum::(); tier_offset + group_offset } - -pub(crate) fn thrash_cache(client: &mut Client) -> Result<(), Box> { - // Thrash Cache by writing random data into slow with a different object store - println!("destroying cache"); - let os = client - .database - .write() - .open_named_object_store(b"destroycache", StoragePreference::SLOW)?; - let obj = os.open_or_create_object(b"foo")?; - let mut cursor = obj.cursor_with_pref(StoragePreference::SLOW); - with_random_bytes( - &mut client.rng, - 1 * 1024 * 1024 * 1024, - 8 * 1024 * 1024, - |b| cursor.write_all(b), - )?; - client.database.write().close_object_store(os); - println!("sync db"); - client.sync().expect("Failed to sync database"); - // Cooldown - std::thread::sleep(std::time::Duration::from_secs(30)); - Ok(()) -} diff --git a/src/filesystem_zip.rs b/src/filesystem_zip.rs index f0616c6..d528654 100644 --- a/src/filesystem_zip.rs +++ b/src/filesystem_zip.rs @@ -4,9 +4,15 @@ use betree_storage_stack::vdev::Block; use betree_storage_stack::StoragePreference; use rand::{ distributions::{DistIter, Slice}, - thread_rng, Rng, seq::SliceRandom, + seq::SliceRandom, + thread_rng, Rng, +}; +use std::{ + error::Error, + io::{Read, Write}, + ops::Range, + path::Path, }; -use std::{error::Error, io::{Write, Read}, ops::Range, path::Path}; fn pref(foo: u8, size: Block, client: &Client) -> StoragePreference { let space = client.database.read().free_space_tier(); @@ -45,7 +51,10 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box>(); + let file_names = zip + .file_names() + .map(|n| n.to_string()) + .collect::>(); let mut file_name_with_size = vec![]; let file_num = file_names.len(); for file in file_names.into_iter() { @@ -58,19 +67,21 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box; 3] = [0;3].map(|_| vec![]); + let mut groups: [Vec<(String, u64)>; 3] = [0; 3].map(|_| vec![]); let mut distributed = 0usize; file_name_with_size.shuffle(&mut client.rng); for (id, part) in GROUPS.iter().enumerate() { let num = (part * file_num as f32) as usize; - groups[id] = file_name_with_size[distributed..(distributed+num)].to_vec(); + groups[id] = file_name_with_size[distributed..(distributed + num)].to_vec(); distributed += num; } @@ -109,34 +120,34 @@ pub fn run(mut client: Client, zip_path: impl AsRef) -> Result<(), Box Date: Wed, 10 Jan 2024 10:06:37 +0100 Subject: [PATCH 77/81] refactor plot filesystem --- haura-plots/haura_plots/__init__.py | 86 +++++++++--------------- haura-plots/haura_plots/metrics_plots.py | 6 +- haura-plots/haura_plots/policy_plots.py | 3 + 3 files changed, 38 insertions(+), 57 deletions(-) create mode 100644 haura-plots/haura_plots/policy_plots.py diff --git a/haura-plots/haura_plots/__init__.py b/haura-plots/haura_plots/__init__.py index d7cf62e..9bd2160 100755 --- a/haura-plots/haura_plots/__init__.py +++ b/haura-plots/haura_plots/__init__.py @@ -176,10 +176,10 @@ def plot_tier_usage(data): tier = 0 for fr in free: - axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200, color=BLUE) - axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200, color=GREEN) + axs[tier].plot((np.array(total[tier]) - np.array(fr)) * 4096 / 1024 / 1024 / 1024, label="Used", marker="o", markevery=200, color=util.BLUE) + axs[tier].plot(np.array(total[tier]) * 4096 / 1024 / 1024 / 1024, label="Total", marker="^", markevery=200, color=util.GREEN) axs[tier].set_ylim(bottom=0) - axs[tier].set_ylabel(f"{num_to_name(tier)}\nCapacity in GiB") + axs[tier].set_ylabel(f"{util.num_to_name(tier)}\nCapacity in GiB") tier += 1 fig.legend(loc='center right',handles=axs[0].get_lines()) @@ -204,60 +204,38 @@ def bytes_to_lexical(byte): return f"{byte/1000}KB" def plot_filesystem_test(): - dat = pd.read_csv(f"{sys.argv[1]}/filesystem_measurements.csv") + dats = [(pd.read_csv(f"{sys.argv[1]}/zip-no.csv"), 'x', 'No Policy'), + (pd.read_csv(f"{sys.argv[1]}/zip-lfu.csv"), 'o', 'LFU'), + (pd.read_csv(f"{sys.argv[1]}/zip-rl.csv"), 's', 'RL')] # groups fig, axs = plt.subplots(2,3, figsize=(15,5)) min_read = 99999999999999999 min_write = 99999999999999999 max_read = 0 max_write = 0 - for n in range(3): - sizes = dat[dat['group'] == n]['size'].to_numpy() - reads = {} - reads_raw = dat[dat['group'] == n]['read_latency_ns'].to_numpy() - writes = {} - writes_raw = dat[dat['group'] == n]['write_latency_ns'].to_numpy() - for (idx, size) in enumerate(sizes): - if size_buckets(size) not in reads: - reads[size_buckets(size)] = [] - reads[size_buckets(size)].append(reads_raw[idx]) - if size_buckets(size) not in writes: - writes[size_buckets(size)] = [] - writes[size_buckets(size)].append(writes_raw[idx]) - - sorted_sizes = list(reads) - sorted_sizes.sort() - labels = [] - reads_plot = [] - writes_plot = [] - for size in sorted_sizes: - labels.append(bytes_to_lexical(size)) - a = np.array(reads[size]) / 1000 - min_read = min(min_read, a.min()) - max_read = max(max_read, a.max()) - reads_plot.append(a) - b = np.array(writes[size]) / 1000 - min_write = min(min_write, b.min()) - max_write = max(max_write, b.max()) - writes_plot.append(b) - axs[0][n].boxplot(reads_plot, vert=True, labels=labels) - axs[0][n].set_yscale('log') - match n: - case 0: - axs[0][n].set_title("Seldomly Accessed") - case 1: - axs[0][n].set_title("Occassionally Accessed") - case 2: - axs[0][n].set_title("Often Accessed") - axs[0][n].set_ylabel("Read latency (μs)") - axs[1][n].boxplot(writes_plot, vert=True, labels=labels) - axs[1][n].set_yscale('log') - axs[1][n].set_ylabel("Write latency (μs)") + foo = [0,0,0] + for (i, (dat, m, l)) in enumerate(dats): + for n in range(3): + sizes = dat[dat['group'] == n]['size'].to_numpy() + reads_raw = dat[dat['group'] == n]['read_latency_ns'].to_numpy() * 10**-3 + writes_raw = dat[dat['group'] == n]['write_latency_ns'].to_numpy() * 10**-3 + min_read = min(np.min(reads_raw), min_read) + min_write = min(np.min(writes_raw), min_read) + max_read = max(np.max(reads_raw), max_read) + max_write = max(np.max(writes_raw), max_read) + foo[i] = axs[0][n].scatter(sizes, reads_raw, marker=m, label=l) + axs[0][n].set_yscale('log') + axs[0][n].set_xscale('log') + axs[0][n].set_ylabel("Read latency (μs)") + axs[1][n].scatter(sizes, writes_raw, marker=m, label=l) + axs[1][n].set_yscale('log') + axs[1][n].set_xscale('log') + axs[1][n].set_ylabel("Write latency (μs)") for n in range(3): axs[0][n].set_ylim(min(min_read, min_write),max_read + 10000000) axs[1][n].set_ylim(min(min_read, min_write),max_write + 10000000) - + fig.legend(handles=foo) fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") @@ -272,15 +250,15 @@ def main(): if len(sys.argv) < 2: print(USAGE_HELP) sys.exit(2) - data = [] - with open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r', encoding="UTF-8") as metrics: - data = util.read_jsonl(metrics) + # data = [] + # with open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r', encoding="UTF-8") as metrics: + # data = util.read_jsonl(metrics) - # Plot actions - metrics_plots.plot_throughput(data) - plot_tier_usage(data) + # # Plot actions + # metrics_plots.plot_throughput(data,sys.argv[1]) + # plot_tier_usage(data) #plot_latency(data) - plot_object_distribution() + #plot_object_distribution() plot_filesystem_test() if __name__ == "__main__": diff --git a/haura-plots/haura_plots/metrics_plots.py b/haura-plots/haura_plots/metrics_plots.py index 11a2323..72a1656 100644 --- a/haura-plots/haura_plots/metrics_plots.py +++ b/haura-plots/haura_plots/metrics_plots.py @@ -42,12 +42,12 @@ def ms_to_string(time): axs[tier_id].set_xlabel("runtime (minute:seconds)") axs[tier_id].set_xticks(epoch, epoch_formatted) axs[tier_id].locator_params(tight=True, nbins=10) - axs[tier_id].set_ylabel(f"{util.num_to_name(x)}\nMiB/s (I/0)") + axs[tier_id].set_ylabel(f"{util.num_to_name(tier_id)}\nMiB/s (I/0)") label=' | '.join(path.split('/')[-2:]) fig.legend(loc="center right",handles=axs[0].get_lines()) # Epoch in seconds fig.suptitle(f"Haura - {label}", y=0.98) # add title - fig.savefig(f"{path[1]}/plot_write.svg") + fig.savefig(f"{path}/plot_write.svg") for tier_id in range(num_tiers): lines = axs[tier_id].get_lines() if len(lines) > 0: @@ -56,4 +56,4 @@ def ms_to_string(time): lines[1].set_linestyle('dotted') lines[1].zorder = 2.0 fig.legend(loc="center right",handles=axs[0].get_lines()) - fig.savefig(f"{path[1]}/plot_read.svg") + fig.savefig(f"{path}/plot_read.svg") diff --git a/haura-plots/haura_plots/policy_plots.py b/haura-plots/haura_plots/policy_plots.py new file mode 100644 index 0000000..f1eb3b8 --- /dev/null +++ b/haura-plots/haura_plots/policy_plots.py @@ -0,0 +1,3 @@ +def plot_delta(data, path): + step_size = data.group_by(data['timestep'])['size'].sum() + step_size From bb6bdf233f6e9236b6ced492532f2137b5f4dc7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 10 Jan 2024 12:11:33 +0100 Subject: [PATCH 78/81] clean up run.sh Removes a few now irrelevant commented out commands and warns about non-existent configurations. --- run.sh | 144 +++++++++++++++++++++------------------------------------ 1 file changed, 53 insertions(+), 91 deletions(-) diff --git a/run.sh b/run.sh index 0d97bdb..1f158d9 100755 --- a/run.sh +++ b/run.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # shellcheck disable=SC2030,SC2031 # we exploit this characteristic to start several test scenarios - merging them would lead to pollution -function ensure_prepared { +function ensure_zip { local url url="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.58.tar.xz" @@ -26,6 +26,14 @@ function ensure_bectl { popd || return } +function ensure_config { + if [ ! -e "$BETREE_CONFIG" ] + then + echo "No Haura configuration found at: ${BETREE_CONFIG}" + exit 1 + fi +} + function run { local vdev_type="$1" local name="$2" @@ -34,16 +42,10 @@ function run { local out_path out_path="results/$(date -I)_${vdev_type}/${name}_$(date +%s)" - #local out_path="results/$(date -I)/${name}_$(date +%s)" mkdir -p "$out_path" pushd "$out_path" || return -# echo "wiping ssd" -# blkdiscard /dev/disk/by-id/nvme-CT500P5SSD8_20512BF90C84 - -# sleep 10 - echo "running $mode with these settings:" env | grep BETREE__ env > "env" @@ -63,95 +65,55 @@ function run { sleep 60 } -cargo build --release - -export BETREE_CONFIG="$PWD/perf-config.json" -export ROOT="$PWD" - function tiered() { - #export PMEM_NO_CLWB=1 - #export BETREE__CACHE_SIZE=$((4 * 1024 * 1024 * 1024)) - #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" - - #local vdev_type="dram" - #local vdev_type="pmem" - #local vdev_type="dram_nvme" - #local vdev_type="pmem_fs" - ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - run "$vdev_type" tiered1_all0_alloc tiered1 + run "$VDEV_TYPE" tiered1_all0_alloc tiered1 ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" tiered1_id_alloc tiered1 + run "$VDEV_TYPE" tiered1_id_alloc tiered1 ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - run "$vdev_type" tiered1_all1_alloc tiered1 + run "$VDEV_TYPE" tiered1_all1_alloc tiered1 ) } function scientific_evaluation() { - #export PMEM_NO_CLWB=1 - #export BETREE__CACHE_SIZE=$((1 * 1024 * 1024 * 1024)) - #export BETREE__STORAGE__TIERS="[ [ \"/my/path/to/file1" ], [ \"/my/path/to/file2\" ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/path/to/file1", direct = false } ], [ { path = \"/my/path/to/file2", direct = false } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { path = \"/my/nvm/file1\", len = $((100 * 1024 * 1024 * 1024)) } ], [ { path = \"/my/nvm/file2\", len = $((100 * 1024 * 1024 * 1024 )) } ] ]" - #export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" - - #local vdev_type="dram" - #local vdev_type="pmem" - #local vdev_type="ssd" - #local vdev_type="pmem_fs" export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" scientific_evaluation_id_alloc evaluation-read 30 + run "$VDEV_TYPE" scientific_evaluation_id_alloc evaluation-read 30 } function evaluation_rw() { export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" file_system_three evaluation-rw + run "$VDEV_TYPE" file_system_three evaluation-rw } function filesystem_zip() { - local path="$PWD/data/archive.zip" export BETREE__ALLOC_STRATEGY='[[0],[1],[2],[]]' - run "$vdev_type" file_system_three "$path" + run "$VDEV_TYPE" file_system_three "$ZIP_ARCHIVE" } function checkpoints() { - #local vdev_type="dram" - #local vdev_type="pmem" - #local vdev_type="ssd" - #local vdev_type="pmem_fs" export BETREE__ALLOC_STRATEGY='[[0, 1],[1],[],[]]' - run "$vdev_type" checkpoints_fastest checkpoints + run "$VDEV_TYPE" checkpoints_fastest checkpoints } function filesystem() { - #local vdev_type="dram" - #local vdev_type="pmem" - #local vdev_type="ssd" - #local vdev_type="pmem_fs" export BETREE__ALLOC_STRATEGY='[[0],[1],[2],[]]' - run "$vdev_type" file_system_three filesystem + run "$VDEV_TYPE" file_system_three filesystem } function zip_cache() { - local F="$PWD/data/linux.zip" local F_CD_START=1040032667 - ensure_prepared - for cache_mib in 32 64 128 256 512 1024 2048 4096 8192; do ( export BETREE__CACHE_SIZE=$((cache_mib * 1024 * 1024)) - run "default" "zip_cache_$cache_mib" zip 4 100 10 "$F" "$F_CD_START" + run "$VDEV_TYPE" "zip_cache_$cache_mib" zip 4 100 10 "$ZIP_ARCHIVE" "$F_CD_START" ) done } @@ -160,8 +122,6 @@ function zip_mt() { local F="$PWD/data/linux.zip" local F_CD_START=1040032667 - ensure_prepared - for cache_mib in 256 512 1024 2048; do echo "using $cache_mib MiB of cache" ( @@ -174,16 +134,14 @@ function zip_mt() { local per_worker=$((total / num_workers)) local per_run=$((per_worker / 10)) - run "default" "zip_mt_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "$VDEV_TYPE" "zip_mt_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" done ) done } function zip_tiered() { - local F="$PWD/data/linux.zip" local F_CD_START=1 #242415017 #1040032667 - ensure_prepared # for cache_mib in 256 512 1024; do for cache_mib in 32 64; do echo "using $cache_mib MiB of cache" @@ -192,10 +150,6 @@ function zip_tiered() { local total=10000 - #local vdev_type="dram" - #local vdev_type="pmem" - #local vdev_type="ssd" - #local vdev_type="pmem_fs" export BETREE__STORAGE__TIERS="[ [ { mem = $((1 * 1024 * 1024 * 1024)) } ], [ { mem = $((1 * 1024 * 1024 * 1024)) } ] ]" for num_workers in 1 2 3 4 5 6 7 8 9 10; do @@ -205,17 +159,17 @@ function zip_tiered() { ( export BETREE__ALLOC_STRATEGY='[[0],[0],[],[]]' - run "$vdev_type" "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "$VDEV_TYPE" "zip_tiered_all0_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$ZIP_ARCHIVE" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[0],[1],[],[]]' - run "$vdev_type" "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "$VDEV_TYPE" "zip_tiered_id_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$ZIP_ARCHIVE" "$F_CD_START" ) ( export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - run "$vdev_type" "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$F" "$F_CD_START" + run "$VDEV_TYPE" "zip_tiered_all1_${cache_mib}_${num_workers}_${per_run}_10" zip "$num_workers" "$per_run" 10 "$ZIP_ARCHIVE" "$F_CD_START" ) done @@ -223,50 +177,58 @@ function zip_tiered() { done } - - function ingest() { - local F="$PWD/data/linux.zip" - local DISK=/dev/disk/by-id/ata-WDC_WD30EFRX-68EUZN0_WD-WMC4N2195306 - - ensure_prepared - ( - export BETREE__STORAGE__TIERS="[ [ { file = \"$DISK\" } ] ]" - export BETREE__DEFAULT_STORAGE_CLASS=0 - ( export BETREE__COMPRESSION="None" - run "default" ingest_hdd_none ingest "$F" + run "default" ingest_hdd_none ingest "$ZIP_ARCHIVE" ) for level in $(seq 1 16); do ( export BETREE__COMPRESSION="{ Zstd = { level = $level } }" - run "default" "ingest_hdd_zstd_$level" ingest "$F" + run "$VDEV_TYPE" "ingest_hdd_zstd_$level" ingest "$ZIP_ARCHIVE" ) done ) } function switchover() { - run "default" switchover_tiny switchover 32 "$((32 * 1024 * 1024))" - run "default" switchover_small switchover 8 "$((128 * 1024 * 1024))" - run "default" switchover_medium switchover 4 "$((2 * 1024 * 1024 * 1024))" - run "default" switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" + run "$VDEV_TYPE" switchover_tiny switchover 32 "$((32 * 1024 * 1024))" + run "$VDEV_TYPE" switchover_small switchover 8 "$((128 * 1024 * 1024))" + run "$VDEV_TYPE" switchover_medium switchover 4 "$((2 * 1024 * 1024 * 1024))" + run "$VDEV_TYPE" switchover_large switchover 4 "$((8 * 1024 * 1024 * 1024))" } +cargo build --release + +if [ -z "$BETREE_CONFIG" ] +then + export BETREE_CONFIG="$PWD/perf-config.json" +fi + +export ROOT="$PWD" +export ZIP_ARCHIVE="$PWD/data/linux.zip" +# Category under which the default runs should be made, a function may modify +# this if multiple categories are needed. +export VDEV_TYPE="default" + ensure_bectl +ensure_zip +ensure_config + +# Uncomment the scenarios which you want to run. Assure that the used +# configuration is valid for the scenario as some of them require a minimum +# amount of tiers. +#zip_cache #zip_tiered +#zip_mt #tiered #scientific_evaluation +#evaluation_rw #filesystem -filesystem_zip +#filesystem_zip #checkpoints -#( - # export BETREE__ALLOC_STRATEGY='[[1],[1],[],[]]' - #export RUST_LOG=info - #export BETREE__CACHE_SIZE=8589934592 - #run rewrite1 rewrite $((500 * 1024 * 1024)) 4 -#) +#switchover +#ingest From 18e07fdf2060c38bee42d6d8ad9414f5cd42117f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 10 Jan 2024 15:49:00 +0100 Subject: [PATCH 79/81] clean up plots --- haura-plots/haura_plots/__init__.py | 80 ++- haura-plots/poetry.lock | 847 ++++++++++++++-------------- 2 files changed, 481 insertions(+), 446 deletions(-) diff --git a/haura-plots/haura_plots/__init__.py b/haura-plots/haura_plots/__init__.py index 9bd2160..6edf683 100755 --- a/haura-plots/haura_plots/__init__.py +++ b/haura-plots/haura_plots/__init__.py @@ -204,38 +204,60 @@ def bytes_to_lexical(byte): return f"{byte/1000}KB" def plot_filesystem_test(): - dats = [(pd.read_csv(f"{sys.argv[1]}/zip-no.csv"), 'x', 'No Policy'), - (pd.read_csv(f"{sys.argv[1]}/zip-lfu.csv"), 'o', 'LFU'), - (pd.read_csv(f"{sys.argv[1]}/zip-rl.csv"), 's', 'RL')] + dat = pd.read_csv(f"{sys.argv[1]}/filesystem_measurements.csv") # groups fig, axs = plt.subplots(2,3, figsize=(15,5)) min_read = 99999999999999999 min_write = 99999999999999999 max_read = 0 max_write = 0 - foo = [0,0,0] - for (i, (dat, m, l)) in enumerate(dats): - for n in range(3): - sizes = dat[dat['group'] == n]['size'].to_numpy() - reads_raw = dat[dat['group'] == n]['read_latency_ns'].to_numpy() * 10**-3 - writes_raw = dat[dat['group'] == n]['write_latency_ns'].to_numpy() * 10**-3 - min_read = min(np.min(reads_raw), min_read) - min_write = min(np.min(writes_raw), min_read) - max_read = max(np.max(reads_raw), max_read) - max_write = max(np.max(writes_raw), max_read) - foo[i] = axs[0][n].scatter(sizes, reads_raw, marker=m, label=l) - axs[0][n].set_yscale('log') - axs[0][n].set_xscale('log') - axs[0][n].set_ylabel("Read latency (μs)") - axs[1][n].scatter(sizes, writes_raw, marker=m, label=l) - axs[1][n].set_yscale('log') - axs[1][n].set_xscale('log') - axs[1][n].set_ylabel("Write latency (μs)") + for n in range(3): + sizes = dat[dat['group'] == n]['size'].to_numpy() + reads = {} + reads_raw = dat[dat['group'] == n]['read_latency_ns'].to_numpy() + writes = {} + writes_raw = dat[dat['group'] == n]['write_latency_ns'].to_numpy() + for (idx, size) in enumerate(sizes): + if size_buckets(size) not in reads: + reads[size_buckets(size)] = [] + reads[size_buckets(size)].append(reads_raw[idx]) + if size_buckets(size) not in writes: + writes[size_buckets(size)] = [] + writes[size_buckets(size)].append(writes_raw[idx]) + + sorted_sizes = list(reads) + sorted_sizes.sort() + labels = [] + reads_plot = [] + writes_plot = [] + for size in sorted_sizes: + labels.append(bytes_to_lexical(size)) + a = np.array(reads[size]) / 1000 + min_read = min(min_read, a.min()) + max_read = max(max_read, a.max()) + reads_plot.append(a) + b = np.array(writes[size]) / 1000 + min_write = min(min_write, b.min()) + max_write = max(max_write, b.max()) + writes_plot.append(b) + axs[0][n].boxplot(reads_plot, vert=True, labels=labels) + axs[0][n].set_yscale('log') + match n: + case 0: + axs[0][n].set_title("Seldomly Accessed") + case 1: + axs[0][n].set_title("Occassionally Accessed") + case 2: + axs[0][n].set_title("Often Accessed") + axs[0][n].set_ylabel("Read latency (μs)") + axs[1][n].boxplot(writes_plot, vert=True, labels=labels) + axs[1][n].set_yscale('log') + axs[1][n].set_ylabel("Write latency (μs)") for n in range(3): axs[0][n].set_ylim(min(min_read, min_write),max_read + 10000000) axs[1][n].set_ylim(min(min_read, min_write),max_write + 10000000) - fig.legend(handles=foo) + fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") @@ -250,16 +272,16 @@ def main(): if len(sys.argv) < 2: print(USAGE_HELP) sys.exit(2) - # data = [] - # with open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r', encoding="UTF-8") as metrics: - # data = util.read_jsonl(metrics) + data = [] + with open(f"{sys.argv[1]}/betree-metrics.jsonl", 'r', encoding="UTF-8") as metrics: + data = util.read_jsonl(metrics) - # # Plot actions - # metrics_plots.plot_throughput(data,sys.argv[1]) - # plot_tier_usage(data) + # Plot actions + metrics_plots.plot_throughput(data, sys.argv[1]) + plot_tier_usage(data) #plot_latency(data) #plot_object_distribution() - plot_filesystem_test() + #plot_filesystem_test() if __name__ == "__main__": main() diff --git a/haura-plots/poetry.lock b/haura-plots/poetry.lock index a30aadf..b5732f0 100644 --- a/haura-plots/poetry.lock +++ b/haura-plots/poetry.lock @@ -1,41 +1,138 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + [[package]] name = "contourpy" -version = "1.0.7" +version = "1.2.0" description = "Python library for calculating contours of 2D quadrilateral grids" -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, +] [package.dependencies] -numpy = ">=1.16" +numpy = ">=1.20,<2.0" [package.extras] -bokeh = ["bokeh", "chromedriver", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy", "docutils-stubs", "mypy (==0.991)", "types-pillow"] -test = ["matplotlib", "pillow", "pytest"] -test-no-images = ["pytest"] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "cycler" -version = "0.11.0" +version = "0.12.1" description = "Composable style cycles" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "fonttools" -version = "4.38.0" +version = "4.47.0" description = "Tools to manipulate font files" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d2404107626f97a221dc1a65b05396d2bb2ce38e435f64f26ed2369f68675d9"}, + {file = "fonttools-4.47.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01f409be619a9a0f5590389e37ccb58b47264939f0e8d58bfa1f3ba07d22671"}, + {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d986b66ff722ef675b7ee22fbe5947a41f60a61a4da15579d5e276d897fbc7fa"}, + {file = "fonttools-4.47.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8acf6dd0434b211b3bd30d572d9e019831aae17a54016629fa8224783b22df8"}, + {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:495369c660e0c27233e3c572269cbe520f7f4978be675f990f4005937337d391"}, + {file = "fonttools-4.47.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c59227d7ba5b232281c26ae04fac2c73a79ad0e236bca5c44aae904a18f14faf"}, + {file = "fonttools-4.47.0-cp310-cp310-win32.whl", hash = "sha256:59a6c8b71a245800e923cb684a2dc0eac19c56493e2f896218fcf2571ed28984"}, + {file = "fonttools-4.47.0-cp310-cp310-win_amd64.whl", hash = "sha256:52c82df66201f3a90db438d9d7b337c7c98139de598d0728fb99dab9fd0495ca"}, + {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:854421e328d47d70aa5abceacbe8eef231961b162c71cbe7ff3f47e235e2e5c5"}, + {file = "fonttools-4.47.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:511482df31cfea9f697930f61520f6541185fa5eeba2fa760fe72e8eee5af88b"}, + {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0e2c88c8c985b7b9a7efcd06511fb0a1fe3ddd9a6cd2895ef1dbf9059719d7"}, + {file = "fonttools-4.47.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7a0a8848726956e9d9fb18c977a279013daadf0cbb6725d2015a6dd57527992"}, + {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e869da810ae35afb3019baa0d0306cdbab4760a54909c89ad8904fa629991812"}, + {file = "fonttools-4.47.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dd23848f877c3754f53a4903fb7a593ed100924f9b4bff7d5a4e2e8a7001ae11"}, + {file = "fonttools-4.47.0-cp311-cp311-win32.whl", hash = "sha256:bf1810635c00f7c45d93085611c995fc130009cec5abdc35b327156aa191f982"}, + {file = "fonttools-4.47.0-cp311-cp311-win_amd64.whl", hash = "sha256:61df4dee5d38ab65b26da8efd62d859a1eef7a34dcbc331299a28e24d04c59a7"}, + {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e3f4d61f3a8195eac784f1d0c16c0a3105382c1b9a74d99ac4ba421da39a8826"}, + {file = "fonttools-4.47.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:174995f7b057e799355b393e97f4f93ef1f2197cbfa945e988d49b2a09ecbce8"}, + {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea592e6a09b71cb7a7661dd93ac0b877a6228e2d677ebacbad0a4d118494c86d"}, + {file = "fonttools-4.47.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40bdbe90b33897d9cc4a39f8e415b0fcdeae4c40a99374b8a4982f127ff5c767"}, + {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:843509ae9b93db5aaf1a6302085e30bddc1111d31e11d724584818f5b698f500"}, + {file = "fonttools-4.47.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9acfa1cdc479e0dde528b61423855913d949a7f7fe09e276228298fef4589540"}, + {file = "fonttools-4.47.0-cp312-cp312-win32.whl", hash = "sha256:66c92ec7f95fd9732550ebedefcd190a8d81beaa97e89d523a0d17198a8bda4d"}, + {file = "fonttools-4.47.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8fa20748de55d0021f83754b371432dca0439e02847962fc4c42a0e444c2d78"}, + {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c75e19971209fbbce891ebfd1b10c37320a5a28e8d438861c21d35305aedb81c"}, + {file = "fonttools-4.47.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e79f1a3970d25f692bbb8c8c2637e621a66c0d60c109ab48d4a160f50856deff"}, + {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:562681188c62c024fe2c611b32e08b8de2afa00c0c4e72bed47c47c318e16d5c"}, + {file = "fonttools-4.47.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a77a60315c33393b2bd29d538d1ef026060a63d3a49a9233b779261bad9c3f71"}, + {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4fabb8cc9422efae1a925160083fdcbab8fdc96a8483441eb7457235df625bd"}, + {file = "fonttools-4.47.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2a78dba8c2a1e9d53a0fb5382979f024200dc86adc46a56cbb668a2249862fda"}, + {file = "fonttools-4.47.0-cp38-cp38-win32.whl", hash = "sha256:e6b968543fde4119231c12c2a953dcf83349590ca631ba8216a8edf9cd4d36a9"}, + {file = "fonttools-4.47.0-cp38-cp38-win_amd64.whl", hash = "sha256:4a9a51745c0439516d947480d4d884fa18bd1458e05b829e482b9269afa655bc"}, + {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62d8ddb058b8e87018e5dc26f3258e2c30daad4c87262dfeb0e2617dd84750e6"}, + {file = "fonttools-4.47.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5dde0eab40faaa5476133123f6a622a1cc3ac9b7af45d65690870620323308b4"}, + {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4da089f6dfdb822293bde576916492cd708c37c2501c3651adde39804630538"}, + {file = "fonttools-4.47.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:253bb46bab970e8aae254cebf2ae3db98a4ef6bd034707aa68a239027d2b198d"}, + {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1193fb090061efa2f9e2d8d743ae9850c77b66746a3b32792324cdce65784154"}, + {file = "fonttools-4.47.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:084511482dd265bce6dca24c509894062f0117e4e6869384d853f46c0e6d43be"}, + {file = "fonttools-4.47.0-cp39-cp39-win32.whl", hash = "sha256:97620c4af36e4c849e52661492e31dc36916df12571cb900d16960ab8e92a980"}, + {file = "fonttools-4.47.0-cp39-cp39-win_amd64.whl", hash = "sha256:e77bdf52185bdaf63d39f3e1ac3212e6cfa3ab07d509b94557a8902ce9c13c82"}, + {file = "fonttools-4.47.0-py3-none-any.whl", hash = "sha256:d6477ba902dd2d7adda7f0fd3bfaeb92885d45993c9e1928c9f28fc3961415f7"}, + {file = "fonttools-4.47.0.tar.gz", hash = "sha256:ec13a10715eef0e031858c1c23bfaee6cba02b97558e4a7bfa089dba4a8c2ebf"}, +] [package.extras] -all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["scipy", "munkres"] +interpolatable = ["munkres", "pycairo", "scipy"] lxml = ["lxml (>=4.0,<5)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] @@ -43,60 +140,261 @@ repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=14.0.0)"] -woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "kiwisolver" -version = "1.4.4" +version = "1.4.5" description = "A fast implementation of the Cassowary constraint solver" -category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] [[package]] name = "matplotlib" -version = "3.6.3" +version = "3.8.2" description = "Python plotting package" -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, + {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, + {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, + {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, + {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, + {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, + {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, + {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, + {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, + {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, +] [package.dependencies] contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" -kiwisolver = ">=1.0.1" -numpy = ">=1.19" +kiwisolver = ">=1.3.1" +numpy = ">=1.21,<2" packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.2.1" +pillow = ">=8" +pyparsing = ">=2.3.1" python-dateutil = ">=2.7" -setuptools_scm = ">=7" [[package]] name = "numpy" -version = "1.24.1" +version = "1.26.3" description = "Fundamental package for array computing in Python" -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, + {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, + {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, + {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, + {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, + {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, + {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, + {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, + {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, + {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, + {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, + {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, + {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, + {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, + {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, + {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, + {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, + {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, + {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, + {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, + {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, + {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, + {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, +] [[package]] name = "packaging" -version = "23.0" +version = "23.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] [[package]] name = "pandas" version = "1.5.3" description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] [package.dependencies] numpy = [ @@ -111,425 +409,140 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pillow" -version = "9.4.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, +] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" optional = false python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, +] [package.extras] -diagrams = ["railroad-diagrams", "jinja2"] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] [package.dependencies] six = ">=1.5" [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.3.post1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" - -[[package]] -name = "setuptools-scm" -version = "7.1.0" -description = "the blessed package to manage your versions by scm tags" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -packaging = ">=20.0" -typing-extensions = "*" - -[package.extras] -test = ["pytest (>=6.2)", "virtualenv (>20)"] -toml = ["setuptools (>=42)"] +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] [metadata] -lock-version = "1.1" +lock-version = "2.0" python-versions = "^3.11" content-hash = "ad21fe3a0cafb75646bdb963f624e74adb0aa1c7ab99fa522f0b64c6da3c2be6" - -[metadata.files] -contourpy = [ - {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:95c3acddf921944f241b6773b767f1cbce71d03307270e2d769fd584d5d1092d"}, - {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc1464c97579da9f3ab16763c32e5c5d5bb5fa1ec7ce509a4ca6108b61b84fab"}, - {file = "contourpy-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8acf74b5d383414401926c1598ed77825cd530ac7b463ebc2e4f46638f56cce6"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c71fdd8f1c0f84ffd58fca37d00ca4ebaa9e502fb49825484da075ac0b0b803"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f99e9486bf1bb979d95d5cffed40689cb595abb2b841f2991fc894b3452290e8"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f4d8941a9564cda3f7fa6a6cd9b32ec575830780677932abdec7bcb61717b0"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9e20e5a1908e18aaa60d9077a6d8753090e3f85ca25da6e25d30dc0a9e84c2c6"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a877ada905f7d69b2a31796c4b66e31a8068b37aa9b78832d41c82fc3e056ddd"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6381fa66866b0ea35e15d197fc06ac3840a9b2643a6475c8fff267db8b9f1e69"}, - {file = "contourpy-1.0.7-cp310-cp310-win32.whl", hash = "sha256:3c184ad2433635f216645fdf0493011a4667e8d46b34082f5a3de702b6ec42e3"}, - {file = "contourpy-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:3caea6365b13119626ee996711ab63e0c9d7496f65641f4459c60a009a1f3e80"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed33433fc3820263a6368e532f19ddb4c5990855e4886088ad84fd7c4e561c71"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38e2e577f0f092b8e6774459317c05a69935a1755ecfb621c0a98f0e3c09c9a5"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae90d5a8590e5310c32a7630b4b8618cef7563cebf649011da80874d0aa8f414"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130230b7e49825c98edf0b428b7aa1125503d91732735ef897786fe5452b1ec2"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58569c491e7f7e874f11519ef46737cea1d6eda1b514e4eb5ac7dab6aa864d02"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d43960d809c4c12508a60b66cb936e7ed57d51fb5e30b513934a4a23874fae"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:152fd8f730c31fd67fe0ffebe1df38ab6a669403da93df218801a893645c6ccc"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9056c5310eb1daa33fc234ef39ebfb8c8e2533f088bbf0bc7350f70a29bde1ac"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a9d7587d2fdc820cc9177139b56795c39fb8560f540bba9ceea215f1f66e1566"}, - {file = "contourpy-1.0.7-cp311-cp311-win32.whl", hash = "sha256:4ee3ee247f795a69e53cd91d927146fb16c4e803c7ac86c84104940c7d2cabf0"}, - {file = "contourpy-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:5caeacc68642e5f19d707471890f037a13007feba8427eb7f2a60811a1fc1350"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd7dc0e6812b799a34f6d12fcb1000539098c249c8da54f3566c6a6461d0dbad"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0f9d350b639db6c2c233d92c7f213d94d2e444d8e8fc5ca44c9706cf72193772"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e96a08b62bb8de960d3a6afbc5ed8421bf1a2d9c85cc4ea73f4bc81b4910500f"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:031154ed61f7328ad7f97662e48660a150ef84ee1bc8876b6472af88bf5a9b98"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e9ebb4425fc1b658e13bace354c48a933b842d53c458f02c86f371cecbedecc"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efb8f6d08ca7998cf59eaf50c9d60717f29a1a0a09caa46460d33b2924839dbd"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6c180d89a28787e4b73b07e9b0e2dac7741261dbdca95f2b489c4f8f887dd810"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b8d587cc39057d0afd4166083d289bdeff221ac6d3ee5046aef2d480dc4b503c"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:769eef00437edf115e24d87f8926955f00f7704bede656ce605097584f9966dc"}, - {file = "contourpy-1.0.7-cp38-cp38-win32.whl", hash = "sha256:62398c80ef57589bdbe1eb8537127321c1abcfdf8c5f14f479dbbe27d0322e66"}, - {file = "contourpy-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:57119b0116e3f408acbdccf9eb6ef19d7fe7baf0d1e9aaa5381489bc1aa56556"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30676ca45084ee61e9c3da589042c24a57592e375d4b138bd84d8709893a1ba4"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e927b3868bd1e12acee7cc8f3747d815b4ab3e445a28d2e5373a7f4a6e76ba1"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:366a0cf0fc079af5204801786ad7a1c007714ee3909e364dbac1729f5b0849e5"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ba9bb365446a22411f0673abf6ee1fea3b2cf47b37533b970904880ceb72f3"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b0bf0c30d432278793d2141362ac853859e87de0a7dee24a1cea35231f0d50"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6d0f9e1d39dbfb3977f9dd79f156c86eb03e57a7face96f199e02b18e58d32a"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7f6979d20ee5693a1057ab53e043adffa1e7418d734c1532e2d9e915b08d8ec2"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5dd34c1ae752515318224cba7fc62b53130c45ac6a1040c8b7c1a223c46e8967"}, - {file = "contourpy-1.0.7-cp39-cp39-win32.whl", hash = "sha256:c5210e5d5117e9aec8c47d9156d1d3835570dd909a899171b9535cb4a3f32693"}, - {file = "contourpy-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:60835badb5ed5f4e194a6f21c09283dd6e007664a86101431bf870d9e86266c4"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce41676b3d0dd16dbcfabcc1dc46090aaf4688fd6e819ef343dbda5a57ef0161"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a011cf354107b47c58ea932d13b04d93c6d1d69b8b6dce885e642531f847566"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31a55dccc8426e71817e3fe09b37d6d48ae40aae4ecbc8c7ad59d6893569c436"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69f8ff4db108815addd900a74df665e135dbbd6547a8a69333a68e1f6e368ac2"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efe99298ba37e37787f6a2ea868265465410822f7bea163edcc1bd3903354ea9"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a1e97b86f73715e8670ef45292d7cc033548266f07d54e2183ecb3c87598888f"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc331c13902d0f50845099434cd936d49d7a2ca76cb654b39691974cb1e4812d"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24847601071f740837aefb730e01bd169fbcaa610209779a78db7ebb6e6a7051"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abf298af1e7ad44eeb93501e40eb5a67abbf93b5d90e468d01fc0c4451971afa"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:64757f6460fc55d7e16ed4f1de193f362104285c667c112b50a804d482777edd"}, - {file = "contourpy-1.0.7.tar.gz", hash = "sha256:d8165a088d31798b59e91117d1f5fc3df8168d8b48c4acc10fc0df0d0bdbcc5e"}, -] -cycler = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, -] -fonttools = [ - {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, - {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"}, -] -kiwisolver = [ - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, - {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, -] -matplotlib = [ - {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:80c166a0e28512e26755f69040e6bf2f946a02ffdb7c00bf6158cca3d2b146e6"}, - {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eb9421c403ffd387fbe729de6d9a03005bf42faba5e8432f4e51e703215b49fc"}, - {file = "matplotlib-3.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5223affa21050fb6118353c1380c15e23aedfb436bf3e162c26dc950617a7519"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00c248ab6b92bea3f8148714837937053a083ff03b4c5e30ed37e28fc0e7e56"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca94f0362f6b6f424b555b956971dcb94b12d0368a6c3e07dc7a40d32d6d873d"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59400cc9451094b7f08cc3f321972e6e1db4cd37a978d4e8a12824bf7fd2f03b"}, - {file = "matplotlib-3.6.3-cp310-cp310-win32.whl", hash = "sha256:57ad1aee29043163374bfa8990e1a2a10ff72c9a1bfaa92e9c46f6ea59269121"}, - {file = "matplotlib-3.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:1fcc4cad498533d3c393a160975acc9b36ffa224d15a6b90ae579eacee5d8579"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:d2cfaa7fd62294d945b8843ea24228a27c8e7c5b48fa634f3c168153b825a21b"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c3f08df2ac4636249b8bc7a85b8b82c983bef1441595936f62c2918370ca7e1d"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff2aa84e74f80891e6bcf292ebb1dd57714ffbe13177642d65fee25384a30894"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11011c97d62c1db7bc20509572557842dbb8c2a2ddd3dd7f20501aa1cde3e54e"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c235bf9be052347373f589e018988cad177abb3f997ab1a2e2210c41562cc0c"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bebcff4c3ed02c6399d47329f3554193abd824d3d53b5ca02cf583bcd94470e2"}, - {file = "matplotlib-3.6.3-cp311-cp311-win32.whl", hash = "sha256:d5f18430f5cfa5571ab8f4c72c89af52aa0618e864c60028f11a857d62200cba"}, - {file = "matplotlib-3.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:dfba7057609ca9567b9704626756f0142e97ec8c5ba2c70c6e7bd1c25ef99f06"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9fb8fb19d03abf3c5dab89a8677e62c4023632f919a62b6dd1d6d2dbf42cd9f5"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:bbf269e1d24bc25247095d71c7a969813f7080e2a7c6fa28931a603f747ab012"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:994637e2995b0342699b396a320698b07cd148bbcf2dd2fa2daba73f34dd19f2"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77b384cee7ab8cf75ffccbfea351a09b97564fc62d149827a5e864bec81526e5"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:73b93af33634ed919e72811c9703e1105185cd3fb46d76f30b7f4cfbbd063f89"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:debeab8e2ab07e5e3dac33e12456da79c7e104270d2b2d1df92b9e40347cca75"}, - {file = "matplotlib-3.6.3-cp38-cp38-win32.whl", hash = "sha256:acc3b1a4bddbf56fe461e36fb9ef94c2cb607fc90d24ccc650040bfcc7610de4"}, - {file = "matplotlib-3.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:1183877d008c752d7d535396096c910f4663e4b74a18313adee1213328388e1e"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6adc441b5b2098a4b904bbf9d9e92fb816fef50c55aa2ea6a823fc89b94bb838"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6d81b11ede69e3a751424b98dc869c96c10256b2206bfdf41f9c720eee86844c"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:29f17b7f2e068dc346687cbdf80b430580bab42346625821c2d3abf3a1ec5417"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f56a7252eee8f3438447f75f5e1148a1896a2756a92285fe5d73bed6deebff4"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbddfeb1495484351fb5b30cf5bdf06b3de0bc4626a707d29e43dfd61af2a780"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:809119d1cba3ece3c9742eb01827fe7a0e781ea3c5d89534655a75e07979344f"}, - {file = "matplotlib-3.6.3-cp39-cp39-win32.whl", hash = "sha256:e0a64d7cc336b52e90f59e6d638ae847b966f68582a7af041e063d568e814740"}, - {file = "matplotlib-3.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:79e501eb847f4a489eb7065bb8d3187117f65a4c02d12ea3a19d6c5bef173bcc"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2787a16df07370dcba385fe20cdd0cc3cfaabd3c873ddabca78c10514c799721"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68d94a436f62b8a861bf3ace82067a71bafb724b4e4f9133521e4d8012420dd7"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b409b2790cf8d7c1ef35920f01676d2ae7afa8241844e7aa5484fdf493a9a0"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:faff486b36530a836a6b4395850322e74211cd81fc17f28b4904e1bd53668e3e"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:38d38cb1ea1d80ee0f6351b65c6f76cad6060bbbead015720ba001348ae90f0c"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f999661589981e74d793ee2f41b924b3b87d65fd929f6153bf0f30675c59b1"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01b7f521a9a73c383825813af255f8c4485d1706e4f3e2ed5ae771e4403a40ab"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9ceebaf73f1a3444fa11014f38b9da37ff7ea328d6efa1652241fe3777bfdab9"}, - {file = "matplotlib-3.6.3.tar.gz", hash = "sha256:1f4d69707b1677560cd952544ee4962f68ff07952fb9069ff8c12b56353cb8c9"}, -] -numpy = [ - {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, - {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, - {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, - {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, - {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, - {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, - {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, - {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, - {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, - {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, - {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, -] -packaging = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, -] -pandas = [ - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, - {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, - {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, - {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, - {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, - {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, - {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, - {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, -] -pillow = [ - {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, - {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, - {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, - {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, - {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, - {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, - {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, - {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, - {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, - {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, - {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, - {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, - {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, - {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, -] -pyparsing = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -pytz = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, -] -setuptools-scm = [ - {file = "setuptools_scm-7.1.0-py3-none-any.whl", hash = "sha256:73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e"}, - {file = "setuptools_scm-7.1.0.tar.gz", hash = "sha256:6c508345a771aad7d56ebff0e70628bf2b0ec7573762be9960214730de278f27"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -typing-extensions = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] From f19c240eb56e83fb3fe95dd65328eb9aa0bd9e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Wed, 10 Jan 2024 15:52:30 +0100 Subject: [PATCH 80/81] fixup wrapper scripts --- plot.sh | 14 ++------------ run.sh | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/plot.sh b/plot.sh index 73dd920..9a2934b 100755 --- a/plot.sh +++ b/plot.sh @@ -1,19 +1,11 @@ #!/bin/env bash -function prepare { - if docker image inspect haura_plots > /dev/null 2>&1 - then - return - else - docker build -t haura_plots . - fi -} - function plot { local run=$1 shift 1 - docker run -v "$PWD":/usr/src/bench -w /usr/src/bench haura_plots python jupyter/plot.py "$run" + poetry --directory=haura-plots run plots "$run" + pushd "$run" if [ -e plot_timestep_000.png ] then @@ -24,8 +16,6 @@ function plot { export ROOT=$PWD -prepare - for run in "$1"/* do plot "$run" diff --git a/run.sh b/run.sh index 1f158d9..1490fea 100755 --- a/run.sh +++ b/run.sh @@ -5,7 +5,7 @@ function ensure_zip { local url url="https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.58.tar.xz" - if [ ! -e "$PWD/data/linux.zip" ] + if [ ! -e "$ZIP_ARCHIVE" ] then mkdir data pushd data || exit From 7ffd62ab822799f73cf404bd8120b8ddf9ddc2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCnsche?= Date: Fri, 12 Jan 2024 15:34:18 +0100 Subject: [PATCH 81/81] add plot for latency evaluation --- haura-plots/haura_plots/__init__.py | 73 ++++++++++++----------------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/haura-plots/haura_plots/__init__.py b/haura-plots/haura_plots/__init__.py index 6edf683..6cbe9e1 100755 --- a/haura-plots/haura_plots/__init__.py +++ b/haura-plots/haura_plots/__init__.py @@ -1,11 +1,11 @@ #!/bin/env python import json import sys +import os import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.ticker as ticker -from mpl_toolkits.axes_grid1 import make_axes_locatable import matplotlib.cm as cm import matplotlib.colors as mat_col import matplotlib @@ -13,50 +13,21 @@ from . import util from . import metrics_plots -# def plot_latency(data): -# epoch = [temp['epoch_ms'] for temp in data] -# util.subtract_first_index(epoch) -# fig, ax = plt.subplots(figsize=(15,5)) -# for x in range(4): -# for y in range(4): -# lat = np.array([]) -# for temp in data: -# if x >= len(temp['storage']['tiers']) or y >= len(temp['storage']['tiers'][x]['vdevs']): -# continue -# -# lat = np.append(lat, temp['storage']['tiers'][x]['vdevs'][y]['read_latency']) -# -# if len(lat) > 0: -# lat = lat / 100000 -# lat.astype(int) -# lat = np.array([np.nan if elem == 0 else elem for elem in lat]) -# -# -# ax.plot(epoch, lat, label = "Average Latency {}/{}".format(x,y)) -# fig.legend() -# # Epoch in seconds -# ms_to_string = lambda time: f"{int(time / 1000 / 60)}:{int(time / 1000) % 60:02d}" -# epoch_formatted = list(map(ms_to_string, epoch)) -# ax.set_xlabel("runtime (minute:seconds)") # add X-axis label -# ax.set_xticks(epoch, epoch_formatted) -# ax.locator_params(tight=True, nbins=10) -# ax.set_ylabel("Read Latency in ms") # add Y-axis label -# label=' | '.join(sys.argv[1].split('/')[-2:]) -# ax.set_title(f"Haura - {label}") # add title -# fig.savefig(f"{sys.argv[1]}/plot_latency.svg") - def sort_by_o_id(key): """ Access string subslice and first tuple member """ return int(key[0][2:]) -def plot_object_distribution(): +def plot_object_distribution(path): """ Plot colorcoded grids to show object distribution """ data = [] - with open(f"{sys.argv[1]}/tier_state.jsonl", 'r', encoding='UTF-8') as state_file: + if not os.path.exists(f"{path}/tier_state.jsonl"): + return + + with open(f"{path}/tier_state.jsonl", 'r', encoding='UTF-8') as state_file: data = util.read_jsonl(state_file) colors = { 0: util.WHITE, @@ -141,7 +112,7 @@ def plot_object_distribution(): #axs[3].set_ylim(0, 100) axs[3].set_xticks(x_ticks, labels=["Fastest", "Fast", "Slow"]) - fig.savefig(f"{sys.argv[1]}/plot_timestep_{num_ts:0>3}.png") + fig.savefig(f"{path}/plot_timestep_{num_ts:0>3}.png") matplotlib.pyplot.close(fig) num_ts += 1 @@ -155,9 +126,9 @@ def plot_object_distribution(): ax.set_title("Mean tier of all object groups over time") ax.set_ylim((1,3)) pls_no_cut_off = ax.legend(bbox_to_anchor=(1.0,1.0), loc="upper left") - fig.savefig(f"{sys.argv[1]}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') + fig.savefig(f"{path}/plot_timestep_means.svg", bbox_extra_artists=(pls_no_cut_off,), bbox_inches='tight') -def plot_tier_usage(data): +def plot_tier_usage(data, path): """ Plot the utilized space of each storage tier. """ @@ -183,7 +154,7 @@ def plot_tier_usage(data): tier += 1 fig.legend(loc='center right',handles=axs[0].get_lines()) - fig.savefig(f"{sys.argv[1]}/tier_usage.svg") + fig.savefig(f"{path}/tier_usage.svg") # TODO: Adjust bucket sizes def size_buckets(byte): @@ -261,6 +232,23 @@ def plot_filesystem_test(): fig.savefig(f"{sys.argv[1]}/filesystem_comp.svg") +def plot_evaluation_latency(path, variant): + if not os.path.exists(f"{path}/evaluation_{variant}.csv"): + return + + data = pd.read_csv(f"{path}/evaluation_{variant}.csv"); + + fig, ax = plt.subplots(1,1,figsize=(6,4)) + ax.scatter(data['size'][:5000], data['latency_ns'][:5000], marker='x') + xticks = np.arange(0, 12 * 1024 * 1024 + 1, 2 * 1024 * 1024) + ax.set_xticks(xticks, [int(x / 1024) for x in xticks]) + ax.set_xlabel("Size in KiB") + ax.set_ylabel("Latency in ns") + ax.set_yscale("log") + label=' | '.join(path.split('/')[-2:]) + ax.set_title(f"Haura - {label}") + fig.savefig(f"{path}/evaluation_read.svg") + USAGE_HELP="""Please specify an input run directory. If you already completed \ benchmarks they can be found under `results/*`. @@ -278,9 +266,10 @@ def main(): # Plot actions metrics_plots.plot_throughput(data, sys.argv[1]) - plot_tier_usage(data) - #plot_latency(data) - #plot_object_distribution() + plot_tier_usage(data, sys.argv[1]) + plot_evaluation_latency(sys.argv[1], "read") + plot_evaluation_latency(sys.argv[1], "rw") + plot_object_distribution(sys.argv[1]) #plot_filesystem_test() if __name__ == "__main__":