From 1f984e506f57531d3462b9095d120d2270017c2c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 19 Oct 2023 20:57:29 -0400 Subject: [PATCH 001/145] Prototype new analyses/methods --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 215 ++++++++++++++++-- conduitpylib/utils/__init__.py | 8 + conduitpylib/utils/count_outliers.py | 31 +++ 3 files changed, 237 insertions(+), 17 deletions(-) create mode 100644 conduitpylib/utils/count_outliers.py diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 81dabe7669..40992b7605 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -29,7 +29,12 @@ "metadata": {}, "outputs": [], "source": [ - "from conduitpylib.utils import consolidate_merge\n" + "from conduitpylib.utils import (\n", + " consolidate_merge,\n", + " count_outliers,\n", + " count_nonoutliers,\n", + " count_proportion_outliers,\n", + ")\n" ] }, { @@ -777,6 +782,13 @@ " )\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Simple Mean and Median\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -794,6 +806,170 @@ "})\n" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Median of Replicate Means\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Latency Walltime Inlet (ns)': np.mean\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Walltime Inlet (ns)': np.mean\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Latency Walltime Inlet (ns)\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Latency Walltime Inlet (ns)\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Median of Replicate Medians\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Latency Walltime Inlet (ns)': np.median\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Walltime Inlet (ns)': np.median\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Latency Walltime Inlet (ns)\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Latency Walltime Inlet (ns)\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Median Absolute Deviance\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xdf = df_snapshot_diffs.copy()\n", + "xdf['median'] = xdf['Latency Walltime Inlet (ns)']\n", + "xdf['median_abs_deviation'] = xdf['Latency Walltime Inlet (ns)']\n", + "xdf = xdf.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'median': np.median,\n", + " 'median_abs_deviation': stats.median_abs_deviation,\n", + "}).reset_index()\n", + "\n", + "name1, name2 = group_medians[allocation_idx_mapped_title].unique()\n", + "\n", + "# Extract medians for each group\n", + "group1 = group_medians[group_medians[allocation_idx_mapped_title] == name1]['Latency Walltime Inlet (ns)']\n", + "group2 = group_medians[group_medians[allocation_idx_mapped_title] == name2]['Latency Walltime Inlet (ns)']\n", + "\n", + "ax = sns.histplot(group1)\n", + "sns.histplot(group2, ax=ax)\n", + "\n", + "print(len(group1), len(group2))\n", + "stats.mannwhitneyu(group1, group2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "xdf['normed MAD'] = xdf[\"median_abs_deviation\"] / xdf[\"median\"]\n", + "\n", + "ax = sns.histplot(data=xdf, x=\"normed MAD\", hue=allocation_idx_mapped_title)\n", + "\n", + "xdf.groupby(allocation_idx_mapped_title)['normed MAD'].median().reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Percent Outliers\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nonoutlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Walltime Inlet (ns)': count_nonoutliers,\n", + "}).reset_index()\n", + "nonoutlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "outlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Walltime Inlet (ns)': count_outliers,\n", + "}).reset_index()\n", + "outlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "stats.chi2_contingency(\n", + " np.vstack(\n", + " [\n", + " outlier_counts[\"Latency Walltime Inlet (ns)\"],\n", + " nonoutlier_counts[\"Latency Walltime Inlet (ns)\"],\n", + " ],\n", + " ),\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Walltime Inlet (ns)': lambda x: count_proportion_outliers(x) * 100,\n", + "}).reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Distributions\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1120,8 +1296,8 @@ " filtered_data = data[ data.apply(eval(row_filter), axis=1) ]\n", "\n", " regfun = {\n", - " 'Ordinary Least Squares Regression' : smf.ols,\n", - " 'Quantile Regression' : smf.quantreg,\n", + " 'Quantile Regression over Means' : smf.quantreg,\n", + " 'Quantile Regression over Medians' : smf.quantreg,\n", " }[regression]\n", " model = regfun(f\"Q('{dependent_variable}') ~ Q('{independent_variable}')\", filtered_data)\n", " fit_model = model.fit()\n", @@ -1139,8 +1315,8 @@ " data[independent_variable] == data[independent_variable].min()\n", " ][dependent_variable]\n", " effect_size_normalization_factor = {\n", - " 'Ordinary Least Squares Regression' : lambda x: x.mean(),\n", - " 'Quantile Regression' : lambda x: x.median(),\n", + " 'Quantile Regression over Means' : lambda x: x.mean(),\n", + " 'Quantile Regression over Medians' : lambda x: x.median(),\n", " }[regression](effect_size_normalization_data)\n", " relative_effect_size = slope / effect_size_normalization_factor\n", " relative_effect_size_ci_lb = slope_ci_lb / effect_size_normalization_factor\n", @@ -1190,8 +1366,8 @@ " 'Regression Model' : regression,\n", " 'Regression Model Slug' : slugify(regression),\n", " 'Statistic' : {\n", - " 'Ordinary Least Squares Regression' : 'mean',\n", - " 'Quantile Regression' : 'median',\n", + " 'Quantile Regression over Means' : 'mean',\n", + " 'Quantile Regression over Medians' : 'median',\n", " }[regression],\n", " }\n", "\n", @@ -1268,7 +1444,7 @@ "\n", "regression_data_tuples = [\n", " (\n", - " 'Ordinary Least Squares Regression',\n", + " 'Quantile Regression over Means',\n", " df_snapshot_diffs.groupby([\n", " 'Execution Instance UUID',\n", " ]).mean().reset_index().astype({\n", @@ -1279,7 +1455,7 @@ " })\n", " ),\n", " (\n", - " 'Quantile Regression',\n", + " 'Quantile Regression over Medians',\n", " df_snapshot_diffs.groupby([\n", " 'Execution Instance UUID',\n", " ]).median().reset_index().astype({\n", @@ -1492,8 +1668,8 @@ " x='Dependent Variable',\n", " y='Relative Effect Size',\n", " estimated_statistic={\n", - " 'Quantile Regression' : 'Median',\n", - " 'Ordinary Least Squares Regression' : 'Mean',\n", + " 'Quantile Regression over Medians' : 'Median',\n", + " 'Quantile Regression over Means' : 'Mean',\n", " }[regression],\n", " size_inches=(8, 8),\n", " teeplot_outattrs={\n", @@ -1530,8 +1706,8 @@ " row='Num Simels Per Cpu',\n", " y='Relative Effect Size',\n", " estimated_statistic={\n", - " 'Quantile Regression' : f'{dependent_variable} Median',\n", - " 'Ordinary Least Squares Regression' : f'{dependent_variable} Mean',\n", + " 'Quantile Regression over Medians' : f'{dependent_variable} Median',\n", + " 'Quantile Regression over Means' : f'{dependent_variable} Mean',\n", " }[regression],\n", " teeplot_outattrs={\n", " **{\n", @@ -1568,8 +1744,8 @@ " row='Num Simels Per Cpu',\n", " y='Absolute Effect Size',\n", " estimated_statistic={\n", - " 'Quantile Regression' : f'{dependent_variable} Median',\n", - " 'Ordinary Least Squares Regression' : f'{dependent_variable} Mean',\n", + " 'Quantile Regression over Medians' : f'{dependent_variable} Median',\n", + " 'Quantile Regression over Means' : f'{dependent_variable} Mean',\n", " }[regression],\n", " teeplot_outattrs={\n", " **{\n", @@ -1678,7 +1854,7 @@ " g.map_dataframe(\n", " unsplit_regression,\n", " regplot={\n", - " 'Ordinary Least Squares Regression' : sns.regplot,\n", + " 'Ordinary Least Squares Regression' : quantile_regplot,\n", " 'Quantile Regression' : quantile_regplot,\n", " }[regression],\n", " x=x,\n", @@ -1691,7 +1867,12 @@ "\n", " # adapted from https://stackoverflow.com/a/29814281\n", " plt.gcf().subplots_adjust(top=0.8)\n", - " plt.gcf().suptitle(regression)\n" + " plt.gcf().suptitle(\n", + " {\n", + " \"Quantile Regression\": \"Quantile Regression over Medians\",\n", + " \"Ordinary Least Squares Regression\": \"Quantile Regression over Means\",\n", + " }[regression],\n", + " )\n" ] }, { diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 4ab0862614..29364c7fbf 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -1,10 +1,18 @@ """Miscellaneous utilities.""" from .consolidate_merge import consolidate_merge +from .count_outliers import ( + count_nonoutliers, + count_outliers, + count_proportion_outliers, +) from .strip_end import strip_end # adapted from https://stackoverflow.com/a/31079085 __all__ = [ 'consolidate_merge', + 'count_nonoutliers', + 'count_outliers', + 'count_proportion_outliers', 'strip_end', ] diff --git a/conduitpylib/utils/count_outliers.py b/conduitpylib/utils/count_outliers.py new file mode 100644 index 0000000000..0b1a400c08 --- /dev/null +++ b/conduitpylib/utils/count_outliers.py @@ -0,0 +1,31 @@ +import pandas as pd + + +def count_outliers(data): + """Calculate the number of outliers in a pandas column using the IQR + method.""" + + # Calculate Q1 and Q3 + Q1 = data.quantile(0.25) + Q3 = data.quantile(0.75) + + # Calculate IQR + IQR = Q3 - Q1 + + # Define bounds for outliers + lower_bound = Q1 - 1.5 * IQR + upper_bound = Q3 + 1.5 * IQR + + # Count outliers + return ( + (data < lower_bound) + | (data > upper_bound) + ).sum() + + +def count_proportion_outliers(data): + return count_outliers(data) / len(data) + + +def count_nonoutliers(data): + return len(data) - count_outliers(data) From b3f66b244fc4f939aa6e89622d9b334884d49c89 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 19 Oct 2023 21:29:37 -0400 Subject: [PATCH 002/145] Switch Docker from git:// to https:// --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 6e1f2606ff..9fd6231359 100644 --- a/Dockerfile +++ b/Dockerfile @@ -211,7 +211,10 @@ RUN \ # magic from https://github.com/puppeteer/puppeteer/issues/3451#issuecomment-523961368 RUN echo 'kernel.unprivileged_userns_clone=1' > /etc/sysctl.d/userns.conf +# git confifg, see https://stackoverflow.com/a/76769867 RUN \ + git config --global url."https://".insteadOf git:// \ + && \ python3 -m pip install --timeout 60 --retries 100 --upgrade pip==21.3.1 \ && \ python3 -m pip install --timeout 60 --retries 100 --ignore-installed -r /opt/conduit/third-party/requirements.txt \ From 062f7180bfbd92f4a64b7e91f67813ad3715218d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 20 Oct 2023 00:38:35 -0400 Subject: [PATCH 003/145] Replace OLS regression, fixup rest of metrics --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 820 ++++++++++++++++-- 1 file changed, 760 insertions(+), 60 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 40992b7605..863e82d8d1 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -6,6 +6,8 @@ "metadata": {}, "outputs": [], "source": [ + "import warnings\n", + "\n", "from iterdub import iterdub as ib\n", "from iterpop import iterpop as ip\n", "from keyname import keyname as kn\n", @@ -878,15 +880,13 @@ " 'median': np.median,\n", " 'median_abs_deviation': stats.median_abs_deviation,\n", "}).reset_index()\n", + "xdf[\"normed median_abs_deviation\"] = xdf[\"median_abs_deviation\"] / xdf[\"median\"] * 100\n", "\n", - "name1, name2 = group_medians[allocation_idx_mapped_title].unique()\n", + "name1, name2 = xdf[allocation_idx_mapped_title].unique()\n", "\n", "# Extract medians for each group\n", - "group1 = group_medians[group_medians[allocation_idx_mapped_title] == name1]['Latency Walltime Inlet (ns)']\n", - "group2 = group_medians[group_medians[allocation_idx_mapped_title] == name2]['Latency Walltime Inlet (ns)']\n", - "\n", - "ax = sns.histplot(group1)\n", - "sns.histplot(group2, ax=ax)\n", + "group1 = xdf[xdf[allocation_idx_mapped_title] == name1]['normed median_abs_deviation']\n", + "group2 = xdf[xdf[allocation_idx_mapped_title] == name2]['normed median_abs_deviation']\n", "\n", "print(len(group1), len(group2))\n", "stats.mannwhitneyu(group1, group2)\n" @@ -898,11 +898,9 @@ "metadata": {}, "outputs": [], "source": [ - "xdf['normed MAD'] = xdf[\"median_abs_deviation\"] / xdf[\"median\"]\n", + "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", "\n", - "ax = sns.histplot(data=xdf, x=\"normed MAD\", hue=allocation_idx_mapped_title)\n", - "\n", - "xdf.groupby(allocation_idx_mapped_title)['normed MAD'].median().reset_index()\n" + "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" ] }, { @@ -1040,9 +1038,18 @@ " )\n" ] }, + { + "cell_type": "markdown", + "id": "3fdb3f6f-4c83-4804-a1e7-b773554af98d", + "metadata": {}, + "source": [ + "### Simple Mean and Median\n" + ] + }, { "cell_type": "code", "execution_count": null, + "id": "05d5be0f-86c7-4104-b318-55caaba2f1ff", "metadata": {}, "outputs": [], "source": [ @@ -1057,6 +1064,171 @@ "})\n" ] }, + { + "cell_type": "markdown", + "id": "f7f5d8c3-5acb-456a-b0b3-d944248f6809", + "metadata": {}, + "source": [ + "### Median of Replicate Means\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cfa1a75-b008-4d25-ae26-cd018aee0a44", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Latency Simsteps Inlet': np.mean\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Simsteps Inlet': np.mean\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Latency Simsteps Inlet\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Latency Simsteps Inlet\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "28d666eb-4ea7-4112-ab4c-fd05c992ad03", + "metadata": {}, + "source": [ + "### Median of Replicate Medians\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02351780-005a-496c-bde5-49a0400f6303", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Latency Simsteps Inlet': np.median\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Simsteps Inlet': np.median\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Latency Simsteps Inlet\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Latency Simsteps Inlet\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "6467fb06-d857-40b3-bdc4-2858ba94a2df", + "metadata": {}, + "source": [ + "### Median Absolute Deviance\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d782ed5-420a-48f4-bb57-d4e8ee8e530c", + "metadata": {}, + "outputs": [], + "source": [ + "xdf = df_snapshot_diffs.copy()\n", + "xdf['median'] = xdf['Latency Simsteps Inlet']\n", + "xdf['median_abs_deviation'] = xdf['Latency Simsteps Inlet']\n", + "xdf = xdf.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'median': np.median,\n", + " 'median_abs_deviation': stats.median_abs_deviation,\n", + "}).reset_index()\n", + "xdf[\"normed median_abs_deviation\"] = xdf[\"median_abs_deviation\"] / xdf[\"median\"] * 100\n", + "\n", + "name1, name2 = xdf[allocation_idx_mapped_title].unique()\n", + "\n", + "# Extract medians for each group\n", + "group1 = xdf[xdf[allocation_idx_mapped_title] == name1]['normed median_abs_deviation']\n", + "group2 = xdf[xdf[allocation_idx_mapped_title] == name2]['normed median_abs_deviation']\n", + "\n", + "print(len(group1), len(group2))\n", + "stats.mannwhitneyu(group1, group2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7fd12be-ab9f-4c97-8d96-8c12836460c0", + "metadata": {}, + "outputs": [], + "source": [ + "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "\n", + "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "id": "bc6e4cf7-6589-4243-8140-29165c4be39d", + "metadata": {}, + "source": [ + "### Percent Outliers\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4413cca-12b7-4552-9b91-cbf5aada8446", + "metadata": {}, + "outputs": [], + "source": [ + "nonoutlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Simsteps Inlet': count_nonoutliers,\n", + "}).reset_index()\n", + "nonoutlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a49edb75-c9eb-4a92-981f-ce75b86516c5", + "metadata": {}, + "outputs": [], + "source": [ + "outlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Simsteps Inlet': count_outliers,\n", + "}).reset_index()\n", + "outlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f606740-6046-44ab-a421-9278c719bdbb", + "metadata": {}, + "outputs": [], + "source": [ + "stats.chi2_contingency(\n", + " np.vstack(\n", + " [\n", + " outlier_counts[\"Latency Simsteps Inlet\"],\n", + " nonoutlier_counts[\"Latency Simsteps Inlet\"],\n", + " ],\n", + " ),\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14469ba8-9d0e-482e-b309-18dbca4a2201", + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Latency Simsteps Inlet': lambda x: count_proportion_outliers(x) * 100,\n", + "}).reset_index()\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1127,9 +1299,18 @@ " )\n" ] }, + { + "cell_type": "markdown", + "id": "583d05ae-9ff3-457b-a9dd-0d6c787f7142", + "metadata": {}, + "source": [ + "### Simple Mean and Median\n" + ] + }, { "cell_type": "code", "execution_count": null, + "id": "904d7985-4a3d-4038-a108-8707eed6a1fb", "metadata": {}, "outputs": [], "source": [ @@ -1146,96 +1327,615 @@ }, { "cell_type": "markdown", + "id": "afae0790-82f6-401e-af06-d59938cd7b44", "metadata": {}, "source": [ - "## Delivery Clumpiness\n" + "### Median of Replicate Means\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "adbccb85-e96a-4dfc-8cd9-14205c572e96", "metadata": {}, "outputs": [], "source": [ - "for viz in facet_barplot, facet_boxplot_withfliers, facet_boxplot_nofliers:\n", - " tp.tee(\n", - " viz,\n", - " data=df_snapshot_diffs,\n", - " row='Num Simels Per Cpu',\n", - " x=allocation_idx_mapped_title,\n", - " y='Delivery Clumpiness',\n", - " teeplot_outattrs={\n", - " **{\n", - " 'transform' : 'snapshot_diffs',\n", - " },\n", - " **nbm.collate_outattr_metadata(),\n", - " },\n", - " teeplot_subdir='delivery-clumpiness',\n", - " )\n" + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Delivery Failure Rate': np.mean\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Failure Rate': np.mean\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Delivery Failure Rate\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Delivery Failure Rate\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "ba4c19ee-ec1c-4b99-9342-8ab53dfc54a0", + "metadata": {}, + "source": [ + "### Median of Replicate Medians\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "68664a4a-5cfa-492e-a736-913d4aade9c6", "metadata": {}, "outputs": [], "source": [ - "# adapted from https://stackoverflow.com/a/13592901\n", - "df_snapshot_diffs.groupby([\n", - " allocation_idx_mapped_title,\n", - "]).agg({\n", - " 'Delivery Clumpiness' : [\n", - " np.mean,\n", - " np.median,\n", - " ],\n", - "})\n" + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Delivery Failure Rate': np.median\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Failure Rate': np.median\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Delivery Failure Rate\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Delivery Failure Rate\"] - baseline) / baseline * 100\n", + "median_of_medians\n" ] }, { "cell_type": "markdown", + "id": "3fbc9ca0-2b86-4d78-93f7-6b82a1501aae", "metadata": {}, "source": [ - "## Simstep Period\n" + "### Median Absolute Deviance\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "541f4ac8-c220-4cea-863b-bd787361236a", "metadata": {}, "outputs": [], "source": [ - "for viz in facet_barplot, facet_boxplot_withfliers, facet_boxplot_nofliers:\n", - " tp.tee(\n", - " viz,\n", - " data=df_snapshot_diffs,\n", - " row='Num Simels Per Cpu',\n", - " x=allocation_idx_mapped_title,\n", - " y='Simstep Period Inlet (ns)',\n", - " teeplot_outattrs={\n", - " **{\n", - " 'transform' : 'snapshot_diffs',\n", - " },\n", - " **nbm.collate_outattr_metadata(),\n", - " },\n", - " teeplot_subdir='simstep-period-inlet-ns',\n", - " )\n" + "xdf = df_snapshot_diffs.copy()\n", + "xdf['median'] = xdf['Delivery Failure Rate']\n", + "xdf['median_abs_deviation'] = xdf['Delivery Failure Rate']\n", + "xdf = xdf.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'median': np.median,\n", + " 'median_abs_deviation': stats.median_abs_deviation,\n", + "}).reset_index()\n", + "xdf[\"normed median_abs_deviation\"] = xdf[\"median_abs_deviation\"] / xdf[\"median\"] * 100\n", + "\n", + "name1, name2 = xdf[allocation_idx_mapped_title].unique()\n", + "\n", + "# Extract medians for each group\n", + "group1 = xdf[xdf[allocation_idx_mapped_title] == name1]['normed median_abs_deviation']\n", + "group2 = xdf[xdf[allocation_idx_mapped_title] == name2]['normed median_abs_deviation']\n", + "\n", + "try:\n", + " print(len(group1), len(group2))\n", + " print(group1.isna().all(), group2.isna().all())\n", + " res = stats.mannwhitneyu(group1, group2)\n", + "except Exception as e:\n", + " warnings.warn(f\"{type(e).__name__}: {e}\", RuntimeWarning)\n", + "\n", + "res\n" ] }, { "cell_type": "code", "execution_count": null, + "id": "a5fbf214-a609-46fa-a98c-541714ed88bb", "metadata": {}, "outputs": [], "source": [ - "# adapted from https://stackoverflow.com/a/13592901\n", - "df_snapshot_diffs.groupby([\n", - " allocation_idx_mapped_title,\n", - "]).agg({\n", - " 'Simstep Period Inlet (ns)' : [\n", - " np.mean,\n", - " np.median,\n", - " ],\n", - "})\n" + "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "\n", + "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "id": "57e88ca0-24c6-4e4e-a336-7820e326c681", + "metadata": {}, + "source": [ + "### Percent Outliers\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e193a7ab-b264-43b4-bec0-85dc1647f247", + "metadata": {}, + "outputs": [], + "source": [ + "nonoutlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Failure Rate': count_nonoutliers,\n", + "}).reset_index()\n", + "nonoutlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3af8cf0f-ba65-4291-b9d6-90abd0ec3e60", + "metadata": {}, + "outputs": [], + "source": [ + "outlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Failure Rate': count_outliers,\n", + "}).reset_index()\n", + "outlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9af1ced2-08e5-4a4c-94f2-3cd9ccc15241", + "metadata": {}, + "outputs": [], + "source": [ + "stats.chi2_contingency(\n", + " np.vstack(\n", + " [\n", + " outlier_counts[\"Delivery Failure Rate\"],\n", + " nonoutlier_counts[\"Delivery Failure Rate\"],\n", + " ],\n", + " ),\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92e27cdd-acef-4753-b395-48026fde9803", + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Failure Rate': lambda x: count_proportion_outliers(x) * 100,\n", + "}).reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Delivery Clumpiness\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for viz in facet_barplot, facet_boxplot_withfliers, facet_boxplot_nofliers:\n", + " tp.tee(\n", + " viz,\n", + " data=df_snapshot_diffs,\n", + " row='Num Simels Per Cpu',\n", + " x=allocation_idx_mapped_title,\n", + " y='Delivery Clumpiness',\n", + " teeplot_outattrs={\n", + " **{\n", + " 'transform' : 'snapshot_diffs',\n", + " },\n", + " **nbm.collate_outattr_metadata(),\n", + " },\n", + " teeplot_subdir='delivery-clumpiness',\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "id": "fa2a7b00-69ed-4ad0-a0a9-75c81905f7b4", + "metadata": {}, + "source": [ + "### Simple Mean and Median\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dda86c6b-e390-4c28-b5c4-491377986542", + "metadata": {}, + "outputs": [], + "source": [ + "# adapted from https://stackoverflow.com/a/13592901\n", + "df_snapshot_diffs.groupby([\n", + " allocation_idx_mapped_title,\n", + "]).agg({\n", + " 'Delivery Clumpiness' : [\n", + " np.mean,\n", + " np.median,\n", + " ],\n", + "})\n" + ] + }, + { + "cell_type": "markdown", + "id": "f3c96c69-348b-457c-86a6-e58bd196f29b", + "metadata": {}, + "source": [ + "### Median of Replicate Means\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98644ac1-cd06-4948-96aa-99578d2d9b2e", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Delivery Clumpiness': np.mean\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Clumpiness': np.mean\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Delivery Clumpiness\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Delivery Clumpiness\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "17984f4e-ecf7-48b5-94cd-7e8f89d8ec95", + "metadata": {}, + "source": [ + "### Median of Replicate Medians\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e23c7941-5073-48c1-b39b-9294fd2a5b06", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Delivery Clumpiness': np.median\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Clumpiness': np.median\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Delivery Clumpiness\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Delivery Clumpiness\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "dfcd7358-58c9-4029-942c-53688bf9261e", + "metadata": {}, + "source": [ + "### Median Absolute Deviance\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cef9e496-f089-4fe7-ac34-5fdd383aa74d", + "metadata": {}, + "outputs": [], + "source": [ + "xdf = df_snapshot_diffs.copy()\n", + "xdf['median'] = xdf['Delivery Clumpiness']\n", + "xdf['median_abs_deviation'] = xdf['Delivery Clumpiness']\n", + "xdf = xdf.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'median': np.median,\n", + " 'median_abs_deviation': stats.median_abs_deviation,\n", + "}).reset_index()\n", + "xdf[\"normed median_abs_deviation\"] = xdf[\"median_abs_deviation\"] / xdf[\"median\"] * 100\n", + "\n", + "name1, name2 = xdf[allocation_idx_mapped_title].unique()\n", + "\n", + "# Extract medians for each group\n", + "group1 = xdf[xdf[allocation_idx_mapped_title] == name1]['normed median_abs_deviation']\n", + "group2 = xdf[xdf[allocation_idx_mapped_title] == name2]['normed median_abs_deviation']\n", + "\n", + "print(len(group1), len(group2))\n", + "stats.mannwhitneyu(group1, group2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a3bbba1-60bd-4422-a2d9-19c22e9c6cd1", + "metadata": {}, + "outputs": [], + "source": [ + "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "\n", + "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "id": "493085c4-5764-4221-9a79-176965927ac9", + "metadata": {}, + "source": [ + "### Percent Outliers\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff5ab4d2-ee9c-48a3-b7f3-c36fd6859412", + "metadata": {}, + "outputs": [], + "source": [ + "nonoutlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Clumpiness': count_nonoutliers,\n", + "}).reset_index()\n", + "nonoutlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0621e3c5-da83-4ee2-9196-07bbb513b58b", + "metadata": {}, + "outputs": [], + "source": [ + "outlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Clumpiness': count_outliers,\n", + "}).reset_index()\n", + "outlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9571015e-40ae-45ca-ad3a-3e2af18d2793", + "metadata": {}, + "outputs": [], + "source": [ + "stats.chi2_contingency(\n", + " np.vstack(\n", + " [\n", + " outlier_counts[\"Delivery Clumpiness\"],\n", + " nonoutlier_counts[\"Delivery Clumpiness\"],\n", + " ],\n", + " ),\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e35fa28f-cc60-4c0c-969e-09a89203502a", + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Delivery Clumpiness': lambda x: count_proportion_outliers(x) * 100,\n", + "}).reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simstep Period\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for viz in facet_barplot, facet_boxplot_withfliers, facet_boxplot_nofliers:\n", + " tp.tee(\n", + " viz,\n", + " data=df_snapshot_diffs,\n", + " row='Num Simels Per Cpu',\n", + " x=allocation_idx_mapped_title,\n", + " y='Simstep Period Inlet (ns)',\n", + " teeplot_outattrs={\n", + " **{\n", + " 'transform' : 'snapshot_diffs',\n", + " },\n", + " **nbm.collate_outattr_metadata(),\n", + " },\n", + " teeplot_subdir='simstep-period-inlet-ns',\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "id": "80e56a70-c0c0-44c3-a1ba-ae587bbcd9c2", + "metadata": {}, + "source": [ + "### Simple Mean and Median\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8416f0f-1577-451a-a2e8-038a6a9ae35a", + "metadata": {}, + "outputs": [], + "source": [ + "# adapted from https://stackoverflow.com/a/13592901\n", + "df_snapshot_diffs.groupby([\n", + " allocation_idx_mapped_title,\n", + "]).agg({\n", + " 'Simstep Period Inlet (ns)' : [\n", + " np.mean,\n", + " np.median,\n", + " ],\n", + "})\n" + ] + }, + { + "cell_type": "markdown", + "id": "2bc12349-f485-4414-a722-2fb770dddc62", + "metadata": {}, + "source": [ + "### Median of Replicate Means\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a3f4265-ab45-49fc-8257-c952e6f81019", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Simstep Period Inlet (ns)': np.mean\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Simstep Period Inlet (ns)': np.mean\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Simstep Period Inlet (ns)\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Simstep Period Inlet (ns)\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "29e918d7-dcd3-4ec5-9651-ea489683b003", + "metadata": {}, + "source": [ + "### Median of Replicate Medians\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b4527daa-195a-4f50-91f9-2cd224b86ed9", + "metadata": {}, + "outputs": [], + "source": [ + "group_medians = df_snapshot_diffs.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'Simstep Period Inlet (ns)': np.median\n", + "}).reset_index()\n", + "\n", + "median_of_medians = group_medians.groupby(allocation_idx_mapped_title).agg({\n", + " 'Simstep Period Inlet (ns)': np.median\n", + "})\n", + "\n", + "baseline = median_of_medians.loc[1, \"Simstep Period Inlet (ns)\"].squeeze()\n", + "median_of_medians[\"normed delta\"] = (median_of_medians[\"Simstep Period Inlet (ns)\"] - baseline) / baseline * 100\n", + "median_of_medians\n" + ] + }, + { + "cell_type": "markdown", + "id": "6ba8ccfb-a27e-40c2-94d0-273fad16b241", + "metadata": {}, + "source": [ + "### Median Absolute Deviance\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "099ea495-33f4-44b1-b197-8e5440e4a3cb", + "metadata": {}, + "outputs": [], + "source": [ + "xdf = df_snapshot_diffs.copy()\n", + "xdf['median'] = xdf['Simstep Period Inlet (ns)']\n", + "xdf['median_abs_deviation'] = xdf['Simstep Period Inlet (ns)']\n", + "xdf = xdf.groupby([allocation_idx_mapped_title, 'Replicate']).agg({\n", + " 'median': np.median,\n", + " 'median_abs_deviation': stats.median_abs_deviation,\n", + "}).reset_index()\n", + "xdf[\"normed median_abs_deviation\"] = xdf[\"median_abs_deviation\"] / xdf[\"median\"] * 100\n", + "\n", + "name1, name2 = xdf[allocation_idx_mapped_title].unique()\n", + "\n", + "# Extract medians for each group\n", + "group1 = xdf[xdf[allocation_idx_mapped_title] == name1]['normed median_abs_deviation']\n", + "group2 = xdf[xdf[allocation_idx_mapped_title] == name2]['normed median_abs_deviation']\n", + "\n", + "print(len(group1), len(group2))\n", + "stats.mannwhitneyu(group1, group2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c8a7abf-a5d3-4099-994a-bf90f63c6a4b", + "metadata": {}, + "outputs": [], + "source": [ + "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "\n", + "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" + ] + }, + { + "cell_type": "markdown", + "id": "0068a609-4cee-4034-a6fa-a56b79072c0f", + "metadata": {}, + "source": [ + "### Percent Outliers\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a6e6ec3-f417-4a85-872b-3786215fb465", + "metadata": {}, + "outputs": [], + "source": [ + "nonoutlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Simstep Period Inlet (ns)': count_nonoutliers,\n", + "}).reset_index()\n", + "nonoutlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9557f1c-6b18-4e32-a0d8-89413a01d813", + "metadata": {}, + "outputs": [], + "source": [ + "outlier_counts = df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Simstep Period Inlet (ns)': count_outliers,\n", + "}).reset_index()\n", + "outlier_counts\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "378faa89-5487-4b05-a789-7f70ff86c5cb", + "metadata": {}, + "outputs": [], + "source": [ + "stats.chi2_contingency(\n", + " np.vstack(\n", + " [\n", + " outlier_counts[\"Simstep Period Inlet (ns)\"],\n", + " nonoutlier_counts[\"Simstep Period Inlet (ns)\"],\n", + " ],\n", + " ),\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78b50650-8d7d-4a4b-9d42-fff088abc596", + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs.groupby(allocation_idx_mapped_title).agg({\n", + " 'Simstep Period Inlet (ns)': lambda x: count_proportion_outliers(x) * 100,\n", + "}).reset_index()\n" ] }, { From 4a2bf9b32fb9b1b5d59700d0a3118967a34cd274 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 20 Oct 2023 00:49:01 -0400 Subject: [PATCH 004/145] Disable git safe directory Cause of "dubious ownership" error on GH actions deploy --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 9fd6231359..5a2cb70862 100644 --- a/Dockerfile +++ b/Dockerfile @@ -294,6 +294,7 @@ RUN \ && \ echo "user added and granted permissions to /opt and /home/user" +# git safe directory: https://stackoverflow.com/a/73100228/17332200 RUN \ mkdir /context/ \ && \ @@ -303,6 +304,8 @@ RUN \ && \ chown user:user /__w/ \ && \ + git config --global --add safe.directory '*' \ + && \ echo "/context/ /__w/ directories set up, user granted permissions" USER user From 0519f9bd6eb059518b653b8244f3e35449d945e2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 20 Oct 2023 05:10:35 -0400 Subject: [PATCH 005/145] Add suggested git safe dir except --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 5a2cb70862..7e78ec397e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -306,6 +306,8 @@ RUN \ && \ git config --global --add safe.directory '*' \ && \ + git config --global --add safe.directory /__w/conduit/conduit \ + && \ echo "/context/ /__w/ directories set up, user granted permissions" USER user From 1cc1ff3276772c454d2b4fdbb130bf2e5eb70169 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 20 Oct 2023 05:54:19 -0400 Subject: [PATCH 006/145] Try setting git safedir in CI step --- .github/workflows/CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a21c82a05b..7fd26a81d6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -54,6 +54,7 @@ jobs: steps: # Adapted from https://askubuntu.com/a/524368 - run: cd /opt/conduit/binder && ./execute_notebooks.sh + - run: git config --global --add safe.directory /__w/conduit/conduit - run: git init - uses: fregante/setup-git-user@v1 - run: git commit --allow-empty -m "Initial commit" From c2bb63b2e3e3dab576c7c704db925ffa8a5e4664 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 31 Oct 2023 14:22:10 -0400 Subject: [PATCH 007/145] Catch median ValueError and warn --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 863e82d8d1..d79a210600 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -36,6 +36,10 @@ " count_outliers,\n", " count_nonoutliers,\n", " count_proportion_outliers,\n", + ")\n", + "\n", + "from conduitpylib.viz import (\n", + " performance_semantics_plot,\n", ")\n" ] }, @@ -1415,10 +1419,9 @@ " print(len(group1), len(group2))\n", " print(group1.isna().all(), group2.isna().all())\n", " res = stats.mannwhitneyu(group1, group2)\n", + " display(res)\n", "except Exception as e:\n", - " warnings.warn(f\"{type(e).__name__}: {e}\", RuntimeWarning)\n", - "\n", - "res\n" + " warnings.warn(f\"{type(e).__name__}: {e}\", RuntimeWarning)\n" ] }, { @@ -1428,9 +1431,15 @@ "metadata": {}, "outputs": [], "source": [ - "ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "try:\n", + " ax = sns.histplot(data=xdf, x=\"normed median_abs_deviation\", hue=allocation_idx_mapped_title)\n", + "except Exception as e:\n", + " warnings.warn(f\"{type(e).__name__}: {e}\", RuntimeWarning)\n", "\n", - "xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n" + "try:\n", + " xdf.groupby(allocation_idx_mapped_title)['normed median_abs_deviation'].median().reset_index()\n", + "except Exception as e:\n", + " warnings.warn(f\"{type(e).__name__}: {e}\", RuntimeWarning)\n" ] }, { From 115cfe8fef9dd2677ee5c0124f49b49c3f309c82 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Tue, 31 Oct 2023 14:23:29 -0400 Subject: [PATCH 008/145] Impl, test performance-semantics plot --- binder/date=2021+project=72k5n/Noto-LICENSE | 94 ++++++++ .../NotoEmoji-Regular.ttf | Bin 0 -> 1049444 bytes ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 28 +++ conduitpylib/viz/__init__.py | 11 + conduitpylib/viz/_frame_scatter_subsets.py | 101 +++++++++ .../viz/_performance_semantics_plot.py | 210 ++++++++++++++++++ 6 files changed, 444 insertions(+) create mode 100644 binder/date=2021+project=72k5n/Noto-LICENSE create mode 100644 binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf create mode 100644 conduitpylib/viz/__init__.py create mode 100644 conduitpylib/viz/_frame_scatter_subsets.py create mode 100644 conduitpylib/viz/_performance_semantics_plot.py diff --git a/binder/date=2021+project=72k5n/Noto-LICENSE b/binder/date=2021+project=72k5n/Noto-LICENSE new file mode 100644 index 0000000000..81286a08df --- /dev/null +++ b/binder/date=2021+project=72k5n/Noto-LICENSE @@ -0,0 +1,94 @@ +Copyright 2015 Google Inc. + +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to +provide a free and open framework in which fonts may be shared and +improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software +components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, +deleting, or substituting -- in part or in whole -- any of the +components of the Original Version, by changing formats or by porting +the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, +modify, redistribute, and sell modified and unmodified copies of the +Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the +corresponding Copyright Holder. This restriction only applies to the +primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created using +the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf b/binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5c8d4194fde782329adec0937b1ae5858b246107 GIT binary patch literal 1049444 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

D6 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

M1|*}L85 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

0NoRkNxs^ulY2_l-lQK+LXj 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 PZcn$>Px=2pE%1K;;WVOp literal 0 HcmV?d00001 diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index d79a210600..a20720221d 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -3472,6 +3472,34 @@ " & (df_snapshot_diffs['Num Simels Per Cpu'] == 2048)\n", "]\n" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs[\"Num Messages Per Pull\"] = (\n", + " df_snapshot_diffs['Net Flux Through Duct']\n", + " / df_snapshot_diffs['Num Pulls That Were Laden Immediately']\n", + " / df_snapshot_diffs[\"Delivery Success Rate\"]\n", + ").clip(lower=1)\n", + "assert (df_snapshot_diffs[\"Num Messages Per Pull\"] >= 1).all()\n", + "df_snapshot_diffs[\"Any Messages Dropped\"] = df_snapshot_diffs[\"Fraction Messages Dropped\"].astype(bool)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "performance_semantics_plot(\n", + " data=df_snapshot_diffs,\n", + " hue=\"Allocation\",\n", + " hue_order=[\"Sans lac-417\", \"With lac-417\"],\n", + ")\n" + ] } ], "metadata": { diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py new file mode 100644 index 0000000000..5e90c68faf --- /dev/null +++ b/conduitpylib/viz/__init__.py @@ -0,0 +1,11 @@ +"""Visualization tools.""" + +from ._frame_scatter_subsets import frame_scatter_subsets +from ._performance_semantics_plot import performance_semantics_plot + + +# adapted from https://stackoverflow.com/a/31079085 +__all__ = [ + '_frame_scatter_subsets', + "_performance_semantics_plot", +] diff --git a/conduitpylib/viz/_frame_scatter_subsets.py b/conduitpylib/viz/_frame_scatter_subsets.py new file mode 100644 index 0000000000..96e588be04 --- /dev/null +++ b/conduitpylib/viz/_frame_scatter_subsets.py @@ -0,0 +1,101 @@ +import itertools as it +import typing + +import numpy as np +import matplotlib as mpl +import matplotlib.patches as mpl_patches +import matplotlib.lines as mpl_lines +import pandas as pd + + +def frame_scatter_subsets( + data: pd.DataFrame, + x: str, + y: str, + frame: str, + ax: typing.Optional[mpl.axes.Axes], + frame_order: typing.Optional[typing.Iterable] = None, + palette: typing.Optional[typing.Iterable] = None, + pad_cm: float = 0.5, + log_y: bool = False, + **kwargs, +) -> mpl.axes.Axes: + """Draw rectangles bounding points associated with each value of `frame` + column. + + Extra kwargs are forwarded to Rectangle initializer. + """ + if ax is None: + ax = mpl.pyplot.gca() + + if palette is None: + palette = [None] + + # Calculate expansion in plot space + x_lb, x_ub = ax.get_xlim() + y_lb, y_ub = ax.get_ylim() + fig_inches_x, fig_inches_y = ax.figure.get_size_inches() + + pad_inches = pad_cm / 2.54 + pad_fraction_x = pad_inches / fig_inches_x + pad_fraction_y = pad_inches / fig_inches_y + + x_padding = (x_ub - x_lb) * pad_fraction_x + if log_y: + y_padding = (np.log10(y_ub) - np.log10(y_lb)) * pad_fraction_y + else: + y_padding = (y_ub - y_lb) * pad_fraction_y + + if frame_order is None: + frame_order = data[frame].unique() + linestyles = it.cycle(["-", "--", ":"]) + hues = it.cycle(palette) + for frame_value, linestyle, hue in zip(frame_order, linestyles, hues): + frame_data = data[data[frame] == frame_value] + + frame_min_x, frame_max_x = ( + frame_data[x].min() - x_padding, + frame_data[x].max() + x_padding, + ) + + frame_min_y, frame_max_y = ( + ( + frame_data[y].min(), + frame_data[y].max(), + ) + if log_y + else ( + frame_data[y].min(), + frame_data[y].max(), + ) + ) + + if log_y: + frame_min_y, frame_max_y = ( + 10 ** (np.log10(frame_min_y) - y_padding), + 10 ** (np.log10(frame_max_y) + y_padding), + ) + else: + frame_min_y, frame_max_y = ( + frame_min_y - y_padding, + frame_max_y + y_padding, + ) + + height = frame_max_y - frame_min_y + width = frame_max_x - frame_min_x + rect = mpl_patches.Rectangle( + (frame_min_x, frame_min_y), + width, + height, + linewidth=1, + edgecolor=hue, + facecolor="none", + linestyle=linestyle, + alpha=0.4, + lw=3, + **kwargs, + ) + + ax.add_patch(rect) + + return ax diff --git a/conduitpylib/viz/_performance_semantics_plot.py b/conduitpylib/viz/_performance_semantics_plot.py new file mode 100644 index 0000000000..a627ecc557 --- /dev/null +++ b/conduitpylib/viz/_performance_semantics_plot.py @@ -0,0 +1,210 @@ +import itertools as it +import typing + + +from matplotlib.collections import ( + PathCollection as mpl_PathCollection, +) +from matplotlib.font_manager import FontProperties as mpl_FontProperties +from matplotlib.legend_handler import ( + HandlerPathCollection as mpl_HandlerPathCollection, + HandlerLine2D as mpl_HandlerLine2D, +) +import matplotlib.patches as mpl_patches +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns + +from ._frame_scatter_subsets import frame_scatter_subsets + + +def performance_semantics_plot( + data: pd.DataFrame, + hue: str, + hue_order: typing.Optional[typing.List[str]] = None, + heat: str = "Fraction Messages Dropped", + x: str="Simstep Period Inlet (ns)", + y: str="Latency Simsteps Inlet", +) -> sns.JointGrid: + hue_order = ["Sans lac-417", "With lac-417"] + assert set(hue_order) == set(data[hue].unique()) + + palette = ["#648FFF", "#40B0A6"] + assert len(palette) == len(hue_order) + + jointgrid = sns.JointGrid( + data=data, + x=x, + y=y, + hue=hue, + ) + + # PLOT JOINT DISTRIBUTION + ########################################################################### + # scatterplot observations + sns.scatterplot( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + hue=heat, + style="Allocation", + markers=["o", "D"], + palette="flare", + alpha=0.4, + ) + + # set up joint plot axes... + # ... annotate latency simsteps inlet values + jointgrid.refline(y=1, ls="-", zorder=-5) + jointgrid.refline(y=2, ls="--", zorder=-5) + # ... set simsteps inlet to log scale + jointgrid.ax_joint.set_yscale("log") + # ... set simstep period time to zero minimum + jointgrid.ax_joint.set_xlim(xmin=0) + # ... set axis labels + jointgrid.ax_joint.set_xlabel("Update Rate (ns)") + jointgrid.ax_joint.set_ylabel("Communication Latency (updates)") + + # outline subsets of scatter points + frame_scatter_subsets( + data, + x=x, + y=y, + frame=hue, + ax=jointgrid.ax_joint, + frame_order=hue_order, + log_y=True, + palette=palette, + ) + + # PLOT MARGINAL DISTRIBUTIONS + ########################################################################### + # plot marginal distributions as kernel density estimates + jointgrid.plot_marginals(sns.kdeplot, palette=palette, fill=True, lw=3, alpha=0.1) + + # set linestyles of marginal KDE outlines + # https://stackoverflow.com/a/70089200 + linestyles = ["--", "-"] + for line, linestyle in it.chain( + zip(jointgrid.ax_marg_x.collections, linestyles), + zip(jointgrid.ax_marg_y.collections, linestyles), + ): + line.set_linestyle(linestyle) + line.set_alpha(0.4) + + + # set density to loc scale + jointgrid.ax_marg_x.set_yscale("symlog", linthresh=0.0000000001) + jointgrid.ax_marg_y.set_xscale("symlog", linthresh=0.0001) + + sns.rugplot( + data=data, + ax=jointgrid.ax_marg_x, + x=x, + hue=heat, + palette="flare", + legend=False, + alpha=0.05, + expand_margins=False, + clip_on=False, + height=-0.3, + ) + + sns.rugplot( + data=data, + ax=jointgrid.ax_marg_y, + y=y, + hue=heat, + palette="flare", + legend=False, + alpha=0.3, + expand_margins=False, + clip_on=False, + height=-0.3, + ) + + # SET UP LEGEND + ########################################################################### + # manually register category splits into legend... + # ... add quasi-title to legend entry by providing key but no value + ( + handles, + labels, + ) = jointgrid.ax_joint.get_legend_handles_labels() # get existing handles and labels + empty_patch = mpl_patches.Patch( + color="none", label="Extra label" + ) + handles.append(empty_patch) + labels.append(hue) + # ... then add legend entries manually + for ls, color, label in zip(reversed(linestyles), palette, hue_order): + example_patch = mpl_patches.Patch( + facecolor=color, + linestyle=ls, + label=label, + lw=2, + edgecolor=color, + alpha=0.4, + ) + handles.append(example_patch) + labels.append(label) + + + # helper function to disable transparency on legend entries + # adapted from https://stackoverflow.com/a/59629242 + def remove_alpha(handle, orig) -> None: + handle.update_from(orig) + handle.set_alpha(1) + + # create legend + legend = jointgrid.ax_joint.legend( + handles, + labels, + handler_map={ + mpl_PathCollection: mpl_HandlerPathCollection(update_func=remove_alpha), + plt.Line2D: mpl_HandlerLine2D(update_func=remove_alpha), + }, # apply helper function + borderaxespad=0, + bbox_to_anchor=(-0.4, 0, 0.2, 1), # place legend to left of plot + ) # apply new handles and labels to plot + legend._legend_box.set_height(legend.get_bbox_to_anchor().height) + + # title background adapted from https://stackoverflow.com/a/76103441 + title = "\n🤕🆚🙂\n" + legend.set_title( + f"{title: ^4}", # pad both sides with spaces to improve centering + # use custom font with monochrome emojis + # because vanilla matplotlib backend doesn't support color bitmap fonts + prop=mpl_FontProperties(fname="../NotoEmoji-Regular.ttf", size=40), + ) + legend._legend_title_box._text.set_bbox( + {"facecolor": "gray", "alpha": 0.3, "lw": 0}, + ) + legend._legend_box.sep = 20 + + # PLOT BUNCHING SMEAR ON JOINT DISTRIBUTION + ########################################################################### + # due to unwanted side effects, must come after legend plot + + max_latency = data["Latency Simsteps Inlet"] + min_latency = data["Latency Simsteps Inlet"] / data["Num Messages Per Pull"] + jointgrid.ax_joint.errorbar( + data=data, + x=x, + y=y, + fmt="none", # don't draw data points + alpha=0.05, + ecolor="lightgray", + yerr=np.vstack( + [ + # below-error height + data["Latency Simsteps Inlet"] - min_latency, + # above-error height + max_latency - data["Latency Simsteps Inlet"], + ], + ), + zorder=-5, + legend=False, + ) From ece4de7b3568ef4f8ae00b22fad6311cb203b4a2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Wed, 1 Nov 2023 01:22:32 -0400 Subject: [PATCH 009/145] Remove redundant code --- conduitpylib/viz/_frame_scatter_subsets.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/conduitpylib/viz/_frame_scatter_subsets.py b/conduitpylib/viz/_frame_scatter_subsets.py index 96e588be04..16c7672e5b 100644 --- a/conduitpylib/viz/_frame_scatter_subsets.py +++ b/conduitpylib/viz/_frame_scatter_subsets.py @@ -59,15 +59,8 @@ def frame_scatter_subsets( ) frame_min_y, frame_max_y = ( - ( - frame_data[y].min(), - frame_data[y].max(), - ) - if log_y - else ( - frame_data[y].min(), - frame_data[y].max(), - ) + frame_data[y].min(), + frame_data[y].max(), ) if log_y: From c5c6a13547dcacc6a55d0600f9498442c328c97f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Wed, 1 Nov 2023 01:24:54 -0400 Subject: [PATCH 010/145] Polish perforamce-semantics plot design --- .../NotoEmoji-Regular.ttf | Bin 1049444 -> 899400 bytes ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 9 + conduitpylib/viz/__init__.py | 2 + .../viz/_performance_semantics_plot.py | 170 +++++++++++------- 4 files changed, 118 insertions(+), 63 deletions(-) diff --git a/binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf b/binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf index 5c8d4194fde782329adec0937b1ae5858b246107..cf1c70105125e41c767e987b5e88119f11fdca95 100644 GIT binary patch delta 65571 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
TyO7@NRQUnBoKfB?_XK*{GbJD5d79gY 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%0D{A+O|DyUd=Gmh< zx5P)*zvmvnV123nKkmW$zq^+j&b{0?&AnxObT$mH;ndT9|HucvI&k>P`Cl7|2mUWU Ca=FC- diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index a20720221d..929b0fee3a 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -3488,6 +3488,15 @@ "df_snapshot_diffs[\"Any Messages Dropped\"] = df_snapshot_diffs[\"Fraction Messages Dropped\"].astype(bool)\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df_snapshot_diffs[\"% Msgs Lost\"] = df_snapshot_diffs[\"Fraction Messages Dropped\"] * 100\n" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 5e90c68faf..a7059b683e 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -2,10 +2,12 @@ from ._frame_scatter_subsets import frame_scatter_subsets from ._performance_semantics_plot import performance_semantics_plot +from ._set_kde_lims import set_kde_lims # adapted from https://stackoverflow.com/a/31079085 __all__ = [ '_frame_scatter_subsets', "_performance_semantics_plot", + "_set_kde_lims", ] diff --git a/conduitpylib/viz/_performance_semantics_plot.py b/conduitpylib/viz/_performance_semantics_plot.py index a627ecc557..0b6fb9eb34 100644 --- a/conduitpylib/viz/_performance_semantics_plot.py +++ b/conduitpylib/viz/_performance_semantics_plot.py @@ -17,29 +17,69 @@ import seaborn as sns from ._frame_scatter_subsets import frame_scatter_subsets +from ._set_kde_lims import set_kde_lims def performance_semantics_plot( data: pd.DataFrame, hue: str, hue_order: typing.Optional[typing.List[str]] = None, - heat: str = "Fraction Messages Dropped", - x: str="Simstep Period Inlet (ns)", - y: str="Latency Simsteps Inlet", + heat: str = "% Msgs Lost", + x: str = "Simstep Period Inlet (ns)", + y: str = "Latency Simsteps Inlet", + linestyles: typing.Optional[typing.List[str]] = None, + palette: typing.Optional[typing.List[str]] = None, + size_inches: typing.Tuple[float, float] = (3.5, 2.5), ) -> sns.JointGrid: hue_order = ["Sans lac-417", "With lac-417"] assert set(hue_order) == set(data[hue].unique()) - palette = ["#648FFF", "#40B0A6"] + if hue_order is None: + hue_order = sorted(data[hue].unique()) + + if linestyles is None: + linestyles = [":", "--"] + + if palette is None: + # alternate palettes: ["#648FFF", "#40B0A6"] & ["#40b07f", "#646eff"] + palette = ["#5c5cff", "#64e0ff"] assert len(palette) == len(hue_order) - jointgrid = sns.JointGrid( + jointgrid = sns.JointGrid(data=data, x=x, y=y, hue=hue, ratio=8, height=8) + + sns.kdeplot( + ax=jointgrid.ax_joint, data=data, x=x, y=y, + alpha=0.4, + cut=10, + fill=True, # remove fill manually below, needed for set_kde_lims hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + palette=palette, + thresh=1e-12, + zorder=100, ) + # ensure that entire KDE is visible + set_kde_lims(jointgrid.ax_joint, log_x=False, log_y=True) + + # set linestyles of marginal KDE outlines + # adapted from https://stackoverflow.com/a/70089200 + for path_collection, linestyle in zip( + jointgrid.ax_joint.collections, + reversed(linestyles), + ): + # need faux fill for set_kde_lims. set + color = path_collection.get_facecolor() + path_collection.set_facecolor("none") + path_collection.set_edgecolor(color) + path_collection.set_linestyle(linestyle) + path_collection.set_linewidth(2) + # PLOT JOINT DISTRIBUTION ########################################################################### # scatterplot observations @@ -49,10 +89,11 @@ def performance_semantics_plot( x=x, y=y, hue=heat, - style="Allocation", - markers=["o", "D"], + markers="D", + # style=hue, + # markers=["o", "D"], palette="flare", - alpha=0.4, + alpha=0.3, ) # set up joint plot axes... @@ -62,31 +103,31 @@ def performance_semantics_plot( # ... set simsteps inlet to log scale jointgrid.ax_joint.set_yscale("log") # ... set simstep period time to zero minimum - jointgrid.ax_joint.set_xlim(xmin=0) + current_xmin = jointgrid.ax_joint.get_xlim()[0] + jointgrid.ax_joint.set_xlim(xmin=min(0, current_xmin)) + # ... set communication latency to at least 0.1 minimum + current_ymin = jointgrid.ax_joint.get_ylim()[0] + jointgrid.ax_joint.set_ylim(ymin=min(0.1, current_ymin)) # ... set axis labels jointgrid.ax_joint.set_xlabel("Update Rate (ns)") jointgrid.ax_joint.set_ylabel("Communication Latency (updates)") - # outline subsets of scatter points - frame_scatter_subsets( - data, - x=x, - y=y, - frame=hue, - ax=jointgrid.ax_joint, - frame_order=hue_order, - log_y=True, - palette=palette, - ) - # PLOT MARGINAL DISTRIBUTIONS ########################################################################### # plot marginal distributions as kernel density estimates - jointgrid.plot_marginals(sns.kdeplot, palette=palette, fill=True, lw=3, alpha=0.1) + jointgrid.plot_marginals( + sns.kdeplot, + alpha=0.1, + fill=True, + lw=3, + palette=palette, + ) + + # now that we have marginals, set figure dimensions + jointgrid.fig.set_size_inches(*size_inches) # set linestyles of marginal KDE outlines # https://stackoverflow.com/a/70089200 - linestyles = ["--", "-"] for line, linestyle in it.chain( zip(jointgrid.ax_marg_x.collections, linestyles), zip(jointgrid.ax_marg_y.collections, linestyles), @@ -94,36 +135,23 @@ def performance_semantics_plot( line.set_linestyle(linestyle) line.set_alpha(0.4) - - # set density to loc scale - jointgrid.ax_marg_x.set_yscale("symlog", linthresh=0.0000000001) - jointgrid.ax_marg_y.set_xscale("symlog", linthresh=0.0001) - - sns.rugplot( - data=data, - ax=jointgrid.ax_marg_x, - x=x, - hue=heat, - palette="flare", - legend=False, - alpha=0.05, - expand_margins=False, - clip_on=False, - height=-0.3, - ) - - sns.rugplot( - data=data, - ax=jointgrid.ax_marg_y, - y=y, - hue=heat, - palette="flare", - legend=False, - alpha=0.3, - expand_margins=False, - clip_on=False, - height=-0.3, - ) + # do manual rugplot because plot_marginals messes up colormapping + for ax, kwarg in ( + (jointgrid.ax_marg_x, {"x": x}), + (jointgrid.ax_marg_y, {"y": y}), + ): + sns.rugplot( + ax=ax, + data=data, + hue=heat, + palette="flare", + legend=False, + alpha=0.03, + expand_margins=False, + clip_on=False, + height=-0.8, + **kwarg, + ) # SET UP LEGEND ########################################################################### @@ -132,10 +160,16 @@ def performance_semantics_plot( ( handles, labels, - ) = jointgrid.ax_joint.get_legend_handles_labels() # get existing handles and labels - empty_patch = mpl_patches.Patch( - color="none", label="Extra label" - ) + ) = ( + jointgrid.ax_joint.get_legend_handles_labels() + ) # get existing handles and labels + empty_patch = mpl_patches.Patch(color="none", label="Extra label") + + # don't know why, but have to manulaly add heat title + # when scatter style is disabled + handles = [empty_patch, *handles] + labels = [heat, *labels] + handles.append(empty_patch) labels.append(hue) # ... then add legend entries manually @@ -151,12 +185,11 @@ def performance_semantics_plot( handles.append(example_patch) labels.append(label) - # helper function to disable transparency on legend entries # adapted from https://stackoverflow.com/a/59629242 def remove_alpha(handle, orig) -> None: handle.update_from(orig) - handle.set_alpha(1) + handle.set_alpha(1.0) # create legend legend = jointgrid.ax_joint.legend( @@ -167,17 +200,17 @@ def remove_alpha(handle, orig) -> None: plt.Line2D: mpl_HandlerLine2D(update_func=remove_alpha), }, # apply helper function borderaxespad=0, - bbox_to_anchor=(-0.4, 0, 0.2, 1), # place legend to left of plot + bbox_to_anchor=(-0.4, -0.1, 0.1, 1.2), # place legend to left of plot ) # apply new handles and labels to plot legend._legend_box.set_height(legend.get_bbox_to_anchor().height) # title background adapted from https://stackoverflow.com/a/76103441 - title = "\n🤕🆚🙂\n" + title = "🙂/🤕" legend.set_title( - f"{title: ^4}", # pad both sides with spaces to improve centering + title, # use custom font with monochrome emojis # because vanilla matplotlib backend doesn't support color bitmap fonts - prop=mpl_FontProperties(fname="../NotoEmoji-Regular.ttf", size=40), + prop=mpl_FontProperties(fname="../NotoEmoji-Regular4.ttf", size=25), ) legend._legend_title_box._text.set_bbox( {"facecolor": "gray", "alpha": 0.3, "lw": 0}, @@ -208,3 +241,14 @@ def remove_alpha(handle, orig) -> None: zorder=-5, legend=False, ) + + # FINALIZE + ########################################################################### + for ax in jointgrid.ax_marg_x, jointgrid.ax_marg_y: + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + + jointgrid.ax_joint.set_ylim(top=jointgrid.ax_joint.get_ylim()[1] * 3) + jointgrid.ax_joint.set_xlim(right=jointgrid.ax_joint.get_xlim()[1] * 1.1) + + plt.tight_layout() From 9a51e83e1f5164bd023eb428471221230149579e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 3 Nov 2023 11:45:58 -0400 Subject: [PATCH 011/145] Implement, test hash_with_lax_fallback --- .../test_utils/test_hash_with_lax_fallback.py | 74 +++++++++++++++++++ conduitpylib/utils/__init__.py | 2 + conduitpylib/utils/hash_with_lax_fallback.py | 35 +++++++++ 3 files changed, 111 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_hash_with_lax_fallback.py create mode 100644 conduitpylib/utils/hash_with_lax_fallback.py diff --git a/conduitpylib/test/test_utils/test_hash_with_lax_fallback.py b/conduitpylib/test/test_utils/test_hash_with_lax_fallback.py new file mode 100644 index 0000000000..afda2b26be --- /dev/null +++ b/conduitpylib/test/test_utils/test_hash_with_lax_fallback.py @@ -0,0 +1,74 @@ +import pytest +import pandas as pd +import numpy as np + +from conduitpylib.utils import hash_with_lax_fallback + + +# Test with hashable objects +@pytest.mark.parametrize("obj, expected", [ + (42, hash(42)), # integer + ("string", hash("string")), # string + ((1, 2), hash((1, 2))), # tuple +]) +def test_hashable_objects(obj, expected): + assert hash_with_lax_fallback(obj) == expected + +# Test with Pandas objects +def test_pandas_objects(): + df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]}) + series = pd.Series([1, 2, 3]) + + df_hash = hash_with_lax_fallback(df) + series_hash = hash_with_lax_fallback(series) + + # The hashes should not be the default id hashes + assert df_hash != id(df) + assert series_hash != id(series) + + # Re-hashing should give the same result + assert df_hash == hash_with_lax_fallback(df) + assert series_hash == hash_with_lax_fallback(series) + +# Test with Numpy arrays +def test_numpy_arrays(): + arr = np.array([1, 2, 3]) + + arr_hash = hash_with_lax_fallback(arr) + + # The hash should not be the default id hash + assert arr_hash != id(arr) + + # Re-hashing should give the same result + assert arr_hash == hash_with_lax_fallback(arr) + +# Test with unhashable and complex objects +def test_unhashable_objects(): + # Use a list as an example of unhashable object + unhashable = [1, 2, 3] + + unhashable_hash = hash_with_lax_fallback(unhashable) + + # The hash should not be the default id hash + assert unhashable_hash != id(unhashable) + + # The hash should be consistent for the same object content + assert unhashable_hash == hash_with_lax_fallback([1, 2, 3]) + +# Test fallback for an object that fails both hash and pickle +class UnhashableAndUnpickleable: + def __eq__(self, other): + return isinstance(other, UnhashableAndUnpickleable) + + def __hash__(self): + raise TypeError + + def __reduce__(self): + raise TypeError + +def test_unhashable_unpickleable_fallback(): + obj = UnhashableAndUnpickleable() + fallback_hash = hash_with_lax_fallback(obj) + + # Should fall back to using id for hashing + assert fallback_hash == id(obj) diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 29364c7fbf..c3393bd751 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -6,6 +6,7 @@ count_outliers, count_proportion_outliers, ) +from .hash_with_lax_fallback import hash_with_lax_fallback from .strip_end import strip_end # adapted from https://stackoverflow.com/a/31079085 @@ -14,5 +15,6 @@ 'count_nonoutliers', 'count_outliers', 'count_proportion_outliers', + 'hash_with_lax_fallback', 'strip_end', ] diff --git a/conduitpylib/utils/hash_with_lax_fallback.py b/conduitpylib/utils/hash_with_lax_fallback.py new file mode 100644 index 0000000000..376c4fa68b --- /dev/null +++ b/conduitpylib/utils/hash_with_lax_fallback.py @@ -0,0 +1,35 @@ +import contextlib +import hashlib +import pickle +import typing + +import numpy as np +import pandas as pd + + +def hash_with_lax_fallback(obj: typing.Any) -> int: + """Hash an object by value, falling back to an arbitrary hash by instance. + + Parameters + ---------- + obj : Any + The object to hash. + + Returns + ------- + int + The computed hash. + """ + with contextlib.suppress(TypeError): + return hash(obj) + + if isinstance(obj, (pd.DataFrame, pd.Series)): + return hash(tuple(pd.util.hash_pandas_object(obj))) + + elif isinstance(obj, np.ndarray): + return hash(hashlib.sha256(obj).hexdigest()) + + with contextlib.suppress(Exception): + return hashlib.sha256(pickle.dumps(obj)).hexdigest() + + return id(obj) From 58bf830e1ae5d6da6538f5e247ee2b902a6e330b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 3 Nov 2023 12:55:43 -0400 Subject: [PATCH 012/145] Implement, test UnequalSentinel --- .../test/test_utils/test_UnequalSentinel.py | 20 +++++++++++++++++++ conduitpylib/utils/UnequalSentinel.py | 11 ++++++++++ conduitpylib/utils/__init__.py | 2 ++ 3 files changed, 33 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_UnequalSentinel.py create mode 100644 conduitpylib/utils/UnequalSentinel.py diff --git a/conduitpylib/test/test_utils/test_UnequalSentinel.py b/conduitpylib/test/test_utils/test_UnequalSentinel.py new file mode 100644 index 0000000000..f68429b2a8 --- /dev/null +++ b/conduitpylib/test/test_utils/test_UnequalSentinel.py @@ -0,0 +1,20 @@ +import typing + +import numpy as np +import pytest + +from conduitpylib.utils import UnequalSentinel + + +def test_self(): + s = UnequalSentinel() + assert s != s and not s == s + + +@pytest.mark.parametrize( + "other", [1, 0, "asdf", "", np.nan, None, True, False, UnequalSentinel()] +) +def test_other(other: typing.Any): + s = UnequalSentinel() + assert s != other and not s == other + assert other != s and not other == s diff --git a/conduitpylib/utils/UnequalSentinel.py b/conduitpylib/utils/UnequalSentinel.py new file mode 100644 index 0000000000..8aaf1ca234 --- /dev/null +++ b/conduitpylib/utils/UnequalSentinel.py @@ -0,0 +1,11 @@ +import typing + + +class UnequalSentinel: + """Sentinel value that is unequal to everything, including itself.""" + + def __eq__(self: "UnequalSentinel", other: typing.Any) -> bool: + return False + + def __ne__(self: "UnequalSentinel", other: typing.Any) -> bool: + return True diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index c3393bd751..43b37904fe 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -8,6 +8,7 @@ ) from .hash_with_lax_fallback import hash_with_lax_fallback from .strip_end import strip_end +from .UnequalSentinel import UnequalSentinel # adapted from https://stackoverflow.com/a/31079085 __all__ = [ @@ -17,4 +18,5 @@ 'count_proportion_outliers', 'hash_with_lax_fallback', 'strip_end', + 'UnequalSentinel', ] From e5dd6d289176b9bb157bab26f026665c124bb54e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 3 Nov 2023 14:12:29 -0400 Subject: [PATCH 013/145] Implement, test lru_cache_universal --- .../test_utils/test_lru_cache_universal.py | 142 ++++++++++++++++++ conduitpylib/utils/__init__.py | 3 + conduitpylib/utils/lru_cache_universal.py | 81 ++++++++++ 3 files changed, 226 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_lru_cache_universal.py create mode 100644 conduitpylib/utils/lru_cache_universal.py diff --git a/conduitpylib/test/test_utils/test_lru_cache_universal.py b/conduitpylib/test/test_utils/test_lru_cache_universal.py new file mode 100644 index 0000000000..8e2960c1f1 --- /dev/null +++ b/conduitpylib/test/test_utils/test_lru_cache_universal.py @@ -0,0 +1,142 @@ +import copy +import pickle + +import pytest + +from conduitpylib.utils import lru_cache_universal + + +# testing helper +class MutableObj: + def __init__(self, value): + self.value = value + + def __eq__(self, other): + return self.value == other.value + + def __hash__(self): + return hash(self.value) + + def __add__(self, other): + return MutableObj(self.value + other.value) + + +class UnhashUnpickle: + def __add__(self, other): + return UnhashUnpickle() + + def __eq__(self, other): + return isinstance(other, UnhashUnpickle) + + def __reduce__(self): + raise pickle.PicklingError() + + +@pytest.mark.parametrize( + "args, kwargs, maxsize, expected_result", + [ + ## ARGS + # Test with hashable arguments + ((1, 2), {}, None, 3), + # Test with mutable but hashable arguments + ((MutableObj(1), MutableObj(2)), {}, None, MutableObj(3)), + # Test cache with a maxsize of 1, expecting eviction of the first key + ((1, 2), {}, 1, 3), + # Test cache with None as maxsize, which means unlimited + ((1, 2), {}, None, 3), + # Test with unhashable arguments + (([1], [2]), {}, None, [1, 2]), + # Test with unhashble and unpickleable arguments + ((UnhashUnpickle(), UnhashUnpickle()), {}, None, UnhashUnpickle()), + ## KWARGS + # Test with hashable arguments + (tuple(), {"a": 1, "b": 2}, None, 3), + # Test with mutable but hashable arguments + (tuple(), {"a": MutableObj(1), "b": MutableObj(2)}, None, MutableObj(3)), + # Test cache with a maxsize of 1, expecting eviction of the first key + (tuple(), {"a": 1, "b": 2}, 1, 3), + # Test cache with None as maxsize, which means unlimited + (tuple(), {"a": 1, "b": 2}, None, 3), + # Test with unhashable arguments + (tuple(), {"a": [1], "b": [2]}, None, [1, 2]), + # Test with unhashble and unpickleable arguments + ( + tuple(), + {"a": UnhashUnpickle(), "b": UnhashUnpickle()}, + None, + UnhashUnpickle(), + ), + ## ARGS AND KWARGS + # Test with hashable arguments + ((1,), {"b": 2}, None, 3), + # Test with mutable but hashable arguments + ((MutableObj(1),), {"b": MutableObj(2)}, None, MutableObj(3)), + # Test cache with a maxsize of 1, expecting eviction of the first key + ((1,), {"b": 2}, 1, 3), + # Test cache with None as maxsize, which means unlimited + ((1,), {"b": 2}, None, 3), + # Test with unhashable arguments + (([1],), {"b": [2]}, None, [1, 2]), + # Test with unhashble and unpickleable arguments + ((UnhashUnpickle(),), {"b": UnhashUnpickle()}, None, UnhashUnpickle()), + ], +) +def test_lru_cache_universal( + args, + kwargs, + maxsize, + expected_result, +): + def test_function(a, b): + return a + b + + cached_test_function = lru_cache_universal(maxsize)(test_function) + for __ in range(2): + assert cached_test_function(*args, **kwargs) == expected_result + + try: + args = copy.deepcopy(args) + kwargs = copy.deepcopy(kwargs) + assert cached_test_function(*args, **kwargs) == expected_result + except Exception: + uutup = (UnhashUnpickle(), UnhashUnpickle()) + if args == uutup: + assert cached_test_function(*uutup) == expected_result + + +def test_cache_eviction_policy(): + call_log = [] + + def logged_test_function(*args, **kwargs): + call_log.append((args, kwargs)) + + cached_test_function = lru_cache_universal(2)(logged_test_function) + + assert len(call_log) == 0 + cached_test_function(1, 2) + assert len(call_log) == 1 + cached_test_function(2, 3) + assert len(call_log) == 2 + cached_test_function(1, 2) + assert len(call_log) == 2 + cached_test_function(2, 3) + assert len(call_log) == 2 + cached_test_function(3, 4) + assert len(call_log) == 3 + cached_test_function(2, 3) + assert len(call_log) == 3 + cached_test_function(1, 2) + assert len(call_log) == 4 + + +def test_cache_clear(): + def test_function(*args, **kwargs): + pass + + cached_test_function = lru_cache_universal(2)(test_function) + + cached_test_function(1, 2) + cached_test_function(2, 3) + assert len(cached_test_function.cache) == 2 + cached_test_function.cache_clear() + assert len(cached_test_function.cache) == 0 diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 43b37904fe..3c402ecbb4 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -7,9 +7,11 @@ count_proportion_outliers, ) from .hash_with_lax_fallback import hash_with_lax_fallback +from .lru_cache_universal import lru_cache_universal from .strip_end import strip_end from .UnequalSentinel import UnequalSentinel + # adapted from https://stackoverflow.com/a/31079085 __all__ = [ 'consolidate_merge', @@ -17,6 +19,7 @@ 'count_outliers', 'count_proportion_outliers', 'hash_with_lax_fallback', + 'lru_cache_universal', 'strip_end', 'UnequalSentinel', ] diff --git a/conduitpylib/utils/lru_cache_universal.py b/conduitpylib/utils/lru_cache_universal.py new file mode 100644 index 0000000000..1987a594fc --- /dev/null +++ b/conduitpylib/utils/lru_cache_universal.py @@ -0,0 +1,81 @@ +import contextlib +import copy +import functools +import typing + +from .hash_with_lax_fallback import hash_with_lax_fallback +from .UnequalSentinel import UnequalSentinel + + +def _robust_copy(obj: typing.Any) -> typing.Any: + with contextlib.suppress(Exception): + return copy.deepcopy(obj) + with contextlib.suppress(Exception): + return copy.copy(obj) + with contextlib.suppress(Exception): + return obj + + +def lru_cache_universal(maxsize: typing.Optional[int] = 64) -> typing.Callable: + """Memoizing decorator that supports calls with mutable and unhashable + arguments. + + Mutable arguments will be hashed by value and unhashable arguments will be + hashed by instance id. (As such, calls with unhashable arguments that + compare equal may result in a cache miss.) + + Parameters + ---------- + maxsize : int or None, default 64 + The cache size limit, if any. + + Returns + ------- + function + Memoizing decorator. + """ + + def decorator(func: typing.Callable) -> typing.Callable: + cache = dict() + + @functools.wraps(func) + def wrapper(*args, **kwargs) -> typing.Any: + # prepare keys + hashable_args = tuple(map(hash_with_lax_fallback, args)) + hashable_kwargs = frozenset( + zip( + kwargs.keys(), + map(hash_with_lax_fallback, kwargs.values()), + ), + ) + query_lookup_key = (hashable_args, hashable_kwargs) + query_full_key = (args, kwargs) + + # try cache lookup + cached_full_key, cached_result = cache.get( + query_lookup_key, + (UnequalSentinel(), None), + ) + + # cache hit! + if cached_full_key == query_full_key: + return _robust_copy(cached_result) + + # ... cache miss! + # trim cache if at max size + if maxsize is not None and len(cache) >= maxsize: + # python iterates dicts in insertion order + del cache[next(iter(cache))] + + # compute result and cache it + call_result = func(*args, **kwargs) + cache[query_lookup_key] = (query_full_key, call_result) + + return _robust_copy(call_result) + + wrapper.cache = cache + wrapper.cache_clear = cache.clear + + return wrapper + + return decorator From e7692f7b30d1327267c687ec43081dc4d7577c3c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 3 Nov 2023 16:48:29 -0400 Subject: [PATCH 014/145] Impl, test seaborn kde-caching monkeypatch --- .../test_seaborn_monkeypatch_kdecache.py | 24 ++++++++++ conduitpylib/utils/__init__.py | 8 ++++ conduitpylib/utils/equals_by_value.py | 31 +++++++++++++ conduitpylib/utils/lru_cache_universal.py | 30 ++++++++++++- .../utils/seaborn_monkeypatch_kdecache.py | 44 +++++++++++++++++++ 5 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 conduitpylib/test/test_utils/test_seaborn_monkeypatch_kdecache.py create mode 100644 conduitpylib/utils/equals_by_value.py create mode 100644 conduitpylib/utils/seaborn_monkeypatch_kdecache.py diff --git a/conduitpylib/test/test_utils/test_seaborn_monkeypatch_kdecache.py b/conduitpylib/test/test_utils/test_seaborn_monkeypatch_kdecache.py new file mode 100644 index 0000000000..18064b3b0b --- /dev/null +++ b/conduitpylib/test/test_utils/test_seaborn_monkeypatch_kdecache.py @@ -0,0 +1,24 @@ +import seaborn as sns + +from conduitpylib.utils import seaborn_monkeypatched_kdecache + + +def test_seaborn_monkeypatch_kdecache() -> None: + geyser = sns.load_dataset("geyser") + + with seaborn_monkeypatched_kdecache(): + sns.kdeplot(data=geyser, x="waiting", y="duration", hue="kind") + sns.kdeplot(data=geyser, x="waiting", y="duration", hue="kind") + + cache_info = sns._statistics.KDE.__call__.cache_info + assert cache_info["hits"] > 0 and cache_info["misses"] > 0 + + prehits = cache_info["hits"] + sns.kdeplot(data=geyser, x="waiting", y="duration") + assert cache_info["hits"] == prehits + + sns.kdeplot(data=geyser, x="waiting", y="duration") + assert cache_info["hits"] > prehits + + assert not hasattr(sns._statistics.KDE.__call__, "cache_info") + sns.kdeplot(data=geyser, x="waiting", y="duration", hue="kind") diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 3c402ecbb4..050f45ed54 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -8,6 +8,11 @@ ) from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal +from .seaborn_monkeypatch_kdecache import ( + seaborn_monkeypatch_kdecache, + seaborn_monkeypatched_kdecache, + seaborn_unmonkeypatch_kdecache, +) from .strip_end import strip_end from .UnequalSentinel import UnequalSentinel @@ -20,6 +25,9 @@ 'count_proportion_outliers', 'hash_with_lax_fallback', 'lru_cache_universal', + 'seaborn_monkeypatch_kdecache', + 'seaborn_monkeypatched_kdecache', + 'seaborn_unmonkeypatch_kdecache', 'strip_end', 'UnequalSentinel', ] diff --git a/conduitpylib/utils/equals_by_value.py b/conduitpylib/utils/equals_by_value.py new file mode 100644 index 0000000000..d7c476b08c --- /dev/null +++ b/conduitpylib/utils/equals_by_value.py @@ -0,0 +1,31 @@ +import contextlib +import typing + +import numpy as np +import pandas as pd + +def _equals_by_value(obj1: typing.Any, obj2: typing.Any) -> bool: + + # Handle comparison between pandas DataFrames or Series + if all(isinstance(o, pd.Series) for o in (obj1, obj2)): + return np.allclose(obj1, obj2) + + elif all(isinstance(o, pd.DataFrame) for o in (obj1, obj2)): + return obj1.equals(obj2) + + # Handle comparison between numpy ndarrays + elif all(isinstance(o, np.ndarray) for o in (obj1, obj2)): + return np.all_close(obj1, obj2) + + # Fall back to 'is' comparison for NaN types + elif pd.isnull(obj1) and pd.isnull(obj2): + return True + + # Handle everything else with the '==' operator + else: + return obj1 == obj2 + + +def equals_by_value(obj1: typing.Any, obj2: typing.Any) -> bool: + with contextlib.suppress(ValueError): + return _equals_by_value(obj1, obj2) diff --git a/conduitpylib/utils/lru_cache_universal.py b/conduitpylib/utils/lru_cache_universal.py index 1987a594fc..c86d76389a 100644 --- a/conduitpylib/utils/lru_cache_universal.py +++ b/conduitpylib/utils/lru_cache_universal.py @@ -3,6 +3,7 @@ import functools import typing +from .equals_by_value import equals_by_value from .hash_with_lax_fallback import hash_with_lax_fallback from .UnequalSentinel import UnequalSentinel @@ -37,6 +38,10 @@ def lru_cache_universal(maxsize: typing.Optional[int] = 64) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: cache = dict() + info = { + "hits": 0, + "misses": 0, + } @functools.wraps(func) def wrapper(*args, **kwargs) -> typing.Any: @@ -57,11 +62,33 @@ def wrapper(*args, **kwargs) -> typing.Any: (UnequalSentinel(), None), ) - # cache hit! + # try indexing by lookupkey if cached_full_key == query_full_key: + # cache hit! + info["hits"] += 1 return _robust_copy(cached_result) + # try searching through all full keys + for cached_full_key, cached_result in cache.values(): + cached_args, cached_kwargs = cached_full_key + + if ( + all( + equals_by_value(arg, cached_arg) + for arg, cached_arg in zip(args, cached_args) + ) + and len(cached_kwargs) == len(hashable_kwargs) + and all( + equals_by_value(kwargs[key], cached_kwargs[key]) + for key in kwargs.keys() + ) + ): + # cache hit! + info["hits"] += 1 + return _robust_copy(cached_result) + # ... cache miss! + info["misses"] += 1 # trim cache if at max size if maxsize is not None and len(cache) >= maxsize: # python iterates dicts in insertion order @@ -75,6 +102,7 @@ def wrapper(*args, **kwargs) -> typing.Any: wrapper.cache = cache wrapper.cache_clear = cache.clear + wrapper.cache_info = info return wrapper diff --git a/conduitpylib/utils/seaborn_monkeypatch_kdecache.py b/conduitpylib/utils/seaborn_monkeypatch_kdecache.py new file mode 100644 index 0000000000..47ad1436da --- /dev/null +++ b/conduitpylib/utils/seaborn_monkeypatch_kdecache.py @@ -0,0 +1,44 @@ +import contextlib + +import seaborn as sns + +from .equals_by_value import equals_by_value +from .lru_cache_universal import lru_cache_universal + + +original_eq_func = sns._statistics.KDE.__eq__ +original_kde_func = sns._statistics.KDE.__call__ + + +def patched_eq_func(self, other): + if type(self) == type(other): + sd, od = self.__dict__, other.__dict__ + if len(sd) != len(od): + return False + for key in sd: + if key in od and equals_by_value(sd[key], od[key]): + continue + else: + return False + + return True + + +patched_kde_func = lru_cache_universal()(original_kde_func) + + +def seaborn_monkeypatch_kdecache() -> None: + sns._statistics.KDE.__call__ = patched_kde_func + sns._statistics.KDE.__eq__ = patched_eq_func + + +def seaborn_unmonkeypatch_kdecache() -> None: + sns._statistics.KDE.__call__ = original_kde_func + sns._statistics.KDE.__eq__ = original_eq_func + + +@contextlib.contextmanager +def seaborn_monkeypatched_kdecache(): + seaborn_monkeypatch_kdecache() + yield + seaborn_unmonkeypatch_kdecache() From 8ad85a4b1a5c6a92d53fb49ff892f2e89969acff Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 3 Nov 2023 19:03:53 -0400 Subject: [PATCH 015/145] Bugfix: don't override hue_order --- conduitpylib/viz/_performance_semantics_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_plot.py b/conduitpylib/viz/_performance_semantics_plot.py index 0b6fb9eb34..66f51aae8e 100644 --- a/conduitpylib/viz/_performance_semantics_plot.py +++ b/conduitpylib/viz/_performance_semantics_plot.py @@ -31,7 +31,7 @@ def performance_semantics_plot( palette: typing.Optional[typing.List[str]] = None, size_inches: typing.Tuple[float, float] = (3.5, 2.5), ) -> sns.JointGrid: - hue_order = ["Sans lac-417", "With lac-417"] + assert set(hue_order) == set(data[hue].unique()) if hue_order is None: From a5975eb5b9c35e21a65d0984a6a2be53552a8119 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 13:29:50 -0500 Subject: [PATCH 016/145] Fix bad __all__ in __init__ --- conduitpylib/viz/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index a7059b683e..2144e2cf14 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -7,7 +7,7 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ - '_frame_scatter_subsets', - "_performance_semantics_plot", - "_set_kde_lims", + "frame_scatter_subsets", + "performance_semantics_plot", + "set_kde_lims", ] From e5d7ccc4c66d112c9959b66f94a157951f0f7d65 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 13:35:19 -0500 Subject: [PATCH 017/145] Impl, test round_to_multiple util --- .../test/test_utils/test_round_to_multiple.py | 13 +++++++++++++ conduitpylib/utils/__init__.py | 2 ++ conduitpylib/utils/round_to_multiple.py | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_round_to_multiple.py create mode 100644 conduitpylib/utils/round_to_multiple.py diff --git a/conduitpylib/test/test_utils/test_round_to_multiple.py b/conduitpylib/test/test_utils/test_round_to_multiple.py new file mode 100644 index 0000000000..3df747c6eb --- /dev/null +++ b/conduitpylib/test/test_utils/test_round_to_multiple.py @@ -0,0 +1,13 @@ +from conduitpylib.utils import round_to_multiple + + +def test_round_to_multiple(): + # Normal cases + assert round_to_multiple(10.5, 2) == 10 + assert round_to_multiple(15.3, 5) == 15 + assert round_to_multiple(2.6, 1) == 3 + + # Edge cases + assert round_to_multiple(0, 1) == 0 + assert round_to_multiple(-5.3, 2) == -6 + assert round_to_multiple(1000000.7, 1000) == 1000000 diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 050f45ed54..88003221c5 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -8,6 +8,7 @@ ) from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal +from .round_to_multiple import round_to_multiple from .seaborn_monkeypatch_kdecache import ( seaborn_monkeypatch_kdecache, seaborn_monkeypatched_kdecache, @@ -25,6 +26,7 @@ 'count_proportion_outliers', 'hash_with_lax_fallback', 'lru_cache_universal', + 'round_to_multiple', 'seaborn_monkeypatch_kdecache', 'seaborn_monkeypatched_kdecache', 'seaborn_unmonkeypatch_kdecache', diff --git a/conduitpylib/utils/round_to_multiple.py b/conduitpylib/utils/round_to_multiple.py new file mode 100644 index 0000000000..11c0193fc2 --- /dev/null +++ b/conduitpylib/utils/round_to_multiple.py @@ -0,0 +1,18 @@ +def round_to_multiple(number: float, multiple: int) -> int: + """Round to the nearest multiple of an integer. + + Parameters + ---------- + number : float + The number to be rounded. + multiple : float + The multiple to which the number will be rounded. + + Returns + ------- + float + The number rounded to the nearest multiple. + """ + res = int(round(number / multiple) * multiple) + assert res % multiple == 0 + return res From c7e475e3775ad3800869275adc4a0c2d036f06b3 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 13:35:53 -0500 Subject: [PATCH 018/145] Bugfix: use robust equals for Pandas support --- conduitpylib/utils/lru_cache_universal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/utils/lru_cache_universal.py b/conduitpylib/utils/lru_cache_universal.py index c86d76389a..58133d7719 100644 --- a/conduitpylib/utils/lru_cache_universal.py +++ b/conduitpylib/utils/lru_cache_universal.py @@ -63,7 +63,7 @@ def wrapper(*args, **kwargs) -> typing.Any: ) # try indexing by lookupkey - if cached_full_key == query_full_key: + if equals_by_value(cached_full_key, query_full_key): # cache hit! info["hits"] += 1 return _robust_copy(cached_result) From a3ef533e67420319965c2caad921b72b14adbef0 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 14:59:42 -0500 Subject: [PATCH 019/145] Implement, test splice --- conduitpylib/test/test_utils/test_splice.py | 29 ++++++++++++++++++ conduitpylib/utils/__init__.py | 2 ++ conduitpylib/utils/splice.py | 33 +++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_splice.py create mode 100644 conduitpylib/utils/splice.py diff --git a/conduitpylib/test/test_utils/test_splice.py b/conduitpylib/test/test_utils/test_splice.py new file mode 100644 index 0000000000..e60eac89a3 --- /dev/null +++ b/conduitpylib/test/test_utils/test_splice.py @@ -0,0 +1,29 @@ +from conduitpylib.utils import splice + + +def test_splice_removal_only(): + assert splice("Hello world", (5, 11)) == "Hello" + + +def test_splice_insertion_only(): + assert splice("123456789", (3, 3), "ABC") == "123ABC456789" + + +def test_splice_removal_and_insertion(): + assert splice("Hello world", (0, 5), "Goodbye") == "Goodbye world" + + +def test_splice_empty_string(): + assert splice("", (0, 0), "Hello") == "Hello" + + +def test_splice_full_replacement(): + assert splice("Hi", (0, 2), "Hello") == "Hello" + + +def test_splice_out_of_bounds(): + assert splice("Hello", (0, 15)) == "" + + +def test_splice_negative_indices(): + splice("Hello", (-3, -1)) diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 88003221c5..0df1c3be54 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -14,6 +14,7 @@ seaborn_monkeypatched_kdecache, seaborn_unmonkeypatch_kdecache, ) +from .splice import splice from .strip_end import strip_end from .UnequalSentinel import UnequalSentinel @@ -30,6 +31,7 @@ 'seaborn_monkeypatch_kdecache', 'seaborn_monkeypatched_kdecache', 'seaborn_unmonkeypatch_kdecache', + 'splice', 'strip_end', 'UnequalSentinel', ] diff --git a/conduitpylib/utils/splice.py b/conduitpylib/utils/splice.py new file mode 100644 index 0000000000..30be40eff9 --- /dev/null +++ b/conduitpylib/utils/splice.py @@ -0,0 +1,33 @@ +import typing + + +def splice(string: str, span: typing.Tuple[int, int], insert: str = "") -> str: + """Remove index span from string and optionally insert new content. + + Parameters + ---------- + string : str + The original string to be spliced. + span : tuple[int, int] + A tuple indicating the start and end indices for the splice operation. + + The start index is inclusive and the end index is exclusive. + insert : str, default "" + The string to be inserted in place of the removed span. + + Defaults to an empty string, i.e., simple removal. + + Returns + ------- + str + The spliced string after removal and insert operation. + + Examples + -------- + >>> splice("Hello world", (1, 6)) + 'Hworld' + >>> splice("Hello world", (0, 5), "Goodbye") + 'Goodbye world' + """ + start, end = span + return string[:start] + insert + string[end:] From dda2b4ea84b6cadffbde7b9ae1d5e49686a6be6a Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 15:34:32 -0500 Subject: [PATCH 020/145] Impl, test compact_xaxis_units --- conduitpylib/test/test_viz/__init__.py | 0 .../test/test_viz/test_compact_xaxis_units.py | 73 ++++++++++++ conduitpylib/viz/__init__.py | 2 + conduitpylib/viz/_compact_xaxis_units.py | 105 ++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 conduitpylib/test/test_viz/__init__.py create mode 100644 conduitpylib/test/test_viz/test_compact_xaxis_units.py create mode 100644 conduitpylib/viz/_compact_xaxis_units.py diff --git a/conduitpylib/test/test_viz/__init__.py b/conduitpylib/test/test_viz/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/conduitpylib/test/test_viz/test_compact_xaxis_units.py b/conduitpylib/test/test_viz/test_compact_xaxis_units.py new file mode 100644 index 0000000000..9aa38614ca --- /dev/null +++ b/conduitpylib/test/test_viz/test_compact_xaxis_units.py @@ -0,0 +1,73 @@ +from matplotlib import pyplot as plt + +from conduitpylib.viz import compact_xaxis_units + + +def test_prefix_removal(): + # setup + ax = plt.gca() + ax.ticklabel_format(style="sci", scilimits=(-2, 2)), + ax.plot([1000, 2000, 3000], [1, 2, 3]) + ax.set_xlabel("Time (ms)") + + # apply + compact_xaxis_units(ax, base_unit="s") + + # verify + expected_label = "Time (s)" + assert ax.get_xlabel() == expected_label + + # clean up + plt.clf() + + +def test_prefix_addition(): + # setup + ax = plt.gca() + ax.ticklabel_format(style="sci", scilimits=(-2, 2)), + ax.plot([1000, 2000, 3000], [1, 2, 3]) + ax.set_xlabel("Weight (g)") + # apply + compact_xaxis_units(ax, base_unit="g") + + # verify + expected_label = "Weight (kg)" + assert ax.get_xlabel() == expected_label + + # clean up + plt.clf() + + +def test_prefix_nop(): + # setup + ax = plt.gca() + ax.ticklabel_format(style="sci", scilimits=(-2, 2)), + ax.plot([1, 2, 3], [1, 2, 3]) + ax.set_xlabel("Weight (g)") + # apply + compact_xaxis_units(ax, base_unit="g") + + # verify + expected_label = "Weight (g)" + assert ax.get_xlabel() == expected_label + + # clean up + plt.clf() + + +def test_nanoseconds_to_milliseconds(): + # setup + ax = plt.gca() + ax.ticklabel_format(style="sci", scilimits=(-2, 2)), + ax.plot([1e6, 2e6, 3e6], [1, 2, 3]) + ax.set_xlabel("Time (ns)") + + # apply + compact_xaxis_units(ax, base_unit="s") + + # verify + expected_label = "Time (ms)" + assert ax.get_xlabel() == expected_label + + # clean up + plt.clf() diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 2144e2cf14..57ab01fdcd 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -1,5 +1,6 @@ """Visualization tools.""" +from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets from ._performance_semantics_plot import performance_semantics_plot from ._set_kde_lims import set_kde_lims @@ -7,6 +8,7 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ + "compact_xaxis_units", "frame_scatter_subsets", "performance_semantics_plot", "set_kde_lims", diff --git a/conduitpylib/viz/_compact_xaxis_units.py b/conduitpylib/viz/_compact_xaxis_units.py new file mode 100644 index 0000000000..78031b4a31 --- /dev/null +++ b/conduitpylib/viz/_compact_xaxis_units.py @@ -0,0 +1,105 @@ +import re + +from bidict import frozenbidict +from matplotlib import axis +import numpy as np + +from ..utils import round_to_multiple, splice + +_si_prefixes = frozenbidict( + { + "Y": 24, # yotta + "Z": 21, # zetta + "E": 18, # exa + "P": 15, # peta + "T": 12, # tera + "G": 9, # giga + "M": 6, # mega + "k": 3, # kilo + "": 0, # base + "m": -3, # milli + "u": -6, # micro + "n": -9, # nano + "p": -12, # pico + "f": -15, # femto + "a": -18, # atto + "z": -21, # zepto + "y": -24, # yocto + }, +) + + +def compact_xaxis_units( + ax: axis.Axis, + base_unit: str = "s", + regex_pattern_template: str = r"\((.*?){base_unit}\)", +) -> None: + r"""Adjusts the units on the x-axis of a matplotlib axis object to a more + compact form. + + This function finds the multiplier (such as 10^3, 10^6, etc.) used by + matplotlib for the axis, identifies the current unit prefix (like k for + kilo, M for mega), and then consolidates these into a new, more compact unit + prefix. This is particularly useful for graphs where the axis values are + very large or very small, and a more readable unit is desired. + + Parameters + ---------- + ax : axis.Axis + Axis object whose x-axis units are to be compacted inplace. + base_unit : str, default "s" + The base unit (without prefix) for the axis. + regex_pattern_template : str, default r"\((.*?){base_unit}\)" + A regular expression template used to identify and extract the unit + prefix from the axis label. + + The template must contain `{base_unit}` as a + placeholder for the actual base unit. Default matches parenthesized expressions like "(ks)" for kiloseconds. + """ + regex_pattern = regex_pattern_template.format(base_unit=base_unit) + regex = re.compile(regex_pattern) + + # force population of + fig = ax.get_figure() + fig.canvas.draw() + + # get unit multiplier chosen by matplotlib + offset_text = ax.xaxis.get_offset_text() + if offset_text is None: # handle unit (i.e., non) multiplier + return + offset_string = offset_text.get_text() + if offset_string == "": # handle unit (i.e., non) multiplier + return + offset_amount = float(offset_string) + + assert str(offset_amount).count("1") == 1 # power of 10 + + # get unit prefix and multiplier in axis label + old_label_string = ax.get_xlabel() + (old_prefix_match,) = regex.finditer(old_label_string) + old_prefix = old_prefix_match.group(1) + old_multiplier_pow = _si_prefixes[old_prefix] + old_multiplier = 10.0**old_multiplier_pow + + # calculate new prefix from net multiplier + new_multiplier = offset_amount * old_multiplier + approx_pow = np.log10(new_multiplier) + new_multiplier_pow = round_to_multiple(approx_pow, multiple=3) + assert np.isclose(approx_pow, new_multiplier_pow) + new_prefix = _si_prefixes.inv[new_multiplier_pow] + + # apply new multiplier, consolidating offset axis scale and label unit + def replace_group(match): + # Extracting the captured group + captured_group = match.group(1) + # Defining the replacement value for the captured group + return replacement_value + + ax.xaxis.get_offset_text().set(visible=False) # remove offset axis scale + old_prefix_span = old_prefix_match.span(1) + new_label_string = splice( + old_label_string, + old_prefix_span, + new_prefix, + ) + ax.set_xlabel(new_label_string) From 83fe842eab90bec51e5d7127ddfabfcd43c8230d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 17:14:50 -0500 Subject: [PATCH 021/145] Break out kde fill, prep for facet figure --- .../_calc_performance_semantics_axis_lims.py | 71 ++++ conduitpylib/viz/_get_defaults.py | 12 + ...performance_semantics_map_distributions.py | 214 ++++++++++ .../viz/_performance_semantics_plot.py | 402 +++++++++++++----- conduitpylib/viz/_set_kde_lims.py | 73 ++++ .../_set_performance_semantics_axis_lims.py | 26 ++ 6 files changed, 688 insertions(+), 110 deletions(-) create mode 100644 conduitpylib/viz/_calc_performance_semantics_axis_lims.py create mode 100644 conduitpylib/viz/_get_defaults.py create mode 100644 conduitpylib/viz/_performance_semantics_map_distributions.py create mode 100644 conduitpylib/viz/_set_kde_lims.py create mode 100644 conduitpylib/viz/_set_performance_semantics_axis_lims.py diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py new file mode 100644 index 0000000000..7a5a71806d --- /dev/null +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -0,0 +1,71 @@ +import itertools as it +import typing + + +from matplotlib.collections import ( + PathCollection as mpl_PathCollection, +) +from matplotlib.font_manager import FontProperties as mpl_FontProperties +from matplotlib.legend_handler import ( + HandlerPathCollection as mpl_HandlerPathCollection, + HandlerLine2D as mpl_HandlerLine2D, +) +import matplotlib.patches as mpl_patches +from matplotlib import pyplot as plt +import numpy as np +import pandas as pd +import seaborn as sns + +from ..utils import ( + lru_cache_universal, + seaborn_monkeypatched_kdecache, +) +from ._frame_scatter_subsets import frame_scatter_subsets +from ._set_kde_lims import set_kde_lims + + +@lru_cache_universal() +@seaborn_monkeypatched_kdecache() +def calc_performance_semantics_axis_limits( + data: pd.DataFrame, + x: str = "Simstep Period Inlet (ns)", + y: str = "Latency Simsteps Inlet", + hue: typing.Optional[str] = None, +) -> typing.Tuple[float, float, float, float]: + + dummy_fig = plt.figure() + dummy_ax = dummy_fig.add_subplot(111) + + sns.kdeplot( + ax=dummy_ax, + data=data, + x=x, + y=y, + alpha=0.0, + cut=10, + fill=True, # needed for set_kde_lims + hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + thresh=1e-12, + zorder=100, + ) + + # ensure that entire KDE is visible + set_kde_lims(dummy_ax, log_x=False, log_y=True) + xmin, xmax = dummy_ax.get_xlim() + ymin, ymax = dummy_ax.get_ylim() + + # prevent dummy axes from showing in jupyter notebook + plt.close(dummy_fig) + + # ensure adequate lower coverage + xmin = min(0, xmin) + ymin = min(0.1, ymin) + + # make room for rugplot elements + xmax *= 1.1 + ymax *= 3 + + return xmin, xmax, ymin, ymax diff --git a/conduitpylib/viz/_get_defaults.py b/conduitpylib/viz/_get_defaults.py new file mode 100644 index 0000000000..8dcd1999ab --- /dev/null +++ b/conduitpylib/viz/_get_defaults.py @@ -0,0 +1,12 @@ +import typing + + +def get_default_linestyles() -> typing.List[str]: + return [":", "--", "-"] + + +def get_default_palette() -> typing.List[str]: + # alternate palettes: + # ["#648FFF", "#40B0A6"] or ["#40b07f", "#646eff"] + # return ["#5c5cff", "#64e0ff", "#40B0A6"] + return ["#91f7ff", "#ff82d4", "#91aaff"] diff --git a/conduitpylib/viz/_performance_semantics_map_distributions.py b/conduitpylib/viz/_performance_semantics_map_distributions.py new file mode 100644 index 0000000000..7d408280f4 --- /dev/null +++ b/conduitpylib/viz/_performance_semantics_map_distributions.py @@ -0,0 +1,214 @@ +import itertools as it +import typing + + +from matplotlib.collections import ( + PathCollection as mpl_PathCollection, +) +from matplotlib import figure as mpl_figure +from matplotlib.font_manager import FontProperties as mpl_FontProperties +from matplotlib.legend_handler import ( + HandlerPathCollection as mpl_HandlerPathCollection, + HandlerLine2D as mpl_HandlerLine2D, +) +import matplotlib.patches as mpl_patches +from matplotlib import pyplot as plt +import numpy as np +import opytional as opyt +import pandas as pd +import seaborn as sns + +from ..utils import seaborn_monkeypatched_kdecache +from ._compact_xaxis_units import compact_xaxis_units +from ._frame_scatter_subsets import frame_scatter_subsets +from ._set_performance_semantics_axis_lims import ( + set_performance_semantics_axis_limits, +) + + +@seaborn_monkeypatched_kdecache() +def performance_semantics_map_distributions( + data: pd.DataFrame, + hue: str, + hue_order: typing.Optional[typing.List[str]] = None, + x: str = "Simstep Period Inlet (ns)", + y: str = "Latency Simsteps Inlet", + background_color: typing.Optional[str] = None, + linestyles: typing.Optional[typing.List[str]] = None, + palette: typing.Optional[typing.List[str]] = None, + size_inches: typing.Tuple[float, float] = (3.5, 2.5), + xlim: typing.Optional[typing.Tuple[float, float]] = None, + ylim: typing.Optional[typing.Tuple[float, float]] = None, +) -> mpl_figure.Figure: + assert set(hue_order) == set(data[hue].unique()) + + if hue_order is None: + hue_order = sorted(data[hue].unique()) + + if linestyles is None: + linestyles = [":", "--"] + + if palette is None: + # alternate palettes: ["#648FFF", "#40B0A6"] & ["#40b07f", "#646eff"] + palette = ["#5c5cff", "#64e0ff"] + + assert len(palette) >= len(hue_order) + + jointgrid = sns.JointGrid(data=data, x=x, y=y, hue=hue, ratio=8, height=8) + + sns.kdeplot( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + alpha=0.4, + cut=10, + fill=True, + hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + palette=palette, + thresh=1e-12, + zorder=101, + ) + + # set linestyles of marginal KDE outlines + # adapted from https://stackoverflow.com/a/70089200 + for path_collection, linestyle in zip( + jointgrid.ax_joint.collections, + reversed(linestyles), + ): + # need faux fill for set_kde_lims. set + color = path_collection.get_facecolor() + path_collection.set_facecolor("none") + path_collection.set_edgecolor("white") + path_collection.set_linestyle(linestyle) + path_collection.set_linewidth(2) + + sns.kdeplot( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + alpha=0.4, + cut=10, + fill=True, + hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + palette=palette, + thresh=1e-12, + zorder=99, + ) + + sns.kdeplot( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + alpha=1.0, + cut=10, + fill=False, + hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + linewidths=4, + linestyles="solid", + palette=palette, + thresh=1e-12, + zorder=100, + ) + + # set up joint plot axes... + # ... annotate latency simsteps inlet values + jointgrid.refline(y=1, ls="-", zorder=-5) + jointgrid.refline(y=2, ls="--", zorder=-5) + # ... set simsteps inlet to log scale + jointgrid.ax_joint.set_yscale("log") + + # ... set axis labels + jointgrid.ax_joint.set_xlabel("Update Rate (ns)") + jointgrid.ax_joint.set_ylabel("Communication Latency (updates)") + + # PLOT MARGINAL DISTRIBUTIONS + ########################################################################### + # plot marginal distributions as kernel density estimates + jointgrid.plot_marginals( + sns.kdeplot, + alpha=0.1 if hue is not None else 1.0, + fill=True, + lw=3, + palette=palette, + ) + + # now that we have marginals, set figure dimensions + jointgrid.fig.set_size_inches(*size_inches) + + # set linestyles of marginal KDE outlines + # https://stackoverflow.com/a/70089200 + for line, linestyle in it.chain( + zip(jointgrid.ax_marg_x.collections, linestyles), + zip(jointgrid.ax_marg_y.collections, linestyles), + ): + line.set_linestyle(linestyle) + line.set_alpha(0.4) + + # do manual rugplot because plot_marginals messes up colormapping + for ax, kwarg in ( + (jointgrid.ax_marg_x, {"x": x}), + (jointgrid.ax_marg_y, {"y": y}), + ): + sns.rugplot( + ax=ax, + color=palette[0], + data=data, + hue=hue, + palette=palette, + legend=False, + alpha=0.03, + expand_margins=False, + clip_on=False, + height=-0.8, + **kwarg, + ) + + # FINALIZE + ########################################################################### + if background_color is not None: + jointgrid.fig.patch.set_facecolor(background_color) + jointgrid.fig.patch.set_alpha(0.2) + for ax, key in [ + (jointgrid.ax_joint, "bottom"), + (jointgrid.ax_joint, "left"), + (jointgrid.ax_marg_x, "bottom"), + (jointgrid.ax_marg_y, "left"), + ]: + ax.tick_params( + colors="black", + length=6, + width=2, + which="both", + ) + + for ax in jointgrid.ax_marg_x, jointgrid.ax_marg_y: + ax.get_xaxis().set_visible(False) + ax.get_yaxis().set_visible(False) + + set_performance_semantics_axis_limits( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + hue=hue, + ) + if xlim is not None: + jointgrid.ax_joint.set_xlim(xlim) + if ylim is not None: + jointgrid.ax_joint.set_ylim(ylim) + + compact_xaxis_units(ax=jointgrid.ax_joint, base_unit="s") + + return jointgrid diff --git a/conduitpylib/viz/_performance_semantics_plot.py b/conduitpylib/viz/_performance_semantics_plot.py index 66f51aae8e..66e8806bbf 100644 --- a/conduitpylib/viz/_performance_semantics_plot.py +++ b/conduitpylib/viz/_performance_semantics_plot.py @@ -1,84 +1,119 @@ +from difflib import restore import itertools as it import typing +import warnings - +from frozendict import frozendict from matplotlib.collections import ( PathCollection as mpl_PathCollection, ) +from matplotlib.figure import Figure as mpl_Figure from matplotlib.font_manager import FontProperties as mpl_FontProperties from matplotlib.legend_handler import ( HandlerPathCollection as mpl_HandlerPathCollection, HandlerLine2D as mpl_HandlerLine2D, ) +import matplotlib.lines as mpl_lines import matplotlib.patches as mpl_patches +import matplotlib.patheffects as mpl_patheffects from matplotlib import pyplot as plt +from matplotlib import rc as mpl_rc import numpy as np +import opytional as opyt import pandas as pd import seaborn as sns +from ..utils import ( + seaborn_monkeypatched_kdecache, +) +from ._compact_xaxis_units import compact_xaxis_units +from ._get_defaults import get_default_linestyles, get_default_palette +from ._set_performance_semantics_axis_lims import ( + set_performance_semantics_axis_limits, +) from ._frame_scatter_subsets import frame_scatter_subsets -from ._set_kde_lims import set_kde_lims +@seaborn_monkeypatched_kdecache() def performance_semantics_plot( data: pd.DataFrame, - hue: str, + hue: typing.Optional[str] = None, hue_order: typing.Optional[typing.List[str]] = None, heat: str = "% Msgs Lost", + heat_norm: typing.Optional[typing.Tuple[float, float]] = (0, 100), x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", + background_color: typing.Optional[str] = None, + bunching_smear_alpha: float = 0.05, + bunching_smear_color: str = "lightgray", + title: str = "", + legend: typing.Literal["hide", "only", "show"] = "show", + legend_contents_pad: bool = False, + legend_prop: typing.Dict = frozendict(), linestyles: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, + show_bunching_smear: bool = True, size_inches: typing.Tuple[float, float] = (3.5, 2.5), -) -> sns.JointGrid: - - assert set(hue_order) == set(data[hue].unique()) - - if hue_order is None: - hue_order = sorted(data[hue].unique()) + xlabel: typing.Optional[str] = None, + xlim: typing.Optional[typing.Tuple[float, float]] = None, + ylabel: typing.Optional[str] = None, + ylim: typing.Optional[typing.Tuple[float, float]] = None, +) -> mpl_Figure: + if hue is not None: + if not set(hue_order) <= set(data[hue].unique()): + raise ValueError("hue_order has hue categories missing from data.") + if hue_order is None: + hue_order = sorted(data[hue].unique()) + elif hue_order is not None: + raise ValueError( + "If hue is None, hue_order must also be None.", + ) if linestyles is None: - linestyles = [":", "--"] + # default linestyles + linestyles = get_default_linestyles() + if hue_order is not None and len(linestyles) < len(hue_order): + warnings.warn("more hue categories than linestyles") if palette is None: - # alternate palettes: ["#648FFF", "#40B0A6"] & ["#40b07f", "#646eff"] - palette = ["#5c5cff", "#64e0ff"] - assert len(palette) == len(hue_order) + # default palette + palette = get_default_palette() + if hue_order is not None and len(palette) < len(hue_order): + warnings.warn("more hue categories than palette colors") jointgrid = sns.JointGrid(data=data, x=x, y=y, hue=hue, ratio=8, height=8) - sns.kdeplot( - ax=jointgrid.ax_joint, - data=data, - x=x, - y=y, - alpha=0.4, - cut=10, - fill=True, # remove fill manually below, needed for set_kde_lims - hue=hue, - legend=False, - levels=2, - log_scale=(False, True), - palette=palette, - thresh=1e-12, - zorder=100, - ) - - # ensure that entire KDE is visible - set_kde_lims(jointgrid.ax_joint, log_x=False, log_y=True) + if hue is not None and legend != "only": + sns.kdeplot( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + alpha=0.4, + color=palette[0], + cut=10, + fill=True, # remove fill manually below, needed for set_kde_lims + hue=hue, + legend=False, + levels=2, + log_scale=(False, True), + palette=palette, + thresh=1e-12, + zorder=100, + ) - # set linestyles of marginal KDE outlines - # adapted from https://stackoverflow.com/a/70089200 - for path_collection, linestyle in zip( - jointgrid.ax_joint.collections, - reversed(linestyles), - ): - # need faux fill for set_kde_lims. set - color = path_collection.get_facecolor() - path_collection.set_facecolor("none") - path_collection.set_edgecolor(color) - path_collection.set_linestyle(linestyle) - path_collection.set_linewidth(2) + # set linestyles of marginal KDE outlines + # adapted from https://stackoverflow.com/a/70089200 + for path_collection, linestyle in zip( + jointgrid.ax_joint.collections, + it.cycle(reversed(linestyles)), + ): + # need faux fill for set_kde_lims. set + color = path_collection.get_facecolor() + path_collection.set_facecolor("none") + path_collection.set_edgecolor(color) + path_collection.set_linestyle(linestyle) + path_collection.set_linewidth(2) # PLOT JOINT DISTRIBUTION ########################################################################### @@ -89,25 +124,36 @@ def performance_semantics_plot( x=x, y=y, hue=heat, + legend=False, # use dummy below instead + hue_norm=heat_norm, + alpha=0.3, markers="D", - # style=hue, - # markers=["o", "D"], palette="flare", - alpha=0.3, + visible=(legend != "only"), ) + if heat is not None: + # use dummy data to force full legend representation of heat + num_legend_samples = 4 + dummy_x = jointgrid.ax_joint.get_xlim()[0] + dummy_y = jointgrid.ax_joint.get_ylim()[0] + sns.scatterplot( + ax=jointgrid.ax_joint, + x=np.full(num_legend_samples, dummy_x), + y=np.full(num_legend_samples, dummy_y), + hue=np.linspace(*heat_norm, num_legend_samples, dtype=int), + hue_norm=heat_norm, + alpha=0.0, + legend="full", + markers="D", + palette="flare", + ) # set up joint plot axes... # ... annotate latency simsteps inlet values - jointgrid.refline(y=1, ls="-", zorder=-5) - jointgrid.refline(y=2, ls="--", zorder=-5) + jointgrid.refline(y=1, ls="-", visible=(legend != "only"), zorder=-5) + jointgrid.refline(y=2, ls="--", visible=(legend != "only"), zorder=-5) # ... set simsteps inlet to log scale jointgrid.ax_joint.set_yscale("log") - # ... set simstep period time to zero minimum - current_xmin = jointgrid.ax_joint.get_xlim()[0] - jointgrid.ax_joint.set_xlim(xmin=min(0, current_xmin)) - # ... set communication latency to at least 0.1 minimum - current_ymin = jointgrid.ax_joint.get_ylim()[0] - jointgrid.ax_joint.set_ylim(ymin=min(0.1, current_ymin)) # ... set axis labels jointgrid.ax_joint.set_xlabel("Update Rate (ns)") jointgrid.ax_joint.set_ylabel("Communication Latency (updates)") @@ -117,10 +163,13 @@ def performance_semantics_plot( # plot marginal distributions as kernel density estimates jointgrid.plot_marginals( sns.kdeplot, - alpha=0.1, + alpha=0.4 if hue is not None else 1.0, + color=palette[0], fill=True, + legend=False, lw=3, palette=palette, + visible=(legend != "only"), ) # now that we have marginals, set figure dimensions @@ -129,8 +178,8 @@ def performance_semantics_plot( # set linestyles of marginal KDE outlines # https://stackoverflow.com/a/70089200 for line, linestyle in it.chain( - zip(jointgrid.ax_marg_x.collections, linestyles), - zip(jointgrid.ax_marg_y.collections, linestyles), + zip(jointgrid.ax_marg_x.collections, it.cycle(linestyles)), + zip(jointgrid.ax_marg_y.collections, it.cycle(linestyles)), ): line.set_linestyle(linestyle) line.set_alpha(0.4) @@ -144,46 +193,112 @@ def performance_semantics_plot( ax=ax, data=data, hue=heat, + hue_norm=heat_norm, palette="flare", legend=False, alpha=0.03, expand_margins=False, clip_on=False, height=-0.8, + visible=(legend != "only"), **kwarg, ) # SET UP LEGEND ########################################################################### + # sns.move_legend( + # jointgrid.ax_joint, + # "upper right", + # bbox_to_anchor=(-0.4, -0.1, 0.1, 1.2), # place legend to left of plot + # frameon=False, + # ) # manually register category splits into legend... # ... add quasi-title to legend entry by providing key but no value + + prefix_labels, prefix_handles = [], [] + postfix_labels, postfix_handles = [], [] + empty_patch = mpl_patches.Patch(alpha=0.0, color="white", label="") + + if hue_order is not None: + # prefix_handles.append(empty_patch) + # prefix_labels.append(hue) + # ... then add legend entries manually + for ls, color, label in zip(reversed(linestyles), palette, hue_order): + example_patch = mpl_patches.Patch( + facecolor=color, + linestyle=ls, + label=label, + lw=2, + edgecolor=color, + alpha=0.4, + ) + prefix_handles.append(example_patch) + prefix_labels.append(label) + + prefix_handles.append(empty_patch) + prefix_labels.append("") + + # this title is now strung on the end of reference points below + # if heat is not None: + # # don't know why, but have to manually add heat title + # # when scatter style is disabled + # prefix_handles.append(empty_patch) + # prefix_labels.append(heat) + + # add the bunching smear to legend + if show_bunching_smear: + bunching_smear_label = "Bunching Smear" + bunching_smear_handle = mpl_lines.Line2D( + [0], + [0], + color=bunching_smear_color, + # color="white", + # marker="_", + # markersize=20, + # markeredgewidth=2, + # markeredgecolor=bunching_smear_color, + # linestyle=None, + linewidth=4, + label=bunching_smear_label, + path_effects=[ + mpl_patheffects.Stroke(linewidth=6, foreground="w"), + mpl_patheffects.Normal(), + ], + ) + postfix_labels.extend([" ", bunching_smear_label]) + postfix_handles.extend([empty_patch, bunching_smear_handle]) + ( handles, labels, ) = ( jointgrid.ax_joint.get_legend_handles_labels() ) # get existing handles and labels - empty_patch = mpl_patches.Patch(color="none", label="Extra label") - - # don't know why, but have to manulaly add heat title - # when scatter style is disabled - handles = [empty_patch, *handles] - labels = [heat, *labels] - - handles.append(empty_patch) - labels.append(hue) - # ... then add legend entries manually - for ls, color, label in zip(reversed(linestyles), palette, hue_order): - example_patch = mpl_patches.Patch( - facecolor=color, - linestyle=ls, - label=label, - lw=2, - edgecolor=color, - alpha=0.4, - ) - handles.append(example_patch) - labels.append(label) + if labels: + first, *rest = map("{} %".format, labels) + labels = [f"{first} Msgs Lost", *rest] + + if legend_contents_pad: + pad_handles = [empty_patch] + pad_labels = [""] + else: + pad_handles = [] + pad_labels = [] + + handles = [ + *pad_handles, + *prefix_handles, + *handles, + *postfix_handles, + *pad_handles, + ] + labels = [ + *pad_labels, + *prefix_labels, + *labels, + *postfix_labels, + *pad_labels, + ] # helper function to disable transparency on legend entries # adapted from https://stackoverflow.com/a/59629242 @@ -192,7 +307,12 @@ def remove_alpha(handle, orig) -> None: handle.set_alpha(1.0) # create legend - legend = jointgrid.ax_joint.legend( + bbox_to_anchor = ( + (-0.4, -0.15, 0.1, 1.25) # place legend to left of plot + if legend != "only" + else None + ) + legend_ = jointgrid.ax_joint.legend( handles, labels, handler_map={ @@ -200,22 +320,29 @@ def remove_alpha(handle, orig) -> None: plt.Line2D: mpl_HandlerLine2D(update_func=remove_alpha), }, # apply helper function borderaxespad=0, - bbox_to_anchor=(-0.4, -0.1, 0.1, 1.2), # place legend to left of plot + bbox_to_anchor=bbox_to_anchor, + prop=legend_prop, ) # apply new handles and labels to plot - legend._legend_box.set_height(legend.get_bbox_to_anchor().height) + # legend_._legend_box.set_height(legend_.get_bbox_to_anchor().height) # title background adapted from https://stackoverflow.com/a/76103441 - title = "🙂/🤕" - legend.set_title( - title, + + mpl_rc("text", usetex=False) + thinspace = '"' + legend_.set_title( + f"{thinspace}{title}{thinspace}", # use custom font with monochrome emojis # because vanilla matplotlib backend doesn't support color bitmap fonts - prop=mpl_FontProperties(fname="../NotoEmoji-Regular4.ttf", size=25), + prop=mpl_FontProperties(fname="../NotoEmoji-Regular4.ttf", size=30), ) - legend._legend_title_box._text.set_bbox( - {"facecolor": "gray", "alpha": 0.3, "lw": 0}, + legend_._legend_title_box._text.set_bbox( + {"facecolor": "gray", "alpha": 0.3, "lw": 3}, ) - legend._legend_box.sep = 20 + legend_._legend_title_box._text.width = 10 + legend_._legend_box.sep = 20 + + if legend == "hide": + legend_.set_visible(False) # PLOT BUNCHING SMEAR ON JOINT DISTRIBUTION ########################################################################### @@ -223,24 +350,25 @@ def remove_alpha(handle, orig) -> None: max_latency = data["Latency Simsteps Inlet"] min_latency = data["Latency Simsteps Inlet"] / data["Num Messages Per Pull"] - jointgrid.ax_joint.errorbar( - data=data, - x=x, - y=y, - fmt="none", # don't draw data points - alpha=0.05, - ecolor="lightgray", - yerr=np.vstack( - [ - # below-error height - data["Latency Simsteps Inlet"] - min_latency, - # above-error height - max_latency - data["Latency Simsteps Inlet"], - ], - ), - zorder=-5, - legend=False, - ) + if legend != "only": + jointgrid.ax_joint.errorbar( + data=data, + x=x, + y=y, + fmt="none", # don't draw data points + alpha=bunching_smear_alpha, + ecolor=bunching_smear_color, + yerr=np.vstack( + [ + # below-error height + data["Latency Simsteps Inlet"] - min_latency, + # above-error height + max_latency - data["Latency Simsteps Inlet"], + ], + ), + # visible=(legend != "only"), # doesn't work, need outer conditional + zorder=-5, + ) # FINALIZE ########################################################################### @@ -248,7 +376,61 @@ def remove_alpha(handle, orig) -> None: ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) - jointgrid.ax_joint.set_ylim(top=jointgrid.ax_joint.get_ylim()[1] * 3) - jointgrid.ax_joint.set_xlim(right=jointgrid.ax_joint.get_xlim()[1] * 1.1) + set_performance_semantics_axis_limits( + ax=jointgrid.ax_joint, + data=data, + x=x, + y=y, + hue=hue, + ) + if xlim is not None: + jointgrid.ax_joint.set_xlim(xlim) + if ylim is not None: + jointgrid.ax_joint.set_ylim(ylim) + + if xlabel is not None: + jointgrid.ax_joint.set_xlabel(xlabel) + if ylabel is not None: + jointgrid.ax_joint.set_ylabel(ylabel) + + # patchworklib strips out background colors... + # jointgrid.fig.patch.set_facecolor(background_color) + # jointgrid.fig.patch.set_alpha(0.2) + # ... so just set axis colors instead + for ax, key in [ + (jointgrid.ax_joint, "bottom"), + (jointgrid.ax_joint, "left"), + (jointgrid.ax_marg_x, "bottom"), + (jointgrid.ax_marg_y, "left"), + ]: + spine = ax.spines[key] + spine.set_visible(True) + spine.set_color(opyt.or_value(background_color, "black")) + spine.set(zorder=-100) + if background_color is not None: + spine.set_lw(5) + # 'both' refers to minor and major axes + ax.tick_params( + colors=opyt.or_value(background_color, "black"), + length=6, + width=2, + which="both", + ) + + compact_xaxis_units(ax=jointgrid.ax_joint, base_unit="s") - plt.tight_layout() + if legend == "only": + # outfig = plt.figure() + # outax = outfig.add_subplot(111) + # outax.legend() + # outax.legend_ = legend + # plt.close(jointgrid.fig) + # return outfig + jointgrid.ax_joint.set_axis_off() + jointgrid.ax_marg_x.set_axis_off() + jointgrid.ax_marg_y.set_axis_off() + jointgrid.fig.set_figwidth(1) + jointgrid.fig.tight_layout() + return jointgrid + else: + return jointgrid diff --git a/conduitpylib/viz/_set_kde_lims.py b/conduitpylib/viz/_set_kde_lims.py new file mode 100644 index 0000000000..00a4cad4fd --- /dev/null +++ b/conduitpylib/viz/_set_kde_lims.py @@ -0,0 +1,73 @@ +import itertools as it + +from matplotlib import axes as mpl_axes +import numpy as np + + +def _iter_path_collection(path_collection): + yield from path_collection.get_paths()[0].vertices + + +def set_kde_lims( + ax: mpl_axes.Axes, + log_x: bool = False, + log_y: bool = False, + pad_cm: float = 0.0, +) -> None: + fig_inches_x, fig_inches_y = ax.figure.get_size_inches() + pad_inches = pad_cm / 2.54 + pad_fraction_x = pad_inches / fig_inches_x + pad_fraction_y = pad_inches / fig_inches_y + assert 0 <= pad_fraction_x <= 1 and 0 <= pad_fraction_y <= 1 + + assert len(ax.collections) + vertices = lambda: it.chain(*map(_iter_path_collection, ax.collections)) + frame_xmin = min(vertex[0] for vertex in vertices()) + frame_xmax = max(vertex[0] for vertex in vertices()) + frame_ymin = min(vertex[1] for vertex in vertices()) + frame_ymax = max(vertex[1] for vertex in vertices()) + assert frame_xmin <= frame_xmax and frame_ymin <= frame_ymax + + x_lb, x_ub = ax.get_xlim() + if log_x: + x_padding = (np.log10(x_ub) - np.log10(x_lb)) * pad_fraction_x + assert x_padding >= 0 + frame_xmin, frame_xmax = ( + 10 ** (np.log10(frame_xmin) - x_padding), + 10 ** (np.log10(frame_xmax) + x_padding), + ) + assert frame_xmin > 0 + else: + x_padding = (x_ub - x_lb) * pad_fraction_x + assert x_padding >= 0 + frame_xmin -= x_padding + frame_xmax += x_padding + + y_lb, y_ub = ax.get_ylim() + if log_y: + y_padding = (np.log10(y_ub) - np.log10(y_lb)) * pad_fraction_y + assert y_padding >= 0 + frame_ymin, frame_ymax = ( + 10 ** (np.log10(frame_ymin) - y_padding), + 10 ** (np.log10(frame_ymax) + y_padding), + ) + assert frame_ymin > 0 + else: + y_padding = (y_ub - y_lb) * pad_fraction_y + assert y_padding >= 0 + frame_ymin -= y_padding + frame_ymax += (y_padding,) + + # Set the plot limits + assert frame_xmin <= frame_xmax + assert frame_ymin <= frame_ymax + + # don't shrink viewport + ax.set_xlim( + min(frame_xmin, ax.get_xlim()[0]), + max(frame_xmax, ax.get_xlim()[1]), + ) + ax.set_ylim( + min(frame_ymin, ax.get_ylim()[0]), + max(frame_ymax, ax.get_ylim()[1]), + ) diff --git a/conduitpylib/viz/_set_performance_semantics_axis_lims.py b/conduitpylib/viz/_set_performance_semantics_axis_lims.py new file mode 100644 index 0000000000..38a9da58e2 --- /dev/null +++ b/conduitpylib/viz/_set_performance_semantics_axis_lims.py @@ -0,0 +1,26 @@ +import typing + +from matplotlib import pyplot as plt +import pandas as pd + +from ._calc_performance_semantics_axis_lims import ( + calc_performance_semantics_axis_limits, +) + + +def set_performance_semantics_axis_limits( + ax: plt.Axes, + data: pd.DataFrame, + x: str = "Simstep Period Inlet (ns)", + y: str = "Latency Simsteps Inlet", + hue: typing.Optional[str] = None, +) -> None: + + xmin, xmax, ymin, ymax = calc_performance_semantics_axis_limits( + data=data, + x=x, + y=y, + hue=hue, + ) + ax.set_xlim(left=xmin, right=xmax) + ax.set_ylim(bottom=ymin, top=ymax) From 894291210eac24787d82c21944c3e1d997a9a533 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 23:22:42 -0500 Subject: [PATCH 022/145] Rename to performance_semantics_{kde,scatter}plot --- conduitpylib/viz/__init__.py | 8 ++++++-- ...distributions.py => _performance_semantics_kdeplot.py} | 2 +- ...tics_plot.py => _performance_semantics_scatterplot.py} | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) rename conduitpylib/viz/{_performance_semantics_map_distributions.py => _performance_semantics_kdeplot.py} (99%) rename conduitpylib/viz/{_performance_semantics_plot.py => _performance_semantics_scatterplot.py} (99%) diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 57ab01fdcd..f6cfca9970 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -2,7 +2,10 @@ from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets -from ._performance_semantics_plot import performance_semantics_plot +from ._performance_semantics_kdeplot import performance_semantics_kdeplot +from ._performance_semantics_scatterplot import ( + performance_semantics_scatterplot, +) from ._set_kde_lims import set_kde_lims @@ -10,6 +13,7 @@ __all__ = [ "compact_xaxis_units", "frame_scatter_subsets", - "performance_semantics_plot", + "performance_semantics_kdeplot", + "performance_semantics_scatterplot", "set_kde_lims", ] diff --git a/conduitpylib/viz/_performance_semantics_map_distributions.py b/conduitpylib/viz/_performance_semantics_kdeplot.py similarity index 99% rename from conduitpylib/viz/_performance_semantics_map_distributions.py rename to conduitpylib/viz/_performance_semantics_kdeplot.py index 7d408280f4..9bf5cb52e5 100644 --- a/conduitpylib/viz/_performance_semantics_map_distributions.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -27,7 +27,7 @@ @seaborn_monkeypatched_kdecache() -def performance_semantics_map_distributions( +def performance_semantics_kdeplot( data: pd.DataFrame, hue: str, hue_order: typing.Optional[typing.List[str]] = None, diff --git a/conduitpylib/viz/_performance_semantics_plot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py similarity index 99% rename from conduitpylib/viz/_performance_semantics_plot.py rename to conduitpylib/viz/_performance_semantics_scatterplot.py index 66e8806bbf..798cc4f152 100644 --- a/conduitpylib/viz/_performance_semantics_plot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -35,7 +35,7 @@ @seaborn_monkeypatched_kdecache() -def performance_semantics_plot( +def performance_semantics_scatterplot( data: pd.DataFrame, hue: typing.Optional[str] = None, hue_order: typing.Optional[typing.List[str]] = None, From beab0099b1185b29da334acea8033e43c14892e5 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 5 Nov 2023 23:36:34 -0500 Subject: [PATCH 023/145] Fix func name axis_limits -> axis_lims --- conduitpylib/viz/_calc_performance_semantics_axis_lims.py | 2 +- conduitpylib/viz/_performance_semantics_kdeplot.py | 4 ++-- conduitpylib/viz/_performance_semantics_scatterplot.py | 4 ++-- conduitpylib/viz/_set_performance_semantics_axis_lims.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py index 7a5a71806d..7d8d461652 100644 --- a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -26,7 +26,7 @@ @lru_cache_universal() @seaborn_monkeypatched_kdecache() -def calc_performance_semantics_axis_limits( +def calc_performance_semantics_axis_lims( data: pd.DataFrame, x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", diff --git a/conduitpylib/viz/_performance_semantics_kdeplot.py b/conduitpylib/viz/_performance_semantics_kdeplot.py index 9bf5cb52e5..ac2d8d7f45 100644 --- a/conduitpylib/viz/_performance_semantics_kdeplot.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -22,7 +22,7 @@ from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets from ._set_performance_semantics_axis_lims import ( - set_performance_semantics_axis_limits, + set_performance_semantics_axis_lims, ) @@ -197,7 +197,7 @@ def performance_semantics_kdeplot( ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) - set_performance_semantics_axis_limits( + set_performance_semantics_axis_lims( ax=jointgrid.ax_joint, data=data, x=x, diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 798cc4f152..cb6bde77d5 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -29,7 +29,7 @@ from ._compact_xaxis_units import compact_xaxis_units from ._get_defaults import get_default_linestyles, get_default_palette from ._set_performance_semantics_axis_lims import ( - set_performance_semantics_axis_limits, + set_performance_semantics_axis_lims, ) from ._frame_scatter_subsets import frame_scatter_subsets @@ -376,7 +376,7 @@ def remove_alpha(handle, orig) -> None: ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) - set_performance_semantics_axis_limits( + set_performance_semantics_axis_lims( ax=jointgrid.ax_joint, data=data, x=x, diff --git a/conduitpylib/viz/_set_performance_semantics_axis_lims.py b/conduitpylib/viz/_set_performance_semantics_axis_lims.py index 38a9da58e2..1570c6d7a5 100644 --- a/conduitpylib/viz/_set_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_set_performance_semantics_axis_lims.py @@ -4,11 +4,11 @@ import pandas as pd from ._calc_performance_semantics_axis_lims import ( - calc_performance_semantics_axis_limits, + calc_performance_semantics_axis_lims, ) -def set_performance_semantics_axis_limits( +def set_performance_semantics_axis_lims( ax: plt.Axes, data: pd.DataFrame, x: str = "Simstep Period Inlet (ns)", @@ -16,7 +16,7 @@ def set_performance_semantics_axis_limits( hue: typing.Optional[str] = None, ) -> None: - xmin, xmax, ymin, ymax = calc_performance_semantics_axis_limits( + xmin, xmax, ymin, ymax = calc_performance_semantics_axis_lims( data=data, x=x, y=y, From bf11e45ce03c6b47d9979ec9ebf1984f39f108be Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 00:39:09 -0500 Subject: [PATCH 024/145] Switch default palette to gold/purple/teal --- conduitpylib/viz/_get_defaults.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conduitpylib/viz/_get_defaults.py b/conduitpylib/viz/_get_defaults.py index 8dcd1999ab..f69a0bd838 100644 --- a/conduitpylib/viz/_get_defaults.py +++ b/conduitpylib/viz/_get_defaults.py @@ -9,4 +9,5 @@ def get_default_palette() -> typing.List[str]: # alternate palettes: # ["#648FFF", "#40B0A6"] or ["#40b07f", "#646eff"] # return ["#5c5cff", "#64e0ff", "#40B0A6"] - return ["#91f7ff", "#ff82d4", "#91aaff"] + # return ["#91f7ff", "#ff82d4", "#91aaff"] + return ['#9467bd', '#bcbd22', '#17becf'] # purple, gold, teal From b671206ba019e76aed97b29e0dc7bab7d69441dd Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 00:39:42 -0500 Subject: [PATCH 025/145] Fixup hue_order setup and checks --- conduitpylib/viz/_performance_semantics_kdeplot.py | 2 +- conduitpylib/viz/_performance_semantics_scatterplot.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_kdeplot.py b/conduitpylib/viz/_performance_semantics_kdeplot.py index ac2d8d7f45..8a62b5cbb8 100644 --- a/conduitpylib/viz/_performance_semantics_kdeplot.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -40,7 +40,7 @@ def performance_semantics_kdeplot( xlim: typing.Optional[typing.Tuple[float, float]] = None, ylim: typing.Optional[typing.Tuple[float, float]] = None, ) -> mpl_figure.Figure: - assert set(hue_order) == set(data[hue].unique()) + assert set(hue_order) >= set(data[hue]) if hue_order is None: hue_order = sorted(data[hue].unique()) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index cb6bde77d5..ea34be9875 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -60,10 +60,10 @@ def performance_semantics_scatterplot( ylim: typing.Optional[typing.Tuple[float, float]] = None, ) -> mpl_Figure: if hue is not None: - if not set(hue_order) <= set(data[hue].unique()): - raise ValueError("hue_order has hue categories missing from data.") if hue_order is None: hue_order = sorted(data[hue].unique()) + if not set(hue_order) <= set(data[hue].unique()): + raise ValueError("hue_order has hue categories missing from data.") elif hue_order is not None: raise ValueError( "If hue is None, hue_order must also be None.", From 5c99aa46312e82b25e112b6541e3454c723029f4 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 00:47:11 -0500 Subject: [PATCH 026/145] Take legend font path by arg --- conduitpylib/viz/_performance_semantics_scatterplot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index ea34be9875..f8a445f9b0 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -49,6 +49,7 @@ def performance_semantics_scatterplot( title: str = "", legend: typing.Literal["hide", "only", "show"] = "show", legend_contents_pad: bool = False, + legend_font_name: typing.Optional[str] = None, legend_prop: typing.Dict = frozendict(), linestyles: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, @@ -333,7 +334,7 @@ def remove_alpha(handle, orig) -> None: f"{thinspace}{title}{thinspace}", # use custom font with monochrome emojis # because vanilla matplotlib backend doesn't support color bitmap fonts - prop=mpl_FontProperties(fname="../NotoEmoji-Regular4.ttf", size=30), + prop=mpl_FontProperties(fname=legend_font_name, size=30), ) legend_._legend_title_box._text.set_bbox( {"facecolor": "gray", "alpha": 0.3, "lw": 3}, From 904c827cc97d57be1a78b7e85b2203cce84b2895 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 00:48:01 -0500 Subject: [PATCH 027/145] Impl performance-semantics facetplot composite --- conduitpylib/viz/__init__.py | 2 + .../viz/_performance_semantics_facetplot.py | 116 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 conduitpylib/viz/_performance_semantics_facetplot.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index f6cfca9970..f3a4e37f12 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -2,6 +2,7 @@ from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets +from ._performance_semantics_facetplot import performance_semantics_facetplot from ._performance_semantics_kdeplot import performance_semantics_kdeplot from ._performance_semantics_scatterplot import ( performance_semantics_scatterplot, @@ -13,6 +14,7 @@ __all__ = [ "compact_xaxis_units", "frame_scatter_subsets", + "performance_semantics_facetplot", "performance_semantics_kdeplot", "performance_semantics_scatterplot", "set_kde_lims", diff --git a/conduitpylib/viz/_performance_semantics_facetplot.py b/conduitpylib/viz/_performance_semantics_facetplot.py new file mode 100644 index 0000000000..43a913fffc --- /dev/null +++ b/conduitpylib/viz/_performance_semantics_facetplot.py @@ -0,0 +1,116 @@ +import functools +import operator +import typing +from unittest.mock import patch +import warnings + +import pandas as pd +import patchworklib as pw + +from. _calc_performance_semantics_axis_lims import ( + calc_performance_semantics_axis_lims, +) +from ._get_defaults import get_default_linestyles, get_default_palette +from ._performance_semantics_kdeplot import performance_semantics_kdeplot +from ._performance_semantics_scatterplot import ( + performance_semantics_scatterplot, +) + + +@patch.dict(pw.param, {"margin": 0.0}) +@pw.patchworklib.patched_axisgrid() +def performance_semantics_facetplot( + data: pd.DataFrame, + x: str="Simstep Period Inlet (ns)", + y: str="Latency Simsteps Inlet", + hue: typing.Optional[str] = None, + hue_order: typing.Optional[typing.List[str]] = None, + title: str = "", + brick_size_graphs: typing.Tuple[float, float] = (0.51, 0.5), + brick_size_legend: typing.Tuple[float, float] = (0.68, 1.2), + legend_font_name: typing.Optional[str] = None, + palette: typing.Optional[typing.List[str]] = None, + linestyles: typing.Optional[typing.List[str]] = None, +) -> pw.Brick: + + if hue is not None: + if hue_order is None: + hue_order = sorted(data[hue].unique()) + if not set(hue_order) <= set(data[hue].unique()): + raise ValueError("hue_order has hue categories missing from data.") + elif hue_order is not None: + raise ValueError( + "If hue is None, hue_order must also be None.", + ) + + if linestyles is None: + # default linestyles + linestyles = get_default_linestyles() + if hue_order is not None and len(linestyles) < len(hue_order): + warnings.warn("more hue categories than linestyles") + + if palette is None: + # default palette + palette = get_default_palette() + if hue_order is not None and len(palette) < len(hue_order): + warnings.warn("more hue categories than palette colors") + + xmin, xmax, ymin, ymax = calc_performance_semantics_axis_lims( + data=data, + x=x, + y=y, + hue=hue, + ) + + + fig_legend = performance_semantics_scatterplot( + data=data, + x=x, + y=y, + hue=hue, + hue_order=hue_order, + legend="only", + legend_font_name=legend_font_name, + linestyles=linestyles, + palette=palette, + title=title, + xlim=(xmin, xmax), + ylim=(ymin, ymax), + ) + brick_legend = pw.load_seaborngrid(fig_legend, figsize=brick_size_legend) + + fig_kde = performance_semantics_kdeplot( + data=data, + x=x, + y=y, + hue=hue, + hue_order=hue_order, + palette=palette[:2], + xlim=(xmin, xmax), + ylim=(ymin, ymax), + ) + brick_kde = pw.load_seaborngrid(fig_kde, figsize=brick_size_graphs) + + fig_scatterplots = [ + performance_semantics_scatterplot( + data=data[data[hue] == hue_order[i]], + hue=None, + background_color=palette[i], + legend="hide", + linestyles=linestyles[i:], + palette=palette[i:], + xlim=(xmin, xmax), + ylabel="", + ylim=(ymin, ymax), + ) + for i in range(len(hue_order)) + ] + bricks_scatterplots = [ + pw.load_seaborngrid(fig_scatterplot, figsize=brick_size_graphs) + for fig_scatterplot in fig_scatterplots + ] + + bricks = [brick_legend, brick_kde, *bricks_scatterplots] + concat = functools.reduce(operator.or_, bricks) + + return concat From 20107fe2e97ef59316abcb3e7519b4d86ef7ee57 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 00:51:48 -0500 Subject: [PATCH 028/145] Set editorconfig python indent 2 -> 4 --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 3994f81184..c0b1f9d595 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,7 +15,7 @@ [*.{js,py}] charset = utf-8 indent_style = space - indent_size = 2 + indent_size = 4 # cpp and hpp file indentation [*.{cpp,hpp}] From 183c9ab68bc083bc0b5e2bdc4b5b11e4c2decdb4 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 11:16:13 -0500 Subject: [PATCH 029/145] Bugfix: show smear unflagged should hide smear --- conduitpylib/viz/_performance_semantics_scatterplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index f8a445f9b0..33b9b8019e 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -351,7 +351,7 @@ def remove_alpha(handle, orig) -> None: max_latency = data["Latency Simsteps Inlet"] min_latency = data["Latency Simsteps Inlet"] / data["Num Messages Per Pull"] - if legend != "only": + if legend != "only" and show_bunching_smear: jointgrid.ax_joint.errorbar( data=data, x=x, From 42cd9e34ba2760792315fe03c0fbdb830c6aee0d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 6 Nov 2023 11:18:03 -0500 Subject: [PATCH 030/145] Reflow overlength comment --- conduitpylib/viz/_performance_semantics_scatterplot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 33b9b8019e..babdaf0b3a 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -367,7 +367,8 @@ def remove_alpha(handle, orig) -> None: max_latency - data["Latency Simsteps Inlet"], ], ), - # visible=(legend != "only"), # doesn't work, need outer conditional + # doesn't work, need outer conditional + # visible=(legend != "only"), zorder=-5, ) From 9be85c15fb78c971bf27698ae76e44a20de585aa Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 11:20:49 -0500 Subject: [PATCH 031/145] Update smear default styling --- conduitpylib/viz/_performance_semantics_scatterplot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index babdaf0b3a..3f41d9ae1e 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -44,8 +44,8 @@ def performance_semantics_scatterplot( x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", background_color: typing.Optional[str] = None, - bunching_smear_alpha: float = 0.05, - bunching_smear_color: str = "lightgray", + bunching_smear_alpha: float = 0.3, + bunching_smear_color: str = "green", title: str = "", legend: typing.Literal["hide", "only", "show"] = "show", legend_contents_pad: bool = False, From 89808175a841ff92a4c229035f4ad769a280839f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 15:42:36 -0500 Subject: [PATCH 032/145] Impl, test pickle_cache --- .../test/test_utils/test_pickle_cache.py | 53 ++++++++++++++++ conduitpylib/utils/__init__.py | 2 + conduitpylib/utils/pickle_cache.py | 61 +++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 conduitpylib/test/test_utils/test_pickle_cache.py create mode 100644 conduitpylib/utils/pickle_cache.py diff --git a/conduitpylib/test/test_utils/test_pickle_cache.py b/conduitpylib/test/test_utils/test_pickle_cache.py new file mode 100644 index 0000000000..34ab3d3671 --- /dev/null +++ b/conduitpylib/test/test_utils/test_pickle_cache.py @@ -0,0 +1,53 @@ +import pytest +import pandas as pd + +from conduitpylib.utils import pickle_cache + + +@pickle_cache() +def sample_function(df): + # A simple function that might perform some operations on a DataFrame + return df.describe() + + +@pickle_cache() +def another_function(df): + # A simple function that might perform some operations on a DataFrame + return f"{df.describe()}42" + + +@pytest.fixture +def sample_dataframe(): + # Creating a sample DataFrame to be used in tests + return pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) + + +@pytest.fixture +def another_dataframe(): + # Creating a sample DataFrame to be used in tests + return pd.DataFrame({"A": [1, 2, 3], "B": [1, 5, 6]}) + + +def test_cache_hit(sample_dataframe: pd.DataFrame): + sample_function(sample_dataframe) + sample_function.info["hits"] = 0 + sample_function(sample_dataframe) + assert sample_function.info["hits"] == 1 + + +def test_cache_integrity( + sample_dataframe: pd.DataFrame, another_dataframe: pd.DataFrame +): + cached_result = sample_function(sample_dataframe) + + new_result = sample_function(sample_dataframe) + assert cached_result.equals(new_result) + + another_result = another_function(another_dataframe) + assert not new_result.equals(another_result) + + yet_another_result = another_function(sample_dataframe) + assert not new_result.equals(yet_another_result) + + +# Additional tests can be added for different scenarios and edge cases diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index 0df1c3be54..f418921857 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -9,6 +9,7 @@ from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal from .round_to_multiple import round_to_multiple +from .pickle_cache import pickle_cache from .seaborn_monkeypatch_kdecache import ( seaborn_monkeypatch_kdecache, seaborn_monkeypatched_kdecache, @@ -28,6 +29,7 @@ 'hash_with_lax_fallback', 'lru_cache_universal', 'round_to_multiple', + 'pickle_cache', 'seaborn_monkeypatch_kdecache', 'seaborn_monkeypatched_kdecache', 'seaborn_unmonkeypatch_kdecache', diff --git a/conduitpylib/utils/pickle_cache.py b/conduitpylib/utils/pickle_cache.py new file mode 100644 index 0000000000..14b0bf42aa --- /dev/null +++ b/conduitpylib/utils/pickle_cache.py @@ -0,0 +1,61 @@ +import inspect +import shelve +import hashlib +import pickle +from pathlib import Path +from functools import wraps +import typing +from collections import OrderedDict + +from .equals_by_value import equals_by_value + + +def pickle_cache(maxsize: int = 256) -> typing.Callable: + def decorator(func: typing.Callable) -> typing.Callable: + info = { + "hits": 0, + "misses": 0, + } + + @wraps(func) + def wrapped(*args, **kwargs) -> typing.Any: + # Serialize the arguments for hashing + own_source = Path(__file__).read_text() + try: + func_source = Path(inspect.getfile(func)).read_text() + except TypeError: + func_source = inspect.getfile(func) + context = (func.__qualname__, func_source, args, kwargs, own_source) + serialized_context = str(context) + hash_value = hashlib.sha256(serialized_context.encode()).hexdigest() + + # Define the shelve file path + cache_dir = ( + Path.home() / ".cache" / "conduitpylib.utils.pickle_cache" + ) + cache_dir.mkdir(exist_ok=True) + shelve_path = cache_dir / f"{func.__qualname__}.shlv" + + with shelve.open(str(shelve_path), "c") as shelf: + # Check if cache size limit is reached + if len(shelf) >= maxsize: + # Remove least recently used item + oldest, *_rest = shelf.keys() + del shelf[oldest] + + if hash_value not in shelf or not equals_by_value( + shelf[hash_value][0], context + ): + info["misses"] += 1 + result = func(*args, **kwargs) + shelf[hash_value] = (context, result) + return result + else: + info["hits"] += 1 + # optimization: could mark item as most recently used here + return shelf[hash_value][1] + + wrapped.info = info + return wrapped + + return decorator From 5520bb025253d629ec56a33eab24b76a3a7d72a0 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 19:22:48 -0500 Subject: [PATCH 033/145] Implement data wrangling helpers --- conduitpylib/wrangle/__init__.py | 18 ++ conduitpylib/wrangle/_diff_snapshot_states.py | 85 +++++++++ .../wrangle/_find_treat_idx_mapped_col.py | 18 ++ .../wrangle/_merge_inlet_outlet_data.py | 98 ++++++++++ .../_retrieve_and_prepare_delta_dataframes.py | 48 +++++ .../wrangle/_wrangle_longitudinal_deltas.py | 85 +++++++++ .../wrangle/_wrangle_snapshot_deltas.py | 173 ++++++++++++++++++ 7 files changed, 525 insertions(+) create mode 100644 conduitpylib/wrangle/__init__.py create mode 100644 conduitpylib/wrangle/_diff_snapshot_states.py create mode 100644 conduitpylib/wrangle/_find_treat_idx_mapped_col.py create mode 100644 conduitpylib/wrangle/_merge_inlet_outlet_data.py create mode 100644 conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py create mode 100644 conduitpylib/wrangle/_wrangle_longitudinal_deltas.py create mode 100644 conduitpylib/wrangle/_wrangle_snapshot_deltas.py diff --git a/conduitpylib/wrangle/__init__.py b/conduitpylib/wrangle/__init__.py new file mode 100644 index 0000000000..be75547c0e --- /dev/null +++ b/conduitpylib/wrangle/__init__.py @@ -0,0 +1,18 @@ +from ._diff_snapshot_states import diff_snapshot_states +from ._find_treat_idx_mapped_col import find_treat_idx_mapped_col +from ._merge_inlet_outlet_data import merge_inlet_outlet_data +from ._retrieve_and_prepare_delta_dataframes import ( + retrieve_and_prepare_delta_dataframes, +) +from ._wrangle_longitudinal_deltas import wrangle_longitudinal_deltas +from ._wrangle_snapshot_deltas import wrangle_snapshot_deltas + + +__all__ = [ + "diff_snapshot_states", + "find_treat_idx_mapped_col", + "merge_inlet_outlet_data", + "retrieve_and_prepare_delta_dataframes", + "wrangle_longitudinal_deltas", + "wrangle_snapshot_deltas", +] diff --git a/conduitpylib/wrangle/_diff_snapshot_states.py b/conduitpylib/wrangle/_diff_snapshot_states.py new file mode 100644 index 0000000000..3adaf94836 --- /dev/null +++ b/conduitpylib/wrangle/_diff_snapshot_states.py @@ -0,0 +1,85 @@ +import numpy as np +import pandas as pd + +from ..utils import pickle_cache + + +# this operation is slow, so put it on its own to minimize cache disruption +@pickle_cache() +def diff_snapshot_states( + merged_df: pd.DataFrame, + max_snapshot: int, +) -> pd.DataFrame: + df_blurry_snapshots = merged_df[ + merged_df["Has Execution Blur"].astype(bool) + # exclude excess, unintended snapshots from runs that took a while to shut down + # (i.e., from at the 6 minute mark and beyond) + & (merged_df["Snapshot"] <= max_snapshot) + ] + + df_snapshot_diffs = df_blurry_snapshots.groupby( + [ + "Process Instance UUID", + "Snapshot", + # subsequent items aren't meaningful to groupby + # but are just included so they pass through untouched + "Async Mode", + "Num Nodes", + "Allocated Tasks Per Node", + "Cpus Per Node", + "Num Processes", + "Log Num Processes", + "Num Simels Per Cpu", + "Replicate", + "proc", + "Hostname", + "Num Inlets", + "Num Outlets", + "Execution Instance UUID", + "Num Threads", + "Allocation", + ], + as_index=False, + ).aggregate( + { + "Has Execution Blur": "size", # dummy column for assert below + "Num Puts Attempted": np.ptp, + "Num Try Puts Attempted": np.ptp, + "Num Blocking Puts": np.ptp, + "Num Try Puts That Succeeded": np.ptp, + "Num Puts That Succeeded Eventually": np.ptp, + "Num Blocking Puts That Succeeded Immediately": np.ptp, + "Num Puts That Succeeded Immediately": np.ptp, + "Num Puts That Blocked": np.ptp, + "Num Dropped Puts": np.ptp, + "Num Reads Performed": np.ptp, + "Num Reads That Were Fresh": np.ptp, + "Num Reads That Were Stale": np.ptp, + "Num Revisions Pulled": np.ptp, + "Num Try Pulls Attempted": np.ptp, + "Num Blocking Pulls": np.ptp, + "Num Blocking Pulls That Blocked": np.ptp, + "Num Revisions From Try Pulls": np.ptp, + "Num Revisions From Blocking Pulls": np.ptp, + "Num Pulls Attempted": np.ptp, + "Num Pulls That Were Laden Eventually": np.ptp, + "Num Blocking Pulls That Were Laden Immediately": np.ptp, + "Num Blocking Pulls That Were Laden Eventually": np.ptp, + "Num Pulls That Were Laden Immediately": np.ptp, + "Num Try Pulls That Were Laden": np.ptp, + "Num Try Pulls That Were Unladen": np.ptp, + "Net Flux Through Duct": np.ptp, + "Num Round Trip Touches Inlet": np.ptp, + "Num Round Trip Touches Outlet": np.ptp, + # why are these missing? + # 'Row Initial Timepoint (ns) Inlet' : np.ptp, + # 'Row Initial Timepoint (ns) Outlet' : np.ptp, + "Row Final Timepoint (ns) Inlet": np.ptp, + "Row Final Timepoint (ns) Outlet": np.ptp, + "Runtime Seconds Elapsed Inlet": np.mean, + "Runtime Seconds Elapsed Outlet": np.mean, + } + ) + assert {2} == set(df_snapshot_diffs["Has Execution Blur"]) + + return df_snapshot_diffs diff --git a/conduitpylib/wrangle/_find_treat_idx_mapped_col.py b/conduitpylib/wrangle/_find_treat_idx_mapped_col.py new file mode 100644 index 0000000000..bd409f7b63 --- /dev/null +++ b/conduitpylib/wrangle/_find_treat_idx_mapped_col.py @@ -0,0 +1,18 @@ +import re + +import pandas as pd + + +def find_treat_idx_mapped_col(df: pd.DataFrame) -> str: + # thanks, chatgpt + regex_pattern = r"(?:\b\d+\s*=\s*.+?\b)(?:\s*\|\s*(?:\b\d+\s*=\s*.+?\b))*" + + # Use a list comprehension to find matching columns + matching_columns = df.columns[df.columns.str.match(regex_pattern)] + + if len(matching_columns) == 1: + return matching_columns[0] + else: + raise ValueError( + f"Too many or too few matching columns: {matching_columns}" + ) diff --git a/conduitpylib/wrangle/_merge_inlet_outlet_data.py b/conduitpylib/wrangle/_merge_inlet_outlet_data.py new file mode 100644 index 0000000000..04097f5ae6 --- /dev/null +++ b/conduitpylib/wrangle/_merge_inlet_outlet_data.py @@ -0,0 +1,98 @@ +from keyname import keyname as kn +import numpy as np +import pandas as pd + +from ..utils import consolidate_merge, pickle_cache + + +@pickle_cache() +def merge_inlet_outlet_data( + df_inlet: pd.DataFrame, + df_outlet: pd.DataFrame, +) -> pd.DataFrame: + df = consolidate_merge( + df_inlet, + df_outlet, + on=["Process Instance UUID", "Update"], + suffixes=(" Inlet", " Outlet"), + how="outer", + ) + if all( + df_inlet["Runtime Seconds Elapsed"] + == df_outlet["Runtime Seconds Elapsed"] + ): + df["Runtime Seconds Elapsed Inlet"] = df["Runtime Seconds Elapsed"] + df["Runtime Seconds Elapsed Outlet"] = df["Runtime Seconds Elapsed"] + + df = df.astype( + { + "Num Inlets": "int64", + "Num Outlets": "int64", + "Num Puts Attempted": "int64", + "Num Try Puts Attempted": "int64", + "Num Blocking Puts": "int64", + "Num Try Puts That Succeeded": "int64", + "Num Puts That Succeeded Eventually": "int64", + "Num Blocking Puts That Succeeded Immediately": "int64", + "Num Puts That Succeeded Immediately": "int64", + "Num Puts That Blocked": "int64", + "Num Dropped Puts": "int64", + "Num Round Trip Touches Inlet": "int64", + "Net Flux Through Duct": "int64", + "proc": "int64", + "Snapshot": "int64", + "Has Execution Blur": "bool", + "Replicate": "int64", + "Async Mode": "int64", + "Num Threads": "int64", + "Num Processes": "int64", + "SLURM_NNODES": "int64", + "SLURM_NTASKS": "int64", + "SLURM_CPUS_ON_NODE": "int64", + } + ) + + + df["Hostname"] = df.apply( + lambda row: kn.unpack(row["Source File Inlet"])["_hostname"], + axis=1, + ) + + df["Num Nodes"] = df["SLURM_NNODES"] + df["Num Tasks"] = df["SLURM_NTASKS"] + df["Num Simels Per Cpu"] = df["Num Simulation Elements Per Cpu"] + df["Num Cpus"] = df["Num Threads"] * df["Num Processes"] + df["Allocated Tasks Per Node"] = df["Num Tasks"] // df["Num Nodes"] + df["Cpus Per Node"] = df["Allocated Tasks Per Node"] + df["Delivery Time Inlet"] = (df["Num Puts Attempted"] - 1) / df[ + "Num Round Trip Touches Inlet" + ] + df["Delivery Time Outlet"] = (df["Num Pulls Attempted"] - 1) / df[ + "Num Round Trip Touches Outlet" + ] + df["Intermittancy"] = df["Num Pulls That Were Laden Immediately"] / df[ + ["Net Flux Through Duct", "Num Pulls Attempted"] + ].min(axis=1) + df["Inlet-Seconds Elapsed"] = ( + df["Num Inlets"] * df["Runtime Seconds Elapsed Inlet"] + ) + df["Outlet-Seconds Elapsed"] = ( + df["Num Outlets"] * df["Runtime Seconds Elapsed Outlet"] + ) + df["Latency Simsteps Inlet"] = df["Delivery Time Inlet"] + df["Latency Simsteps Outlet"] = df["Delivery Time Inlet"] + df["Simstep Period Inlet (s)"] = ( + df["Inlet-Seconds Elapsed"] / df["Num Puts Attempted"] + ) + df["Simstep Period Outlet (s)"] = ( + df["Outlet-Seconds Elapsed"] / df["Num Pulls Attempted"] + ) + df["Latency Walltime Inlet (s)"] = ( + df["Latency Simsteps Inlet"] * df["Simstep Period Inlet (s)"] + ) + df["Latency Walltime Outlet (s)"] = ( + df["Latency Simsteps Outlet"] * df["Simstep Period Outlet (s)"] + ) + df["Log Num Processes"] = np.log(df["Num Processes"]) / np.log(4) + + return df diff --git a/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py new file mode 100644 index 0000000000..9802c3a3c2 --- /dev/null +++ b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py @@ -0,0 +1,48 @@ +import typing + +from nbmetalog import nbmetalog as nbm +import pandas as pd + +from ._find_treat_idx_mapped_col import find_treat_idx_mapped_col +from ._merge_inlet_outlet_data import merge_inlet_outlet_data +from ._wrangle_longitudinal_deltas import wrangle_longitudinal_deltas +from ._wrangle_snapshot_deltas import wrangle_snapshot_deltas + + +def retrieve_and_prepare_delta_dataframes( + df_inlet_url: str = "https://osf.io/jgpnv/download", + df_outlet_url: str = "https://osf.io/ncdfq/download", + treatment_column: typing.Optional[str] = None, +) -> pd.DataFrame: + df_inlet = pd.read_csv( + df_inlet_url, + compression="gzip", + ) + nbm.print_dataframe_summary(*eval(nbm.nvp_expr("df_inlet"))) + + df_outlet = pd.read_csv( + df_outlet_url, + compression="gzip", + ) + nbm.print_dataframe_summary(*eval(nbm.nvp_expr("df_outlet"))) + + df = merge_inlet_outlet_data(df_inlet, df_outlet) + + if treatment_column is not None: + treat_idx_mapper = { + val: idx for idx, val in enumerate(df[treatment_column].unique()) + } + treat_idx_mapped_title = " | ".join( + f"{idx} = {val}" for val, idx in treat_idx_mapper.items() + ) + df[treat_idx_mapped_title] = df.apply( + lambda row: treat_idx_mapper[row[treatment_column]], + axis=1, + ) + + assert find_treat_idx_mapped_col(df) == treat_idx_mapped_title + + return ( + wrangle_longitudinal_deltas(df), + wrangle_snapshot_deltas(df), + ) diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py new file mode 100644 index 0000000000..d5334df9e4 --- /dev/null +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -0,0 +1,85 @@ +import numpy as np +import pandas as pd + + +from ..utils import pickle_cache + + +@pickle_cache() +def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: + # https://stackoverflow.com/a/40629420 + df_finalized_observations = merged_df.sort_values( + "Update", ascending=False + ).drop_duplicates(["Process Instance UUID"]) + + df_finalized_observations["Dominance"] = ( + df_finalized_observations["Num Try Puts Attempted"] + / df_finalized_observations["Net Flux Through Duct"] + ) + + df_finalized_observations[ + "Fraction Messages Dropped" + ] = df_finalized_observations["Fraction Try Puts Dropped"] + + df_finalized_observations["Simstep Period Inlet (ns)"] = ( + df_finalized_observations["Simstep Period Inlet (s)"] * 1e9 + ) + + df_finalized_observations["Allocation"] = df_finalized_observations[ + "Treatment" + ] + + df_finalized_observations["Num Messages Per Pull"] = ( + df_finalized_observations["Net Flux Through Duct"] + / df_finalized_observations["Num Pulls Attempted"] + ) + + df_finalized_observations["Num Messages Per Laden Pull"] = ( + df_finalized_observations["Net Flux Through Duct"] + / df_finalized_observations["Num Pulls That Were Laden Immediately"] + ) + + df_finalized_observations["Bunchiness"] = ( + df_finalized_observations["Num Messages Per Laden Pull"] + / df_finalized_observations["Num Messages Per Pull"] + ) + + df_finalized_observations["Latency, Log10 Updates"] = np.log10( + df_finalized_observations["Latency Simsteps Inlet"] + ) + + df_finalized_observations["ms Per Update"] = ( + df_finalized_observations["Simstep Period Inlet (ns)"] / 10**6 + ) + + df_finalized_observations["Delivery Failure, %"] = ( + df_finalized_observations["Fraction Messages Dropped"] * 100 + ) + + df_finalized_observations["Bunching"] = df_finalized_observations[ + "Bunchiness" + ] + + df_finalized_observations[ + "Msgs Received Per Sent" + ] = df_finalized_observations["Num Messages Per Pull"] + + df_finalized_observations[ + "Messages Received Per Second" + ] = df_finalized_observations["Net Flux Through Duct"] / ( + df_finalized_observations["Outlet-Seconds Elapsed"] + ) + df_finalized_observations[ + "Messages Sent Per Second" + ] = df_finalized_observations["Num Try Puts Attempted"] / ( + df_finalized_observations["Inlet-Seconds Elapsed"] + ) + + df_finalized_observations["Messages Received Per Second"] = df_finalized_observations["Net Flux Through Duct"] / ( + df_finalized_observations["Outlet-Seconds Elapsed"] + ) + df_finalized_observations["Messages Sent Per Second"] = df_finalized_observations["Num Try Puts Attempted"] / ( + df_finalized_observations["Inlet-Seconds Elapsed"] + ) + + return df_finalized_observations diff --git a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py new file mode 100644 index 0000000000..32569d84ce --- /dev/null +++ b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py @@ -0,0 +1,173 @@ +import numpy as np +import pandas as pd + +from ..utils import pickle_cache + +from ._diff_snapshot_states import diff_snapshot_states + + +@pickle_cache() +def wrangle_snapshot_deltas( + merged_df: pd.DataFrame, + max_snapshot: int = 5, +) -> pd.DataFrame: + df_snapshot_diffs = diff_snapshot_states(merged_df, max_snapshot) + + df_snapshot_diffs["Fraction Messages Delivered"] = ( + df_snapshot_diffs["Num Try Puts That Succeeded"] + / df_snapshot_diffs["Num Try Puts Attempted"] + ) + df_snapshot_diffs["Delivery Success Rate"] = ( + df_snapshot_diffs["Num Try Puts That Succeeded"] + / df_snapshot_diffs["Num Try Puts Attempted"] + ) + df_snapshot_diffs["Delivery Failure Rate"] = ( + 1 - df_snapshot_diffs["Delivery Success Rate"] + ) + df_snapshot_diffs["Fraction Messages Dropped"] = df_snapshot_diffs[ + "Delivery Failure Rate" + ] + df_snapshot_diffs["Fraction Try Pulls That Were Laden"] = ( + df_snapshot_diffs["Num Try Pulls That Were Laden"] + / df_snapshot_diffs["Num Try Pulls Attempted"] + ) + + df_snapshot_diffs["Round Trip Touches Per Attempted Put"] = ( + df_snapshot_diffs["Num Round Trip Touches Inlet"] + ) / df_snapshot_diffs["Num Try Puts Attempted"] + + df_snapshot_diffs["Round Trip Touches Per Attempted Pull"] = ( + df_snapshot_diffs["Num Round Trip Touches Outlet"] + ) / df_snapshot_diffs["Num Try Pulls Attempted"] + + df_snapshot_diffs["Round Trip Touches Per Runtime Nanosecond"] = ( + df_snapshot_diffs["Num Round Trip Touches Outlet"] + ) / df_snapshot_diffs["Row Final Timepoint (ns) Outlet"] + + df_snapshot_diffs["Latency Simsteps Inlet"] = ( + df_snapshot_diffs["Num Puts Attempted"] + / df_snapshot_diffs["Num Round Trip Touches Inlet"] + ) + df_snapshot_diffs["Latency Simsteps Outlet"] = ( + df_snapshot_diffs["Num Pulls Attempted"] + / df_snapshot_diffs["Num Round Trip Touches Outlet"] + ) + df_snapshot_diffs["Delivery Clumpiness"] = 1.0 - df_snapshot_diffs[ + "Num Pulls That Were Laden Immediately" + ] / df_snapshot_diffs[["Net Flux Through Duct", "Num Pulls Attempted"]].min( + axis=1 + ) + df_snapshot_diffs["Intermittancy"] = df_snapshot_diffs[ + "Delivery Clumpiness" + ] + df_snapshot_diffs["Inlet-Nanoseconds Elapsed"] = ( + df_snapshot_diffs["Num Inlets"] + * df_snapshot_diffs["Row Final Timepoint (ns) Inlet"] + ) + df_snapshot_diffs["Outlet-Nanoseconds Elapsed"] = ( + df_snapshot_diffs["Num Outlets"] + * df_snapshot_diffs["Row Final Timepoint (ns) Outlet"] + ) + df_snapshot_diffs["Simsteps Elapsed Inlet"] = ( + df_snapshot_diffs["Num Puts Attempted"] + / df_snapshot_diffs["Num Inlets"] + ) + df_snapshot_diffs["Simsteps Elapsed Outlet"] = ( + df_snapshot_diffs["Num Pulls Attempted"] + / df_snapshot_diffs["Num Outlets"] + ) + df_snapshot_diffs["Simstep Period Inlet (ns)"] = ( + df_snapshot_diffs["Inlet-Nanoseconds Elapsed"] + / df_snapshot_diffs["Num Puts Attempted"] + ) + df_snapshot_diffs["Simstep Period Outlet (ns)"] = ( + df_snapshot_diffs["Outlet-Nanoseconds Elapsed"] + / df_snapshot_diffs["Num Pulls Attempted"] + ) + df_snapshot_diffs["Latency Walltime Inlet (ns)"] = ( + df_snapshot_diffs["Latency Simsteps Inlet"] + * df_snapshot_diffs["Simstep Period Inlet (ns)"] + ) + df_snapshot_diffs["Latency Walltime Outlet (ns)"] = ( + df_snapshot_diffs["Latency Simsteps Outlet"] + * df_snapshot_diffs["Simstep Period Outlet (ns)"] + ) + + df_snapshot_diffs = df_snapshot_diffs.astype( + { + "Num Inlets": "int64", + "Num Outlets": "int64", + "proc": "int64", + "Snapshot": "int64", + "Replicate": "int64", + "Async Mode": "int64", + "Num Threads": "int64", + "Num Processes": "int64", + "Allocated Tasks Per Node": "int64", + "Cpus Per Node": "int64", + "Num Nodes": "int64", + "Num Simels Per Cpu": "int64", + } + ) + + df_snapshot_diffs["% Msgs Lost"] = ( + df_snapshot_diffs["Fraction Messages Dropped"] * 100 + ) + + df_snapshot_diffs["Dominance"] = ( + df_snapshot_diffs["Num Try Puts Attempted"] + / df_snapshot_diffs["Net Flux Through Duct"] + ) + + df_snapshot_diffs["Num Messages Per Pull"] = ( + df_snapshot_diffs["Net Flux Through Duct"] + / df_snapshot_diffs["Num Pulls Attempted"] + ) + + df_snapshot_diffs["Num Messages Per Laden Pull"] = ( + df_snapshot_diffs["Net Flux Through Duct"] + / df_snapshot_diffs["Num Pulls That Were Laden Immediately"] + ) + + df_snapshot_diffs["Bunchiness"] = ( + df_snapshot_diffs["Num Messages Per Laden Pull"] + / df_snapshot_diffs["Num Messages Per Pull"] + ) - 1 + + df_snapshot_diffs["Latency, Log10 Updates"] = np.log10( + df_snapshot_diffs["Latency Simsteps Inlet"] + ) + + df_snapshot_diffs["ms Per Update"] = ( + df_snapshot_diffs["Simstep Period Inlet (ns)"] / 10**6 + ) + + df_snapshot_diffs["Delivery Failure, %"] = ( + df_snapshot_diffs["Fraction Messages Dropped"] * 100 + ) + + df_snapshot_diffs["Bunching"] = df_snapshot_diffs["Bunchiness"] + + df_snapshot_diffs["Msgs Received Per Sent"] = df_snapshot_diffs[ + "Num Messages Per Pull" + ] + + df_snapshot_diffs["Messages Received Per Second"] = df_snapshot_diffs[ + "Net Flux Through Duct" + ] / (df_snapshot_diffs["Outlet-Nanoseconds Elapsed"] / 10**9) + df_snapshot_diffs["Messages Sent Per Second"] = df_snapshot_diffs[ + "Num Try Puts Attempted" + ] / (df_snapshot_diffs["Inlet-Nanoseconds Elapsed"] / 10**9) + + df_snapshot_diffs["Any Messages Dropped"] = df_snapshot_diffs[ + "Fraction Messages Dropped" + ].astype(bool) + + df_snapshot_diffs["Messages Received Per Second"] = df_snapshot_diffs[ + "Net Flux Through Duct" + ] / (df_snapshot_diffs["Outlet-Nanoseconds Elapsed"] / 10**9) + df_snapshot_diffs["Messages Sent Per Second"] = df_snapshot_diffs[ + "Num Try Puts Attempted" + ] / (df_snapshot_diffs["Inlet-Nanoseconds Elapsed"] / 10**9) + + return df_snapshot_diffs From 3fb27744f0c0e4d3faf71f91c4f16567fd3fa294 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 20:19:36 -0500 Subject: [PATCH 034/145] Implement beleaguerment regplot --- conduitpylib/utils/__init__.py | 2 + conduitpylib/utils/get_signif_asterisks.py | 9 ++++ conduitpylib/viz/__init__.py | 4 ++ conduitpylib/viz/_annotate_spearman.py | 26 ++++++++++ conduitpylib/viz/_beleaguerment_regplot.py | 59 ++++++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 conduitpylib/utils/get_signif_asterisks.py create mode 100644 conduitpylib/viz/_annotate_spearman.py create mode 100644 conduitpylib/viz/_beleaguerment_regplot.py diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index f418921857..d61cdf1644 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -8,6 +8,7 @@ ) from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal +from .get_signif_asterisks import get_signif_asterisks from .round_to_multiple import round_to_multiple from .pickle_cache import pickle_cache from .seaborn_monkeypatch_kdecache import ( @@ -28,6 +29,7 @@ 'count_proportion_outliers', 'hash_with_lax_fallback', 'lru_cache_universal', + 'get_signif_asterisks', 'round_to_multiple', 'pickle_cache', 'seaborn_monkeypatch_kdecache', diff --git a/conduitpylib/utils/get_signif_asterisks.py b/conduitpylib/utils/get_signif_asterisks.py new file mode 100644 index 0000000000..a833035650 --- /dev/null +++ b/conduitpylib/utils/get_signif_asterisks.py @@ -0,0 +1,9 @@ +def get_signif_asterisks(pvalue: float) -> str: + if pvalue < 0.001: + return "***" + elif pvalue < 0.01: + return "**" + elif pvalue < 0.05: + return "*" + else: + return "" diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index f3a4e37f12..c99852f1b8 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -1,5 +1,7 @@ """Visualization tools.""" +from ._annotate_spearman import annotate_spearman +from ._beleaguerment_regplot import beleaguerment_regplot from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets from ._performance_semantics_facetplot import performance_semantics_facetplot @@ -12,6 +14,8 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ + "annotate_spearman", + "beleaguerment_regplot", "compact_xaxis_units", "frame_scatter_subsets", "performance_semantics_facetplot", diff --git a/conduitpylib/viz/_annotate_spearman.py b/conduitpylib/viz/_annotate_spearman.py new file mode 100644 index 0000000000..3660f65d4f --- /dev/null +++ b/conduitpylib/viz/_annotate_spearman.py @@ -0,0 +1,26 @@ +from matplotlib import pyplot as plt +from scipy import stats + +from ..utils import get_signif_asterisks + +def annotate_spearman(x: str, y: str, **kws) -> None: + data = kws.pop("data") + ax = kws.get("ax", plt.gca()) + + # Calculate Spearman correlation and significance + corr, p_value = stats.spearmanr(data[x], data[y]) + stars = get_signif_asterisks(p_value) + + # Linear regression + slope, _intercept, _r_value, _p_value, _std_err = stats.linregress(data[x], data[y]) + + # Annotate the plot + ax.annotate( + f"Spear Rho:\n {corr:.2f} {stars}\nn:{len(data)}\nLinReg Slope:\n {slope:.2f}", + xy=(0.05, 0.95), + xycoords="axes fraction", + ha="left", + va="top", + bbox=dict(boxstyle="round,pad=0.5", facecolor="white", alpha=0.5), + zorder=100, + ) diff --git a/conduitpylib/viz/_beleaguerment_regplot.py b/conduitpylib/viz/_beleaguerment_regplot.py new file mode 100644 index 0000000000..8e27ba1875 --- /dev/null +++ b/conduitpylib/viz/_beleaguerment_regplot.py @@ -0,0 +1,59 @@ +from matplotlib import axes as mpl_axes +from matplotlib import patheffects as mpl_pe +from matplotlib import pyplot as plt +import pandas as pd +import seaborn as sns + +from ._annotate_spearman import annotate_spearman + + +def beleaguerment_regplot( + data: pd.DataFrame, + x: str = "Messages Received Per Second", + y: str = "Messages Sent Per Second", + ax: mpl_axes.Axes = None, + **kwargs, +) -> mpl_axes.Axes: + if ax is None: + ax = plt.gca() + + sns.regplot( + data=data, + x=x, + y=y, + ax=ax, + line_kws={ + "zorder": 100, + "lw": 3, + "ls": "--", + "path_effects": [ + mpl_pe.Stroke(linewidth=4, foreground="white"), + mpl_pe.Stroke(linewidth=2, foreground="lightsalmon"), + ], + }, + scatter_kws=dict( + alpha=0.1, + s=10, + lw=0.5, + marker="D", + **kwargs, + ), + truncate=False, + ) + + # outline scattered points + sns.kdeplot( + data=data, + x=x, + y=y, + ax=ax, + fill=False, + thresh=1e-6, + cut=10, + lw=0.5, + alpha=0.6, + levels=1, + **kwargs, + ) + + annotate_spearman(data=data, x=x, y=y, ax=ax, **kwargs) From 8fd8302a6e20bf0306f56bc91b6784376b416556 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 20:20:19 -0500 Subject: [PATCH 035/145] Make equals_by_value support nested lists and dict --- conduitpylib/utils/equals_by_value.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/conduitpylib/utils/equals_by_value.py b/conduitpylib/utils/equals_by_value.py index d7c476b08c..c3514616b7 100644 --- a/conduitpylib/utils/equals_by_value.py +++ b/conduitpylib/utils/equals_by_value.py @@ -6,6 +6,15 @@ def _equals_by_value(obj1: typing.Any, obj2: typing.Any) -> bool: + # Handle builtin datatypes recursively + if isinstance(obj1, (tuple, list)) and isinstance(obj2, (tuple, list)): + return all(_equals_by_value(o1, o2) for o1, o2 in zip(obj1, obj2)) + + if isinstance(obj1, dict) and isinstance(obj2, dict): + return len(obj1) == len(obj2) and all( + k in obj2 and _equals_by_value(obj1[k], obj2[k]) for k in obj1 + ) + # Handle comparison between pandas DataFrames or Series if all(isinstance(o, pd.Series) for o in (obj1, obj2)): return np.allclose(obj1, obj2) From b1c4bc95ee0713da50af3120fe988d6eb542a280 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 21:00:13 -0500 Subject: [PATCH 036/145] Implement beleaguerment facetplot --- conduitpylib/viz/__init__.py | 2 + conduitpylib/viz/_annotate_spearman.py | 11 +++- conduitpylib/viz/_beleaguerment_facetplot.py | 68 ++++++++++++++++++++ conduitpylib/wrangle/__init__.py | 2 + 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 conduitpylib/viz/_beleaguerment_facetplot.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index c99852f1b8..384f9b220e 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -2,6 +2,7 @@ from ._annotate_spearman import annotate_spearman from ._beleaguerment_regplot import beleaguerment_regplot +from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets from ._performance_semantics_facetplot import performance_semantics_facetplot @@ -15,6 +16,7 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ "annotate_spearman", + "beleaguerment_facetplot", "beleaguerment_regplot", "compact_xaxis_units", "frame_scatter_subsets", diff --git a/conduitpylib/viz/_annotate_spearman.py b/conduitpylib/viz/_annotate_spearman.py index 3660f65d4f..64f0c29e3a 100644 --- a/conduitpylib/viz/_annotate_spearman.py +++ b/conduitpylib/viz/_annotate_spearman.py @@ -3,6 +3,7 @@ from ..utils import get_signif_asterisks + def annotate_spearman(x: str, y: str, **kws) -> None: data = kws.pop("data") ax = kws.get("ax", plt.gca()) @@ -12,7 +13,9 @@ def annotate_spearman(x: str, y: str, **kws) -> None: stars = get_signif_asterisks(p_value) # Linear regression - slope, _intercept, _r_value, _p_value, _std_err = stats.linregress(data[x], data[y]) + slope, _intercept, _r_value, _p_value, _std_err = stats.linregress( + data[x], data[y] + ) # Annotate the plot ax.annotate( @@ -21,6 +24,8 @@ def annotate_spearman(x: str, y: str, **kws) -> None: xycoords="axes fraction", ha="left", va="top", - bbox=dict(boxstyle="round,pad=0.5", facecolor="white", alpha=0.5), - zorder=100, + bbox=dict( + alpha=1.0, boxstyle="round,pad=0.5", facecolor="white", zorder=900 + ), + zorder=1000, ) diff --git a/conduitpylib/viz/_beleaguerment_facetplot.py b/conduitpylib/viz/_beleaguerment_facetplot.py new file mode 100644 index 0000000000..49c7ab8da0 --- /dev/null +++ b/conduitpylib/viz/_beleaguerment_facetplot.py @@ -0,0 +1,68 @@ +import typing + +import pandas as pd +import seaborn as sns + +from ._beleaguerment_regplot import beleaguerment_regplot +from ._get_defaults import get_default_palette + + +def beleaguerment_facetplot( + data: pd.DataFrame, + x: str = "Messages Received Per Second", + y: str = "Messages Sent Per Second", + hue: typing.Optional[str] = None, + palette: typing.Optional[typing.List[str]] = None, +) -> sns.FacetGrid: + if palette is None: + palette = get_default_palette() + + data_real = data.copy() + data_dummy = data.copy() + + if hue is not None: + data_dummy[hue] = "dummy" + + data_with_spoof = pd.concat([data_dummy, data_real]) + + g = sns.FacetGrid( + data_with_spoof, + aspect=1.2, + col=hue, + hue=hue, + sharex=True, + sharey=True, + palette=["white", *palette], + height=4, + ) + + g.map_dataframe( + beleaguerment_regplot, + x=x, + y=y, + ) + + bothax = g.axes.flat[0] + bothax.cla() + sns.kdeplot( + data=data, + x=x, + y=y, + hue=hue, + ax=bothax, + alpha=0.7, + fill=True, + legend=True, + palette=palette, + ) + sns.move_legend(bothax, loc="upper left") + + bothax.axline((0, 0), slope=1, color="black", linestyle=":", lw=2) + + for ax in g.axes.flat: + ax.set_xlim(left=0) + ax.set_ylim(bottom=0) + ax.set_xticks(ax.get_yticks()) + ax.ticklabel_format(scilimits=(-2, 2)) + + return g diff --git a/conduitpylib/wrangle/__init__.py b/conduitpylib/wrangle/__init__.py index be75547c0e..f575c30405 100644 --- a/conduitpylib/wrangle/__init__.py +++ b/conduitpylib/wrangle/__init__.py @@ -4,6 +4,7 @@ from ._retrieve_and_prepare_delta_dataframes import ( retrieve_and_prepare_delta_dataframes, ) +from ._wrangle_instrumentation_longform import wrangle_instrumentation_longform from ._wrangle_longitudinal_deltas import wrangle_longitudinal_deltas from ._wrangle_snapshot_deltas import wrangle_snapshot_deltas @@ -13,6 +14,7 @@ "find_treat_idx_mapped_col", "merge_inlet_outlet_data", "retrieve_and_prepare_delta_dataframes", + "wrangle_instrumentation_longform", "wrangle_longitudinal_deltas", "wrangle_snapshot_deltas", ] From ec65d59351d2e6b490ffeb81595d8048028bd578 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 22:19:41 -0500 Subject: [PATCH 037/145] Bugfix: use hue_order in beleaguerment viz --- conduitpylib/viz/_beleaguerment_facetplot.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/conduitpylib/viz/_beleaguerment_facetplot.py b/conduitpylib/viz/_beleaguerment_facetplot.py index 49c7ab8da0..daf92c4798 100644 --- a/conduitpylib/viz/_beleaguerment_facetplot.py +++ b/conduitpylib/viz/_beleaguerment_facetplot.py @@ -12,6 +12,7 @@ def beleaguerment_facetplot( x: str = "Messages Received Per Second", y: str = "Messages Sent Per Second", hue: typing.Optional[str] = None, + hue_order: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, ) -> sns.FacetGrid: if palette is None: @@ -20,6 +21,14 @@ def beleaguerment_facetplot( data_real = data.copy() data_dummy = data.copy() + if hue is not None: + if hue_order is None: + hue_order = sorted(data[hue].unique()) + if not set(hue_order) <= set(data[hue].unique()): + raise ValueError("hue_order has hue categories missing from data.") + elif hue_order is not None: + raise ValueError("If hue is None, hue_order must also be None.") + if hue is not None: data_dummy[hue] = "dummy" @@ -30,6 +39,7 @@ def beleaguerment_facetplot( aspect=1.2, col=hue, hue=hue, + hue_order=["dummy", *hue_order], sharex=True, sharey=True, palette=["white", *palette], @@ -49,6 +59,7 @@ def beleaguerment_facetplot( x=x, y=y, hue=hue, + hue_order=hue_order, ax=bothax, alpha=0.7, fill=True, From 8341b8eb038fa2401aa7825c82d1cadb329e4e71 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 9 Nov 2023 22:23:14 -0500 Subject: [PATCH 038/145] Add lac 417 beleaguerment notebook --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..949bf78c3f --- /dev/null +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,129 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/jgpnv/download\",\n", + " df_outlet_url=\"https://osf.io/ncdfq/download\",\n", + " treatment_column=\"Allocation\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(longitudinal_df, snapshot_df)\n", + "\n", + "for allocation, group in data.groupby(\"Allocation\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " beleaguerment_facetplot,\n", + " data=group_df,\n", + " x=\"Messages Received Per Second\",\n", + " y=\"Messages Sent Per Second\",\n", + " hue=\"Instrumentation\",\n", + " )\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 3adf5b3081171301cb2c40354fe438269c7e5522 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 01:21:45 -0500 Subject: [PATCH 039/145] Implement apply_symmetric_axes helper --- conduitpylib/viz/__init__.py | 2 ++ conduitpylib/viz/_apply_symmetric_axes.py | 37 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 conduitpylib/viz/_apply_symmetric_axes.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 384f9b220e..eba6b3656a 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -1,6 +1,7 @@ """Visualization tools.""" from ._annotate_spearman import annotate_spearman +from ._apply_symmetric_axes import apply_symmetric_axes from ._beleaguerment_regplot import beleaguerment_regplot from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units @@ -15,6 +16,7 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ + "apply_symmetric_axes", "annotate_spearman", "beleaguerment_facetplot", "beleaguerment_regplot", diff --git a/conduitpylib/viz/_apply_symmetric_axes.py b/conduitpylib/viz/_apply_symmetric_axes.py new file mode 100644 index 0000000000..7b1bc100ca --- /dev/null +++ b/conduitpylib/viz/_apply_symmetric_axes.py @@ -0,0 +1,37 @@ +import itertools as it +import operator + +from matplotlib import pyplot as plt +from matplotlib import ticker as mpl_ticker + + +def apply_symmetric_axes(ax: plt.Axes) -> None: + """ + Configures a Matplotlib axis to have a square aspect ratio, + the same axis limits on X and Y, and uses the default Matplotlib ticker + to set the ticks on X and Y. + + Parameters: + ax (matplotlib.axes.Axes): The axis to configure. + """ + # 1) Setting the aspect of the axis to be equal (square plot) + ax.set_aspect("equal", adjustable="box") + + # 2) Setting the same limits for x and y axes + xlim = ax.get_xlim() + ylim = ax.get_ylim() + + shared_lim = (min(*xlim, *ylim), max(*xlim, *ylim)) + lim_width = operator.sub(*shared_lim) + + padded_lim = ( + shared_lim[0] - lim_width * 0.05, + shared_lim[1] + lim_width * 0.05, + ) + + ax.set_xlim(*padded_lim) + ax.set_ylim(*padded_lim) + + # 3) Using the default Matplotlib ticker for setting the ticks + ax.xaxis.set_major_locator(mpl_ticker.AutoLocator()) + ax.yaxis.set_major_locator(mpl_ticker.AutoLocator()) From 23ceb9833a0e29069a2a4331e76826a2f94bf288 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 01:23:17 -0500 Subject: [PATCH 040/145] Bugfix: missing -1 to longitudinal bunching calc --- conduitpylib/wrangle/_wrangle_longitudinal_deltas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index d5334df9e4..c5cef9c60b 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -42,7 +42,7 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: df_finalized_observations["Bunchiness"] = ( df_finalized_observations["Num Messages Per Laden Pull"] / df_finalized_observations["Num Messages Per Pull"] - ) + ) - 1 df_finalized_observations["Latency, Log10 Updates"] = np.log10( df_finalized_observations["Latency Simsteps Inlet"] From f8f4f387d89ce7d4a30dff69775807ec956e9512 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 01:25:30 -0500 Subject: [PATCH 041/145] Alias new bunchiness metric to clumpiness, etc. --- .../wrangle/_wrangle_longitudinal_deltas.py | 14 ++++++++++---- conduitpylib/wrangle/_wrangle_snapshot_deltas.py | 13 +++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index c5cef9c60b..e74a5789fa 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -44,6 +44,16 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: / df_finalized_observations["Num Messages Per Pull"] ) - 1 + df_finalized_observations[ + "Delivery Clumpiness" + ] = df_finalized_observations["Bunchiness"] + df_finalized_observations["Intermittancy"] = df_finalized_observations[ + "Bunchiness" + ] + df_finalized_observations["Bunching"] = df_finalized_observations[ + "Bunchiness" + ] + df_finalized_observations["Latency, Log10 Updates"] = np.log10( df_finalized_observations["Latency Simsteps Inlet"] ) @@ -56,10 +66,6 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: df_finalized_observations["Fraction Messages Dropped"] * 100 ) - df_finalized_observations["Bunching"] = df_finalized_observations[ - "Bunchiness" - ] - df_finalized_observations[ "Msgs Received Per Sent" ] = df_finalized_observations["Num Messages Per Pull"] diff --git a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py index 32569d84ce..5291ac22c3 100644 --- a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py +++ b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py @@ -52,14 +52,6 @@ def wrangle_snapshot_deltas( df_snapshot_diffs["Num Pulls Attempted"] / df_snapshot_diffs["Num Round Trip Touches Outlet"] ) - df_snapshot_diffs["Delivery Clumpiness"] = 1.0 - df_snapshot_diffs[ - "Num Pulls That Were Laden Immediately" - ] / df_snapshot_diffs[["Net Flux Through Duct", "Num Pulls Attempted"]].min( - axis=1 - ) - df_snapshot_diffs["Intermittancy"] = df_snapshot_diffs[ - "Delivery Clumpiness" - ] df_snapshot_diffs["Inlet-Nanoseconds Elapsed"] = ( df_snapshot_diffs["Num Inlets"] * df_snapshot_diffs["Row Final Timepoint (ns) Inlet"] @@ -133,6 +125,9 @@ def wrangle_snapshot_deltas( df_snapshot_diffs["Num Messages Per Laden Pull"] / df_snapshot_diffs["Num Messages Per Pull"] ) - 1 + df_snapshot_diffs["Delivery Clumpiness"] = df_snapshot_diffs["Bunchiness"] + df_snapshot_diffs["Intermittancy"] = df_snapshot_diffs["Bunchiness"] + df_snapshot_diffs["Bunching"] = df_snapshot_diffs["Bunchiness"] df_snapshot_diffs["Latency, Log10 Updates"] = np.log10( df_snapshot_diffs["Latency Simsteps Inlet"] @@ -146,8 +141,6 @@ def wrangle_snapshot_deltas( df_snapshot_diffs["Fraction Messages Dropped"] * 100 ) - df_snapshot_diffs["Bunching"] = df_snapshot_diffs["Bunchiness"] - df_snapshot_diffs["Msgs Received Per Sent"] = df_snapshot_diffs[ "Num Messages Per Pull" ] From 809dd2351005e8b56dd7e103b9c8212c745d6e34 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 01:26:28 -0500 Subject: [PATCH 042/145] Apply black format --- conduitpylib/wrangle/_wrangle_longitudinal_deltas.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index e74a5789fa..3e167e6791 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -81,10 +81,14 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: df_finalized_observations["Inlet-Seconds Elapsed"] ) - df_finalized_observations["Messages Received Per Second"] = df_finalized_observations["Net Flux Through Duct"] / ( + df_finalized_observations[ + "Messages Received Per Second" + ] = df_finalized_observations["Net Flux Through Duct"] / ( df_finalized_observations["Outlet-Seconds Elapsed"] ) - df_finalized_observations["Messages Sent Per Second"] = df_finalized_observations["Num Try Puts Attempted"] / ( + df_finalized_observations[ + "Messages Sent Per Second" + ] = df_finalized_observations["Num Try Puts Attempted"] / ( df_finalized_observations["Inlet-Seconds Elapsed"] ) From c3d3b3f68c6997e074cad5c47c2521216630c76e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 01:27:25 -0500 Subject: [PATCH 043/145] Impl runtime indicator regplot, pairplot --- conduitpylib/viz/__init__.py | 6 ++ conduitpylib/viz/_get_defaults.py | 11 +++ .../viz/_runtime_indicator_regplot.py | 64 +++++++++++++ .../viz/_runtime_indicators_pairplot.py | 49 ++++++++++ .../viz/_runtime_indicators_regplot.py | 91 +++++++++++++++++++ 5 files changed, 221 insertions(+) create mode 100644 conduitpylib/viz/_runtime_indicator_regplot.py create mode 100644 conduitpylib/viz/_runtime_indicators_pairplot.py create mode 100644 conduitpylib/viz/_runtime_indicators_regplot.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index eba6b3656a..c34141f9ca 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -11,6 +11,9 @@ from ._performance_semantics_scatterplot import ( performance_semantics_scatterplot, ) +from ._runtime_indicator_regplot import runtime_indicator_regplot +from ._runtime_indicators_pairplot import runtime_indicators_pairplot +from ._runtime_indicators_regplot import runtime_indicators_regplot from ._set_kde_lims import set_kde_lims @@ -25,5 +28,8 @@ "performance_semantics_facetplot", "performance_semantics_kdeplot", "performance_semantics_scatterplot", + "runtime_indicator_regplot", + "runtime_indicators_pairplot", + "runtime_indicators_regplot", "set_kde_lims", ] diff --git a/conduitpylib/viz/_get_defaults.py b/conduitpylib/viz/_get_defaults.py index f69a0bd838..4f9cd1245e 100644 --- a/conduitpylib/viz/_get_defaults.py +++ b/conduitpylib/viz/_get_defaults.py @@ -11,3 +11,14 @@ def get_default_palette() -> typing.List[str]: # return ["#5c5cff", "#64e0ff", "#40B0A6"] # return ["#91f7ff", "#ff82d4", "#91aaff"] return ['#9467bd', '#bcbd22', '#17becf'] # purple, gold, teal + + +def get_default_runtime_indicators() -> typing.List[str]: + return [ + # "Num Messages Per Laden Pull", + "Latency, Log10 Updates", + "ms Per Update", + "Msgs Received Per Sent", + "Bunching", + # "Delivery Failure, %", + ] diff --git a/conduitpylib/viz/_runtime_indicator_regplot.py b/conduitpylib/viz/_runtime_indicator_regplot.py new file mode 100644 index 0000000000..cd5b2f4f23 --- /dev/null +++ b/conduitpylib/viz/_runtime_indicator_regplot.py @@ -0,0 +1,64 @@ +import typing + +from matplotlib import patheffects as mpl_pe +from matplotlib import pyplot as plt +import pandas as pd +import seaborn as sns + +from ._apply_symmetric_axes import apply_symmetric_axes + + +def runtime_indicator_regplot( + data: pd.DataFrame, + x: str = "Longitudinal", + y: str = "Snapshot", + color: str = "purple", + ax: typing.Optional[plt.Axes] = None, +) -> plt.Axes: + if ax is None: + ax = plt.gca() + + sns.regplot( + data=data, + x=x, + y=y, + ax=ax, + line_kws={ + "color": "darkorchid", + "zorder": 100, + "lw": 3, + "ls": "--", + "path_effects": [ + mpl_pe.Stroke(linewidth=6, foreground="white"), + mpl_pe.Stroke(linewidth=4, foreground="slateblue"), + ], + }, + scatter_kws={ + "alpha": 0.4, + "s": 10, + "lw": 0.5, + "ec": "gold", + "color": color, + "marker": "D", + }, + ) + sns.kdeplot( + data=data, + x=x, + y=y, + ax=ax, + fill=False, + thresh=1e-6, + cut=10, + color="#fdff52", + lw=0.5, + ) + # ax.set_title(f"{indicator}") + ax.axline((0, 0), slope=1, color="black", linestyle=":", lw=2) + + ax.grid(True) + ax.set_axisbelow(True) + + apply_symmetric_axes(ax) + + return ax diff --git a/conduitpylib/viz/_runtime_indicators_pairplot.py b/conduitpylib/viz/_runtime_indicators_pairplot.py new file mode 100644 index 0000000000..51ca2cd988 --- /dev/null +++ b/conduitpylib/viz/_runtime_indicators_pairplot.py @@ -0,0 +1,49 @@ +import typing + +import pandas as pd +import seaborn as sns + +from ._get_defaults import get_default_runtime_indicators + + +def runtime_indicators_pairplot( + data: pd.DataFrame, + hue: typing.Optional[str] = None, + hue_order: typing.Optional[str] = None, + indicators: typing.Optional[typing.List[str]] = None, + palette: typing.Optional[typing.List[str]] = None, +) -> sns.PairGrid: + + if palette is None: + palette = sns.color_palette() + + if hue is not None: + if hue_order is None: + hue_order = sorted(data[hue].unique()) + if not set(hue_order) <= set(data[hue].unique()): + raise ValueError("hue_order has hue categories missing from data.") + elif hue_order is not None: + raise ValueError("If hue is None, hue_order must also be None.") + + if indicators is None: + indictors = get_default_runtime_indicators() + + # ideas for enhancement: + # - flip a facetgrid axis so the diagonal is ascending + # - color code axes by indicator + g = sns.PairGrid( + data, + diag_sharey=False, + vars=indictors, + hue=hue, + hue_order=hue_order, + ) + g.map_diag(sns.kdeplot, common_norm=True, palette=palette) + g.map_lower(sns.kdeplot, fill=True, thresh=1e-5, palette=palette) + g.map_upper(sns.scatterplot, palette=palette) + + handles = g._legend_data.values() + labels = g._legend_data.keys() + g.axes.flat[0].legend(handles=handles, labels=labels) + + return g diff --git a/conduitpylib/viz/_runtime_indicators_regplot.py b/conduitpylib/viz/_runtime_indicators_regplot.py new file mode 100644 index 0000000000..8ef5b9f51e --- /dev/null +++ b/conduitpylib/viz/_runtime_indicators_regplot.py @@ -0,0 +1,91 @@ +import itertools as it +import typing + +from matplotlib import patheffects as mpl_pe +from matplotlib import pyplot as plt +import pandas as pd +import seaborn as sns + +from ._get_defaults import get_default_runtime_indicators +from ._runtime_indicator_regplot import runtime_indicator_regplot + + +def runtime_indicators_regplot( + data: pd.DataFrame, + compare: str = "Instrumentation", + comparison_x: str = "Longitudinal", + comparison_y: str = "Snapshot", + indicators: typing.Optional[typing.List[str]] = None, + palette: typing.Optional[typing.List[str]] = None, +) -> sns.FacetGrid: + if indicators is None: + indicators = get_default_runtime_indicators() + + if palette is None: + palette = sns.color_palette() + + melted = pd.melt( + data, + id_vars=[compare, "Process Instance UUID"], + value_vars=indicators, + var_name="Runtime Indicator", + value_name="Value", + ) + pivoted = pd.pivot( + melted, + index=["Process Instance UUID", "Runtime Indicator"], + columns=compare, + values="Value", + ).reset_index() + + # hack to make a FacetGrid + facetgrid = sns.FacetGrid( + data=pivoted, + col="Runtime Indicator", + col_order=indicators, + sharex=False, + sharey=False, + ) + facetgrid.set_titles(col_template="{col_name}") + + facetgrid.map_dataframe( + runtime_indicator_regplot, + x=comparison_x, + y=comparison_y, + color="purple", + ) + + # add colorcoded axis backgrounds + for i, ax in enumerate(facetgrid.axes.flat): + xmin, xmax = ax.get_xlim() + ymin, ymax = ax.get_ylim() + dx = (xmax - xmin) / 8 + dy = (ymax - ymin) / 6 + if i == 0: + ax.add_patch( + plt.Rectangle( + (xmin - dx, ymin), + dx, + ymax - ymin, + facecolor=palette[0], + alpha=0.3, + clip_on=False, + linewidth=0, + zorder=-999, + ) + ) + + ax.add_patch( + plt.Rectangle( + (xmin, ymin - dy), + xmax - xmin, + dy, + facecolor=palette[1], + alpha=0.3, + clip_on=False, + linewidth=0, + zorder=-999, + ) + ) + + return facetgrid From 9254999508f8a0c26f758f788c292cd261bd831f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 05:35:49 -0500 Subject: [PATCH 044/145] Impl, test perruntime indicators concat --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 164 ++++++++++++++++++ conduitpylib/viz/__init__.py | 4 + .../viz/_performance_semantics_facetplot.py | 1 - ...time_indicators_concat_regplot_pairplot.py | 27 +++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb create mode 100644 conduitpylib/viz/_runtime_indicators_concat_regplot_pairplot.py diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..da56e09148 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,164 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import contextlib\n", + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import (\n", + " runtime_indicators_concat_regplot_pairplot,\n", + " runtime_indicators_pairplot,\n", + " runtime_indicators_regplot,\n", + ")\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/jgpnv/download\",\n", + " df_outlet_url=\"https://osf.io/ncdfq/download\",\n", + " treatment_column=\"Allocation\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", + "\n", + "patchwork_context = pw.patched_axisgrid\n", + "for context in contextlib.nullcontext, patchwork_context:\n", + " for allocation, group in data.groupby(\"Allocation\"):\n", + " plt.clf()\n", + " with context():\n", + " group_df = group.reset_index()\n", + " regplot_facetgrid = tp.tee(\n", + " runtime_indicators_regplot,\n", + " data=group_df,\n", + " compare=\"Instrumentation\",\n", + " comparison_x=\"Longitudinal\",\n", + " comparison_y=\"Snapshot\",\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " },\n", + " teeplot_save=(context is not patchwork_context),\n", + " )\n", + " pairplot_grid = tp.tee(\n", + " runtime_indicators_pairplot,\n", + " data=group_df,\n", + " hue=\"Instrumentation\",\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " },\n", + " teeplot_save=(context is not patchwork_context),\n", + " )\n", + "\n", + " if context is patchwork_context:\n", + " tp.tee(\n", + " runtime_indicators_concat_regplot_pairplot,\n", + " regplot_facetgrid,\n", + " pairplot_grid,\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " },\n", + " )\n", + "\n", + " plt.show()\n", + " plt.clf()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index c34141f9ca..a1ccdd20fc 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -12,6 +12,9 @@ performance_semantics_scatterplot, ) from ._runtime_indicator_regplot import runtime_indicator_regplot +from ._runtime_indicators_concat_regplot_pairplot import ( + runtime_indicators_concat_regplot_pairplot, +) from ._runtime_indicators_pairplot import runtime_indicators_pairplot from ._runtime_indicators_regplot import runtime_indicators_regplot from ._set_kde_lims import set_kde_lims @@ -29,6 +32,7 @@ "performance_semantics_kdeplot", "performance_semantics_scatterplot", "runtime_indicator_regplot", + "runtime_indicators_concat_regplot_pairplot", "runtime_indicators_pairplot", "runtime_indicators_regplot", "set_kde_lims", diff --git a/conduitpylib/viz/_performance_semantics_facetplot.py b/conduitpylib/viz/_performance_semantics_facetplot.py index 43a913fffc..e1604638b9 100644 --- a/conduitpylib/viz/_performance_semantics_facetplot.py +++ b/conduitpylib/viz/_performance_semantics_facetplot.py @@ -18,7 +18,6 @@ @patch.dict(pw.param, {"margin": 0.0}) -@pw.patchworklib.patched_axisgrid() def performance_semantics_facetplot( data: pd.DataFrame, x: str="Simstep Period Inlet (ns)", diff --git a/conduitpylib/viz/_runtime_indicators_concat_regplot_pairplot.py b/conduitpylib/viz/_runtime_indicators_concat_regplot_pairplot.py new file mode 100644 index 0000000000..160974fbe3 --- /dev/null +++ b/conduitpylib/viz/_runtime_indicators_concat_regplot_pairplot.py @@ -0,0 +1,27 @@ +from unittest.mock import patch + +import patchworklib as pw +import seaborn as sns + + +@patch.dict("patchworklib.param", {"margin": 0}) +def runtime_indicators_concat_regplot_pairplot( + regplot_facetgrid: sns.FacetGrid, + pairplot_grid: sns.PairGrid, +) -> pw.Brick: + f = regplot_facetgrid + g = pairplot_grid + + f.fig.set_size_inches(*g.fig.get_size_inches()) + + for gax, fax in zip(g.axes.flat, f.axes.flat): + # Set the position of the corresponding subplot + fax.set_position(gax.get_position()) + axlim = gax.get_xlim() + fax.set_ylim(*axlim) + fax.set_xlim(*axlim) + + fbrick = pw.load_seaborngrid(f) + gbrick = pw.load_seaborngrid(g) + + return fbrick / gbrick From 628fe4e0f0a6a6287b19bfa7cf1a60d84b7138f8 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 05:37:44 -0500 Subject: [PATCH 045/145] Commit missing instrumentation wrangling content --- conduitpylib/wrangle/__init__.py | 2 + .../_wrangle_instrumentation_longform.py | 19 +++++++ .../_wrangle_instrumentation_wideform.py | 55 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 conduitpylib/wrangle/_wrangle_instrumentation_longform.py create mode 100644 conduitpylib/wrangle/_wrangle_instrumentation_wideform.py diff --git a/conduitpylib/wrangle/__init__.py b/conduitpylib/wrangle/__init__.py index f575c30405..798214d5e9 100644 --- a/conduitpylib/wrangle/__init__.py +++ b/conduitpylib/wrangle/__init__.py @@ -5,6 +5,7 @@ retrieve_and_prepare_delta_dataframes, ) from ._wrangle_instrumentation_longform import wrangle_instrumentation_longform +from ._wrangle_instrumentation_wideform import wrangle_instrumentation_wideform from ._wrangle_longitudinal_deltas import wrangle_longitudinal_deltas from ._wrangle_snapshot_deltas import wrangle_snapshot_deltas @@ -15,6 +16,7 @@ "merge_inlet_outlet_data", "retrieve_and_prepare_delta_dataframes", "wrangle_instrumentation_longform", + "wrangle_instrumentation_wideform", "wrangle_longitudinal_deltas", "wrangle_snapshot_deltas", ] diff --git a/conduitpylib/wrangle/_wrangle_instrumentation_longform.py b/conduitpylib/wrangle/_wrangle_instrumentation_longform.py new file mode 100644 index 0000000000..594793a8cd --- /dev/null +++ b/conduitpylib/wrangle/_wrangle_instrumentation_longform.py @@ -0,0 +1,19 @@ +import pandas as pd + + +def wrangle_instrumentation_longform( + longitudinal_df: pd.DataFrame, + snapshot_df: pd.DataFrame, + column_name: str = "Instrumentation", + snapshot_moniker: str = "Snapshot", + longitudinal_moniker: str = "Longitudinal", +) -> pd.DataFrame: + snapshot = snapshot_df.copy().groupby("Process Instance UUID").sample(n=1) + snapshot[column_name] = snapshot_moniker + + longitudinal = ( + longitudinal_df.copy().groupby("Process Instance UUID").sample(n=1) + ) + longitudinal[column_name] = longitudinal_moniker + + return pd.concat([snapshot, longitudinal]) diff --git a/conduitpylib/wrangle/_wrangle_instrumentation_wideform.py b/conduitpylib/wrangle/_wrangle_instrumentation_wideform.py new file mode 100644 index 0000000000..4a056135f3 --- /dev/null +++ b/conduitpylib/wrangle/_wrangle_instrumentation_wideform.py @@ -0,0 +1,55 @@ +import pandas as pd + +from ..viz._get_defaults import get_default_runtime_indicators + + +def wrangle_instrumentation_wideform( + longitudinal_df: pd.DataFrame, + snapshot_df: pd.DataFrame, + column_name: str = "Instrumentation", + snapshot_moniker: str = "Snapshot", + longitudinal_moniker: str = "Longitudinal", +) -> pd.DataFrame: + assert not snapshot_df.columns.duplicated().any() + + roll = snapshot_df.copy().groupby("Process Instance UUID").sample(n=1) + roll[column_name] = snapshot_moniker + assert not roll.columns.duplicated().any() + + assert not longitudinal_df.columns.duplicated().any() + fin = longitudinal_df.copy().groupby("Process Instance UUID").sample(n=1) + fin[column_name] = longitudinal_moniker + assert not fin.columns.duplicated().any() + + suffixes = (f" {snapshot_moniker}", f" {longitudinal_moniker}") + cat = pd.merge( + roll, + fin, + how="right", + on=["Process Instance UUID"], + suffixes=suffixes, + ).reset_index(drop=True) + assert not cat.columns.duplicated().any() + + keep_columns = [] + rename_columns = {} + + col_pairs = [ + (c, c.replace(*suffixes)) + for c in cat.columns + if suffixes[0] in c and c.replace(*suffixes) in cat.columns + ] + + for c1, c2 in col_pairs: + assert c1 != c2 + keep_columns.append(c1) + assert len(cat[c1]) == len(cat[c2]) + root = c1.replace(suffixes[0], "") + if ( + cat[c1] != cat[c2] + ).any() or root in get_default_runtime_indicators(): + keep_columns.append(c2) + else: + rename_columns[c1] = root + + return cat[keep_columns].rename(columns=rename_columns).copy() From 3b7b790d107dcbb75a6591c771d12ca861b2cdcf Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 06:08:05 -0500 Subject: [PATCH 046/145] Fix smear errorbar calculation --- .../viz/_performance_semantics_scatterplot.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 3f41d9ae1e..1c6a1ff284 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -349,8 +349,13 @@ def remove_alpha(handle, orig) -> None: ########################################################################### # due to unwanted side effects, must come after legend plot - max_latency = data["Latency Simsteps Inlet"] - min_latency = data["Latency Simsteps Inlet"] / data["Num Messages Per Pull"] + smear_duration_updates = ( + data["Num Messages Per Laden Pull"] / data["Num Messages Per Pull"] + ) - 1 # noqa: fmt + # smear_duration_updates = np.max(smear_duration_updates, 0) + # max_latency = data["Latency Simsteps Inlet"] + smear_duration_updates / 2 + data["Latency lb"] = data["Latency Simsteps Inlet"] - (smear_duration_updates / 2) + # assert (smear_duration_updates / 2 <= data[y]).all() if legend != "only" and show_bunching_smear: jointgrid.ax_joint.errorbar( data=data, @@ -362,9 +367,11 @@ def remove_alpha(handle, orig) -> None: yerr=np.vstack( [ # below-error height - data["Latency Simsteps Inlet"] - min_latency, + # data["Latency Simsteps Inlet"] - min_latency, + smear_duration_updates / 2, # above-error height - max_latency - data["Latency Simsteps Inlet"], + # max_latency - data["Latency Simsteps Inlet"], + smear_duration_updates / 2, ], ), # doesn't work, need outer conditional From c31aecfb8879c6d6fd94a001e33437ae6961a51f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 06:10:50 -0500 Subject: [PATCH 047/145] Make performance semantics notebook --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 167 ++++++++++++++++++ conduitpylib/viz/__init__.py | 2 + conduitpylib/viz/_get_notomoji_font_path.py | 4 + .../viz/assets}/Noto-LICENSE | 0 .../viz/assets}/NotoEmoji-Regular.ttf | Bin .../wrangle/_wrangle_longitudinal_deltas.py | 3 + .../wrangle/_wrangle_snapshot_deltas.py | 5 +- 7 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb create mode 100644 conduitpylib/viz/_get_notomoji_font_path.py rename {binder/date=2021+project=72k5n => conduitpylib/viz/assets}/Noto-LICENSE (100%) rename {binder/date=2021+project=72k5n => conduitpylib/viz/assets}/NotoEmoji-Regular.ttf (100%) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..e5106f0b1a --- /dev/null +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,167 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import itertools as it\n", + "from iterdub import iterdub as ib\n", + "from iterpop import iterpop as ip\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "import matplotlib\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "import pathlib\n", + "import random\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import (\n", + " get_notomoji_font_path,\n", + " performance_semantics_scatterplot,\n", + " performance_semantics_facetplot,\n", + ")\n", + "\n", + "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal, snapshot = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/jgpnv/download\",\n", + " df_outlet_url=\"https://osf.io/ncdfq/download\",\n", + " treatment_column=\"Allocation\",\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " for allocation, group in eval(data).groupby(\"Allocation\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " performance_semantics_scatterplot,\n", + " data=group_df,\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"__{}__\".format(\n", + " {\n", + " \"With lac-417\": \"\ud83e\udd15\",\n", + " \"Sans lac-417\": \"\ud83d\ude42\",\n", + " }[allocation]\n", + " ),\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " plt.clf()\n", + " group_df = group.reset_index()\n", + " with pw.patched_axisgrid():\n", + " facetplot = tp.tee(\n", + " performance_semantics_facetplot,\n", + " data=eval(data).map(\n", + " {\n", + " \"With lac-417\": \"Incl. lac-417\",\n", + " \"Sans lac-417\": \"Excl. lac-417\",\n", + " },\n", + " ),\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " hue=\"Allocation\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"\ud83d\ude42/\ud83e\udd15\",\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " display(facetplot)\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index a1ccdd20fc..0bed8ecdd1 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -6,6 +6,7 @@ from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets +from ._get_notomoji_font_path import get_notomoji_font_path from ._performance_semantics_facetplot import performance_semantics_facetplot from ._performance_semantics_kdeplot import performance_semantics_kdeplot from ._performance_semantics_scatterplot import ( @@ -28,6 +29,7 @@ "beleaguerment_regplot", "compact_xaxis_units", "frame_scatter_subsets", + "get_notomoji_font_path", "performance_semantics_facetplot", "performance_semantics_kdeplot", "performance_semantics_scatterplot", diff --git a/conduitpylib/viz/_get_notomoji_font_path.py b/conduitpylib/viz/_get_notomoji_font_path.py new file mode 100644 index 0000000000..45ff644fc7 --- /dev/null +++ b/conduitpylib/viz/_get_notomoji_font_path.py @@ -0,0 +1,4 @@ +from pathlib import Path + +def get_notomoji_font_path() -> Path: + return Path(__file__).parent / "assets" / "NotoEmoji-Regular.ttf" diff --git a/binder/date=2021+project=72k5n/Noto-LICENSE b/conduitpylib/viz/assets/Noto-LICENSE similarity index 100% rename from binder/date=2021+project=72k5n/Noto-LICENSE rename to conduitpylib/viz/assets/Noto-LICENSE diff --git a/binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf b/conduitpylib/viz/assets/NotoEmoji-Regular.ttf similarity index 100% rename from binder/date=2021+project=72k5n/NotoEmoji-Regular.ttf rename to conduitpylib/viz/assets/NotoEmoji-Regular.ttf diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index 3e167e6791..b9c7b286c9 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -65,6 +65,9 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: df_finalized_observations["Delivery Failure, %"] = ( df_finalized_observations["Fraction Messages Dropped"] * 100 ) + df_finalized_observations["% Msgs Lost"] = df_finalized_observations[ + "Delivery Failure, %" + ] df_finalized_observations[ "Msgs Received Per Sent" diff --git a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py index 5291ac22c3..62304874af 100644 --- a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py +++ b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py @@ -102,10 +102,6 @@ def wrangle_snapshot_deltas( } ) - df_snapshot_diffs["% Msgs Lost"] = ( - df_snapshot_diffs["Fraction Messages Dropped"] * 100 - ) - df_snapshot_diffs["Dominance"] = ( df_snapshot_diffs["Num Try Puts Attempted"] / df_snapshot_diffs["Net Flux Through Duct"] @@ -140,6 +136,7 @@ def wrangle_snapshot_deltas( df_snapshot_diffs["Delivery Failure, %"] = ( df_snapshot_diffs["Fraction Messages Dropped"] * 100 ) + df_snapshot_diffs["% Msgs Lost"] = df_snapshot_diffs["Delivery Failure, %"] df_snapshot_diffs["Msgs Received Per Sent"] = df_snapshot_diffs[ "Num Messages Per Pull" From 579b674ff29e6f0fec99232c9e4117882417779c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 06:13:49 -0500 Subject: [PATCH 048/145] Fixup beleaguerment notebook --- ...=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 949bf78c3f..22f7e72bd7 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -91,7 +91,10 @@ "metadata": {}, "outputs": [], "source": [ - "data = wrangle_instrumentation_longform(longitudinal_df, snapshot_df)\n", + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", "\n", "for allocation, group in data.groupby(\"Allocation\"):\n", " group_df = group.reset_index()\n", @@ -101,6 +104,9 @@ " x=\"Messages Received Per Second\",\n", " y=\"Messages Sent Per Second\",\n", " hue=\"Instrumentation\",\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " },\n", " )\n" ] } From eed820dcfa71b9fe4895e52fac3d4fb747c20fe5 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 07:18:24 -0500 Subject: [PATCH 049/145] Handle desserial except in pickle_cache e.g., due to package version changes --- conduitpylib/utils/pickle_cache.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/conduitpylib/utils/pickle_cache.py b/conduitpylib/utils/pickle_cache.py index 14b0bf42aa..b333729c7b 100644 --- a/conduitpylib/utils/pickle_cache.py +++ b/conduitpylib/utils/pickle_cache.py @@ -10,6 +10,15 @@ from .equals_by_value import equals_by_value +def _raises(callable: typing.Callable) -> bool: + try: + callable() + except Exception: + return True + else: + return False + + def pickle_cache(maxsize: int = 256) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: info = { @@ -43,8 +52,10 @@ def wrapped(*args, **kwargs) -> typing.Any: oldest, *_rest = shelf.keys() del shelf[oldest] - if hash_value not in shelf or not equals_by_value( - shelf[hash_value][0], context + if ( + hash_value not in shelf + or _raises(lambda: shelf[hash_value]) + or not equals_by_value(shelf[hash_value][0], context) ): info["misses"] += 1 result = func(*args, **kwargs) From d91fa36a6b75d4ea626780d4cf1dc27cd7d2bd5c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 07:44:00 -0500 Subject: [PATCH 050/145] Factor out copy/paste spam from lac-417 nb --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 805 ++---------------- conduitpylib/viz/__init__.py | 18 + conduitpylib/viz/_errplot.py | 79 ++ conduitpylib/viz/_facet_barplot.py | 20 + conduitpylib/viz/_facet_boxplot.py | 57 ++ conduitpylib/viz/_quantile_regplot.py | 44 + conduitpylib/viz/_unsplit_regression.py | 62 ++ conduitpylib/wrangle/__init__.py | 4 + conduitpylib/wrangle/_make_regression_row.py | 132 +++ .../_retrieve_and_prepare_delta_dataframes.py | 48 +- conduitpylib/wrangle/_wrangle_world_sums.py | 95 +++ 11 files changed, 587 insertions(+), 777 deletions(-) create mode 100644 conduitpylib/viz/_errplot.py create mode 100644 conduitpylib/viz/_facet_barplot.py create mode 100644 conduitpylib/viz/_facet_boxplot.py create mode 100644 conduitpylib/viz/_quantile_regplot.py create mode 100644 conduitpylib/viz/_unsplit_regression.py create mode 100644 conduitpylib/wrangle/_make_regression_row.py create mode 100644 conduitpylib/wrangle/_wrangle_world_sums.py diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 929b0fee3a..f39324c8b6 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=with-lac-417-vs-sans-lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -38,8 +38,10 @@ " count_proportion_outliers,\n", ")\n", "\n", - "from conduitpylib.viz import (\n", - " performance_semantics_plot,\n", + "from conduitpylib.wrangle import (\n", + " find_treat_idx_mapped_col,\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_world_sums,\n", ")\n" ] }, @@ -65,182 +67,18 @@ "metadata": {}, "outputs": [], "source": [ - "df_inlet = pd.read_csv(\n", - " 'https://osf.io/jgpnv/download',\n", - " compression='gzip',\n", - ").dropna(\n", - " subset=['Process Instance UUID'],\n", - ")\n", - "nbm.print_dataframe_summary(*eval(nbm.nvp_expr(\n", - " 'df_inlet'\n", - ")))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_outlet = pd.read_csv(\n", - " 'https://osf.io/ncdfq/download',\n", - " compression='gzip',\n", - ").dropna(\n", - " subset=['Process Instance UUID'],\n", - ")\n", - "nbm.print_dataframe_summary(*eval(nbm.nvp_expr(\n", - " 'df_outlet'\n", - ")))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = consolidate_merge(\n", - " df_inlet,\n", - " df_outlet,\n", - " on=['Process Instance UUID', 'Update'],\n", - " suffixes=(' Inlet', ' Outlet'),\n", - " how='outer',\n", + "merge_df, (\n", + " df_finalized_observations,\n", + " df_snapshot_diffs,\n", + ") = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/jgpnv/download\",\n", + " df_outlet_url=\"https://osf.io/ncdfq/download\",\n", + " treatment_column=\"Allocation\",\n", + " return_merge_df=True,\n", ")\n", - "if all(df_inlet['Runtime Seconds Elapsed'] == df_outlet['Runtime Seconds Elapsed']):\n", - " df['Runtime Seconds Elapsed Inlet'] = df['Runtime Seconds Elapsed']\n", - " df['Runtime Seconds Elapsed Outlet'] = df['Runtime Seconds Elapsed']\n", - "nbm.print_dataframe_synopsis(*eval(nbm.nvp_expr(\n", - " 'df'\n", - ")))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prep Data\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = df.astype({\n", - " 'Num Inlets' : 'int64',\n", - " 'Num Outlets' : 'int64',\n", - " 'Num Puts Attempted' : 'int64',\n", - " 'Num Try Puts Attempted' : 'int64',\n", - " 'Num Blocking Puts' : 'int64',\n", - " 'Num Try Puts That Succeeded' : 'int64',\n", - " 'Num Puts That Succeeded Eventually' : 'int64',\n", - " 'Num Blocking Puts That Succeeded Immediately' : 'int64',\n", - " 'Num Puts That Succeeded Immediately' : 'int64',\n", - " 'Num Puts That Blocked' : 'int64',\n", - " 'Num Dropped Puts' : 'int64',\n", - " 'Num Round Trip Touches Inlet' : 'int64',\n", - " 'Net Flux Through Duct' : 'int64',\n", - " 'proc' : 'int64',\n", - " 'Snapshot' : 'int64',\n", - " 'Has Execution Blur' : 'bool',\n", - " 'Replicate' : 'int64',\n", - " 'Async Mode' : 'int64',\n", - " 'Num Threads' : 'int64',\n", - " 'Num Processes' : 'int64',\n", - " 'SLURM_NNODES' : 'int64',\n", - " 'SLURM_NTASKS' : 'int64',\n", - " 'SLURM_CPUS_ON_NODE' : 'int64',\n", - "})\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df['Hostname'] = df.apply(\n", - " lambda row: kn.unpack(row['Source File Inlet'])['_hostname'],\n", - " axis=1,\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df['Num Nodes'] = df['SLURM_NNODES']\n", - "df['Num Tasks'] = df['SLURM_NTASKS']\n", - "df['Num Simels Per Cpu'] = df['Num Simulation Elements Per Cpu']\n", - "df['Num Cpus'] = df['Num Threads'] * df['Num Processes']\n", - "df['Allocated Tasks Per Node'] = df['Num Tasks'] // df['Num Nodes']\n", - "df['Cpus Per Node'] = df['Allocated Tasks Per Node']\n", - "df['Delivery Time Inlet'] = (df['Num Puts Attempted'] - 1) / df['Num Round Trip Touches Inlet']\n", - "df['Delivery Time Outlet'] = (df['Num Pulls Attempted'] - 1) / df['Num Round Trip Touches Outlet']\n", - "df['Intermittancy'] = df['Num Pulls That Were Laden Immediately'] / df[['Net Flux Through Duct', 'Num Pulls Attempted']].min(axis=1)\n", - "df['Inlet-Seconds Elapsed'] = df['Num Inlets'] * df['Runtime Seconds Elapsed Inlet']\n", - "df['Outlet-Seconds Elapsed'] = df['Num Outlets'] * df['Runtime Seconds Elapsed Outlet']\n", - "df['Latency Simsteps Inlet'] = df['Delivery Time Inlet']\n", - "df['Latency Simsteps Outlet'] = df['Delivery Time Inlet']\n", - "df['Simstep Period Inlet (s)'] = df['Inlet-Seconds Elapsed'] / df['Num Puts Attempted']\n", - "df['Simstep Period Outlet (s)'] = df['Outlet-Seconds Elapsed'] / df['Num Pulls Attempted']\n", - "df['Latency Walltime Inlet (s)'] = df['Latency Simsteps Inlet'] * df['Simstep Period Inlet (s)']\n", - "df['Latency Walltime Outlet (s)'] = df['Latency Simsteps Outlet'] * df['Simstep Period Outlet (s)']\n", - "df['Log Num Processes'] = np.log(df['Num Processes']) / np.log(4)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "row_distiller = lambda row: {k : v for k, v in row.items() if k in ('Num Nodes', 'Num Processes')}\n", "\n", - "allocation_idx_mapper = {\n", - " val : idx\n", - " for idx, val\n", - " in enumerate(df['Allocation'].unique())\n", - "}\n", - "allocation_idx_mapped_title = ' | '.join(f'{idx} = {val}' for val, idx in allocation_idx_mapper.items())\n", - "df[allocation_idx_mapped_title] = df.apply(\n", - " lambda row: allocation_idx_mapper[row['Allocation']],\n", - " axis=1,\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prep DataFrame Variants\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# https://stackoverflow.com/a/40629420\n", - "df_finalized_observations = df.sort_values('Update', ascending=False).drop_duplicates(['Process Instance UUID'])\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_blurry_snapshots = df[\n", - " df['Has Execution Blur'].astype(bool)\n", - " & (df['Snapshot'] <= 5 )\n", - " # exclude excess, unintended snapshots from runs that took a while to shut down\n", - " # (i.e., from at the 6 minute mark and beyond)\n", - "]\n" + "allocation_idx_mapped_title = find_treat_idx_mapped_col(df_snapshot_diffs)\n", + "allocation_idx_mapped_title\n" ] }, { @@ -249,178 +87,7 @@ "metadata": {}, "outputs": [], "source": [ - "df_world_sum = df_finalized_observations.groupby([\n", - " 'Replicate',\n", - " 'Async Mode',\n", - " 'Num Processes',\n", - " 'Num Nodes',\n", - " 'Num Simels Per Cpu',\n", - " 'Allocated Tasks Per Node',\n", - " 'Cpus Per Node',\n", - " 'Allocation',\n", - " allocation_idx_mapped_title,\n", - "], as_index=False).sum()\n", - "\n", - "df_world_sum['Fraction Messages Utilized'] = df_world_sum['Num Reads That Were Fresh'] / df_world_sum['Num Try Puts Attempted']\n", - "df_world_sum['Fraction Messages Delivered'] = df_world_sum['Num Try Puts That Succeeded'] / df_world_sum['Num Try Puts Attempted']\n", - "df_world_sum['Delivery Failure Rate'] = 1.0 - df_world_sum['Fraction Messages Delivered']\n", - "df_world_sum['Fraction Messages Dropped'] = df_world_sum['Delivery Failure Rate']\n", - "df_world_sum['Fraction Try Pulls That Were Laden'] = df_world_sum['Num Try Pulls That Were Laden'] / df_world_sum['Num Try Pulls Attempted']\n", - "df_world_sum['Round Trip Touches Per Attempted Pull'] = df_world_sum['Num Round Trip Touches Outlet'] / df_world_sum['Num Try Pulls Attempted']\n", - "df_world_sum['Round Trip Touches Per Attempted Put'] = df_world_sum['Num Round Trip Touches Inlet'] / df_world_sum['Num Try Puts Attempted']\n", - "df_world_sum['Num Inflight Messages'] = 2.0 / df_world_sum['Round Trip Touches Per Attempted Put'] - 1\n", - "df_world_sum['Fraction Duct Flux Stepped Through'] = df_world_sum['Num Revisions Pulled'] / df_world_sum['Net Flux Through Duct']\n", - "df_world_sum['Fraction Duct Flux Jumped Over'] = 1.0 - df_world_sum['Fraction Duct Flux Stepped Through']\n", - "df_world_sum['Round Trip Touches Per Runtime Second'] = df_world_sum['Num Round Trip Touches Inlet'] / df_world_sum['Runtime Seconds Elapsed Inlet']\n", - "df_world_sum['Latency Simsteps Inlet'] = (df_world_sum['Num Puts Attempted'] - 1) / df_world_sum['Num Round Trip Touches Inlet']\n", - "df_world_sum['Latency Simsteps Outlet'] = (df_world_sum['Num Pulls Attempted'] - 1) / df_world_sum['Num Round Trip Touches Outlet']\n", - "df_world_sum['Delivery Clumpiness'] = 1.0 - df_world_sum['Num Pulls That Were Laden Immediately'] / df_world_sum[['Net Flux Through Duct', 'Num Pulls Attempted']].min(axis=1)\n", - "df_world_sum['Intermittancy'] = df_world_sum['Delivery Clumpiness']\n", - "df_world_sum['Simstep Period Inlet (s)'] = df_world_sum['Inlet-Seconds Elapsed'] / df_world_sum['Num Puts Attempted']\n", - "df_world_sum['Simstep Period Outlet (s)'] = df_world_sum['Outlet-Seconds Elapsed'] / df_world_sum['Num Pulls Attempted']\n", - "df_world_sum['Latency Walltime Inlet (s)'] = df_world_sum['Latency Simsteps Inlet'] * df_world_sum['Simstep Period Inlet (s)']\n", - "df_world_sum['Latency Walltime Outlet (s)'] = df_world_sum['Latency Simsteps Outlet'] * df_world_sum['Simstep Period Outlet (s)']\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_snapshot_diffs = df_blurry_snapshots.groupby(\n", - " [\n", - " 'Process Instance UUID',\n", - " 'Snapshot',\n", - " # subsequent items aren't meaningful to groupby\n", - " # but are just included so they pass through untouched\n", - " 'Async Mode',\n", - " 'Num Nodes',\n", - " 'Allocated Tasks Per Node',\n", - " 'Cpus Per Node',\n", - " 'Num Processes',\n", - " 'Log Num Processes',\n", - " 'Num Simels Per Cpu',\n", - " 'Replicate',\n", - " 'proc',\n", - " 'Hostname',\n", - " 'Num Inlets',\n", - " 'Num Outlets',\n", - " 'Execution Instance UUID',\n", - " 'Num Threads',\n", - " 'Allocation',\n", - " allocation_idx_mapped_title,\n", - "\n", - " ],\n", - " as_index=False,\n", - ").aggregate({\n", - " 'Num Puts Attempted' : np.ptp,\n", - " 'Num Try Puts Attempted' : np.ptp,\n", - " 'Num Blocking Puts' : np.ptp,\n", - " 'Num Try Puts That Succeeded' : np.ptp,\n", - " 'Num Puts That Succeeded Eventually' : np.ptp,\n", - " 'Num Blocking Puts That Succeeded Immediately' : np.ptp,\n", - " 'Num Puts That Succeeded Immediately' : np.ptp,\n", - " 'Num Puts That Blocked' : np.ptp,\n", - " 'Num Dropped Puts' : np.ptp,\n", - " 'Num Reads Performed' : np.ptp,\n", - " 'Num Reads That Were Fresh' : np.ptp,\n", - " 'Num Reads That Were Stale' : np.ptp,\n", - " 'Num Revisions Pulled' : np.ptp,\n", - " 'Num Try Pulls Attempted' : np.ptp,\n", - " 'Num Blocking Pulls' : np.ptp,\n", - " 'Num Blocking Pulls That Blocked' : np.ptp,\n", - " 'Num Revisions From Try Pulls' : np.ptp,\n", - " 'Num Revisions From Blocking Pulls' : np.ptp,\n", - " 'Num Pulls Attempted' : np.ptp,\n", - " 'Num Pulls That Were Laden Eventually' : np.ptp,\n", - " 'Num Blocking Pulls That Were Laden Immediately' : np.ptp,\n", - " 'Num Blocking Pulls That Were Laden Eventually' : np.ptp,\n", - " 'Num Pulls That Were Laden Immediately' : np.ptp,\n", - " 'Num Try Pulls That Were Laden' : np.ptp,\n", - " 'Num Try Pulls That Were Unladen' : np.ptp,\n", - " 'Net Flux Through Duct' : np.ptp,\n", - " 'Num Round Trip Touches Inlet' : np.ptp,\n", - " 'Num Round Trip Touches Outlet' : np.ptp,\n", - "# why are these missing?\n", - "# 'Row Initial Timepoint (ns) Inlet' : np.ptp,\n", - "# 'Row Initial Timepoint (ns) Outlet' : np.ptp,\n", - " 'Row Final Timepoint (ns) Inlet' : np.ptp,\n", - " 'Row Final Timepoint (ns) Outlet' : np.ptp,\n", - " 'Runtime Seconds Elapsed Inlet' : np.mean,\n", - " 'Runtime Seconds Elapsed Outlet' : np.mean,\n", - "})\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_snapshot_diffs['Fraction Messages Delivered'] = (\n", - " df_snapshot_diffs['Num Try Puts That Succeeded']\n", - " / df_snapshot_diffs['Num Try Puts Attempted']\n", - ")\n", - "df_snapshot_diffs['Delivery Success Rate'] = (\n", - " df_snapshot_diffs['Num Try Puts That Succeeded']\n", - " / df_snapshot_diffs['Num Try Puts Attempted']\n", - ")\n", - "df_snapshot_diffs['Delivery Failure Rate'] = 1 - df_snapshot_diffs['Delivery Success Rate']\n", - "df_snapshot_diffs['Fraction Messages Dropped'] = df_snapshot_diffs['Delivery Failure Rate']\n", - "df_snapshot_diffs['Fraction Try Pulls That Were Laden'] = (\n", - " df_snapshot_diffs['Num Try Pulls That Were Laden']\n", - " / df_snapshot_diffs['Num Try Pulls Attempted']\n", - ")\n", - "\n", - "df_snapshot_diffs['Round Trip Touches Per Attempted Put'] = (\n", - " df_snapshot_diffs['Num Round Trip Touches Inlet']\n", - ") / df_snapshot_diffs['Num Try Puts Attempted']\n", - "\n", - "df_snapshot_diffs['Round Trip Touches Per Attempted Pull'] = (\n", - " df_snapshot_diffs['Num Round Trip Touches Outlet']\n", - ") / df_snapshot_diffs['Num Try Pulls Attempted']\n", - "\n", - "df_snapshot_diffs['Round Trip Touches Per Runtime Nanosecond'] = (\n", - " df_snapshot_diffs['Num Round Trip Touches Outlet']\n", - ") / df_snapshot_diffs['Row Final Timepoint (ns) Outlet']\n", - "\n", - "df_snapshot_diffs['Latency Simsteps Inlet'] = df_snapshot_diffs['Num Puts Attempted'] / df_snapshot_diffs['Num Round Trip Touches Inlet']\n", - "df_snapshot_diffs['Latency Simsteps Outlet'] = df_snapshot_diffs['Num Pulls Attempted'] / df_snapshot_diffs['Num Round Trip Touches Outlet']\n", - "df_snapshot_diffs['Delivery Clumpiness'] = 1.0 - df_snapshot_diffs['Num Pulls That Were Laden Immediately'] / df_snapshot_diffs[['Net Flux Through Duct', 'Num Pulls Attempted']].min(axis=1)\n", - "df_snapshot_diffs['Intermittancy'] = df_snapshot_diffs['Delivery Clumpiness']\n", - "df_snapshot_diffs['Inlet-Nanoseconds Elapsed'] = df_snapshot_diffs['Num Inlets'] * df_snapshot_diffs['Row Final Timepoint (ns) Inlet']\n", - "df_snapshot_diffs['Outlet-Nanoseconds Elapsed'] = df_snapshot_diffs['Num Outlets'] * df_snapshot_diffs['Row Final Timepoint (ns) Outlet']\n", - "df_snapshot_diffs['Simsteps Elapsed Inlet'] = df_snapshot_diffs['Num Puts Attempted'] / df_snapshot_diffs['Num Inlets']\n", - "df_snapshot_diffs['Simsteps Elapsed Outlet'] = df_snapshot_diffs['Num Pulls Attempted'] / df_snapshot_diffs['Num Outlets']\n", - "df_snapshot_diffs['Simstep Period Inlet (ns)'] = df_snapshot_diffs['Inlet-Nanoseconds Elapsed'] / df_snapshot_diffs['Num Puts Attempted']\n", - "df_snapshot_diffs['Simstep Period Outlet (ns)'] = df_snapshot_diffs['Outlet-Nanoseconds Elapsed'] / df_snapshot_diffs['Num Pulls Attempted']\n", - "df_snapshot_diffs['Latency Walltime Inlet (ns)'] = df_snapshot_diffs['Latency Simsteps Inlet'] * df_snapshot_diffs['Simstep Period Inlet (ns)']\n", - "df_snapshot_diffs['Latency Walltime Outlet (ns)'] = df_snapshot_diffs['Latency Simsteps Outlet'] * df_snapshot_diffs['Simstep Period Outlet (ns)']\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_snapshot_diffs = df_snapshot_diffs.astype({\n", - " 'Num Inlets' : 'int64',\n", - " 'Num Outlets' : 'int64',\n", - " 'proc' : 'int64',\n", - " 'Snapshot' : 'int64',\n", - " 'Replicate' : 'int64',\n", - " 'Async Mode' : 'int64',\n", - " 'Num Threads' : 'int64',\n", - " 'Num Processes' : 'int64',\n", - " 'Allocated Tasks Per Node' : 'int64',\n", - " 'Cpus Per Node' : 'int64',\n", - " 'Num Nodes' : 'int64',\n", - " 'Num Simels Per Cpu' : 'int64',\n", - " allocation_idx_mapped_title : 'int64',\n", - "\n", - "})\n" + "df_world_sum = wrangle_world_sums(df_finalized_observations)\n" ] }, { @@ -438,20 +105,7 @@ "metadata": {}, "outputs": [], "source": [ - "def facet_boxplot(*, data, col=None, row=None, x, y, showfliers=False):\n", - " g = sns.FacetGrid(\n", - " data,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey='row',\n", - " )\n", - " g.map_dataframe(\n", - " sns.boxplot,\n", - " x,\n", - " y,\n", - " showfliers=showfliers,\n", - " )\n" + "from conduitpylib.viz import facet_boxplot\n" ] }, { @@ -687,75 +341,11 @@ "metadata": {}, "outputs": [], "source": [ - "def facet_barplot(*, data, col=None, row=None, x, y, hue=None):\n", - " g = sns.FacetGrid(\n", - " data,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey='row',\n", - " )\n", - " g.map_dataframe(\n", - " sns.barplot,\n", - " x=x,\n", - " y=y,\n", - " hue=hue,\n", - " )\n", - "\n", - " # adapted from https://stackoverflow.com/a/48208266\n", - " g.set_axis_labels(x_var=x, y_var=y)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def facet_boxplot_withfliers(*, data, col=None, row=None, x, y, hue=None):\n", - " g = sns.FacetGrid(\n", - " data,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey='row',\n", - " )\n", - " g.map_dataframe(\n", - " sns.boxplot,\n", - " x=x,\n", - " y=y,\n", - " hue=hue,\n", - " showfliers=True,\n", - " )\n", - "\n", - " # adapted from https://stackoverflow.com/a/48208266\n", - " g.set_axis_labels(x_var=x, y_var=y)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def facet_boxplot_nofliers(*, data, col=None, row=None, x, y, hue=None):\n", - " g = sns.FacetGrid(\n", - " data,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey='row',\n", - " )\n", - " g.map_dataframe(\n", - " sns.boxplot,\n", - " x=x,\n", - " y=y,\n", - " hue=hue,\n", - " showfliers=False,\n", - " )\n", - "\n", - " # adapted from https://stackoverflow.com/a/48208266\n", - " g.set_axis_labels(x_var=x, y_var=y)\n" + "from conduitpylib.viz import (\n", + " facet_barplot,\n", + " facet_boxplot_withfliers,\n", + " facet_boxplot_nofliers,\n", + ")\n" ] }, { @@ -1262,15 +852,19 @@ "metadata": {}, "outputs": [], "source": [ - "# adapted from https://stackoverflow.com/a/13592901\n", - "df_snapshot_diffs.groupby([\n", - " allocation_idx_mapped_title,\n", - "]).agg({\n", - " 'Latency Simsteps Outlet' : [\n", - " np.mean,\n", - " np.median,\n", - " ],\n", - "})\n" + "# adapted fmke_regr_make_regression_rowrom https://stackoverflow.com/a/13592901\n", + "df_snapshot_diffs.groupby(\n", + " [\n", + " allocation_idx_mapped_title,\n", + " ]\n", + ").agg(\n", + " {\n", + " \"Latency Simsteps Outlet\": [\n", + " np.mean,\n", + " np.median,\n", + " ],\n", + " }\n", + ")\n" ] }, { @@ -2000,110 +1594,7 @@ "metadata": {}, "outputs": [], "source": [ - "def make_regression_row(*, data, independent_variable, dependent_variable, regression, row_filter):\n", - "\n", - " filtered_data = data[ data.apply(eval(row_filter), axis=1) ]\n", - "\n", - " regfun = {\n", - " 'Quantile Regression over Means' : smf.quantreg,\n", - " 'Quantile Regression over Medians' : smf.quantreg,\n", - " }[regression]\n", - " model = regfun(f\"Q('{dependent_variable}') ~ Q('{independent_variable}')\", filtered_data)\n", - " fit_model = model.fit()\n", - "\n", - " slope = fit_model.params[f\"Q('{independent_variable}')\"]\n", - " intercept = fit_model.params['Intercept']\n", - "\n", - " slope_ci_lb, slope_ci_ub = fit_model.conf_int().loc[f\"Q('{independent_variable}')\"].tolist()\n", - " intercept_ci_lb, intercept_ci_ub = fit_model.conf_int().loc['Intercept'].tolist()\n", - "\n", - " p = fit_model.pvalues.loc[f\"Q('{independent_variable}')\"]\n", - "\n", - " # normalize to \"control\", i.e., lowest num processes observed\n", - " effect_size_normalization_data = data[\n", - " data[independent_variable] == data[independent_variable].min()\n", - " ][dependent_variable]\n", - " effect_size_normalization_factor = {\n", - " 'Quantile Regression over Means' : lambda x: x.mean(),\n", - " 'Quantile Regression over Medians' : lambda x: x.median(),\n", - " }[regression](effect_size_normalization_data)\n", - " relative_effect_size = slope / effect_size_normalization_factor\n", - " relative_effect_size_ci_lb = slope_ci_lb / effect_size_normalization_factor\n", - " relative_effect_size_ci_ub = slope_ci_ub / effect_size_normalization_factor\n", - " relative_effect_size_ci_width = (\n", - " relative_effect_size_ci_ub\n", - " - relative_effect_size_ci_lb\n", - " )\n", - "\n", - " is_significant = p < 0.05 if np.isfinite(p) else None\n", - "\n", - " res = {\n", - " 'Independent Variable' : independent_variable,\n", - " 'Dependent Variable' : dependent_variable,\n", - " 'Dependent Variable Slug' : slugify(dependent_variable),\n", - " 'Cpus Per Node' : ib.dub( data['Cpus Per Node'] ),\n", - " 'Num Simels Per Cpu' : ip.pophomogeneous( data['Num Simels Per Cpu'] ),\n", - " 'Slope Estimate' : slope,\n", - " 'Slope Estimate 95% CI Lower Bound' : slope_ci_lb,\n", - " 'Slope Estimate 95% CI Upper Bound' : slope_ci_ub,\n", - " 'Absolute Effect Size' : slope,\n", - " 'Absolute Effect Size 95% CI Lower Bound' : slope_ci_lb,\n", - " 'Absolute Effect Size 95% CI Upper Bound' : slope_ci_ub,\n", - " 'Absolute Effect Size 95% CI Width' : slope_ci_ub - slope_ci_lb,\n", - " 'Relative Effect Size' : relative_effect_size,\n", - " 'Relative Effect Size 95% CI Lower Bound' : relative_effect_size_ci_lb,\n", - " 'Relative Effect Size 95% CI Upper Bound' : relative_effect_size_ci_ub,\n", - " 'Relative Effect Size 95% CI Width' : relative_effect_size_ci_width,\n", - " 'Intercept Estimate' : intercept,\n", - " 'Intercept Estimate 95% CI Lower Bound' : intercept_ci_lb,\n", - " 'Intercept Estimate 95% CI Upper Bound' : intercept_ci_ub,\n", - " 'R^2' : fit_model.rsquared,\n", - " 'p' : fit_model.pvalues.loc[f\"Q('{independent_variable}')\"],\n", - " 'Significant?' : is_significant,\n", - " 'Significant Effect Sign' : (\n", - " '-' if is_significant and slope < 0\n", - " else '+' if is_significant and slope > 0\n", - " else '0' if is_significant is not None\n", - " else None\n", - " ),\n", - " 'n' : len(filtered_data),\n", - " 'Filter' : row_filter,\n", - " 'Num Processes' : ib.dub(filtered_data['Num Processes']),\n", - " 'Num Processes Prettyprint' : (\n", - " '/'.join(filtered_data['Num Processes'].sort_values().astype(str).unique())\n", - " ),\n", - " 'Regression Model' : regression,\n", - " 'Regression Model Slug' : slugify(regression),\n", - " 'Statistic' : {\n", - " 'Quantile Regression over Means' : 'mean',\n", - " 'Quantile Regression over Medians' : 'median',\n", - " }[regression],\n", - " }\n", - "\n", - " # dump regression summary to file\n", - " summary_filename = kn.pack({\n", - " **{\n", - " 'a' : 'regression_summary',\n", - " 'ext' : '.txt',\n", - " },\n", - " **{\n", - " slugify(k) : slugify(str(v))\n", - " for k, v in res.items()\n", - " if k in [\n", - " 'Independent Variable',\n", - " 'Dependent Variable',\n", - " 'Cpus Per Node',\n", - " 'Num Simels Per Cpu',\n", - " 'Regression Model',\n", - " ]\n", - " },\n", - " })\n", - "\n", - " pathlib.Path('outplots').mkdir(parents=True, exist_ok=True)\n", - " with open(f'outplots/{summary_filename}', 'w') as file:\n", - " print(fit_model.summary(), file=file)\n", - "\n", - " return res\n" + "from conduitpylib.wrangle import make_regression_row\n" ] }, { @@ -2223,8 +1714,8 @@ " if k and k[0] != '_' and k != 'ext'\n", " }\n", " for source_filename in [\n", - " *df['Source File Inlet'].unique(),\n", - " *df['Source File Outlet'].unique(),\n", + " *merge_df['Source File Inlet'].unique(),\n", + " *merge_df['Source File Outlet'].unique(),\n", " ]\n", "]).dropna(\n", " axis='columns',\n", @@ -2288,70 +1779,7 @@ "metadata": {}, "outputs": [], "source": [ - "# adapted from https://stackoverflow.com/questions/30385975/seaborn-factor-plot-custom-error-bars\n", - "# and https://pandas.pydata.org/pandas-docs/stable/user_guide/visualization.html#visualization-errorbars\n", - "def errplot(x, y, err_lb, err_ub, **kwargs):\n", - " ax = plt.gca()\n", - " data = kwargs.pop('data')\n", - " yerr=np.abs(\n", - " data[[err_lb, err_ub]].to_numpy()\n", - " - data[[y, y]].to_numpy()\n", - " ).transpose()\n", - " plt.axhline(\n", - " y=0,\n", - " zorder=1,\n", - " color='black',\n", - " linewidth=2,\n", - " )\n", - " data.plot(\n", - " x=x,\n", - " y=y,\n", - " yerr=yerr,\n", - " kind='bar',\n", - " ax=ax,\n", - " zorder=3,\n", - " **kwargs,\n", - " ).grid(\n", - " axis='y',\n", - " zorder=0,\n", - " )\n", - "\n", - " if x is None:\n", - " # adapted from https://stackoverflow.com/a/12998531\n", - " plt.tick_params(\n", - " axis='x', # changes apply to the x-axis\n", - " which='both', # both major and minor ticks are affected\n", - " bottom=False, # ticks along the bottom edge are off\n", - " top=False, # ticks along the top edge are off\n", - " labelbottom=False,\n", - " )\n", - "\n", - "\n", - "def facet_errplot(*, data, x=None, y, err_lb, err_ub, estimated_statistic, col=None, row=None, size_inches=None, **kwargs):\n", - " g = sns.FacetGrid(\n", - " subset,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey=False,\n", - " )\n", - " g.map_dataframe(\n", - " errplot,\n", - " x,\n", - " y,\n", - " err_lb,\n", - " err_ub,\n", - " **kwargs,\n", - " )\n", - "\n", - " if size_inches is not None:\n", - " plt.gcf().set_size_inches(*size_inches)\n", - "\n", - " # adapted from https://stackoverflow.com/a/29814281\n", - " plt.gcf().subplots_adjust(top=0.9)\n", - " plt.gcf().suptitle(\n", - " f\"Estimated Statistic = {estimated_statistic}\",\n", - " )\n" + "from conduitpylib.viz import errplot, facet_errplot\n" ] }, { @@ -2472,116 +1900,16 @@ "metadata": {}, "outputs": [], "source": [ - "def quantile_regplot(fit_reg=True, color=None, *args, **kwargs):\n", - " x, y, data = kwargs['x'], kwargs['y'], kwargs['data']\n", - " sns.regplot(\n", - " *args,\n", - " **kwargs,\n", - " fit_reg=False,\n", - " color=color,\n", - " )\n", - "\n", - " if fit_reg:\n", - " model = smf.quantreg(\n", - " f\"Q('{y}') ~ Q('{x}')\",\n", - " data\n", - " )\n", - " res = model.fit(q=0.5)\n", - " m = res.params[f\"Q('{x}')\"]\n", - " b = res.params['Intercept']\n", - "\n", - " m_ci = res.conf_int().loc[f\"Q('{x}')\"].tolist()\n", - " b_ci = res.conf_int().loc['Intercept'].tolist()\n", - "\n", - " center_x = np.mean([data[x].min(), data[x].max()])\n", - " center_y = m * center_x + b\n", - "\n", - " xs = sorted(set(data[x]) | {center_x})\n", - " ys = [\n", - " m * x_ + b\n", - " for x_ in xs\n", - " ]\n", - " y1 = [ min(\n", - " m_ * ( x_ - center_x ) + center_y\n", - " for m_ in m_ci\n", - " ) for x_ in xs ]\n", - " y2 = [ max(\n", - " m_ * ( x_ - center_x ) + center_y\n", - " for m_ in m_ci\n", - " ) for x_ in xs ]\n", - "\n", - " plt.gca().plot(\n", - " xs,\n", - " ys,\n", - " color=color,\n", - " )\n", - " plt.gca().fill_between(\n", - " xs,\n", - " y1,\n", - " y2,\n", - " alpha=0.2,\n", - " color=color,\n", - " )\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def unsplit_regression(*args, regplot, **kwargs):\n", - " del kwargs['color']\n", - " regplot(\n", - " *args,\n", - " **kwargs,\n", - " color='black',\n", - " fit_reg=False,\n", - " )\n", - " regplot(\n", - " *args,\n", - " **kwargs,\n", - " color='purple',\n", - " scatter=False,\n", - " )\n", - "\n", - " # adapted from https://www.scivision.dev/matplotlib-force-integer-labeling-of-axis/\n", - " plt.gca().xaxis.set_major_locator(\n", - " matplotlib.ticker.MaxNLocator(\n", - " integer=True,\n", - " ),\n", - " )\n", - "\n", - "def facet_unsplit_regression(*, data, col=None, row=None, x, y, regression, **kwargs):\n", - " g = sns.FacetGrid(\n", - " data,\n", - " col=col if col is not None and data[col].nunique() > 1 else None,\n", - " row=row if row is not None and data[row].nunique() > 1 else None,\n", - " margin_titles=True,\n", - " sharey=False,\n", - " )\n", - " g.map_dataframe(\n", - " unsplit_regression,\n", - " regplot={\n", - " 'Ordinary Least Squares Regression' : quantile_regplot,\n", - " 'Quantile Regression' : quantile_regplot,\n", - " }[regression],\n", - " x=x,\n", - " y=y,\n", - " **kwargs,\n", - " )\n", - "\n", - " # adapted from https://stackoverflow.com/a/48208266\n", - " g.set_axis_labels(x_var=x, y_var=y)\n", - "\n", - " # adapted from https://stackoverflow.com/a/29814281\n", - " plt.gcf().subplots_adjust(top=0.8)\n", - " plt.gcf().suptitle(\n", - " {\n", - " \"Quantile Regression\": \"Quantile Regression over Medians\",\n", - " \"Ordinary Least Squares Regression\": \"Quantile Regression over Means\",\n", - " }[regression],\n", - " )\n" + "from conduitpylib.viz import quantile_regplot\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import unsplit_regression, facet_unsplit_regression\n" ] }, { @@ -3472,43 +2800,6 @@ " & (df_snapshot_diffs['Num Simels Per Cpu'] == 2048)\n", "]\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_snapshot_diffs[\"Num Messages Per Pull\"] = (\n", - " df_snapshot_diffs['Net Flux Through Duct']\n", - " / df_snapshot_diffs['Num Pulls That Were Laden Immediately']\n", - " / df_snapshot_diffs[\"Delivery Success Rate\"]\n", - ").clip(lower=1)\n", - "assert (df_snapshot_diffs[\"Num Messages Per Pull\"] >= 1).all()\n", - "df_snapshot_diffs[\"Any Messages Dropped\"] = df_snapshot_diffs[\"Fraction Messages Dropped\"].astype(bool)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df_snapshot_diffs[\"% Msgs Lost\"] = df_snapshot_diffs[\"Fraction Messages Dropped\"] * 100\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "performance_semantics_plot(\n", - " data=df_snapshot_diffs,\n", - " hue=\"Allocation\",\n", - " hue_order=[\"Sans lac-417\", \"With lac-417\"],\n", - ")\n" - ] } ], "metadata": { diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 0bed8ecdd1..c8cf43b90c 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -5,6 +5,13 @@ from ._beleaguerment_regplot import beleaguerment_regplot from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units +from ._errplot import errplot, facet_errplot +from ._facet_barplot import facet_barplot +from ._facet_boxplot import ( + facet_boxplot, + facet_boxplot_nofliers, + facet_boxplot_withfliers, +) from ._frame_scatter_subsets import frame_scatter_subsets from ._get_notomoji_font_path import get_notomoji_font_path from ._performance_semantics_facetplot import performance_semantics_facetplot @@ -12,6 +19,7 @@ from ._performance_semantics_scatterplot import ( performance_semantics_scatterplot, ) +from ._quantile_regplot import quantile_regplot from ._runtime_indicator_regplot import runtime_indicator_regplot from ._runtime_indicators_concat_regplot_pairplot import ( runtime_indicators_concat_regplot_pairplot, @@ -19,6 +27,7 @@ from ._runtime_indicators_pairplot import runtime_indicators_pairplot from ._runtime_indicators_regplot import runtime_indicators_regplot from ._set_kde_lims import set_kde_lims +from ._unsplit_regression import facet_unsplit_regression, unsplit_regression # adapted from https://stackoverflow.com/a/31079085 @@ -28,14 +37,23 @@ "beleaguerment_facetplot", "beleaguerment_regplot", "compact_xaxis_units", + "errplot", + "facet_barplot", + "facet_errplot", "frame_scatter_subsets", + "facet_barplot", + "facet_boxplot_nofliers", + "facet_boxplot_withfliers", + "facet_unsplit_regression", "get_notomoji_font_path", "performance_semantics_facetplot", "performance_semantics_kdeplot", "performance_semantics_scatterplot", + "quantile_regplot", "runtime_indicator_regplot", "runtime_indicators_concat_regplot_pairplot", "runtime_indicators_pairplot", "runtime_indicators_regplot", "set_kde_lims", + "unsplit_regression", ] diff --git a/conduitpylib/viz/_errplot.py b/conduitpylib/viz/_errplot.py new file mode 100644 index 0000000000..82c13ed23b --- /dev/null +++ b/conduitpylib/viz/_errplot.py @@ -0,0 +1,79 @@ +from matplotlib import pyplot as plt +import numpy as np +import seaborn as sns + +# adapted from https://stackoverflow.com/questions/30385975/seaborn-factor-plot-custom-error-bars +# and https://pandas.pydata.org/pandas-docs/stable/user_guide/visualization.html#visualization-errorbars +def errplot(x, y, err_lb, err_ub, **kwargs): + ax = plt.gca() + data = kwargs.pop("data") + yerr = np.abs( + data[[err_lb, err_ub]].to_numpy() - data[[y, y]].to_numpy() + ).transpose() + plt.axhline( + y=0, + zorder=1, + color="black", + linewidth=2, + ) + data.plot( + x=x, + y=y, + yerr=yerr, + kind="bar", + ax=ax, + zorder=3, + **kwargs, + ).grid( + axis="y", + zorder=0, + ) + + if x is None: + # adapted from https://stackoverflow.com/a/12998531 + plt.tick_params( + axis="x", # changes apply to the x-axis + which="both", # both major and minor ticks are affected + bottom=False, # ticks along the bottom edge are off + top=False, # ticks along the top edge are off + labelbottom=False, + ) + + +def facet_errplot( + *, + data, + x=None, + y, + err_lb, + err_ub, + estimated_statistic, + col=None, + row=None, + size_inches=None, + **kwargs, +): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey=False, + ) + g.map_dataframe( + errplot, + x, + y, + err_lb, + err_ub, + **kwargs, + ) + + if size_inches is not None: + plt.gcf().set_size_inches(*size_inches) + + # adapted from https://stackoverflow.com/a/29814281 + plt.gcf().subplots_adjust(top=0.9) + plt.gcf().suptitle( + f"Estimated Statistic = {estimated_statistic}", + ) diff --git a/conduitpylib/viz/_facet_barplot.py b/conduitpylib/viz/_facet_barplot.py new file mode 100644 index 0000000000..681ee525eb --- /dev/null +++ b/conduitpylib/viz/_facet_barplot.py @@ -0,0 +1,20 @@ +import seaborn as sns + + +def facet_barplot(*, data, col=None, row=None, x, y, hue=None): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey="row", + ) + g.map_dataframe( + sns.barplot, + x=x, + y=y, + hue=hue, + ) + + # adapted from https://stackoverflow.com/a/48208266 + g.set_axis_labels(x_var=x, y_var=y) diff --git a/conduitpylib/viz/_facet_boxplot.py b/conduitpylib/viz/_facet_boxplot.py new file mode 100644 index 0000000000..c393f8f12b --- /dev/null +++ b/conduitpylib/viz/_facet_boxplot.py @@ -0,0 +1,57 @@ +import seaborn as sns + + +def facet_boxplot(*, data, col=None, row=None, x, y, showfliers=False): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey="row", + ) + g.map_dataframe( + sns.boxplot, + x, + y, + showfliers=showfliers, + ) + + +def facet_boxplot_withfliers(*, data, col=None, row=None, x, y, hue=None): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey="row", + ) + g.map_dataframe( + sns.boxplot, + x=x, + y=y, + hue=hue, + showfliers=True, + ) + + # adapted from https://stackoverflow.com/a/48208266 + g.set_axis_labels(x_var=x, y_var=y) + + +def facet_boxplot_nofliers(*, data, col=None, row=None, x, y, hue=None): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey="row", + ) + g.map_dataframe( + sns.boxplot, + x=x, + y=y, + hue=hue, + showfliers=False, + ) + + # adapted from https://stackoverflow.com/a/48208266 + g.set_axis_labels(x_var=x, y_var=y) diff --git a/conduitpylib/viz/_quantile_regplot.py b/conduitpylib/viz/_quantile_regplot.py new file mode 100644 index 0000000000..a87f3986a2 --- /dev/null +++ b/conduitpylib/viz/_quantile_regplot.py @@ -0,0 +1,44 @@ +from matplotlib import pyplot as plt +import numpy as np +import seaborn as sns +import statsmodels.formula.api as smf + + +def quantile_regplot(fit_reg=True, color=None, *args, **kwargs): + x, y, data = kwargs["x"], kwargs["y"], kwargs["data"] + sns.regplot( + *args, + **kwargs, + fit_reg=False, + color=color, + ) + + if fit_reg: + model = smf.quantreg(f"Q('{y}') ~ Q('{x}')", data) + res = model.fit(q=0.5) + m = res.params[f"Q('{x}')"] + b = res.params["Intercept"] + + m_ci = res.conf_int().loc[f"Q('{x}')"].tolist() + b_ci = res.conf_int().loc["Intercept"].tolist() + + center_x = np.mean([data[x].min(), data[x].max()]) + center_y = m * center_x + b + + xs = sorted(set(data[x]) | {center_x}) + ys = [m * x_ + b for x_ in xs] + y1 = [min(m_ * (x_ - center_x) + center_y for m_ in m_ci) for x_ in xs] + y2 = [max(m_ * (x_ - center_x) + center_y for m_ in m_ci) for x_ in xs] + + plt.gca().plot( + xs, + ys, + color=color, + ) + plt.gca().fill_between( + xs, + y1, + y2, + alpha=0.2, + color=color, + ) diff --git a/conduitpylib/viz/_unsplit_regression.py b/conduitpylib/viz/_unsplit_regression.py new file mode 100644 index 0000000000..2b48c8927c --- /dev/null +++ b/conduitpylib/viz/_unsplit_regression.py @@ -0,0 +1,62 @@ +import matplotlib +from matplotlib import pyplot as plt +import seaborn as sns + +from ._quantile_regplot import quantile_regplot + + +def unsplit_regression(*args, regplot, **kwargs): + del kwargs["color"] + regplot( + *args, + **kwargs, + color="black", + fit_reg=False, + ) + regplot( + *args, + **kwargs, + color="purple", + scatter=False, + ) + + # adapted from https://www.scivision.dev/matplotlib-force-integer-labeling-of-axis/ + plt.gca().xaxis.set_major_locator( + matplotlib.ticker.MaxNLocator( + integer=True, + ), + ) + + +def facet_unsplit_regression( + *, data, col=None, row=None, x, y, regression, **kwargs +): + g = sns.FacetGrid( + data, + col=col if col is not None and data[col].nunique() > 1 else None, + row=row if row is not None and data[row].nunique() > 1 else None, + margin_titles=True, + sharey=False, + ) + g.map_dataframe( + unsplit_regression, + regplot={ + "Ordinary Least Squares Regression": quantile_regplot, + "Quantile Regression": quantile_regplot, + }[regression], + x=x, + y=y, + **kwargs, + ) + + # adapted from https://stackoverflow.com/a/48208266 + g.set_axis_labels(x_var=x, y_var=y) + + # adapted from https://stackoverflow.com/a/29814281 + plt.gcf().subplots_adjust(top=0.8) + plt.gcf().suptitle( + { + "Quantile Regression": "Quantile Regression over Medians", + "Ordinary Least Squares Regression": "Quantile Regression over Means", + }[regression], + ) diff --git a/conduitpylib/wrangle/__init__.py b/conduitpylib/wrangle/__init__.py index 798214d5e9..21082a7de5 100644 --- a/conduitpylib/wrangle/__init__.py +++ b/conduitpylib/wrangle/__init__.py @@ -1,5 +1,6 @@ from ._diff_snapshot_states import diff_snapshot_states from ._find_treat_idx_mapped_col import find_treat_idx_mapped_col +from ._make_regression_row import make_regression_row from ._merge_inlet_outlet_data import merge_inlet_outlet_data from ._retrieve_and_prepare_delta_dataframes import ( retrieve_and_prepare_delta_dataframes, @@ -8,15 +9,18 @@ from ._wrangle_instrumentation_wideform import wrangle_instrumentation_wideform from ._wrangle_longitudinal_deltas import wrangle_longitudinal_deltas from ._wrangle_snapshot_deltas import wrangle_snapshot_deltas +from ._wrangle_world_sums import wrangle_world_sums __all__ = [ "diff_snapshot_states", "find_treat_idx_mapped_col", + "make_regression_row", "merge_inlet_outlet_data", "retrieve_and_prepare_delta_dataframes", "wrangle_instrumentation_longform", "wrangle_instrumentation_wideform", "wrangle_longitudinal_deltas", "wrangle_snapshot_deltas", + "wrangle_world_sums", ] diff --git a/conduitpylib/wrangle/_make_regression_row.py b/conduitpylib/wrangle/_make_regression_row.py new file mode 100644 index 0000000000..da724d80de --- /dev/null +++ b/conduitpylib/wrangle/_make_regression_row.py @@ -0,0 +1,132 @@ +import pathlib + +from iterdub import iterdub as ib +from iterpop import iterpop as ip +from keyname import keyname as kn +import numpy as np +from slugify import slugify +import statsmodels.formula.api as smf + + +def make_regression_row( + *, data, independent_variable, dependent_variable, regression, row_filter +): + filtered_data = data[data.apply(eval(row_filter), axis=1)] + + regfun = { + "Quantile Regression over Means": smf.quantreg, + "Quantile Regression over Medians": smf.quantreg, + }[regression] + model = regfun( + f"Q('{dependent_variable}') ~ Q('{independent_variable}')", + filtered_data, + ) + fit_model = model.fit() + + slope = fit_model.params[f"Q('{independent_variable}')"] + intercept = fit_model.params["Intercept"] + + slope_ci_lb, slope_ci_ub = ( + fit_model.conf_int().loc[f"Q('{independent_variable}')"].tolist() + ) + intercept_ci_lb, intercept_ci_ub = ( + fit_model.conf_int().loc["Intercept"].tolist() + ) + + p = fit_model.pvalues.loc[f"Q('{independent_variable}')"] + + # normalize to "control", i.e., lowest num processes observed + effect_size_normalization_data = data[ + data[independent_variable] == data[independent_variable].min() + ][dependent_variable] + effect_size_normalization_factor = { + "Quantile Regression over Means": lambda x: x.mean(), + "Quantile Regression over Medians": lambda x: x.median(), + }[regression](effect_size_normalization_data) + relative_effect_size = slope / effect_size_normalization_factor + relative_effect_size_ci_lb = slope_ci_lb / effect_size_normalization_factor + relative_effect_size_ci_ub = slope_ci_ub / effect_size_normalization_factor + relative_effect_size_ci_width = ( + relative_effect_size_ci_ub - relative_effect_size_ci_lb + ) + + is_significant = p < 0.05 if np.isfinite(p) else None + + res = { + "Independent Variable": independent_variable, + "Dependent Variable": dependent_variable, + "Dependent Variable Slug": slugify(dependent_variable), + "Cpus Per Node": ib.dub(data["Cpus Per Node"]), + "Num Simels Per Cpu": ip.pophomogeneous(data["Num Simels Per Cpu"]), + "Slope Estimate": slope, + "Slope Estimate 95% CI Lower Bound": slope_ci_lb, + "Slope Estimate 95% CI Upper Bound": slope_ci_ub, + "Absolute Effect Size": slope, + "Absolute Effect Size 95% CI Lower Bound": slope_ci_lb, + "Absolute Effect Size 95% CI Upper Bound": slope_ci_ub, + "Absolute Effect Size 95% CI Width": slope_ci_ub - slope_ci_lb, + "Relative Effect Size": relative_effect_size, + "Relative Effect Size 95% CI Lower Bound": relative_effect_size_ci_lb, + "Relative Effect Size 95% CI Upper Bound": relative_effect_size_ci_ub, + "Relative Effect Size 95% CI Width": relative_effect_size_ci_width, + "Intercept Estimate": intercept, + "Intercept Estimate 95% CI Lower Bound": intercept_ci_lb, + "Intercept Estimate 95% CI Upper Bound": intercept_ci_ub, + "R^2": fit_model.rsquared, + "p": fit_model.pvalues.loc[f"Q('{independent_variable}')"], + "Significant?": is_significant, + "Significant Effect Sign": ( + "-" + if is_significant and slope < 0 + else "+" + if is_significant and slope > 0 + else "0" + if is_significant is not None + else None + ), + "n": len(filtered_data), + "Filter": row_filter, + "Num Processes": ib.dub(filtered_data["Num Processes"]), + "Num Processes Prettyprint": ( + "/".join( + filtered_data["Num Processes"] + .sort_values() + .astype(str) + .unique() + ) + ), + "Regression Model": regression, + "Regression Model Slug": slugify(regression), + "Statistic": { + "Quantile Regression over Means": "mean", + "Quantile Regression over Medians": "median", + }[regression], + } + + # dump regression summary to file + summary_filename = kn.pack( + { + **{ + "a": "regression_summary", + "ext": ".txt", + }, + **{ + slugify(k): slugify(str(v)) + for k, v in res.items() + if k + in [ + "Independent Variable", + "Dependent Variable", + "Cpus Per Node", + "Num Simels Per Cpu", + "Regression Model", + ] + }, + } + ) + + pathlib.Path("outplots").mkdir(parents=True, exist_ok=True) + with open(f"outplots/{summary_filename}", "w") as file: + print(fit_model.summary(), file=file) + + return res diff --git a/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py index 9802c3a3c2..3476c2b0a4 100644 --- a/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py +++ b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py @@ -13,7 +13,8 @@ def retrieve_and_prepare_delta_dataframes( df_inlet_url: str = "https://osf.io/jgpnv/download", df_outlet_url: str = "https://osf.io/ncdfq/download", treatment_column: typing.Optional[str] = None, -) -> pd.DataFrame: + return_merge_df: bool = False, +) -> typing.Union[pd.DataFrame, typing.Tuple[pd.DataFrame, pd.DataFrame]]: df_inlet = pd.read_csv( df_inlet_url, compression="gzip", @@ -26,23 +27,30 @@ def retrieve_and_prepare_delta_dataframes( ) nbm.print_dataframe_summary(*eval(nbm.nvp_expr("df_outlet"))) - df = merge_inlet_outlet_data(df_inlet, df_outlet) - - if treatment_column is not None: - treat_idx_mapper = { - val: idx for idx, val in enumerate(df[treatment_column].unique()) - } - treat_idx_mapped_title = " | ".join( - f"{idx} = {val}" for val, idx in treat_idx_mapper.items() - ) - df[treat_idx_mapped_title] = df.apply( - lambda row: treat_idx_mapper[row[treatment_column]], - axis=1, - ) - - assert find_treat_idx_mapped_col(df) == treat_idx_mapped_title - - return ( - wrangle_longitudinal_deltas(df), - wrangle_snapshot_deltas(df), + merge_df = merge_inlet_outlet_data(df_inlet, df_outlet) + + res = ( + wrangle_longitudinal_deltas(merge_df), + wrangle_snapshot_deltas(merge_df), ) + + for df_ in res: + if treatment_column is not None: + treat_idx_mapper = { + val: idx + for idx, val in enumerate(df_[treatment_column].unique()) + } + treat_idx_mapped_title = " | ".join( + f"{idx} = {val}" for val, idx in treat_idx_mapper.items() + ) + df_[treat_idx_mapped_title] = df_.apply( + lambda row: treat_idx_mapper[row[treatment_column]], + axis=1, + ) + + assert find_treat_idx_mapped_col(df_) == treat_idx_mapped_title + + if not return_merge_df: + return res + else: + return (merge_df, res) diff --git a/conduitpylib/wrangle/_wrangle_world_sums.py b/conduitpylib/wrangle/_wrangle_world_sums.py new file mode 100644 index 0000000000..236f6a9415 --- /dev/null +++ b/conduitpylib/wrangle/_wrangle_world_sums.py @@ -0,0 +1,95 @@ +import pandas as pd + +from ._find_treat_idx_mapped_col import find_treat_idx_mapped_col + + +def wrangle_world_sums(df_finalized_observations: pd.DataFrame) -> pd.DataFrame: + df_world_sum = df_finalized_observations.groupby( + [ + "Replicate", + "Async Mode", + "Num Processes", + "Num Nodes", + "Num Simels Per Cpu", + "Allocated Tasks Per Node", + "Cpus Per Node", + "Allocation", + find_treat_idx_mapped_col(df_finalized_observations), + ], + as_index=False, + ).sum() + + df_world_sum["Fraction Messages Utilized"] = ( + df_world_sum["Num Reads That Were Fresh"] + / df_world_sum["Num Try Puts Attempted"] + ) + df_world_sum["Fraction Messages Delivered"] = ( + df_world_sum["Num Try Puts That Succeeded"] + / df_world_sum["Num Try Puts Attempted"] + ) + df_world_sum["Delivery Failure Rate"] = ( + 1.0 - df_world_sum["Fraction Messages Delivered"] + ) + df_world_sum["Fraction Messages Dropped"] = df_world_sum[ + "Delivery Failure Rate" + ] + df_world_sum["Fraction Try Pulls That Were Laden"] = ( + df_world_sum["Num Try Pulls That Were Laden"] + / df_world_sum["Num Try Pulls Attempted"] + ) + df_world_sum["Round Trip Touches Per Attempted Pull"] = ( + df_world_sum["Num Round Trip Touches Outlet"] + / df_world_sum["Num Try Pulls Attempted"] + ) + df_world_sum["Round Trip Touches Per Attempted Put"] = ( + df_world_sum["Num Round Trip Touches Inlet"] + / df_world_sum["Num Try Puts Attempted"] + ) + df_world_sum["Num Inflight Messages"] = ( + 2.0 / df_world_sum["Round Trip Touches Per Attempted Put"] - 1 + ) + df_world_sum["Fraction Duct Flux Stepped Through"] = ( + df_world_sum["Num Revisions Pulled"] + / df_world_sum["Net Flux Through Duct"] + ) + df_world_sum["Fraction Duct Flux Jumped Over"] = ( + 1.0 - df_world_sum["Fraction Duct Flux Stepped Through"] + ) + df_world_sum["Round Trip Touches Per Runtime Second"] = ( + df_world_sum["Num Round Trip Touches Inlet"] + / df_world_sum["Runtime Seconds Elapsed Inlet"] + ) + df_world_sum["Latency Simsteps Inlet"] = ( + df_world_sum["Num Puts Attempted"] - 1 + ) / df_world_sum["Num Round Trip Touches Inlet"] + df_world_sum["Latency Simsteps Outlet"] = ( + df_world_sum["Num Pulls Attempted"] - 1 + ) / df_world_sum["Num Round Trip Touches Outlet"] + + df_world_sum["Bunchiness"] = ( + df_world_sum["Num Messages Per Laden Pull"] + / df_world_sum["Num Messages Per Pull"] + ) - 1 + df_world_sum["Delivery Clumpiness"] = df_world_sum["Bunchiness"] + df_world_sum["Intermittancy"] = df_world_sum["Bunchiness"] + df_world_sum["Bunching"] = df_world_sum["Bunchiness"] + + + df_world_sum["Simstep Period Inlet (s)"] = ( + df_world_sum["Inlet-Seconds Elapsed"] + / df_world_sum["Num Puts Attempted"] + ) + df_world_sum["Simstep Period Outlet (s)"] = ( + df_world_sum["Outlet-Seconds Elapsed"] + / df_world_sum["Num Pulls Attempted"] + ) + df_world_sum["Latency Walltime Inlet (s)"] = ( + df_world_sum["Latency Simsteps Inlet"] + * df_world_sum["Simstep Period Inlet (s)"] + ) + df_world_sum["Latency Walltime Outlet (s)"] = ( + df_world_sum["Latency Simsteps Outlet"] + * df_world_sum["Simstep Period Outlet (s)"] + ) + + return df_world_sum From 4c24f4115d799f7f54db5ceb9f1af4d6a297b1ba Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:10:18 -0500 Subject: [PATCH 051/145] Update python requirements, fiddle with pins --- third-party/requirements.in | 20 ++++++--- third-party/requirements.txt | 84 +++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index 973215cb49..5d8ecb2e4d 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -1,16 +1,17 @@ git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient -keyname==0.4.1 +keyname==0.5.3 +numpy==1.24.4 pandas==1.1.2 frozendict==1.2 -seaborn==0.11.0 -matplotlib==3.3.2 +# 0.13.0 with override of pandas version pin +git+git://github.com/mmore500/seaborn@bb07f1fa8e55a3cbd4c1e5c08c20c9dd014860d8#egg=seaborn +matplotlib==3.7.3 python-slugify==4.0.1 iterpop==0.3.4 exdown==0.7.0 networkx==2.5 -numpy==1.19.5 scipy==1.5.4 -teeplot==0.3.0 +teeplot==0.6.1 nbmetalog==0.2.6 nbconvert==5.6.1 jupyter_client==6.1.12 @@ -23,3 +24,12 @@ iterdub==0.2.0 python-slugify==4.0.1 statsmodels==0.12.2 nose==1.3.7 +git+git://github.com/mmore500/patchworklib@010008a90d859f54efdaec19b250f8e6c978d51a#egg=patchworklib +# unused depndency, loosend version pin for installability +git+git://github.com/mmore500/plotnine@833700abf9c917f4ee839ffc6cb81109a5f5df1f#egg=plotnine +mizani==0.7.3 # unused dependency pinned to force installability +bidict==0.22.1 +opytional==0.1.0 +# prevent true +pip-tools==5.5.0 +pip==20.1 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index e7a2048da6..93a726900c 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -2,41 +2,52 @@ # This file is autogenerated by pip-compile # To update, run: # -# pip-compile requirements.in +# pip-compile --pip-args='--no-warn-conflicts' requirements.in # attrs==21.2.0 # via jsonschema backcall==0.2.0 # via ipython +bidict==0.22.1 + # via -r requirements.in bleach==4.1.0 # via nbconvert certifi==2020.12.5 - # via - # matplotlib - # requests + # via requests chardet==4.0.0 # via requests click==7.1.2 - # via keyname + # via + # keyname + # pip-tools +contourpy==1.1.1 + # via matplotlib cycler==0.10.0 # via matplotlib decorator==4.4.2 # via # ipython # networkx + # retry # traitlets defusedxml==0.7.1 # via nbconvert +dill==0.3.7 + # via patchworklib entrypoints==0.3 # via nbconvert exdown==0.7.0 # via -r requirements.in +fonttools==4.44.0 + # via matplotlib frozendict==1.2 # via -r requirements.in hurry.filesize==0.9 # via nbmetalog idna==2.10 # via requests +importlib-resources==6.1.1 + # via matplotlib ipykernel==5.5.3 # via # -r requirements.in @@ -71,7 +82,7 @@ jupyter_client==6.1.12 # via # -r requirements.in # ipykernel -keyname==0.4.1 +keyname==0.5.3 # via # -r requirements.in # nbmetalog @@ -80,13 +91,22 @@ kiwisolver==1.3.1 # via matplotlib markupsafe==2.0.1 # via jinja2 -matplotlib==3.3.2 +matplotlib==3.7.3 # via # -r requirements.in + # mizani + # patchworklib + # plotnine # seaborn # teeplot mistune==0.8.4 # via nbconvert +mizani==0.7.3 + # via + # -r requirements.in + # plotnine +more-itertools==10.1.0 + # via keyname nb-clean==2.0.2 # via -r requirements.in nbconvert==5.6.1 @@ -101,25 +121,38 @@ networkx==2.5 # via -r requirements.in nose==1.3.7 # via -r requirements.in -numpy==1.19.5 +numpy==1.24.4 # via # -r requirements.in + # contourpy # iterdub # matplotlib + # mizani # pandas + # patchworklib # patsy + # plotnine # scipy # seaborn # statsmodels # teeplot +opytional==0.1.0 + # via -r requirements.in git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient # via -r requirements.in packaging==21.0 - # via bleach + # via + # bleach + # matplotlib +palettable==3.3.3 + # via mizani pandas==1.1.2 # via # -r requirements.in + # mizani # nbmetalog + # patchworklib + # plotnine # seaborn # statsmodels # teeplot @@ -127,18 +160,30 @@ pandocfilters==1.4.3 # via nbconvert parso==0.8.2 # via jedi +git+git://github.com/mmore500/patchworklib@010008a90d859f54efdaec19b250f8e6c978d51a#egg=patchworklib + # via -r requirements.in patsy==0.5.1 - # via statsmodels + # via + # plotnine + # statsmodels pexpect==4.8.0 # via ipython pickleshare==0.7.5 # via ipython pillow==8.1.0 # via matplotlib +pip-tools==5.5.0 + # via -r requirements.in +git+git://github.com/mmore500/plotnine@833700abf9c917f4ee839ffc6cb81109a5f5df1f#egg=plotnine + # via + # -r requirements.in + # patchworklib prompt-toolkit==3.0.20 # via ipython ptyprocess==0.7.0 # via pexpect +py==1.11.0 + # via retry pygments==2.10.0 # via # ipython @@ -166,13 +211,17 @@ pyzmq==22.2.1 # via jupyter-client requests==2.25.1 # via osfclient +retry==0.9.2 + # via keyname scipy==1.5.4 # via # -r requirements.in - # seaborn + # plotnine # statsmodels -seaborn==0.11.0 - # via -r requirements.in +git+git://github.com/mmore500/seaborn@bb07f1fa8e55a3cbd4c1e5c08c20c9dd014860d8#egg=seaborn + # via + # -r requirements.in + # patchworklib six==1.15.0 # via # bleach @@ -183,8 +232,10 @@ six==1.15.0 # python-dateutil # traitlets statsmodels==0.12.2 - # via -r requirements.in -teeplot==0.3.0 + # via + # -r requirements.in + # plotnine +teeplot==0.6.1 # via -r requirements.in testpath==0.5.0 # via nbconvert @@ -211,6 +262,9 @@ wcwidth==0.2.5 # via prompt-toolkit webencodings==0.5.1 # via bleach +zipp==3.17.0 + # via importlib-resources # The following packages are considered to be unsafe in a requirements file: +# pip # setuptools From 1da20db46a5c7dba3d18a471ebf77762ba544c25 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:18:32 -0500 Subject: [PATCH 052/145] Pin older bidict that docker build can find --- third-party/requirements.in | 2 +- third-party/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index 5d8ecb2e4d..71178d7f7d 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -28,7 +28,7 @@ git+git://github.com/mmore500/patchworklib@010008a90d859f54efdaec19b250f8e6c978d # unused depndency, loosend version pin for installability git+git://github.com/mmore500/plotnine@833700abf9c917f4ee839ffc6cb81109a5f5df1f#egg=plotnine mizani==0.7.3 # unused dependency pinned to force installability -bidict==0.22.1 +bidict==0.21.4 opytional==0.1.0 # prevent true pip-tools==5.5.0 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index 93a726900c..e7cf5fa09a 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -8,7 +8,7 @@ attrs==21.2.0 # via jsonschema backcall==0.2.0 # via ipython -bidict==0.22.1 +bidict==0.21.4 # via -r requirements.in bleach==4.1.0 # via nbconvert From d84dcd80148b6e1d28b11364b8c8b450d8f6082f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:27:11 -0500 Subject: [PATCH 053/145] Put venv on Docker path to upgrade python to 3.8 --- Dockerfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Dockerfile b/Dockerfile index 7e78ec397e..51dcf01f46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,21 @@ # Pull base image. FROM ubuntu:bionic-20180125@sha256:d6f6cc62b6bed64387d84ca227b76b9cc45049b0d0aefee0deec21ed19a300bf +# adapted from https://stackoverflow.com/a/63944890 +RUN : \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + software-properties-common \ + && add-apt-repository -y ppa:deadsnakes \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + python3.8-venv \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + && : + +RUN python3.8 -m venv /venv +ENV PATH=/venv/bin:$PATH + COPY . /opt/conduit/ SHELL ["/bin/bash", "-c"] From 3956ce2e7d48c367fcb61a719a14a61592970334 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:36:26 -0500 Subject: [PATCH 054/145] Try installing packages and curling gpg key --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index 51dcf01f46..2306cdc863 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,16 @@ FROM ubuntu:bionic-20180125@sha256:d6f6cc62b6bed64387d84ca227b76b9cc45049b0d0aefee0deec21ed19a300bf # adapted from https://stackoverflow.com/a/63944890 +# and https://stackoverflow.com/a/59282256 RUN : \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ software-properties-common \ + apt-transport-https \ + ca-certificates \ + curl \ + software-properties-common \ + && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \ && add-apt-repository -y ppa:deadsnakes \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ python3.8-venv \ From f8513d0bd42c8603a1e1eae9fa5018c3b00ba6f2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:44:23 -0500 Subject: [PATCH 055/145] Try another Docker setup strategy --- Dockerfile | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2306cdc863..65e96c5663 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,21 +3,19 @@ FROM ubuntu:bionic-20180125@sha256:d6f6cc62b6bed64387d84ca227b76b9cc45049b0d0aef # adapted from https://stackoverflow.com/a/63944890 # and https://stackoverflow.com/a/59282256 -RUN : \ - && apt-get update \ +RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ software-properties-common \ apt-transport-https \ ca-certificates \ curl \ - software-properties-common \ - && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \ + && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ && add-apt-repository -y ppa:deadsnakes \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ python3.8-venv \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* \ - && : + && rm -rf /var/lib/apt/lists/* RUN python3.8 -m venv /venv ENV PATH=/venv/bin:$PATH From 1df548d0d9080fb1b7f083445e8d590c3ecfcfcc Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:52:19 -0500 Subject: [PATCH 056/145] Try adding deadsnames with RUN command --- Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 65e96c5663..4925230320 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,16 @@ RUN apt-get update \ apt-transport-https \ ca-certificates \ curl \ - && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ - && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ - && add-apt-repository -y ppa:deadsnakes \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + tzdata + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN add-apt-repository 'ppa:deadsnakes/ppa' + +RUN apt-get -y update \ + && apt-get install -y --no-install-recommends \ + python3.8 \ + python3.8-dev \ python3.8-venv \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From beb0f248522f6000b92ecf38b9bc074cdded15ad Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:56:08 -0500 Subject: [PATCH 057/145] Bump ubuntu 18 -> 20 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4925230320..624c86e35d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Pull base image. -FROM ubuntu:bionic-20180125@sha256:d6f6cc62b6bed64387d84ca227b76b9cc45049b0d0aefee0deec21ed19a300bf +FROM ubuntu:focal-20231003@sha256:4bab3d12db59c8f2427dbec33d65e2e18d15562effcc0a021d624b1b7385a612 # adapted from https://stackoverflow.com/a/63944890 # and https://stackoverflow.com/a/59282256 From e72516390b72d99b7e30eada4180de15ea8f7a75 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:56:58 -0500 Subject: [PATCH 058/145] Fix Dockerfile syntax error --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 624c86e35d..bafb636f4b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN apt-get update \ apt-transport-https \ ca-certificates \ curl \ - tzdata + tzdata \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* From 42a87b35d493c99f28e020f30227ef5719e7c2a9 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 10:59:00 -0500 Subject: [PATCH 059/145] Drop python3.8 sideload, it's default on ubuntu 20 --- Dockerfile | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index bafb636f4b..e281dde92d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,6 @@ # Pull base image. FROM ubuntu:focal-20231003@sha256:4bab3d12db59c8f2427dbec33d65e2e18d15562effcc0a021d624b1b7385a612 -# adapted from https://stackoverflow.com/a/63944890 -# and https://stackoverflow.com/a/59282256 -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - software-properties-common \ - apt-transport-https \ - ca-certificates \ - curl \ - tzdata \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -RUN add-apt-repository 'ppa:deadsnakes/ppa' - -RUN apt-get -y update \ - && apt-get install -y --no-install-recommends \ - python3.8 \ - python3.8-dev \ - python3.8-venv \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -RUN python3.8 -m venv /venv -ENV PATH=/venv/bin:$PATH - COPY . /opt/conduit/ SHELL ["/bin/bash", "-c"] From 84c70b35c9bc916d5f6928917977122d265d1075 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:05:34 -0500 Subject: [PATCH 060/145] Try an amd64 digest --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e281dde92d..72c19e34cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Pull base image. -FROM ubuntu:focal-20231003@sha256:4bab3d12db59c8f2427dbec33d65e2e18d15562effcc0a021d624b1b7385a612 +FROM ubuntu:focal-20231003@sha256:218bb51abbd1864df8be26166f847547b3851a89999ca7bfceb85ca9b5d2e95d COPY . /opt/conduit/ From dc85f0c08b0137f109f0e1fe63440dd7e45f5e5f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:13:46 -0500 Subject: [PATCH 061/145] Update apt packages ubuntu 18 -> 20 --- Dockerfile | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 72c19e34cf..512788313e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -80,14 +80,14 @@ RUN \ libgtk-3-0 \ libicu-dev \ libjpeg-dev \ - libhdf5-100 \ - libhdf5-cpp-100 \ + libhdf5-103 \ + libhdf5-cpp-103 \ libhdf5-dev \ libhdf5-doc \ libhdf5-mpi-dev \ - libhdf5-mpich-100 \ + libhdf5-mpich-103 \ libhdf5-mpich-dev \ - libhdf5-openmpi-100 \ + libhdf5-openmpi-103 \ libhdf5-openmpi-dev \ libhdf5-serial-dev \ libmpich-dev \ @@ -95,13 +95,13 @@ RUN \ libnspr4 \ libnss3 \ libopenmpi-dev \ - libopenmpi2 \ + # libopenmpi2 \ libpango-1.0-0 \ libpangocairo-1.0-0 \ libpng-dev \ libpthread-stubs0-dev \ libstdc++-7-dev \ - libstdc++6=8-20180414-1ubuntu2 \ + libstdc++6 \ libx11-6 \ libx11-xcb1 \ libxcb1 \ @@ -128,24 +128,24 @@ RUN \ openmpi-common \ openmpi-doc \ openssh-server \ - python-dev \ - python-h5py \ - python-pip \ - python-setuptools \ - python-sphinx \ - python-virtualenv \ - python-wheel \ + # python-dev \ + # python-h5py \ + # python-pip \ + # python-setuptools \ + # python-virtualenv \ + # python-wheel \ python3-dev \ python3-h5py \ python3-pip \ python3-setuptools \ - python3-sphinx \ python3-virtualenv \ python3-wheel \ rename \ rsync \ slurm-client \ software-properties-common \ + sphinx-doc \ + sphinx-common \ tar \ unzip \ vim \ From 204e0834eda84cd68044d1e73676fafa26f56828 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:23:17 -0500 Subject: [PATCH 062/145] Try using aptitude to fix apt versioning issue --- Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 512788313e..03dcd5a62c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,7 +47,9 @@ RUN \ RUN \ apt-get update -qq \ && \ - apt-get install -y --allow-downgrades --no-install-recommends \ + apt-get install -y aptitude --allow-downgrades --no-install-recommends aptitude \ + && \ + aptitude install -y --without-recommends \ build-essential \ ca-certificates \ cmake \ From 8e80528152b86759cb3df0931aa775b83304a1c6 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:34:47 -0500 Subject: [PATCH 063/145] Remove special install for newer git --- Dockerfile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 03dcd5a62c..d9eaf06304 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,6 +59,7 @@ RUN \ fonts-liberation \ gconf-service \ gdb \ + git \ gpg-agent \ gzip \ hdf5-helpers \ @@ -154,12 +155,6 @@ RUN \ wget \ xdg-utils \ && \ - add-apt-repository ppa:git-core/ppa -y \ - && \ - apt-get update -qq \ - && \ - apt-get install -y --no-install-recommends git \ - && \ apt-get clean \ && \ rm -rf /var/lib/apt/lists/* \ From 6cdd2ffeba5187997699553166664a6cfbc65973 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:37:49 -0500 Subject: [PATCH 064/145] Try installing software-properties-common with apt --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index d9eaf06304..4a8b2777c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -165,6 +165,8 @@ RUN \ RUN \ apt-get update -qq \ && \ + apt-get install -qq software-properties-common \ + && \ rm /etc/apt/apt.conf.d/docker-gzip-indexes \ && \ apt-get purge apt-show-versions \ From 42cb0f4586adada12523be7b99acac49e8d7d591 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:44:02 -0500 Subject: [PATCH 065/145] Try installing compilers directly, not through ppa --- Dockerfile | 81 +++++++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 44 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4a8b2777c3..ea52a2e5d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -52,6 +52,7 @@ RUN \ aptitude install -y --without-recommends \ build-essential \ ca-certificates \ + clang-7 \ cmake \ curl \ doxygen \ @@ -62,6 +63,7 @@ RUN \ git \ gpg-agent \ gzip \ + g++-9 \ hdf5-helpers \ hdf5-tools \ htop \ @@ -70,6 +72,7 @@ RUN \ libatk1.0-0 \ libc6 \ libcairo2 \ + libclang-7-dev \ libcups2 \ libcurl4 \ libcurl4-openssl-dev \ @@ -118,6 +121,8 @@ RUN \ libxrender1 \ libxss1 \ libxtst6 \ + llvm-7 \ + llvm-7-dev \ locales \ lsb-release \ man \ @@ -161,51 +166,39 @@ RUN \ && \ echo "installed fundamentals" -# adapted in part from https://askubuntu.com/a/916451 -RUN \ - apt-get update -qq \ - && \ - apt-get install -qq software-properties-common \ - && \ - rm /etc/apt/apt.conf.d/docker-gzip-indexes \ - && \ - apt-get purge apt-show-versions \ - && \ - rm /var/lib/apt/lists/*lz4 \ - && \ - apt-get -o Acquire::GzipIndexes=false update \ - && \ - add-apt-repository -y ppa:ubuntu-toolchain-r/test \ - && \ - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \ - && \ - apt-add-repository "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" \ - && \ - add-apt-repository -y ppa:ubuntu-toolchain-r/test \ - && \ - apt-get update -qq \ - && \ - apt-get clean \ - && \ - rm -rf /var/lib/apt/lists/* \ - && \ - echo "configured packaging system" -RUN \ - apt-get update -qq \ - && \ - apt-get install -qq \ - libclang-7-dev=1:7.1.0~svn353565-1~exp1~20190408084827.60 \ - llvm-7=1:7.1.0~svn353565-1~exp1~20190408084827.60 \ - llvm-7-dev=1:7.1.0~svn353565-1~exp1~20190408084827.60 \ - clang-7=1:7.1.0~svn353565-1~exp1~20190408084827.60 \ - g++-9=9.4.0-1ubuntu1~18.04 \ - && \ - apt-get clean \ - && \ - rm -rf /var/lib/apt/lists/* \ - && \ - echo "installed llvm-7 dependencies" + + + +# adapted in part from https://askubuntu.com/a/916451 +# RUN \ +# apt-get update -qq \ +# && \ +# apt-get install -qq software-properties-common \ +# && \ +# rm /etc/apt/apt.conf.d/docker-gzip-indexes \ +# && \ +# apt-get purge apt-show-versions \ +# && \ +# rm /var/lib/apt/lists/*lz4 \ +# && \ +# apt-get -o Acquire::GzipIndexes=false update \ +# && \ +# add-apt-repository -y ppa:ubuntu-toolchain-r/test \ +# && \ +# wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \ +# && \ +# apt-add-repository "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" \ +# && \ +# add-apt-repository -y ppa:ubuntu-toolchain-r/test \ +# && \ +# apt-get update -qq \ +# && \ +# apt-get clean \ +# && \ +# rm -rf /var/lib/apt/lists/* \ +# && \ +# echo "configured packaging system" # magic from https://github.com/puppeteer/puppeteer/issues/3451#issuecomment-523961368 RUN echo 'kernel.unprivileged_userns_clone=1' > /etc/sysctl.d/userns.conf From 3441f820316ca374aa324943614b88e0341c2fea Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:51:57 -0500 Subject: [PATCH 066/145] Install git with apt not aptitude --- Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ea52a2e5d4..4e7e5c3e85 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,7 +47,7 @@ RUN \ RUN \ apt-get update -qq \ && \ - apt-get install -y aptitude --allow-downgrades --no-install-recommends aptitude \ + apt-get install -y aptitude git --allow-downgrades --no-install-recommends aptitude \ && \ aptitude install -y --without-recommends \ build-essential \ @@ -60,7 +60,6 @@ RUN \ fonts-liberation \ gconf-service \ gdb \ - git \ gpg-agent \ gzip \ g++-9 \ From 2653a67c1597a07b5298aba0e17d0e5351544a5c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 11:55:22 -0500 Subject: [PATCH 067/145] Try removing deletion of updates repositories --- Dockerfile | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e7e5c3e85..12eb328702 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,13 +36,6 @@ RUN \ && \ echo "buffed apt-get resiliency" -RUN \ - find /etc/apt -type f -name '*.list' -exec sed -i 's/\(^deb.*-backports.*\)/#\1/; s/\(^deb.*-updates.*\)/#\1/; s/\(^deb.*-proposed.*\)/#\1/; s/\(^deb.*-security.*\)/#\1/' {} + \ - && \ - rm -rf /var/lib/apt/lists/* \ - && \ - echo "removed -backports, -updates, -proposed, -security repositories" - # adapted in part form https://www.cloudsavvyit.com/13461/how-to-run-puppeteer-and-headless-chrome-in-a-docker-container/ RUN \ apt-get update -qq \ From f4bd73ce61824177bccd2cd59fe61d665f1aee8f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 12:06:35 -0500 Subject: [PATCH 068/145] Try cache clean to fix npm crash --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 12eb328702..da91d1b447 100644 --- a/Dockerfile +++ b/Dockerfile @@ -220,6 +220,8 @@ RUN \ && \ npm install -g n@6.7.0 \ && \ + npm cache clean --force \ + && \ n 12.18.2 \ && \ export python="/usr/bin/python" \ From 502c757219ce11ce5db5114846038fc4f633394d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 12:14:34 -0500 Subject: [PATCH 069/145] Try fix npm crash with manual semver install --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index da91d1b447..a35997b468 100644 --- a/Dockerfile +++ b/Dockerfile @@ -218,7 +218,7 @@ RUN \ && \ update-alternatives --install /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-7 90 \ && \ - npm install -g n@6.7.0 \ + npm install -g n@6.7.0 semver \ && \ npm cache clean --force \ && \ From 60633d1d717e4eb9d5dcdd1b7285de5c87ef08c4 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 12:27:18 -0500 Subject: [PATCH 070/145] Try pinning semver and reinitializing path --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a35997b468..2d0574ede7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -218,11 +218,11 @@ RUN \ && \ update-alternatives --install /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-7 90 \ && \ - npm install -g n@6.7.0 semver \ + npm install -g n@6.7.0 semver@7.5.4 \ && \ npm cache clean --force \ && \ - n 12.18.2 \ + PATH="$PATH" n 12.18.2 \ && \ export python="/usr/bin/python" \ && \ From db656bd7a059328008da3168579f417a5d249a2a Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 15:17:50 -0500 Subject: [PATCH 071/145] Bump numpy back to provide statsmodels MachAr --- third-party/requirements.in | 2 +- third-party/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index 71178d7f7d..01629e7f08 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -1,6 +1,6 @@ git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient keyname==0.5.3 -numpy==1.24.4 +numpy==1.23.5 pandas==1.1.2 frozendict==1.2 # 0.13.0 with override of pandas version pin diff --git a/third-party/requirements.txt b/third-party/requirements.txt index e7cf5fa09a..261fdc2379 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -121,7 +121,7 @@ networkx==2.5 # via -r requirements.in nose==1.3.7 # via -r requirements.in -numpy==1.24.4 +numpy==1.23.5 # via # -r requirements.in # contourpy From f512524ae77fb50744027a95d578f93950a01508 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 20:11:40 -0500 Subject: [PATCH 072/145] Drop back mplotlib pin for pandas compat --- third-party/requirements.in | 4 ++-- third-party/requirements.txt | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index 01629e7f08..1764e8c509 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -5,7 +5,7 @@ pandas==1.1.2 frozendict==1.2 # 0.13.0 with override of pandas version pin git+git://github.com/mmore500/seaborn@bb07f1fa8e55a3cbd4c1e5c08c20c9dd014860d8#egg=seaborn -matplotlib==3.7.3 +matplotlib==3.5.2 python-slugify==4.0.1 iterpop==0.3.4 exdown==0.7.0 @@ -26,7 +26,7 @@ statsmodels==0.12.2 nose==1.3.7 git+git://github.com/mmore500/patchworklib@010008a90d859f54efdaec19b250f8e6c978d51a#egg=patchworklib # unused depndency, loosend version pin for installability -git+git://github.com/mmore500/plotnine@833700abf9c917f4ee839ffc6cb81109a5f5df1f#egg=plotnine +git+git://github.com/mmore500/plotnine@3daf0e81c0405b1eeebb9daf53489f423eefef2f#egg=plotnine mizani==0.7.3 # unused dependency pinned to force installability bidict==0.21.4 opytional==0.1.0 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index 261fdc2379..777000a63d 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -20,8 +20,6 @@ click==7.1.2 # via # keyname # pip-tools -contourpy==1.1.1 - # via matplotlib cycler==0.10.0 # via matplotlib decorator==4.4.2 @@ -46,8 +44,6 @@ hurry.filesize==0.9 # via nbmetalog idna==2.10 # via requests -importlib-resources==6.1.1 - # via matplotlib ipykernel==5.5.3 # via # -r requirements.in @@ -91,7 +87,7 @@ kiwisolver==1.3.1 # via matplotlib markupsafe==2.0.1 # via jinja2 -matplotlib==3.7.3 +matplotlib==3.5.2 # via # -r requirements.in # mizani @@ -124,7 +120,6 @@ nose==1.3.7 numpy==1.23.5 # via # -r requirements.in - # contourpy # iterdub # matplotlib # mizani @@ -174,7 +169,7 @@ pillow==8.1.0 # via matplotlib pip-tools==5.5.0 # via -r requirements.in -git+git://github.com/mmore500/plotnine@833700abf9c917f4ee839ffc6cb81109a5f5df1f#egg=plotnine +git+git://github.com/mmore500/plotnine@3daf0e81c0405b1eeebb9daf53489f423eefef2f#egg=plotnine # via # -r requirements.in # patchworklib @@ -262,8 +257,6 @@ wcwidth==0.2.5 # via prompt-toolkit webencodings==0.5.1 # via bleach -zipp==3.17.0 - # via importlib-resources # The following packages are considered to be unsafe in a requirements file: # pip From 7bfc68198a4f2e5496990b0b5e5e50ce06377bb5 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 20:14:08 -0500 Subject: [PATCH 073/145] Delete unneeded Dockerfile content --- Dockerfile | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d0574ede7..a717af3591 100644 --- a/Dockerfile +++ b/Dockerfile @@ -158,40 +158,6 @@ RUN \ && \ echo "installed fundamentals" - - - - -# adapted in part from https://askubuntu.com/a/916451 -# RUN \ -# apt-get update -qq \ -# && \ -# apt-get install -qq software-properties-common \ -# && \ -# rm /etc/apt/apt.conf.d/docker-gzip-indexes \ -# && \ -# apt-get purge apt-show-versions \ -# && \ -# rm /var/lib/apt/lists/*lz4 \ -# && \ -# apt-get -o Acquire::GzipIndexes=false update \ -# && \ -# add-apt-repository -y ppa:ubuntu-toolchain-r/test \ -# && \ -# wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \ -# && \ -# apt-add-repository "deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" \ -# && \ -# add-apt-repository -y ppa:ubuntu-toolchain-r/test \ -# && \ -# apt-get update -qq \ -# && \ -# apt-get clean \ -# && \ -# rm -rf /var/lib/apt/lists/* \ -# && \ -# echo "configured packaging system" - # magic from https://github.com/puppeteer/puppeteer/issues/3451#issuecomment-523961368 RUN echo 'kernel.unprivileged_userns_clone=1' > /etc/sysctl.d/userns.conf From 93e488281cf821bb86fed601dc4ba7196d27bd25 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 20:16:12 -0500 Subject: [PATCH 074/145] Strip out dead code --- conduitpylib/utils/pickle_cache.py | 8 +++----- conduitpylib/viz/_annotate_spearman.py | 6 +++--- conduitpylib/viz/_compact_xaxis_units.py | 7 ------- conduitpylib/viz/_runtime_indicators_regplot.py | 2 -- conduitpylib/wrangle/_find_treat_idx_mapped_col.py | 2 -- conduitpylib/wrangle/_wrangle_longitudinal_deltas.py | 1 - 6 files changed, 6 insertions(+), 20 deletions(-) diff --git a/conduitpylib/utils/pickle_cache.py b/conduitpylib/utils/pickle_cache.py index b333729c7b..f7c9fbd539 100644 --- a/conduitpylib/utils/pickle_cache.py +++ b/conduitpylib/utils/pickle_cache.py @@ -1,11 +1,9 @@ -import inspect -import shelve +from functools import wraps import hashlib -import pickle +import inspect from pathlib import Path -from functools import wraps +import shelve import typing -from collections import OrderedDict from .equals_by_value import equals_by_value diff --git a/conduitpylib/viz/_annotate_spearman.py b/conduitpylib/viz/_annotate_spearman.py index 64f0c29e3a..e816641727 100644 --- a/conduitpylib/viz/_annotate_spearman.py +++ b/conduitpylib/viz/_annotate_spearman.py @@ -4,9 +4,9 @@ from ..utils import get_signif_asterisks -def annotate_spearman(x: str, y: str, **kws) -> None: - data = kws.pop("data") - ax = kws.get("ax", plt.gca()) +def annotate_spearman(x: str, y: str, **kwargs) -> None: + data = kwargs.pop("data") + ax = kwargs.pop("ax", plt.gca()) # Calculate Spearman correlation and significance corr, p_value = stats.spearmanr(data[x], data[y]) diff --git a/conduitpylib/viz/_compact_xaxis_units.py b/conduitpylib/viz/_compact_xaxis_units.py index 78031b4a31..04e0f2b695 100644 --- a/conduitpylib/viz/_compact_xaxis_units.py +++ b/conduitpylib/viz/_compact_xaxis_units.py @@ -88,13 +88,6 @@ def compact_xaxis_units( assert np.isclose(approx_pow, new_multiplier_pow) new_prefix = _si_prefixes.inv[new_multiplier_pow] - # apply new multiplier, consolidating offset axis scale and label unit - def replace_group(match): - # Extracting the captured group - captured_group = match.group(1) - # Defining the replacement value for the captured group - return replacement_value - ax.xaxis.get_offset_text().set(visible=False) # remove offset axis scale old_prefix_span = old_prefix_match.span(1) new_label_string = splice( diff --git a/conduitpylib/viz/_runtime_indicators_regplot.py b/conduitpylib/viz/_runtime_indicators_regplot.py index 8ef5b9f51e..230be62ebd 100644 --- a/conduitpylib/viz/_runtime_indicators_regplot.py +++ b/conduitpylib/viz/_runtime_indicators_regplot.py @@ -1,7 +1,5 @@ -import itertools as it import typing -from matplotlib import patheffects as mpl_pe from matplotlib import pyplot as plt import pandas as pd import seaborn as sns diff --git a/conduitpylib/wrangle/_find_treat_idx_mapped_col.py b/conduitpylib/wrangle/_find_treat_idx_mapped_col.py index bd409f7b63..146aeb23f9 100644 --- a/conduitpylib/wrangle/_find_treat_idx_mapped_col.py +++ b/conduitpylib/wrangle/_find_treat_idx_mapped_col.py @@ -1,5 +1,3 @@ -import re - import pandas as pd diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index b9c7b286c9..8674dc0051 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -1,7 +1,6 @@ import numpy as np import pandas as pd - from ..utils import pickle_cache From d1941030d11ddfc3fc58a7b92b9249ec254b3635 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 20:17:19 -0500 Subject: [PATCH 075/145] Create intra/internode beleaguerment notebook --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 170 ++++++++++++++++++ conduitpylib/viz/_annotate_spearman.py | 26 ++- conduitpylib/viz/_beleaguerment_facetplot.py | 42 +++-- conduitpylib/viz/_beleaguerment_regplot.py | 51 ++++-- conduitpylib/wrangle/_diff_snapshot_states.py | 7 +- .../wrangle/_merge_inlet_outlet_data.py | 75 ++++---- .../_retrieve_and_prepare_delta_dataframes.py | 21 ++- .../wrangle/_wrangle_longitudinal_deltas.py | 4 - .../wrangle/_wrangle_snapshot_deltas.py | 7 +- 9 files changed, 325 insertions(+), 78 deletions(-) create mode 100644 binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..894ac5231f --- /dev/null +++ b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,170 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(df: pd.DataFrame) -> pd.DataFrame:\n", + " row_distiller = lambda row: {\n", + " k: v for k, v in row.items() if k in (\"Num Nodes\", \"Num Processes\")\n", + " }\n", + " df[\"Multiprocessing\"] = df.apply(\n", + " lambda row: {\n", + " frozenset(\n", + " {\"Num Nodes\": 1, \"Num Processes\": 2}.items()\n", + " ): \"Intranode\",\n", + " frozenset(\n", + " {\"Num Nodes\": 2, \"Num Processes\": 2}.items()\n", + " ): \"Internode\",\n", + " }[frozenset(row_distiller(row).items())],\n", + " axis=1,\n", + " )\n", + " return df\n", + "\n", + "\n", + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/4ys9v/download\",\n", + " df_outlet_url=\"https://osf.io/aum7w/download\",\n", + " apply=apply,\n", + " treatment_column=\"Multiprocessing\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", + "\n", + "for treatment, group in data.groupby(\"Multiprocessing\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " beleaguerment_facetplot,\n", + " data=group_df,\n", + " x=\"Messages Received Per Second\",\n", + " y=\"Messages Sent Per Second\",\n", + " hue=\"Instrumentation\",\n", + " annotation_kwargs=dict(\n", + " xy=(0.05, 0.95),\n", + " ),\n", + " scatter_kwargs=dict(\n", + " alpha=0.6,\n", + " s=30,\n", + " zorder=999,\n", + " ),\n", + " kde_kwargs=dict(\n", + " cut=10,\n", + " kde_thresh=1e-3,\n", + " ),\n", + " regline_kwargs=dict(\n", + " linewidth=6,\n", + " zorder=-9999,\n", + " ),\n", + " teeplot_outattrs={\n", + " \"treatment\": slugify(treatment),\n", + " },\n", + " )\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/conduitpylib/viz/_annotate_spearman.py b/conduitpylib/viz/_annotate_spearman.py index e816641727..21cc946f0e 100644 --- a/conduitpylib/viz/_annotate_spearman.py +++ b/conduitpylib/viz/_annotate_spearman.py @@ -19,13 +19,21 @@ def annotate_spearman(x: str, y: str, **kwargs) -> None: # Annotate the plot ax.annotate( - f"Spear Rho:\n {corr:.2f} {stars}\nn:{len(data)}\nLinReg Slope:\n {slope:.2f}", - xy=(0.05, 0.95), - xycoords="axes fraction", - ha="left", - va="top", - bbox=dict( - alpha=1.0, boxstyle="round,pad=0.5", facecolor="white", zorder=900 - ), - zorder=1000, + f"Rho: {corr:.2f} {stars} / Slope: {slope:.2f}\nn:{len(data)}", + **{ + **dict( + xy=(0.05, 0.95), + xycoords="axes fraction", + ha="left", + va="top", + bbox=dict( + alpha=1.0, + boxstyle="round,pad=0.5", + facecolor="white", + zorder=900, + ), + zorder=1000, + ), + **kwargs, + }, ) diff --git a/conduitpylib/viz/_beleaguerment_facetplot.py b/conduitpylib/viz/_beleaguerment_facetplot.py index daf92c4798..319b8060db 100644 --- a/conduitpylib/viz/_beleaguerment_facetplot.py +++ b/conduitpylib/viz/_beleaguerment_facetplot.py @@ -1,5 +1,6 @@ import typing +from frozendict import frozendict import pandas as pd import seaborn as sns @@ -14,6 +15,11 @@ def beleaguerment_facetplot( hue: typing.Optional[str] = None, hue_order: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, + annotation_kwargs: typing.Dict = frozendict(), + kde_kwargs: typing.Dict = frozendict(), + regline_kwargs: typing.Dict = frozendict(), + scatter_kwargs: typing.Dict = frozendict(), + scatter_outline_kwargs: typing.Dict = frozendict(), ) -> sns.FacetGrid: if palette is None: palette = get_default_palette() @@ -31,6 +37,8 @@ def beleaguerment_facetplot( if hue is not None: data_dummy[hue] = "dummy" + data_dummy[x] = -1 + data_dummy[y] = -1 data_with_spoof = pd.concat([data_dummy, data_real]) @@ -42,18 +50,12 @@ def beleaguerment_facetplot( hue_order=["dummy", *hue_order], sharex=True, sharey=True, - palette=["white", *palette], + palette=[(0.0, 0.0, 0.0, 0.0), *palette], height=4, ) - g.map_dataframe( - beleaguerment_regplot, - x=x, - y=y, - ) - bothax = g.axes.flat[0] - bothax.cla() + bothax.clear() sns.kdeplot( data=data, x=x, @@ -61,15 +63,31 @@ def beleaguerment_facetplot( hue=hue, hue_order=hue_order, ax=bothax, - alpha=0.7, - fill=True, - legend=True, - palette=palette, + **{ + **dict( + alpha=0.7, + cut=10, + fill=True, + legend=True, + palette=palette, + ), + **kde_kwargs, + }, ) sns.move_legend(bothax, loc="upper left") bothax.axline((0, 0), slope=1, color="black", linestyle=":", lw=2) + g.map_dataframe( + beleaguerment_regplot, + x=x, + y=y, + annotation_kwargs=annotation_kwargs, + regline_kwargs=regline_kwargs, + scatter_kwargs=scatter_kwargs, + scatter_outline_kwargs=scatter_outline_kwargs, + ) + for ax in g.axes.flat: ax.set_xlim(left=0) ax.set_ylim(bottom=0) diff --git a/conduitpylib/viz/_beleaguerment_regplot.py b/conduitpylib/viz/_beleaguerment_regplot.py index 8e27ba1875..7dfd86bf54 100644 --- a/conduitpylib/viz/_beleaguerment_regplot.py +++ b/conduitpylib/viz/_beleaguerment_regplot.py @@ -1,3 +1,6 @@ +import typing + +from frozendict import frozendict from matplotlib import axes as mpl_axes from matplotlib import patheffects as mpl_pe from matplotlib import pyplot as plt @@ -12,6 +15,10 @@ def beleaguerment_regplot( x: str = "Messages Received Per Second", y: str = "Messages Sent Per Second", ax: mpl_axes.Axes = None, + annotation_kwargs: typing.Dict = frozendict(), + regline_kwargs: typing.Dict = frozendict(), + scatter_kwargs: typing.Dict = frozendict(), + scatter_outline_kwargs: typing.Dict = frozendict(), **kwargs, ) -> mpl_axes.Axes: if ax is None: @@ -23,20 +30,24 @@ def beleaguerment_regplot( y=y, ax=ax, line_kws={ - "zorder": 100, - "lw": 3, - "ls": "--", - "path_effects": [ - mpl_pe.Stroke(linewidth=4, foreground="white"), - mpl_pe.Stroke(linewidth=2, foreground="lightsalmon"), - ], + **dict( + # zorder=100, + lw=3, + ls="--", + path_effects=[ + mpl_pe.Stroke(linewidth=4, foreground="white"), + mpl_pe.Stroke(linewidth=2, foreground="lightsalmon"), + ], + ), + **regline_kwargs, }, scatter_kws=dict( - alpha=0.1, - s=10, lw=0.5, marker="D", - **kwargs, + **{ + **scatter_kwargs, + **kwargs, + }, ), truncate=False, ) @@ -48,12 +59,18 @@ def beleaguerment_regplot( y=y, ax=ax, fill=False, - thresh=1e-6, - cut=10, - lw=0.5, - alpha=0.6, - levels=1, - **kwargs, + **{ + **dict( + thresh=1e-6, + cut=10, + lw=0.5, + alpha=0.6, + levels=1, + ), + **scatter_outline_kwargs, + }, ) - annotate_spearman(data=data, x=x, y=y, ax=ax, **kwargs) + annotate_spearman( + data=data, x=x, y=y, ax=ax, **annotation_kwargs + ) diff --git a/conduitpylib/wrangle/_diff_snapshot_states.py b/conduitpylib/wrangle/_diff_snapshot_states.py index 3adaf94836..b4806586f1 100644 --- a/conduitpylib/wrangle/_diff_snapshot_states.py +++ b/conduitpylib/wrangle/_diff_snapshot_states.py @@ -1,3 +1,5 @@ +import typing + import numpy as np import pandas as pd @@ -9,6 +11,7 @@ def diff_snapshot_states( merged_df: pd.DataFrame, max_snapshot: int, + treatment_column: typing.Optional[str] = None, ) -> pd.DataFrame: df_blurry_snapshots = merged_df[ merged_df["Has Execution Blur"].astype(bool) @@ -37,7 +40,9 @@ def diff_snapshot_states( "Num Outlets", "Execution Instance UUID", "Num Threads", - "Allocation", + *( + [treatment_column] if treatment_column is not None else [] + ), ], as_index=False, ).aggregate( diff --git a/conduitpylib/wrangle/_merge_inlet_outlet_data.py b/conduitpylib/wrangle/_merge_inlet_outlet_data.py index 04097f5ae6..3faa8b5f0b 100644 --- a/conduitpylib/wrangle/_merge_inlet_outlet_data.py +++ b/conduitpylib/wrangle/_merge_inlet_outlet_data.py @@ -23,40 +23,51 @@ def merge_inlet_outlet_data( ): df["Runtime Seconds Elapsed Inlet"] = df["Runtime Seconds Elapsed"] df["Runtime Seconds Elapsed Outlet"] = df["Runtime Seconds Elapsed"] + else: + df["Runtime Seconds Elapsed Inlet"] = df_inlet["Runtime Seconds Elapsed"] + df["Runtime Seconds Elapsed Outlet"] = df_outlet["Runtime Seconds Elapsed"] - df = df.astype( - { - "Num Inlets": "int64", - "Num Outlets": "int64", - "Num Puts Attempted": "int64", - "Num Try Puts Attempted": "int64", - "Num Blocking Puts": "int64", - "Num Try Puts That Succeeded": "int64", - "Num Puts That Succeeded Eventually": "int64", - "Num Blocking Puts That Succeeded Immediately": "int64", - "Num Puts That Succeeded Immediately": "int64", - "Num Puts That Blocked": "int64", - "Num Dropped Puts": "int64", - "Num Round Trip Touches Inlet": "int64", - "Net Flux Through Duct": "int64", - "proc": "int64", - "Snapshot": "int64", - "Has Execution Blur": "bool", - "Replicate": "int64", - "Async Mode": "int64", - "Num Threads": "int64", - "Num Processes": "int64", - "SLURM_NNODES": "int64", - "SLURM_NTASKS": "int64", - "SLURM_CPUS_ON_NODE": "int64", - } - ) - + conv = { + "Num Inlets": "int64", + "Num Outlets": "int64", + "Num Puts Attempted": "int64", + "Num Try Puts Attempted": "int64", + "Num Blocking Puts": "int64", + "Num Try Puts That Succeeded": "int64", + "Num Puts That Succeeded Eventually": "int64", + "Num Blocking Puts That Succeeded Immediately": "int64", + "Num Puts That Succeeded Immediately": "int64", + "Num Puts That Blocked": "int64", + "Num Dropped Puts": "int64", + "Num Round Trip Touches Inlet": "int64", + "Net Flux Through Duct": "int64", + "proc": "int64", + "Snapshot": "int64", + "Has Execution Blur": "bool", + "Replicate": "int64", + "Async Mode": "int64", + "Num Threads": "int64", + "Num Processes": "int64", + "SLURM_NNODES": "int64", + "SLURM_NTASKS": "int64", + "SLURM_CPUS_ON_NODE": "int64", + } + for key, value in conv.items(): + df[key] = df[key].astype(value, errors="ignore") - df["Hostname"] = df.apply( - lambda row: kn.unpack(row["Source File Inlet"])["_hostname"], - axis=1, - ) + try: + df["Hostname"] = df.apply( + lambda row: kn.unpack(row["Source File Inlet"])["_hostname"], + axis=1, + ) + except Exception: + try: + df["Hostname"] = df.apply( + lambda row: kn.unpack(row["Source File Outlet"])["_hostname"], + axis=1, + ) + except Exception: + df["Hostname"] = df["Process Instance UUID"] df["Num Nodes"] = df["SLURM_NNODES"] df["Num Tasks"] = df["SLURM_NTASKS"] diff --git a/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py index 3476c2b0a4..2224540a5f 100644 --- a/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py +++ b/conduitpylib/wrangle/_retrieve_and_prepare_delta_dataframes.py @@ -12,6 +12,7 @@ def retrieve_and_prepare_delta_dataframes( df_inlet_url: str = "https://osf.io/jgpnv/download", df_outlet_url: str = "https://osf.io/ncdfq/download", + apply: typing.Callable = lambda df: df, treatment_column: typing.Optional[str] = None, return_merge_df: bool = False, ) -> typing.Union[pd.DataFrame, typing.Tuple[pd.DataFrame, pd.DataFrame]]: @@ -27,11 +28,27 @@ def retrieve_and_prepare_delta_dataframes( ) nbm.print_dataframe_summary(*eval(nbm.nvp_expr("df_outlet"))) - merge_df = merge_inlet_outlet_data(df_inlet, df_outlet) + if df_inlet["Process Instance UUID"].isna().any(): + print( + f"""df_inlet has { + df_inlet["Process Instance UUID"].isna().sum() + } na rows, dropping them""" + ) + if df_outlet["Process Instance UUID"].isna().any(): + print( + f"""df_outlet has { + df_outlet["Process Instance UUID"].isna().sum() + } na rows, dropping them""" + ) + + df_inlet.dropna(subset=["Process Instance UUID"], inplace=True) + df_outlet.dropna(subset=["Process Instance UUID"], inplace=True) + + merge_df = apply(merge_inlet_outlet_data(df_inlet, df_outlet)) res = ( wrangle_longitudinal_deltas(merge_df), - wrangle_snapshot_deltas(merge_df), + wrangle_snapshot_deltas(merge_df, treatment_column=treatment_column), ) for df_ in res: diff --git a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py index 8674dc0051..a4eb7cc9e6 100644 --- a/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py +++ b/conduitpylib/wrangle/_wrangle_longitudinal_deltas.py @@ -24,10 +24,6 @@ def wrangle_longitudinal_deltas(merged_df: pd.DataFrame) -> pd.DataFrame: df_finalized_observations["Simstep Period Inlet (s)"] * 1e9 ) - df_finalized_observations["Allocation"] = df_finalized_observations[ - "Treatment" - ] - df_finalized_observations["Num Messages Per Pull"] = ( df_finalized_observations["Net Flux Through Duct"] / df_finalized_observations["Num Pulls Attempted"] diff --git a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py index 62304874af..b437708a00 100644 --- a/conduitpylib/wrangle/_wrangle_snapshot_deltas.py +++ b/conduitpylib/wrangle/_wrangle_snapshot_deltas.py @@ -1,3 +1,5 @@ +import typing + import numpy as np import pandas as pd @@ -10,8 +12,11 @@ def wrangle_snapshot_deltas( merged_df: pd.DataFrame, max_snapshot: int = 5, + treatment_column: typing.Optional[str] = None, ) -> pd.DataFrame: - df_snapshot_diffs = diff_snapshot_states(merged_df, max_snapshot) + df_snapshot_diffs = diff_snapshot_states( + merged_df, max_snapshot, treatment_column=treatment_column + ) df_snapshot_diffs["Fraction Messages Delivered"] = ( df_snapshot_diffs["Num Try Puts That Succeeded"] From 7e87da3b6268ee673d43d7c194633be5e48c28ea Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Fri, 10 Nov 2023 20:26:20 -0500 Subject: [PATCH 076/145] Hide regplot artifacts from summary panel --- conduitpylib/viz/_annotate_spearman.py | 5 +++++ conduitpylib/viz/_beleaguerment_facetplot.py | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_annotate_spearman.py b/conduitpylib/viz/_annotate_spearman.py index 21cc946f0e..8ff3caf15e 100644 --- a/conduitpylib/viz/_annotate_spearman.py +++ b/conduitpylib/viz/_annotate_spearman.py @@ -1,3 +1,4 @@ +import numpy as np from matplotlib import pyplot as plt from scipy import stats @@ -17,6 +18,10 @@ def annotate_spearman(x: str, y: str, **kwargs) -> None: data[x], data[y] ) + if np.isnan(corr): + assert np.isnan(slope) + return # Nop + # Annotate the plot ax.annotate( f"Rho: {corr:.2f} {stars} / Slope: {slope:.2f}\nn:{len(data)}", diff --git a/conduitpylib/viz/_beleaguerment_facetplot.py b/conduitpylib/viz/_beleaguerment_facetplot.py index 319b8060db..398a271d25 100644 --- a/conduitpylib/viz/_beleaguerment_facetplot.py +++ b/conduitpylib/viz/_beleaguerment_facetplot.py @@ -1,6 +1,7 @@ import typing from frozendict import frozendict +import numpy as np import pandas as pd import seaborn as sns @@ -37,8 +38,8 @@ def beleaguerment_facetplot( if hue is not None: data_dummy[hue] = "dummy" - data_dummy[x] = -1 - data_dummy[y] = -1 + data_dummy[x] = np.nan + data_dummy[y] = np.nan data_with_spoof = pd.concat([data_dummy, data_real]) @@ -56,6 +57,7 @@ def beleaguerment_facetplot( bothax = g.axes.flat[0] bothax.clear() + bothax.cla() sns.kdeplot( data=data, x=x, From 0a80dbc7f741341f0fd29920a58031779ac863c9 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 18:54:30 -0500 Subject: [PATCH 077/145] Fix bad column aliasing --- .../_rename_allocation.py | 12 ++++++++++++ ...417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 11 +++-------- 2 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/_rename_allocation.py diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/_rename_allocation.py b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/_rename_allocation.py new file mode 100644 index 0000000000..c107d5f157 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/_rename_allocation.py @@ -0,0 +1,12 @@ +import pandas as pd + + +def rename_allocation(df: pd.DataFrame) -> pd.DataFrame: + df = df.copy() + df["Allocation"] = df["Allocation"].map( + { + "With lac-417": "Incl. lac-417", + "Sans lac-417": "Excl. lac-417", + } + ) + return df diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index e5106f0b1a..dd8b579e14 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -43,7 +43,6 @@ "outputs": [], "source": [ "from conduitpylib.viz import _get_defaults as cfg\n", - "\n", "from conduitpylib.viz import (\n", " get_notomoji_font_path,\n", " performance_semantics_scatterplot,\n", @@ -51,6 +50,7 @@ ")\n", "\n", "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + "from _rename_allocation import rename_allocation\n" ] }, { @@ -93,7 +93,7 @@ " group_df = group.reset_index()\n", " tp.tee(\n", " performance_semantics_scatterplot,\n", - " data=group_df,\n", + " data=rename_allocation(group_df),\n", " x=\"Simstep Period Inlet (ns)\",\n", " y=\"Latency Simsteps Inlet\",\n", " legend_font_name=get_notomoji_font_path(),\n", @@ -123,12 +123,7 @@ " with pw.patched_axisgrid():\n", " facetplot = tp.tee(\n", " performance_semantics_facetplot,\n", - " data=eval(data).map(\n", - " {\n", - " \"With lac-417\": \"Incl. lac-417\",\n", - " \"Sans lac-417\": \"Excl. lac-417\",\n", - " },\n", - " ),\n", + " data=rename_allocation(eval(data)),\n", " x=\"Simstep Period Inlet (ns)\",\n", " y=\"Latency Simsteps Inlet\",\n", " hue=\"Allocation\",\n", From 8e8bc24a305f940e7c7c7e57300e2833772fcdba Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 18:59:14 -0500 Subject: [PATCH 078/145] Fixup imports --- ...c-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 10 ---------- ...c-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 1 - ...c-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 3 +-- conduitpylib/utils/__init__.py | 2 +- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 22f7e72bd7..26b74babf8 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -12,15 +12,8 @@ "from matplotlib import pyplot as plt\n", "from nbmetalog import nbmetalog as nbm\n", "import numpy as np\n", - "import pandas as pd\n", - "from scipy import stats\n", - "import seaborn as sns\n", "from slugify import slugify\n", - "import statsmodels.api as sm\n", - "import statsmodels.formula.api as smf\n", "from teeplot import teeplot as tp\n", - "import itertools as it\n", - "import matplotlib.patheffects as pe\n" ] }, { @@ -39,10 +32,7 @@ "metadata": {}, "outputs": [], "source": [ - "from conduitpylib.viz import _get_defaults as cfg\n", - "\n", "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", - "\n", "from conduitpylib.wrangle import (\n", " retrieve_and_prepare_delta_dataframes,\n", " wrangle_instrumentation_longform,\n", diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index da56e09148..01d6dd7cd2 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -44,7 +44,6 @@ " runtime_indicators_pairplot,\n", " runtime_indicators_regplot,\n", ")\n", - "\n", "from conduitpylib.wrangle import (\n", " retrieve_and_prepare_delta_dataframes,\n", " wrangle_instrumentation_longform,\n", diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index dd8b579e14..bdbc7f139d 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -48,8 +48,7 @@ " performance_semantics_scatterplot,\n", " performance_semantics_facetplot,\n", ")\n", - "\n", - "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n", "from _rename_allocation import rename_allocation\n" ] }, diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index d61cdf1644..fc46aefa5a 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -6,9 +6,9 @@ count_outliers, count_proportion_outliers, ) +from .get_signif_asterisks import get_signif_asterisks from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal -from .get_signif_asterisks import get_signif_asterisks from .round_to_multiple import round_to_multiple from .pickle_cache import pickle_cache from .seaborn_monkeypatch_kdecache import ( From d62971151288f6a4cdb318df441f8403ab17652b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:00:02 -0500 Subject: [PATCH 079/145] Bugfix: handle case where hue not provided --- conduitpylib/viz/_calc_performance_semantics_axis_lims.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py index 7d8d461652..bcb7fb22d3 100644 --- a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -44,12 +44,12 @@ def calc_performance_semantics_axis_lims( alpha=0.0, cut=10, fill=True, # needed for set_kde_lims - hue=hue, legend=False, levels=2, log_scale=(False, True), thresh=1e-12, zorder=100, + **({"hue": hue} if hue is not None else {}), ) # ensure that entire KDE is visible From dace62385509929a7be366c6a3487d2365393f65 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:00:41 -0500 Subject: [PATCH 080/145] Implement DrawBatched functor --- conduitpylib/viz/_DrawBatched.py | 54 ++++++++++++++++++++++++++++++++ conduitpylib/viz/__init__.py | 2 ++ 2 files changed, 56 insertions(+) create mode 100644 conduitpylib/viz/_DrawBatched.py diff --git a/conduitpylib/viz/_DrawBatched.py b/conduitpylib/viz/_DrawBatched.py new file mode 100644 index 0000000000..8e28325edd --- /dev/null +++ b/conduitpylib/viz/_DrawBatched.py @@ -0,0 +1,54 @@ +import typing +import sys + +from matplotlib import pyplot as plt +import more_itertools as mit +import numpy as np +import pandas as pd + + +class DrawBatched: + DataPlaceholder = object() + ZorderPlaceholder = object() + + _batches: typing.Any + _draw_func: typing.Callable + + def __init__( + self: "DrawBatched", + draw_func: typing.Callable, + data: pd.DataFrame, + batch_size: int = 1, + batch_limit: int = sys.maxsize, + mutate: bool = False, + progress_apply: typing.Callable = lambda x: x, + random_state: typing.Optional[int] = 1, + sort_by: typing.Optional[str] = None, + ) -> None: + if not mutate: + data = data.copy() + + num_batches = min(len(data) // batch_size, batch_limit) + + data = data.sample(frac=1, random_state=random_state) + if sort_by is not None: + data = data.sort_values(sort_by) + data.reset_index(drop=True, inplace=True) + + self._draw_func = draw_func + batches = np.array_split(data, num_batches) + self._batches = progress_apply(batches) + + def __call__(self: "DrawBatched", *args, **kwargs) -> typing.Any: + for i, batch in enumerate(self._batches): + def replace(obj): + return { + id(self.DataPlaceholder): batch, + id(self.ZorderPlaceholder): i, + }.get(id(obj), obj) + + kwargs_ = {key: replace(value) for key, value in kwargs.items()} + self._draw_func( + *map(replace, args), + **{"zorder": i, **kwargs_}, + ) diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index c8cf43b90c..63677bf14f 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -5,6 +5,7 @@ from ._beleaguerment_regplot import beleaguerment_regplot from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units +from ._DrawBatched import DrawBatched from ._errplot import errplot, facet_errplot from ._facet_barplot import facet_barplot from ._facet_boxplot import ( @@ -37,6 +38,7 @@ "beleaguerment_facetplot", "beleaguerment_regplot", "compact_xaxis_units", + "DrawBatched", "errplot", "facet_barplot", "facet_errplot", From fe5535b7fd0bdbfc9c44128d74839f8280cec7d8 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:02:02 -0500 Subject: [PATCH 081/145] Impl open_dymmy_axis context --- conduitpylib/utils/__init__.py | 2 ++ conduitpylib/utils/open_dummy_axis.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 conduitpylib/utils/open_dummy_axis.py diff --git a/conduitpylib/utils/__init__.py b/conduitpylib/utils/__init__.py index fc46aefa5a..3af836e9e5 100644 --- a/conduitpylib/utils/__init__.py +++ b/conduitpylib/utils/__init__.py @@ -9,6 +9,7 @@ from .get_signif_asterisks import get_signif_asterisks from .hash_with_lax_fallback import hash_with_lax_fallback from .lru_cache_universal import lru_cache_universal +from .open_dummy_axis import open_dummy_axis from .round_to_multiple import round_to_multiple from .pickle_cache import pickle_cache from .seaborn_monkeypatch_kdecache import ( @@ -30,6 +31,7 @@ 'hash_with_lax_fallback', 'lru_cache_universal', 'get_signif_asterisks', + 'open_dummy_axis', 'round_to_multiple', 'pickle_cache', 'seaborn_monkeypatch_kdecache', diff --git a/conduitpylib/utils/open_dummy_axis.py b/conduitpylib/utils/open_dummy_axis.py new file mode 100644 index 0000000000..016a7b80c0 --- /dev/null +++ b/conduitpylib/utils/open_dummy_axis.py @@ -0,0 +1,25 @@ +from contextlib import contextmanager + +from matplotlib import pyplot as plt + + +@contextmanager +def open_dummy_axis(): + # Save current figure and axis + original_fig = plt.gcf() + original_ax = plt.gca() + + dummy_fig = None + try: + # Create a new figure for the dummy axis + dummy_fig = plt.figure() + dummy_ax = dummy_fig.add_subplot(111) + + # Yield control back to the block of code using the context manager + yield dummy_ax + finally: + # Close the dummy figure and restore the original figure and axis + if dummy_fig is not None: + plt.close(dummy_fig) + plt.figure(original_fig.number) + plt.sca(original_ax) From 2d4ecd0466ea9ea06f65ec42e9c2fc9a7f4f73f9 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:06:11 -0500 Subject: [PATCH 082/145] Apply column alias incl/excl lac417 --- ...t=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 5 +++-- ...t=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 26b74babf8..287b0d3fd5 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -36,7 +36,8 @@ "from conduitpylib.wrangle import (\n", " retrieve_and_prepare_delta_dataframes,\n", " wrangle_instrumentation_longform,\n", - ")\n" + ")\n", + "from _rename_allocation import rename_allocation\n" ] }, { @@ -90,7 +91,7 @@ " group_df = group.reset_index()\n", " tp.tee(\n", " beleaguerment_facetplot,\n", - " data=group_df,\n", + " data=rename_allocation(group_df),\n", " x=\"Messages Received Per Second\",\n", " y=\"Messages Sent Per Second\",\n", " hue=\"Instrumentation\",\n", diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 01d6dd7cd2..4fba542f42 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=instrumentation+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -47,7 +47,8 @@ "from conduitpylib.wrangle import (\n", " retrieve_and_prepare_delta_dataframes,\n", " wrangle_instrumentation_longform,\n", - ")\n" + ")\n", + "from _rename_allocation import rename_allocation\n" ] }, { @@ -105,7 +106,7 @@ " group_df = group.reset_index()\n", " regplot_facetgrid = tp.tee(\n", " runtime_indicators_regplot,\n", - " data=group_df,\n", + " data=rename_allocation(group_df),\n", " compare=\"Instrumentation\",\n", " comparison_x=\"Longitudinal\",\n", " comparison_y=\"Snapshot\",\n", @@ -116,7 +117,7 @@ " )\n", " pairplot_grid = tp.tee(\n", " runtime_indicators_pairplot,\n", - " data=group_df,\n", + " data=rename_allocation(group_df),\n", " hue=\"Instrumentation\",\n", " teeplot_outattrs={\n", " \"allocation\": slugify(allocation),\n", From 387f4978f589f16c029b7ca5b4dfd2a3797806c7 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:08:31 -0500 Subject: [PATCH 083/145] Restyle beleaguerment plots --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 21 +++++- conduitpylib/viz/_beleaguerment_facetplot.py | 67 +++++++++++++++---- conduitpylib/viz/_beleaguerment_regplot.py | 61 +++++++++-------- 3 files changed, 105 insertions(+), 44 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 287b0d3fd5..8723612574 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=beleaguerment+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -14,6 +14,7 @@ "import numpy as np\n", "from slugify import slugify\n", "from teeplot import teeplot as tp\n", + "from tqdm import tqdm\n" ] }, { @@ -85,8 +86,15 @@ "data = wrangle_instrumentation_longform(\n", " longitudinal_df=longitudinal_df,\n", " snapshot_df=snapshot_df,\n", - ")\n", - "\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "for allocation, group in data.groupby(\"Allocation\"):\n", " group_df = group.reset_index()\n", " tp.tee(\n", @@ -95,10 +103,17 @@ " x=\"Messages Received Per Second\",\n", " y=\"Messages Sent Per Second\",\n", " hue=\"Instrumentation\",\n", + " rugplot_kwargs={\n", + " \"alpha\": 1.0,\n", + " \"linewidth\": 1,\n", + " \"batch_limit\": 5,\n", + " \"progress_apply\": tqdm,\n", + " },\n", " teeplot_outattrs={\n", " \"allocation\": slugify(allocation),\n", " },\n", - " )\n" + " )\n", + " plt.show()\n" ] } ], diff --git a/conduitpylib/viz/_beleaguerment_facetplot.py b/conduitpylib/viz/_beleaguerment_facetplot.py index 398a271d25..863946a90f 100644 --- a/conduitpylib/viz/_beleaguerment_facetplot.py +++ b/conduitpylib/viz/_beleaguerment_facetplot.py @@ -5,6 +5,8 @@ import pandas as pd import seaborn as sns +from ._apply_symmetric_axes import apply_symmetric_axes +from ._DrawBatched import DrawBatched from ._beleaguerment_regplot import beleaguerment_regplot from ._get_defaults import get_default_palette @@ -19,6 +21,7 @@ def beleaguerment_facetplot( annotation_kwargs: typing.Dict = frozendict(), kde_kwargs: typing.Dict = frozendict(), regline_kwargs: typing.Dict = frozendict(), + rugplot_kwargs: typing.Dict = frozendict(), scatter_kwargs: typing.Dict = frozendict(), scatter_outline_kwargs: typing.Dict = frozendict(), ) -> sns.FacetGrid: @@ -49,8 +52,8 @@ def beleaguerment_facetplot( col=hue, hue=hue, hue_order=["dummy", *hue_order], - sharex=True, - sharey=True, + sharex=False, + sharey=False, palette=[(0.0, 0.0, 0.0, 0.0), *palette], height=4, ) @@ -66,20 +69,62 @@ def beleaguerment_facetplot( hue_order=hue_order, ax=bothax, **{ - **dict( - alpha=0.7, - cut=10, - fill=True, - legend=True, - palette=palette, - ), + "alpha": 0.7, + "cut": 10, + "fill": True, + "legend": True, + "palette": palette, **kde_kwargs, }, ) + sns.rugplot( + data=data, + x=x, + y=y, + ax=bothax, + **{ + "color": "darkgray", + "linewidth": 20, + "height": 0.12, + "legend": False, + }, + ) + + batching_kwargs = { + key: rugplot_kwargs.pop(key) + for key in ( + "batch_size", + "batch_limit", + "progress_apply", + "random_state", + "sort_by", + ) + if key in rugplot_kwargs + } + DrawBatched(sns.rugplot, data, **batching_kwargs)( + data=DrawBatched.DataPlaceholder, + x=x, + y=y, + hue=hue, + hue_order=hue_order, + ax=bothax, + **{ + "linewidth": 5, + "height": 0.1, + "legend": False, + "palette": palette, + **rugplot_kwargs, + }, + ) sns.move_legend(bothax, loc="upper left") bothax.axline((0, 0), slope=1, color="black", linestyle=":", lw=2) + g.axes.flat[0].set_xlim(left=0) + g.axes.flat[0].set_ylim(bottom=0) + + map(apply_symmetric_axes, g.axes.flat) + g.map_dataframe( beleaguerment_regplot, x=x, @@ -91,9 +136,7 @@ def beleaguerment_facetplot( ) for ax in g.axes.flat: - ax.set_xlim(left=0) - ax.set_ylim(bottom=0) - ax.set_xticks(ax.get_yticks()) ax.ticklabel_format(scilimits=(-2, 2)) + ax.grid(True) return g diff --git a/conduitpylib/viz/_beleaguerment_regplot.py b/conduitpylib/viz/_beleaguerment_regplot.py index 7dfd86bf54..b7e72b97e6 100644 --- a/conduitpylib/viz/_beleaguerment_regplot.py +++ b/conduitpylib/viz/_beleaguerment_regplot.py @@ -24,6 +24,23 @@ def beleaguerment_regplot( if ax is None: ax = plt.gca() + # outline scattered points + sns.kdeplot( + data=data, + x=x, + y=y, + ax=ax, + fill=False, + **{ + "thresh": 1e-6, + "cut": 10, + "lw": 0.5, + "alpha": 0.6, + "levels": 1, + **scatter_outline_kwargs, + }, + ) + sns.regplot( data=data, x=x, @@ -41,36 +58,22 @@ def beleaguerment_regplot( ), **regline_kwargs, }, - scatter_kws=dict( - lw=0.5, - marker="D", - **{ - **scatter_kwargs, - **kwargs, - }, - ), + scatter_kws={ + "linewidth": 1, + "marker": "D", + "edgecolors": "black", + **scatter_kwargs, + **kwargs, + }, truncate=False, ) - - # outline scattered points - sns.kdeplot( - data=data, - x=x, - y=y, - ax=ax, - fill=False, - **{ - **dict( - thresh=1e-6, - cut=10, - lw=0.5, - alpha=0.6, - levels=1, - ), - **scatter_outline_kwargs, - }, + # style seaborn's regplot error band + # adapted from https://stackoverflow.com/a/48673499 + plt.setp( + ax.collections[-1], + alpha=0.2, + ec="gray", + linewidth=2, ) - annotate_spearman( - data=data, x=x, y=y, ax=ax, **annotation_kwargs - ) + annotate_spearman(data=data, x=x, y=y, ax=ax, **annotation_kwargs) From fda2f0122dc2c4db42383ad77e81ae1ce30480af Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:12:29 -0500 Subject: [PATCH 084/145] Restyle performance semantics scatter --- .../_calc_performance_semantics_axis_lims.py | 2 +- .../viz/_performance_semantics_scatterplot.py | 155 ++++++++++-------- 2 files changed, 88 insertions(+), 69 deletions(-) diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py index bcb7fb22d3..ba982e1126 100644 --- a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -62,7 +62,7 @@ def calc_performance_semantics_axis_lims( # ensure adequate lower coverage xmin = min(0, xmin) - ymin = min(0.1, ymin) + ymin = min(0.4, ymin) # make room for rugplot elements xmax *= 1.1 diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 1c6a1ff284..40f64fc96c 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -1,5 +1,6 @@ from difflib import restore import itertools as it +import sys import typing import warnings @@ -24,9 +25,11 @@ import seaborn as sns from ..utils import ( + open_dummy_axis, seaborn_monkeypatched_kdecache, ) from ._compact_xaxis_units import compact_xaxis_units +from ._DrawBatched import DrawBatched from ._get_defaults import get_default_linestyles, get_default_palette from ._set_performance_semantics_axis_lims import ( set_performance_semantics_axis_lims, @@ -43,8 +46,9 @@ def performance_semantics_scatterplot( heat_norm: typing.Optional[typing.Tuple[float, float]] = (0, 100), x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", + batch_kwargs: typing.Dict = frozendict(batch_size=sys.maxsize), background_color: typing.Optional[str] = None, - bunching_smear_alpha: float = 0.3, + bunching_smear_alpha: float = 0.2, bunching_smear_color: str = "green", title: str = "", legend: typing.Literal["hide", "only", "show"] = "show", @@ -53,6 +57,7 @@ def performance_semantics_scatterplot( legend_prop: typing.Dict = frozendict(), linestyles: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, + scatter_kwargs: typing.Dict = frozendict(), show_bunching_smear: bool = True, size_inches: typing.Tuple[float, float] = (3.5, 2.5), xlabel: typing.Optional[str] = None, @@ -118,37 +123,68 @@ def performance_semantics_scatterplot( # PLOT JOINT DISTRIBUTION ########################################################################### - # scatterplot observations - sns.scatterplot( - ax=jointgrid.ax_joint, - data=data, - x=x, - y=y, - hue=heat, - legend=False, # use dummy below instead - hue_norm=heat_norm, - alpha=0.3, - markers="D", - palette="flare", - visible=(legend != "only"), - ) - if heat is not None: - # use dummy data to force full legend representation of heat - num_legend_samples = 4 - dummy_x = jointgrid.ax_joint.get_xlim()[0] - dummy_y = jointgrid.ax_joint.get_ylim()[0] + def scatter_batch(data, zorder): + # PLOT BUNCHING SMEAR ON JOINT DISTRIBUTION + ########################################################################### + # due to unwanted side effects, must come after legend plot + smear_duration_updates = ( + data["Num Messages Per Laden Pull"] / data["Num Messages Per Pull"] + ) - 1 # noqa: fmt + if legend != "only" and show_bunching_smear: + jointgrid.ax_joint.errorbar( + data=data, + x=x, + y=y, + fmt="none", # don't draw dat points + alpha=bunching_smear_alpha, + ecolor=bunching_smear_color, + yerr=np.vstack( + [ + # below-error height + smear_duration_updates / 2, + # above-error height + smear_duration_updates / 2, + ], + ), + # doesn't work, need outer conditional + # visible=(legend != "only"), + # zorder=-5, + # legend=False, + zorder=zorder, + ) + + # PLOT P/S Scatter ON JOINT DISTRIBUTION + ####################################################################### sns.scatterplot( ax=jointgrid.ax_joint, - x=np.full(num_legend_samples, dummy_x), - y=np.full(num_legend_samples, dummy_y), - hue=np.linspace(*heat_norm, num_legend_samples, dtype=int), + data=data, + x=x, + y=y, + hue=heat, + legend=False, # use dummy below instead hue_norm=heat_norm, - alpha=0.0, - legend="full", - markers="D", - palette="flare", + **{ + "alpha": 0.4, + "markers": "D", + "palette": "flare", + "visible": (legend != "only"), + **scatter_kwargs, + }, + zorder=zorder, ) + DrawBatched( + scatter_batch, + data, + { + "sort_by": heat, + **batch_kwargs, + }, + )( + data=DrawBatched.DataPlaceholder, + zorder=DrawBatched.ZorderPlaceholder, + ) + # set up joint plot axes... # ... annotate latency simsteps inlet values jointgrid.refline(y=1, ls="-", visible=(legend != "only"), zorder=-5) @@ -269,12 +305,27 @@ def performance_semantics_scatterplot( postfix_labels.extend([" ", bunching_smear_label]) postfix_handles.extend([empty_patch, bunching_smear_handle]) - ( - handles, - labels, - ) = ( - jointgrid.ax_joint.get_legend_handles_labels() - ) # get existing handles and labels + with open_dummy_axis() as dummy_ax: + if heat is not None: + # use dummy data to force full legend representation of heat + num_legend_samples = 4 + sns.scatterplot( + ax=dummy_ax, + x=np.full(num_legend_samples, 0), + y=np.full(num_legend_samples, 0), + hue=np.linspace(*heat_norm, num_legend_samples, dtype=int), + hue_norm=heat_norm, + alpha=0.0, + legend="full", + markers="D", + palette="flare", + ) + + ( + handles, + labels, + ) = dummy_ax.get_legend_handles_labels() + if labels: first, *rest = map("{} %".format, labels) labels = [f"{first} Msgs Lost", *rest] @@ -317,7 +368,9 @@ def remove_alpha(handle, orig) -> None: handles, labels, handler_map={ - mpl_PathCollection: mpl_HandlerPathCollection(update_func=remove_alpha), + mpl_PathCollection: mpl_HandlerPathCollection( + update_func=remove_alpha + ), plt.Line2D: mpl_HandlerLine2D(update_func=remove_alpha), }, # apply helper function borderaxespad=0, @@ -345,40 +398,6 @@ def remove_alpha(handle, orig) -> None: if legend == "hide": legend_.set_visible(False) - # PLOT BUNCHING SMEAR ON JOINT DISTRIBUTION - ########################################################################### - # due to unwanted side effects, must come after legend plot - - smear_duration_updates = ( - data["Num Messages Per Laden Pull"] / data["Num Messages Per Pull"] - ) - 1 # noqa: fmt - # smear_duration_updates = np.max(smear_duration_updates, 0) - # max_latency = data["Latency Simsteps Inlet"] + smear_duration_updates / 2 - data["Latency lb"] = data["Latency Simsteps Inlet"] - (smear_duration_updates / 2) - # assert (smear_duration_updates / 2 <= data[y]).all() - if legend != "only" and show_bunching_smear: - jointgrid.ax_joint.errorbar( - data=data, - x=x, - y=y, - fmt="none", # don't draw data points - alpha=bunching_smear_alpha, - ecolor=bunching_smear_color, - yerr=np.vstack( - [ - # below-error height - # data["Latency Simsteps Inlet"] - min_latency, - smear_duration_updates / 2, - # above-error height - # max_latency - data["Latency Simsteps Inlet"], - smear_duration_updates / 2, - ], - ), - # doesn't work, need outer conditional - # visible=(legend != "only"), - zorder=-5, - ) - # FINALIZE ########################################################################### for ax in jointgrid.ax_marg_x, jointgrid.ax_marg_y: From f7794ac965288ef7328af3d39b704fd78d292e41 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:13:28 -0500 Subject: [PATCH 085/145] Add computation/communication beleaguerment nb --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 152 ++++++++++++++++++ .../wrangle/_merge_inlet_outlet_data.py | 3 + 2 files changed, 155 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..7ef8b6f092 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,152 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/k873q/download\",\n", + " df_outlet_url=\"https://osf.io/5bn96/download\",\n", + " treatment_column=\"Log Compute Work\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", + "\n", + "for treatment, group in data.groupby(\"Log Compute Work\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " beleaguerment_facetplot,\n", + " data=group_df,\n", + " x=\"Messages Received Per Second\",\n", + " y=\"Messages Sent Per Second\",\n", + " hue=\"Instrumentation\",\n", + " annotation_kwargs=dict(\n", + " xy=(0.05, 0.95),\n", + " ),\n", + " scatter_kwargs=dict(\n", + " alpha=0.6,\n", + " s=30,\n", + " zorder=999,\n", + " ),\n", + " kde_kwargs=dict(\n", + " cut=10,\n", + " kde_thresh=1e-3,\n", + " ),\n", + " regline_kwargs=dict(\n", + " linewidth=6,\n", + " zorder=-9999,\n", + " ),\n", + " teeplot_outattrs={\n", + " \"treatment\": slugify(str(treatment)),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/conduitpylib/wrangle/_merge_inlet_outlet_data.py b/conduitpylib/wrangle/_merge_inlet_outlet_data.py index 3faa8b5f0b..96e90b3532 100644 --- a/conduitpylib/wrangle/_merge_inlet_outlet_data.py +++ b/conduitpylib/wrangle/_merge_inlet_outlet_data.py @@ -105,5 +105,8 @@ def merge_inlet_outlet_data( df["Latency Simsteps Outlet"] * df["Simstep Period Outlet (s)"] ) df["Log Num Processes"] = np.log(df["Num Processes"]) / np.log(4) + df["Log Compute Work"] = ( + np.log(np.maximum(df["Amount Compute Work"], 1)) / np.log(64) + ).astype("int64") return df From 8d510aae3e3abeda50d8a618155ab9e195fb7410 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:15:48 -0500 Subject: [PATCH 086/145] Set max_line_length in editorconfig --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index c0b1f9d595..d6072f52ec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,7 @@ [*] end_of_line = lf insert_final_newline = true + max_line_length = 79 # Matches multiple files with brace expansion notation # Set default charset and tab width From 75e8612d37b1a3315699117393acf255fbe5cb9d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:17:16 -0500 Subject: [PATCH 087/145] fixup! Restyle performance semantics scatter --- ...417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index bdbc7f139d..5729a6828b 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -23,7 +23,8 @@ "from slugify import slugify\n", "import statsmodels.api as sm\n", "import statsmodels.formula.api as smf\n", - "from teeplot import teeplot as tp\n" + "from teeplot import teeplot as tp\n", + "from tqdm import tqdm\n" ] }, { @@ -95,6 +96,7 @@ " data=rename_allocation(group_df),\n", " x=\"Simstep Period Inlet (ns)\",\n", " y=\"Latency Simsteps Inlet\",\n", + " heat=\"% Msgs Lost\",\n", " legend_font_name=get_notomoji_font_path(),\n", " title=\"__{}__\".format(\n", " {\n", @@ -102,6 +104,14 @@ " \"Sans lac-417\": \"\ud83d\ude42\",\n", " }[allocation]\n", " ),\n", + " batch_kwargs={\n", + " \"batch_size\": 10,\n", + " \"progress_apply\": tqdm,\n", + " },\n", + " bunching_smear_alpha=0.2,\n", + " scatter_kwargs={\n", + " \"alpha\": 0.4,\n", + " },\n", " teeplot_outattrs={\n", " \"allocation\": slugify(allocation),\n", " \"data\": slugify(data),\n", From 647b68c5c979ea629ac970eef481ff5e003aac92 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:17:29 -0500 Subject: [PATCH 088/145] Fix whitespace --- Dockerfile | 2 +- conduitpylib/wrangle/_merge_inlet_outlet_data.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index a717af3591..0424e4246d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,7 +40,7 @@ RUN \ RUN \ apt-get update -qq \ && \ - apt-get install -y aptitude git --allow-downgrades --no-install-recommends aptitude \ + apt-get install -y aptitude git --allow-downgrades --no-install-recommends aptitude \ && \ aptitude install -y --without-recommends \ build-essential \ diff --git a/conduitpylib/wrangle/_merge_inlet_outlet_data.py b/conduitpylib/wrangle/_merge_inlet_outlet_data.py index 96e90b3532..10ce397d43 100644 --- a/conduitpylib/wrangle/_merge_inlet_outlet_data.py +++ b/conduitpylib/wrangle/_merge_inlet_outlet_data.py @@ -24,8 +24,12 @@ def merge_inlet_outlet_data( df["Runtime Seconds Elapsed Inlet"] = df["Runtime Seconds Elapsed"] df["Runtime Seconds Elapsed Outlet"] = df["Runtime Seconds Elapsed"] else: - df["Runtime Seconds Elapsed Inlet"] = df_inlet["Runtime Seconds Elapsed"] - df["Runtime Seconds Elapsed Outlet"] = df_outlet["Runtime Seconds Elapsed"] + df["Runtime Seconds Elapsed Inlet"] = df_inlet[ + "Runtime Seconds Elapsed" + ] + df["Runtime Seconds Elapsed Outlet"] = df_outlet[ + "Runtime Seconds Elapsed" + ] conv = { "Num Inlets": "int64", From 94a0ae862c46b2bf00ff9b09ebf64154aa424aaf Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 11 Nov 2023 19:17:38 -0500 Subject: [PATCH 089/145] Remove unnecessary dropna --- ...weak-scaling+compute-work=0+simels_per_cpu=1_2048+ext=.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=weak-scaling/a=weak-scaling+compute-work=0+simels_per_cpu=1_2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=weak-scaling/a=weak-scaling+compute-work=0+simels_per_cpu=1_2048+ext=.ipynb index b15be51622..b741cbe68d 100644 --- a/binder/date=2021+project=72k5n/a=weak-scaling/a=weak-scaling+compute-work=0+simels_per_cpu=1_2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=weak-scaling/a=weak-scaling+compute-work=0+simels_per_cpu=1_2048+ext=.ipynb @@ -57,8 +57,6 @@ "df_inlet = pd.read_csv(\n", " 'https://osf.io/2rdj6/download',\n", " compression='gzip',\n", - ").dropna(\n", - " subset=['Process Instance UUID'],\n", ")\n", "nbm.print_dataframe_summary(*eval(nbm.nvp_expr(\n", " 'df_inlet'\n", From 659519b706ee5a306509a2ace17d973e87b025e0 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 13 Nov 2023 18:39:13 -0500 Subject: [PATCH 090/145] Fix kwarg linewidth -> linewidths --- conduitpylib/viz/_beleaguerment_regplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_beleaguerment_regplot.py b/conduitpylib/viz/_beleaguerment_regplot.py index b7e72b97e6..f157341166 100644 --- a/conduitpylib/viz/_beleaguerment_regplot.py +++ b/conduitpylib/viz/_beleaguerment_regplot.py @@ -59,7 +59,7 @@ def beleaguerment_regplot( **regline_kwargs, }, scatter_kws={ - "linewidth": 1, + "linewidths": 1, "marker": "D", "edgecolors": "black", **scatter_kwargs, From 146ded7174ec60b7a94085de8d1b44df0cd70c17 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 13 Nov 2023 18:39:36 -0500 Subject: [PATCH 091/145] Fix missing column key error --- conduitpylib/wrangle/_merge_inlet_outlet_data.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/conduitpylib/wrangle/_merge_inlet_outlet_data.py b/conduitpylib/wrangle/_merge_inlet_outlet_data.py index 10ce397d43..e89094328c 100644 --- a/conduitpylib/wrangle/_merge_inlet_outlet_data.py +++ b/conduitpylib/wrangle/_merge_inlet_outlet_data.py @@ -108,9 +108,11 @@ def merge_inlet_outlet_data( df["Latency Walltime Outlet (s)"] = ( df["Latency Simsteps Outlet"] * df["Simstep Period Outlet (s)"] ) - df["Log Num Processes"] = np.log(df["Num Processes"]) / np.log(4) - df["Log Compute Work"] = ( - np.log(np.maximum(df["Amount Compute Work"], 1)) / np.log(64) - ).astype("int64") + if "Num Processes" in df: + df["Log Num Processes"] = np.log(df["Num Processes"]) / np.log(4) + if "Amount Compute Work" in df: + df["Log Compute Work"] = ( + np.log(np.maximum(df["Amount Compute Work"], 1)) / np.log(64) + ).astype("int64") return df From bb564bbbabd523aa7dcc2ef5d247700272706be3 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 13 Nov 2023 21:08:45 -0500 Subject: [PATCH 092/145] Bugfix: remember to unpack kwargs --- conduitpylib/viz/_performance_semantics_scatterplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 40f64fc96c..0a11ff92be 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -176,7 +176,7 @@ def scatter_batch(data, zorder): DrawBatched( scatter_batch, data, - { + **{ "sort_by": heat, **batch_kwargs, }, From 024aa8b5b3328268e9667be654ef860f83d86dfb Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 13 Nov 2023 21:52:56 -0500 Subject: [PATCH 093/145] Bugfix: prevent and handle zero batches case --- conduitpylib/viz/_DrawBatched.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_DrawBatched.py b/conduitpylib/viz/_DrawBatched.py index 8e28325edd..32a342a184 100644 --- a/conduitpylib/viz/_DrawBatched.py +++ b/conduitpylib/viz/_DrawBatched.py @@ -28,7 +28,11 @@ def __init__( if not mutate: data = data.copy() - num_batches = min(len(data) // batch_size, batch_limit) + round_up = batch_size - 1 + num_batches = (len(data) + round_up) // batch_size + num_batches = min(num_batches, batch_limit) + if num_batches == 0: + assert len(data) == 0 data = data.sample(frac=1, random_state=random_state) if sort_by is not None: @@ -36,11 +40,12 @@ def __init__( data.reset_index(drop=True, inplace=True) self._draw_func = draw_func - batches = np.array_split(data, num_batches) + batches = np.array_split(data, num_batches) if num_batches else [] self._batches = progress_apply(batches) def __call__(self: "DrawBatched", *args, **kwargs) -> typing.Any: for i, batch in enumerate(self._batches): + def replace(obj): return { id(self.DataPlaceholder): batch, From 92261e7791727e7222ed427b409416552b7f2a4d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 18:11:53 -0500 Subject: [PATCH 094/145] Add comp vs com beleaguerment nb --- ...s-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=computation-vs-communication/{a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb} (100%) diff --git a/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb similarity index 100% rename from binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb From a4dbead4d8b7945f9f8d4c73ade31f14593ebeae Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 18:40:52 -0500 Subject: [PATCH 095/145] Add thread vs proc beleaguerment nb --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..dc438e0c70 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,170 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(df: pd.DataFrame) -> pd.DataFrame:\n", + " row_distiller = lambda row: {\n", + " k: v for k, v in row.items() if k in (\"Num Threads\", \"Num Processes\")\n", + " }\n", + " df[\"Concurrency\"] = df.apply(\n", + " lambda row: {\n", + " frozenset(\n", + " {\"Num Threads\": 1, \"Num Processes\": 2}.items()\n", + " ): \"Multiprocessing\",\n", + " frozenset(\n", + " {\"Num Threads\": 2, \"Num Processes\": 1}.items()\n", + " ): \"Multithreading\",\n", + " }[frozenset(row_distiller(row).items())],\n", + " axis=1,\n", + " )\n", + " return df\n", + "\n", + "\n", + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/pe987/download\",\n", + " df_outlet_url=\"https://osf.io/vrxmq/download\",\n", + " apply=apply,\n", + " treatment_column=\"Concurrency\",\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", + "\n", + "for treatment, group in data.groupby(\"Concurrency\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " beleaguerment_facetplot,\n", + " data=group_df,\n", + " x=\"Messages Received Per Second\",\n", + " y=\"Messages Sent Per Second\",\n", + " hue=\"Instrumentation\",\n", + " annotation_kwargs=dict(\n", + " xy=(0.05, 0.95),\n", + " ),\n", + " scatter_kwargs=dict(\n", + " alpha=0.6,\n", + " s=30,\n", + " zorder=999,\n", + " ),\n", + " kde_kwargs=dict(\n", + " cut=10,\n", + " kde_thresh=1e-3,\n", + " ),\n", + " regline_kwargs=dict(\n", + " linewidth=6,\n", + " zorder=-9999,\n", + " ),\n", + " teeplot_outattrs={\n", + " \"treatment\": slugify(treatment),\n", + " },\n", + " )\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From eef03bdead26ed8235c3a91a3e9d0492c11f53b7 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 19:04:46 -0500 Subject: [PATCH 096/145] Fix copy/paste nb name --- ...-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename binder/date=2021+project=72k5n/a=computation-vs-communication/{a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=beleaguerment+what=computation-vs-communication+compute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb} (98%) diff --git a/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb similarity index 98% rename from binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb index 7ef8b6f092..c0bdf5df11 100644 --- a/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=beleaguerment+what=computation-vs-communication+compute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb @@ -121,7 +121,7 @@ " zorder=-9999,\n", " ),\n", " teeplot_outattrs={\n", - " \"treatment\": slugify(str(treatment)),\n", + " \"log-compute-work\": slugify(str(treatment)),\n", " },\n", " )\n", " plt.show()\n" From 9f85640629b58ff4df3c25c987782dbf20c098ce Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 19:48:48 -0500 Subject: [PATCH 097/145] Add weak scaling beleaguerment nb --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..fd7e4d3683 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,165 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import beleaguerment_facetplot, beleaguerment_regplot\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + " wrangle_instrumentation_longform,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal_df, snapshot_df = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/2rdj6/download\",\n", + " df_outlet_url=\"https://osf.io/9utpr/download\",\n", + " treatment_column=None,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = wrangle_instrumentation_longform(\n", + " longitudinal_df=longitudinal_df,\n", + " snapshot_df=snapshot_df,\n", + ")\n", + "treatment_variables = [\n", + " \"Cpus Per Node\",\n", + " \"Num Simels Per Cpu\",\n", + " \"Num Processes\",\n", + "]\n", + "\n", + "\n", + "for treatment, group in data.groupby(treatment_variables):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " beleaguerment_facetplot,\n", + " data=group_df,\n", + " x=\"Messages Received Per Second\",\n", + " y=\"Messages Sent Per Second\",\n", + " hue=\"Instrumentation\",\n", + " annotation_kwargs=dict(\n", + " xy=(0.05, 0.95),\n", + " ),\n", + " scatter_kwargs=dict(\n", + " alpha=0.6,\n", + " s=30,\n", + " zorder=999,\n", + " ),\n", + " kde_kwargs=dict(\n", + " cut=10,\n", + " kde_thresh=1e-3,\n", + " ),\n", + " regline_kwargs=dict(\n", + " linewidth=6,\n", + " zorder=-9999,\n", + " ),\n", + " teeplot_outattrs={\n", + " \"treatment\": slugify(\n", + " \"-\".join(\n", + " map(\n", + " \"-\".join,\n", + " zip(treatment_variables, map(str, treatment)),\n", + " ),\n", + " ),\n", + " ),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 1441e183d2e0382172e0075bb1fb5b2d59c65fa8 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:15:24 -0500 Subject: [PATCH 098/145] Fix copy/paste name --- ...de-vs-internode+compute-work=0+simels_per_cpu=1+ext=.ipynb} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename binder/date=2021+project=72k5n/a=intranode-vs-internode/{a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=1+ext=.ipynb} (98%) diff --git a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=1+ext=.ipynb similarity index 98% rename from binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=1+ext=.ipynb index 894ac5231f..2678c0e792 100644 --- a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=beleaguerment+what=intranode-vs-internode+compute-work=0+simels_per_cpu=1+ext=.ipynb @@ -161,8 +161,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.18" + "pygments_lexer": "ipython3" } }, "nbformat": 4, From 4df53707b4a561a34c1039547a046041c922a334 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:36:06 -0500 Subject: [PATCH 099/145] Bugfix: ps kdeplot should respect hue_order --- conduitpylib/viz/_performance_semantics_kdeplot.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_kdeplot.py b/conduitpylib/viz/_performance_semantics_kdeplot.py index 8a62b5cbb8..db2743a6e5 100644 --- a/conduitpylib/viz/_performance_semantics_kdeplot.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -54,7 +54,15 @@ def performance_semantics_kdeplot( assert len(palette) >= len(hue_order) - jointgrid = sns.JointGrid(data=data, x=x, y=y, hue=hue, ratio=8, height=8) + jointgrid = sns.JointGrid( + data=data, + x=x, + y=y, + hue=hue, + hue_order=hue_order, + ratio=8, + height=8, + ) sns.kdeplot( ax=jointgrid.ax_joint, @@ -65,6 +73,7 @@ def performance_semantics_kdeplot( cut=10, fill=True, hue=hue, + hue_order=hue_order, legend=False, levels=2, log_scale=(False, True), @@ -95,6 +104,7 @@ def performance_semantics_kdeplot( cut=10, fill=True, hue=hue, + hue_order=hue_order, legend=False, levels=2, log_scale=(False, True), @@ -112,6 +122,7 @@ def performance_semantics_kdeplot( cut=10, fill=False, hue=hue, + hue_order=hue_order, legend=False, levels=2, log_scale=(False, True), @@ -166,6 +177,7 @@ def performance_semantics_kdeplot( color=palette[0], data=data, hue=hue, + hue_order=hue_order, palette=palette, legend=False, alpha=0.03, From 4b7de5b22e2c91b7f223cd6893cc134c89639bee Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:36:39 -0500 Subject: [PATCH 100/145] Bugfix: use linewidth kwarg, not linewidths --- conduitpylib/viz/_performance_semantics_kdeplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_kdeplot.py b/conduitpylib/viz/_performance_semantics_kdeplot.py index db2743a6e5..fc529fbffe 100644 --- a/conduitpylib/viz/_performance_semantics_kdeplot.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -126,7 +126,7 @@ def performance_semantics_kdeplot( legend=False, levels=2, log_scale=(False, True), - linewidths=4, + linewidth=4, linestyles="solid", palette=palette, thresh=1e-12, From 805bd3eb418617a6fe8cdecc1231fa1b16199c50 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:39:03 -0500 Subject: [PATCH 101/145] Add inter/intranode psp nb --- ...compute-work=0+simels_per_cpu=1+ext=.ipynb | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb new file mode 100644 index 0000000000..de0e5e5c67 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import itertools as it\n", + "from iterdub import iterdub as ib\n", + "from iterpop import iterpop as ip\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "import matplotlib\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "import pathlib\n", + "import random\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "from tqdm import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "from conduitpylib.viz import (\n", + " get_notomoji_font_path,\n", + " performance_semantics_scatterplot,\n", + " performance_semantics_facetplot,\n", + ")\n", + "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(df: pd.DataFrame) -> pd.DataFrame:\n", + " row_distiller = lambda row: {\n", + " k: v for k, v in row.items() if k in (\"Num Nodes\", \"Num Processes\")\n", + " }\n", + " df[\"Multiprocessing\"] = df.apply(\n", + " lambda row: {\n", + " frozenset(\n", + " {\"Num Nodes\": 1, \"Num Processes\": 2}.items()\n", + " ): \"Intranode\",\n", + " frozenset(\n", + " {\"Num Nodes\": 2, \"Num Processes\": 2}.items()\n", + " ): \"Internode\",\n", + " }[frozenset(row_distiller(row).items())],\n", + " axis=1,\n", + " )\n", + " return df\n", + "\n", + "\n", + "longitudinal, snapshot = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/4ys9v/download\",\n", + " df_outlet_url=\"https://osf.io/aum7w/download\",\n", + " apply=apply,\n", + " treatment_column=\"Multiprocessing\",\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " for allocation, group in eval(data).groupby(\"Multiprocessing\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " performance_semantics_scatterplot,\n", + " data=group_df,\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " heat=\"% Msgs Lost\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"__{}__\".format(\n", + " {\n", + " \"Intranode\": \"\u2681\",\n", + " \"Internode\": \"\u2680\u2680\",\n", + " }[allocation]\n", + " ),\n", + " batch_kwargs={\n", + " \"batch_size\": 10,\n", + " \"progress_apply\": tqdm,\n", + " },\n", + " bunching_smear_alpha=0.2,\n", + " scatter_kwargs={\n", + " \"alpha\": 0.4,\n", + " },\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " plt.clf()\n", + " group_df = group.reset_index()\n", + " with pw.patched_axisgrid():\n", + " facetplot = tp.tee(\n", + " performance_semantics_facetplot,\n", + " data=eval(data),\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " hue=\"Multiprocessing\",\n", + " hue_order=[\"Intranode\", \"Internode\"],\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"\u2680\u2680/\u2681\",\n", + " teeplot_outattrs={\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " display(facetplot)\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 4fcbf4a46388293395e47294f24fe3e710b6e66d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:40:40 -0500 Subject: [PATCH 102/145] Fix copy/paste nb name --- ...vs-multiprocessing+compute-work=0+simels_per_cpu=1+ext=.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/{a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=1+ext=.ipynb} (100%) diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=1+ext=.ipynb similarity index 100% rename from binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=beleaguerment+what=multithreading-vs-multiprocessing+compute-work=0+simels_per_cpu=1+ext=.ipynb From 605757f988375a33914666872d2111ab625ce219 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 20:47:43 -0500 Subject: [PATCH 103/145] Add multithread/proc psp notebook --- ...compute-work=0+simels_per_cpu=1+ext=.ipynb | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb new file mode 100644 index 0000000000..c4a24d7084 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import itertools as it\n", + "from iterdub import iterdub as ib\n", + "from iterpop import iterpop as ip\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "import matplotlib\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "import pathlib\n", + "import random\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "from tqdm import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "from conduitpylib.viz import (\n", + " get_notomoji_font_path,\n", + " performance_semantics_scatterplot,\n", + " performance_semantics_facetplot,\n", + ")\n", + "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(df: pd.DataFrame) -> pd.DataFrame:\n", + " row_distiller = lambda row: {\n", + " k: v for k, v in row.items() if k in (\"Num Threads\", \"Num Processes\")\n", + " }\n", + " df[\"Concurrency\"] = df.apply(\n", + " lambda row: {\n", + " frozenset(\n", + " {\"Num Threads\": 1, \"Num Processes\": 2}.items()\n", + " ): \"Multiprocessing\",\n", + " frozenset(\n", + " {\"Num Threads\": 2, \"Num Processes\": 1}.items()\n", + " ): \"Multithreading\",\n", + " }[frozenset(row_distiller(row).items())],\n", + " axis=1,\n", + " )\n", + " return df\n", + "\n", + "\n", + "longitudinal, snapshot = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/pe987/download\",\n", + " df_outlet_url=\"https://osf.io/vrxmq/download\",\n", + " apply=apply,\n", + " treatment_column=\"Concurrency\",\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " for allocation, group in eval(data).groupby(\"Concurrency\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " performance_semantics_scatterplot,\n", + " data=group_df,\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " heat=\"% Msgs Lost\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"__{}__\".format(\n", + " {\n", + " \"Multithreading\": \"\ud83e\udea1\",\n", + " \"Multiprocessing\": \"\u2699\ufe0f\",\n", + " }[allocation]\n", + " ),\n", + " batch_kwargs={\n", + " \"batch_size\": 10,\n", + " \"progress_apply\": tqdm,\n", + " },\n", + " bunching_smear_alpha=0.2,\n", + " scatter_kwargs={\n", + " \"alpha\": 0.4,\n", + " },\n", + " teeplot_outattrs={\n", + " \"allocation\": slugify(allocation),\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " plt.clf()\n", + " group_df = group.reset_index()\n", + " with pw.patched_axisgrid():\n", + " facetplot = tp.tee(\n", + " performance_semantics_facetplot,\n", + " data=eval(data),\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " hue=\"Concurrency\",\n", + " hue_order=[\"Multithreading\", \"Multiprocessing\"],\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"\ud83e\udea1/\u2699\ufe0f\",\n", + " teeplot_outattrs={\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " display(facetplot)\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 5c03186947ca0f5095d70e459e23fea02735c8b3 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 22:53:56 -0500 Subject: [PATCH 104/145] Handle orders of magnitude % 3 != 0 --- conduitpylib/viz/_compact_xaxis_units.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_compact_xaxis_units.py b/conduitpylib/viz/_compact_xaxis_units.py index 04e0f2b695..bcdfe4b198 100644 --- a/conduitpylib/viz/_compact_xaxis_units.py +++ b/conduitpylib/viz/_compact_xaxis_units.py @@ -83,10 +83,13 @@ def compact_xaxis_units( # calculate new prefix from net multiplier new_multiplier = offset_amount * old_multiplier - approx_pow = np.log10(new_multiplier) + approx_pow = round_to_multiple(np.log10(new_multiplier), multiple=1) new_multiplier_pow = round_to_multiple(approx_pow, multiple=3) - assert np.isclose(approx_pow, new_multiplier_pow) + leftover_pow = approx_pow - new_multiplier_pow + new_prefix = _si_prefixes.inv[new_multiplier_pow] + if leftover_pow: + new_prefix = f"10^{leftover_pow}" + new_prefix ax.xaxis.get_offset_text().set(visible=False) # remove offset axis scale old_prefix_span = old_prefix_match.span(1) From 5a26b1e4e56a65da4c6e60110ba1bedc4638c579 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 22:54:49 -0500 Subject: [PATCH 105/145] Add fourth entry to style carousel --- conduitpylib/viz/_get_defaults.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_get_defaults.py b/conduitpylib/viz/_get_defaults.py index 4f9cd1245e..b0793cca71 100644 --- a/conduitpylib/viz/_get_defaults.py +++ b/conduitpylib/viz/_get_defaults.py @@ -2,7 +2,7 @@ def get_default_linestyles() -> typing.List[str]: - return [":", "--", "-"] + return [":", "--", "-", "-."] def get_default_palette() -> typing.List[str]: @@ -10,7 +10,12 @@ def get_default_palette() -> typing.List[str]: # ["#648FFF", "#40B0A6"] or ["#40b07f", "#646eff"] # return ["#5c5cff", "#64e0ff", "#40B0A6"] # return ["#91f7ff", "#ff82d4", "#91aaff"] - return ['#9467bd', '#bcbd22', '#17becf'] # purple, gold, teal + return [ + "#9467bd", + "#bcbd22", + "#17becf", + "#59a14f", + ] # purple, gold, teal, green def get_default_runtime_indicators() -> typing.List[str]: From bd5767fdd08efda432206b581599e116fb44126a Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 22:57:16 -0500 Subject: [PATCH 106/145] Fix style handling in perf semantics plots --- conduitpylib/viz/_performance_semantics_kdeplot.py | 12 ++++++------ .../viz/_performance_semantics_scatterplot.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_kdeplot.py b/conduitpylib/viz/_performance_semantics_kdeplot.py index fc529fbffe..ebdffaaa38 100644 --- a/conduitpylib/viz/_performance_semantics_kdeplot.py +++ b/conduitpylib/viz/_performance_semantics_kdeplot.py @@ -21,6 +21,7 @@ from ..utils import seaborn_monkeypatched_kdecache from ._compact_xaxis_units import compact_xaxis_units from ._frame_scatter_subsets import frame_scatter_subsets +from . import _get_defaults as cfg from ._set_performance_semantics_axis_lims import ( set_performance_semantics_axis_lims, ) @@ -46,11 +47,10 @@ def performance_semantics_kdeplot( hue_order = sorted(data[hue].unique()) if linestyles is None: - linestyles = [":", "--"] + linestyles = cfg.get_default_linestyles() if palette is None: - # alternate palettes: ["#648FFF", "#40B0A6"] & ["#40b07f", "#646eff"] - palette = ["#5c5cff", "#64e0ff"] + palette = cfg.get_default_palette() assert len(palette) >= len(hue_order) @@ -86,7 +86,7 @@ def performance_semantics_kdeplot( # adapted from https://stackoverflow.com/a/70089200 for path_collection, linestyle in zip( jointgrid.ax_joint.collections, - reversed(linestyles), + linestyles, ): # need faux fill for set_kde_lims. set color = path_collection.get_facecolor() @@ -161,8 +161,8 @@ def performance_semantics_kdeplot( # set linestyles of marginal KDE outlines # https://stackoverflow.com/a/70089200 for line, linestyle in it.chain( - zip(jointgrid.ax_marg_x.collections, linestyles), - zip(jointgrid.ax_marg_y.collections, linestyles), + zip(reversed(jointgrid.ax_marg_x.collections), linestyles), + zip(reversed(jointgrid.ax_marg_y.collections), linestyles), ): line.set_linestyle(linestyle) line.set_alpha(0.4) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 0a11ff92be..41f6fbed46 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -112,7 +112,7 @@ def performance_semantics_scatterplot( # adapted from https://stackoverflow.com/a/70089200 for path_collection, linestyle in zip( jointgrid.ax_joint.collections, - it.cycle(reversed(linestyles)), + it.cycle(linestyles), ): # need faux fill for set_kde_lims. set color = path_collection.get_facecolor() @@ -260,7 +260,7 @@ def scatter_batch(data, zorder): # prefix_handles.append(empty_patch) # prefix_labels.append(hue) # ... then add legend entries manually - for ls, color, label in zip(reversed(linestyles), palette, hue_order): + for ls, color, label in zip(linestyles, palette, hue_order): example_patch = mpl_patches.Patch( facecolor=color, linestyle=ls, From 26aa12d998096fb3278d73e94caa34ba6024d489 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 22:58:58 -0500 Subject: [PATCH 107/145] Style code --- conduitpylib/viz/_performance_semantics_facetplot.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_facetplot.py b/conduitpylib/viz/_performance_semantics_facetplot.py index e1604638b9..4987076021 100644 --- a/conduitpylib/viz/_performance_semantics_facetplot.py +++ b/conduitpylib/viz/_performance_semantics_facetplot.py @@ -7,7 +7,7 @@ import pandas as pd import patchworklib as pw -from. _calc_performance_semantics_axis_lims import ( +from ._calc_performance_semantics_axis_lims import ( calc_performance_semantics_axis_lims, ) from ._get_defaults import get_default_linestyles, get_default_palette @@ -20,18 +20,17 @@ @patch.dict(pw.param, {"margin": 0.0}) def performance_semantics_facetplot( data: pd.DataFrame, - x: str="Simstep Period Inlet (ns)", - y: str="Latency Simsteps Inlet", + x: str = "Simstep Period Inlet (ns)", + y: str = "Latency Simsteps Inlet", hue: typing.Optional[str] = None, hue_order: typing.Optional[typing.List[str]] = None, title: str = "", brick_size_graphs: typing.Tuple[float, float] = (0.51, 0.5), brick_size_legend: typing.Tuple[float, float] = (0.68, 1.2), legend_font_name: typing.Optional[str] = None, - palette: typing.Optional[typing.List[str]] = None, linestyles: typing.Optional[typing.List[str]] = None, + palette: typing.Optional[typing.List[str]] = None, ) -> pw.Brick: - if hue is not None: if hue_order is None: hue_order = sorted(data[hue].unique()) From bf7d9636cbef20e2d810383b7b2c4841a4b9704b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 23:05:25 -0500 Subject: [PATCH 108/145] Take and forward subplot kwargs --- .../viz/_performance_semantics_facetplot.py | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_facetplot.py b/conduitpylib/viz/_performance_semantics_facetplot.py index 4987076021..ae4858cde6 100644 --- a/conduitpylib/viz/_performance_semantics_facetplot.py +++ b/conduitpylib/viz/_performance_semantics_facetplot.py @@ -4,6 +4,7 @@ from unittest.mock import patch import warnings +from frozendict import frozendict import pandas as pd import patchworklib as pw @@ -27,9 +28,11 @@ def performance_semantics_facetplot( title: str = "", brick_size_graphs: typing.Tuple[float, float] = (0.51, 0.5), brick_size_legend: typing.Tuple[float, float] = (0.68, 1.2), + kde_kwargs: typing.Dict = frozendict(), legend_font_name: typing.Optional[str] = None, linestyles: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, + scatter_kwargs: typing.Dict = frozendict(), ) -> pw.Brick: if hue is not None: if hue_order is None: @@ -59,7 +62,8 @@ def performance_semantics_facetplot( y=y, hue=hue, ) - + xlim = (xmin, xmax) + ylim = (ymin, ymax) fig_legend = performance_semantics_scatterplot( data=data, @@ -72,34 +76,42 @@ def performance_semantics_facetplot( linestyles=linestyles, palette=palette, title=title, - xlim=(xmin, xmax), - ylim=(ymin, ymax), + xlim=xlim, + ylim=ylim, ) brick_legend = pw.load_seaborngrid(fig_legend, figsize=brick_size_legend) fig_kde = performance_semantics_kdeplot( - data=data, - x=x, - y=y, - hue=hue, - hue_order=hue_order, - palette=palette[:2], - xlim=(xmin, xmax), - ylim=(ymin, ymax), + **{ + "data": data, + "x": x, + "y": y, + "hue": hue, + "hue_order": hue_order, + "palette": palette, + "xlim": xlim, + "ylim": ylim, + **kde_kwargs, + }, ) brick_kde = pw.load_seaborngrid(fig_kde, figsize=brick_size_graphs) fig_scatterplots = [ performance_semantics_scatterplot( - data=data[data[hue] == hue_order[i]], - hue=None, - background_color=palette[i], - legend="hide", - linestyles=linestyles[i:], - palette=palette[i:], - xlim=(xmin, xmax), - ylabel="", - ylim=(ymin, ymax), + **{ + "data": data[data[hue] == hue_order[i]], + "x": x, + "y": y, + "hue": None, + "background_color": palette[i], + "legend": "hide", + "linestyles": linestyles[i:], + "palette": palette[i:], + "xlim": xlim, + "ylabel": "", + "ylim": ylim, + **scatter_kwargs, + }, ) for i in range(len(hue_order)) ] From 54b7bd293cebc0ee4940674737e5679783b50ffb Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 23:05:47 -0500 Subject: [PATCH 109/145] Add option to disable shared x/y axis scales --- conduitpylib/viz/_performance_semantics_facetplot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conduitpylib/viz/_performance_semantics_facetplot.py b/conduitpylib/viz/_performance_semantics_facetplot.py index ae4858cde6..ccf1d3d82f 100644 --- a/conduitpylib/viz/_performance_semantics_facetplot.py +++ b/conduitpylib/viz/_performance_semantics_facetplot.py @@ -33,6 +33,7 @@ def performance_semantics_facetplot( linestyles: typing.Optional[typing.List[str]] = None, palette: typing.Optional[typing.List[str]] = None, scatter_kwargs: typing.Dict = frozendict(), + sharexy: bool = True, ) -> pw.Brick: if hue is not None: if hue_order is None: @@ -62,8 +63,8 @@ def performance_semantics_facetplot( y=y, hue=hue, ) - xlim = (xmin, xmax) - ylim = (ymin, ymax) + xlim = (xmin, xmax) if sharexy else None + ylim = (ymin, ymax) if sharexy else None fig_legend = performance_semantics_scatterplot( data=data, From 17a9da4887934060bcc01d5e3ed0a9a44cd51a49 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 23:09:43 -0500 Subject: [PATCH 110/145] Fork clean notebook operations for speedup --- binder/clear_notebooks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/clear_notebooks.sh b/binder/clear_notebooks.sh index f83722ff1e..763d18030c 100755 --- a/binder/clear_notebooks.sh +++ b/binder/clear_notebooks.sh @@ -90,7 +90,7 @@ echo "-------------------------" shopt -s nullglob for script in "${script_dir}/"*/clear_notebooks.sh; do - "${script}" + "${script}" & done shopt -u nullglob From 091e5e95543e5c379dcd11cdb805632bf8a85ce2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sat, 18 Nov 2023 23:10:33 -0500 Subject: [PATCH 111/145] Add comp vs comm ps plot notebook --- ...62144_16777216+simels_per_cpu=1+ext=.ipynb | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=computation-vs-communication/a=performance_semantics+what=comp-vs-commcompute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=computation-vs-communication/a=performance_semantics+what=comp-vs-commcompute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=performance_semantics+what=comp-vs-commcompute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb new file mode 100644 index 0000000000..6a72ef2a54 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=computation-vs-communication/a=performance_semantics+what=comp-vs-commcompute-work=0_64_4096_262144_16777216+simels_per_cpu=1+ext=.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import itertools as it\n", + "from iterdub import iterdub as ib\n", + "from iterpop import iterpop as ip\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "import matplotlib\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "import pathlib\n", + "import random\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "from tqdm import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "from conduitpylib.viz import (\n", + " get_notomoji_font_path,\n", + " performance_semantics_scatterplot,\n", + " performance_semantics_facetplot,\n", + ")\n", + "from conduitpylib.wrangle import retrieve_and_prepare_delta_dataframes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def apply(df: pd.DataFrame) -> pd.DataFrame:\n", + " df = df[\n", + " df[\"Log Compute Work\"] <= 3\n", + " ].copy()\n", + "\n", + " return df\n", + "\n", + "longitudinal, snapshot = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/k873q/download\",\n", + " df_outlet_url=\"https://osf.io/5bn96/download\",\n", + " treatment_column=\"Log Compute Work\",\n", + " apply=apply,\n", + ")\n", + "\n", + "longitudinal[\"Log Simstep Period Inlet (ns)\"] = np.log10(\n", + " longitudinal[\"Simstep Period Inlet (ns)\"]\n", + ")\n", + "snapshot[\"Log Simstep Period Inlet (ns)\"] = np.log10(\n", + " snapshot[\"Simstep Period Inlet (ns)\"]\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " for work, group in eval(data).groupby(\"Log Compute Work\"):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " performance_semantics_scatterplot,\n", + " data=group_df,\n", + " x=\"Log Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " heat=\"% Msgs Lost\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=\"{}\u2716\ufe0f\ud83e\uddee\".format(work),\n", + " batch_kwargs={\n", + " \"batch_size\": 10,\n", + " \"progress_apply\": tqdm,\n", + " },\n", + " bunching_smear_alpha=0.2,\n", + " scatter_kwargs={\n", + " \"alpha\": 0.4,\n", + " },\n", + " teeplot_outattrs={\n", + " \"work\": slugify(str(work)),\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for data in \"longitudinal\", \"snapshot\":\n", + " plt.clf()\n", + " with pw.patched_axisgrid():\n", + " facetplot = tp.tee(\n", + " performance_semantics_facetplot,\n", + " data=eval(data),\n", + " x=\"Log Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " hue=\"Log Compute Work\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " scatter_kwargs={\n", + " \"x\": \"Simstep Period Inlet (ns)\",\n", + " },\n", + " sharexy=False,\n", + " title=\"\ud83e\uddee/\ud83d\udcec\",\n", + " teeplot_outattrs={\n", + " \"data\": slugify(data),\n", + " },\n", + " )\n", + " display(facetplot)\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From f5100fbfde904023dabf5ee945afd3099799d042 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 19 Nov 2023 00:02:19 -0500 Subject: [PATCH 112/145] Add weak scaling performance semantics nb --- ...pute-work=0+simels_per_cpu=2048+ext=.ipynb | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb diff --git a/binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb new file mode 100644 index 0000000000..1ddfcd0fb2 --- /dev/null +++ b/binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "\n", + "from keyname import keyname as kn\n", + "from matplotlib import pyplot as plt\n", + "from nbmetalog import nbmetalog as nbm\n", + "import numpy as np\n", + "import pandas as pd\n", + "import patchworklib as pw\n", + "from scipy import stats\n", + "import seaborn as sns\n", + "from slugify import slugify\n", + "import statsmodels.api as sm\n", + "import statsmodels.formula.api as smf\n", + "from teeplot import teeplot as tp\n", + "import itertools as it\n", + "import matplotlib.patheffects as pe\n", + "from tqdm import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.random.seed(1)\n", + "random.seed(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from conduitpylib.viz import _get_defaults as cfg\n", + "\n", + "from conduitpylib.viz import (\n", + " get_notomoji_font_path,\n", + " performance_semantics_scatterplot,\n", + " performance_semantics_facetplot,\n", + ")\n", + "\n", + "from conduitpylib.wrangle import (\n", + " retrieve_and_prepare_delta_dataframes,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nbm.print_metadata()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get Data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "longitudinal, snapshot = retrieve_and_prepare_delta_dataframes(\n", + " df_inlet_url=\"https://osf.io/2rdj6/download\",\n", + " df_outlet_url=\"https://osf.io/9utpr/download\",\n", + " treatment_column=None,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Compare Finalized and Rolling Measures\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "treatment_variables = [\n", + " \"Cpus Per Node\",\n", + " \"Num Simels Per Cpu\",\n", + " \"Num Processes\",\n", + "]\n", + "\n", + "for data in \"longitudinal\", \"snapshot\":\n", + " for treatment, group in eval(data).groupby(treatment_variables):\n", + " group_df = group.reset_index()\n", + " tp.tee(\n", + " performance_semantics_scatterplot,\n", + " data=group_df,\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " heat=\"% Msgs Lost\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " title=(\n", + " \"\ud83d\udcf6\"\n", + " + \"{}\".format(\"\u2610\u2680\u2681\u2682\u2683\u2684\u2685\"[treatment[0]])\n", + " + (\"\ud83c\udfe0\" if treatment[1] == 1 else \"\ud83c\udfd8\ufe0f\")\n", + " ),\n", + " batch_kwargs={\n", + " \"batch_size\": 10,\n", + " \"progress_apply\": tqdm,\n", + " },\n", + " bunching_smear_alpha=0.2,\n", + " scatter_kwargs={\n", + " \"alpha\": 0.4,\n", + " },\n", + " teeplot_outattrs={\n", + " \"treatment\": slugify(\n", + " \"-\".join(\n", + " map(\n", + " \"-\".join,\n", + " zip(treatment_variables, map(str, treatment)),\n", + " ),\n", + " ),\n", + " ),\n", + " },\n", + " )\n", + " plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "treatment_variables = [\n", + " \"Cpus Per Node\",\n", + " \"Num Simels Per Cpu\",\n", + "]\n", + "\n", + "for data in \"longitudinal\", \"snapshot\":\n", + " for treatment, group in eval(data).groupby(treatment_variables):\n", + " group_df = group.reset_index()\n", + " plt.clf()\n", + " with pw.patched_axisgrid():\n", + " facetplot = tp.tee(\n", + " performance_semantics_facetplot,\n", + " data=eval(data),\n", + " x=\"Simstep Period Inlet (ns)\",\n", + " y=\"Latency Simsteps Inlet\",\n", + " hue=\"Log Num Processes\",\n", + " legend_font_name=get_notomoji_font_path(),\n", + " scatter_kwargs={\n", + " \"x\": \"Simstep Period Inlet (ns)\",\n", + " },\n", + " sharexy=True,\n", + " title=(\n", + " \"\ud83d\udcf6\"\n", + " + \"{}\".format(\"\u2610\u2680\u2681\u2682\u2683\u2684\u2685\"[treatment[0]])\n", + " + (\"\ud83c\udfe0\" if treatment[1] == 1 else \"\ud83c\udfd8\ufe0f\")\n", + " ),\n", + " teeplot_outattrs={\n", + " \"data\": slugify(data),\n", + " \"treatment\": slugify(\n", + " \"-\".join(\n", + " map(\n", + " \"-\".join,\n", + " zip(treatment_variables, map(str, treatment)),\n", + " ),\n", + " ),\n", + " ),\n", + " },\n", + " )\n", + " display(facetplot)\n", + " plt.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 6ab85719538fd26cd1cc5549ea75fdbf63861520 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 19 Nov 2023 00:02:51 -0500 Subject: [PATCH 113/145] Remove unused copy/paste cruft --- ...at=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb | 1 - ...s+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb | 1 - ...s+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb | 2 -- 3 files changed, 4 deletions(-) diff --git a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb index de0e5e5c67..8ccd0bb180 100644 --- a/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=intranode-vs-internode/a=performance_semantics+what=interintranode+compute-work=0+simels_per_cpu=1+ext=.ipynb @@ -146,7 +146,6 @@ "source": [ "for data in \"longitudinal\", \"snapshot\":\n", " plt.clf()\n", - " group_df = group.reset_index()\n", " with pw.patched_axisgrid():\n", " facetplot = tp.tee(\n", " performance_semantics_facetplot,\n", diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb index c4a24d7084..b3e13c7290 100644 --- a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb @@ -146,7 +146,6 @@ "source": [ "for data in \"longitudinal\", \"snapshot\":\n", " plt.clf()\n", - " group_df = group.reset_index()\n", " with pw.patched_axisgrid():\n", " facetplot = tp.tee(\n", " performance_semantics_facetplot,\n", diff --git a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb index 5729a6828b..72eb811b9f 100644 --- a/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb +++ b/binder/date=2021+project=72k5n/a=with-lac-417-vs-sans-lac-417/a=performance_semantics+what=lac-417+compute-work=0+simels_per_cpu=2048+ext=.ipynb @@ -128,7 +128,6 @@ "source": [ "for data in \"longitudinal\", \"snapshot\":\n", " plt.clf()\n", - " group_df = group.reset_index()\n", " with pw.patched_axisgrid():\n", " facetplot = tp.tee(\n", " performance_semantics_facetplot,\n", @@ -139,7 +138,6 @@ " legend_font_name=get_notomoji_font_path(),\n", " title=\"\ud83d\ude42/\ud83e\udd15\",\n", " teeplot_outattrs={\n", - " \"allocation\": slugify(allocation),\n", " \"data\": slugify(data),\n", " },\n", " )\n", From ba4b0c19741e44ea87e1deff4ac5abee1c49a36b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 19 Nov 2023 02:01:13 -0500 Subject: [PATCH 114/145] Alphabetize kwargs --- conduitpylib/viz/_performance_semantics_scatterplot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 41f6fbed46..788f7796d3 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -50,7 +50,6 @@ def performance_semantics_scatterplot( background_color: typing.Optional[str] = None, bunching_smear_alpha: float = 0.2, bunching_smear_color: str = "green", - title: str = "", legend: typing.Literal["hide", "only", "show"] = "show", legend_contents_pad: bool = False, legend_font_name: typing.Optional[str] = None, @@ -60,6 +59,7 @@ def performance_semantics_scatterplot( scatter_kwargs: typing.Dict = frozendict(), show_bunching_smear: bool = True, size_inches: typing.Tuple[float, float] = (3.5, 2.5), + title: str = "", xlabel: typing.Optional[str] = None, xlim: typing.Optional[typing.Tuple[float, float]] = None, ylabel: typing.Optional[str] = None, From 54ae9d9e41a5ba2a8805ea699992ebe5164681ed Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Sun, 19 Nov 2023 18:57:14 -0500 Subject: [PATCH 115/145] Exclude outliers and mark on axis edges --- conduitpylib/viz/__init__.py | 2 + .../_calc_performance_semantics_axis_lims.py | 7 +- conduitpylib/viz/_draw_edge_markers.py | 136 ++++++++++++++++++ .../viz/_performance_semantics_scatterplot.py | 7 + .../_set_performance_semantics_axis_lims.py | 3 +- 5 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 conduitpylib/viz/_draw_edge_markers.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 63677bf14f..9a55c26227 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -5,6 +5,7 @@ from ._beleaguerment_regplot import beleaguerment_regplot from ._beleaguerment_facetplot import beleaguerment_facetplot from ._compact_xaxis_units import compact_xaxis_units +from ._draw_edge_markers import draw_edge_markers from ._DrawBatched import DrawBatched from ._errplot import errplot, facet_errplot from ._facet_barplot import facet_barplot @@ -38,6 +39,7 @@ "beleaguerment_facetplot", "beleaguerment_regplot", "compact_xaxis_units", + "draw_edge_markers", "DrawBatched", "errplot", "facet_barplot", diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py index ba982e1126..f2f41bb4ff 100644 --- a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -31,14 +31,17 @@ def calc_performance_semantics_axis_lims( x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", hue: typing.Optional[str] = None, + outlier_percentile_x: float = 99.0, ) -> typing.Tuple[float, float, float, float]: - dummy_fig = plt.figure() dummy_ax = dummy_fig.add_subplot(111) + percentile99x = np.percentile(data[x], outlier_percentile_x) + outlier_thresh = percentile99x * 2 + sns.kdeplot( ax=dummy_ax, - data=data, + data=data[data[x] < outlier_thresh], x=x, y=y, alpha=0.0, diff --git a/conduitpylib/viz/_draw_edge_markers.py b/conduitpylib/viz/_draw_edge_markers.py new file mode 100644 index 0000000000..616a8761f6 --- /dev/null +++ b/conduitpylib/viz/_draw_edge_markers.py @@ -0,0 +1,136 @@ +import operator +import typing + +from frozendict import frozendict + +from matplotlib.axes import Axes as mpl_Axes +from matplotlib.collections import PathCollection as mpl_PathCollection + + +def draw_edge_marker( + ax: mpl_Axes, + x: float, + y: float, + annotation_kwargs: typing.Dict, + marker_kwargs: typing.Dict, + offset: float = 0.10, +) -> mpl_Axes: + """ + Draw an edge marker for a single point if it's out of bounds. + + Parameters + ---------- + ax : matplotlib.axes.Axes + The axes object to draw markers on. + x, y : float + The x and y coordinates of the point. + """ + xlim, ylim = ax.get_xlim(), ax.get_ylim() + edge_x, edge_y, marker, annotation = x, y, None, "" + ha, va, xytext = "left", "center", (5, 0) # default alignment and offset + + xwidth = -operator.__sub__(*xlim) + ywidth = -operator.__sub__(*ylim) + xoff = xwidth * offset + yoff = ywidth * offset + if x < xlim[0]: + amount = int((xlim[0] - x) / xwidth) + backslash = "\\" + edge_x, marker, annotation, ha = ( + xlim[0] - xoff, + f"$◅{backslash * amount}$", + f"{x:.0f}", + "right", + ) + elif x > xlim[1]: + amount = int((x - xlim[1]) / xwidth) + edge_x, marker, annotation, ha = ( + xlim[1] + xoff, + rf"$| \!\! \leftrightarrow \!\!|{{\times}}{amount}\rangle\!\rangle\!\rangle$", + f"{x:.0f}", + "left", + ) + + if y < ylim[0]: + edge_y, marker, annotation, va, xytext = ( + ylim[0] - yoff, + "^", + f"{y:.2f}" if not annotation else f"({annotation}, {y:.2f})", + "bottom", + (0, 5), + ) + elif y > ylim[1]: + edge_y, marker, annotation, va, xytext = ( + ylim[1] + yoff, + "v", + f"{y:.2f}" if not annotation else f"({annotation}, {y:.2f})", + "top", + (0, -5), + ) + + if marker: + ax.plot( + edge_x, + edge_y, + **{ + "color": "none", + "clip_on": False, + "linewidth": 1, + "color": "red", + "marker": marker, + "markersize": 20, + "markeredgewidth": 0.5, + "zorder": 10000, + **marker_kwargs, + }, + ) + ax.annotate( + annotation, + (edge_x, edge_y), + **{ + "ha": ha, + "va": va, + "textcoords": "offset points", + "xytext": xytext, + **annotation_kwargs, + }, + ) + + return edge_x, edge_y + + +def draw_edge_markers( + ax: mpl_Axes, + annotation_kwargs: typing.Dict = frozendict(), + marker_kwargs: typing.Dict = frozendict(), + offset: float = 0.10, +) -> mpl_Axes: + """ + Draw edge markers for points lying outside the plot's bounds. + + Parameters + ---------- + ax : matplotlib.axes.Axes + The axes object to draw markers on. + """ + xlim, ylim = ax.get_xlim(), ax.get_ylim() + + for collection in ax.collections: + if isinstance(collection, mpl_PathCollection): + # Extract points from the line + points = list(collection.get_offsets()) + + new_offsets = [] + for x, y in points: + # Draw edge marker if the point is out of bounds + if x < xlim[0] or x > xlim[1] or y < ylim[0] or y > ylim[1]: + x_, y_ = draw_edge_marker( + ax, + x, + y, + annotation_kwargs=annotation_kwargs, + marker_kwargs=marker_kwargs, + offset=offset, + ) + else: + new_offsets.append((x, y)) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 788f7796d3..4925e61dff 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -29,6 +29,7 @@ seaborn_monkeypatched_kdecache, ) from ._compact_xaxis_units import compact_xaxis_units +from ._draw_edge_markers import draw_edge_markers from ._DrawBatched import DrawBatched from ._get_defaults import get_default_linestyles, get_default_palette from ._set_performance_semantics_axis_lims import ( @@ -50,11 +51,13 @@ def performance_semantics_scatterplot( background_color: typing.Optional[str] = None, bunching_smear_alpha: float = 0.2, bunching_smear_color: str = "green", + edge_marker_kwargs: typing.Dict = frozendict(), legend: typing.Literal["hide", "only", "show"] = "show", legend_contents_pad: bool = False, legend_font_name: typing.Optional[str] = None, legend_prop: typing.Dict = frozendict(), linestyles: typing.Optional[typing.List[str]] = None, + outlier_percentile_x: float = 99.0, palette: typing.Optional[typing.List[str]] = None, scatter_kwargs: typing.Dict = frozendict(), show_bunching_smear: bool = True, @@ -403,6 +406,7 @@ def remove_alpha(handle, orig) -> None: for ax in jointgrid.ax_marg_x, jointgrid.ax_marg_y: ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) + ax.patch.set_alpha(0.0) set_performance_semantics_axis_lims( ax=jointgrid.ax_joint, @@ -410,12 +414,15 @@ def remove_alpha(handle, orig) -> None: x=x, y=y, hue=hue, + outlier_percentile_x=outlier_percentile_x, ) if xlim is not None: jointgrid.ax_joint.set_xlim(xlim) if ylim is not None: jointgrid.ax_joint.set_ylim(ylim) + draw_edge_markers(jointgrid.ax_joint, **edge_marker_kwargs) + if xlabel is not None: jointgrid.ax_joint.set_xlabel(xlabel) if ylabel is not None: diff --git a/conduitpylib/viz/_set_performance_semantics_axis_lims.py b/conduitpylib/viz/_set_performance_semantics_axis_lims.py index 1570c6d7a5..8c3dd2cc80 100644 --- a/conduitpylib/viz/_set_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_set_performance_semantics_axis_lims.py @@ -14,13 +14,14 @@ def set_performance_semantics_axis_lims( x: str = "Simstep Period Inlet (ns)", y: str = "Latency Simsteps Inlet", hue: typing.Optional[str] = None, + **kwargs, ) -> None: - xmin, xmax, ymin, ymax = calc_performance_semantics_axis_lims( data=data, x=x, y=y, hue=hue, + **kwargs, ) ax.set_xlim(left=xmin, right=xmax) ax.set_ylim(bottom=ymin, top=ymax) From e53ffad871e213498321d2d59bffc86358c17c3b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 20 Nov 2023 00:38:07 -0500 Subject: [PATCH 116/145] Improve off-axis outlier annotation --- conduitpylib/viz/__init__.py | 2 + conduitpylib/viz/_align_marker.py | 70 +++++++++++++ .../_calc_performance_semantics_axis_lims.py | 2 +- conduitpylib/viz/_draw_edge_markers.py | 99 ++++++++++--------- .../viz/_performance_semantics_scatterplot.py | 9 ++ 5 files changed, 135 insertions(+), 47 deletions(-) create mode 100644 conduitpylib/viz/_align_marker.py diff --git a/conduitpylib/viz/__init__.py b/conduitpylib/viz/__init__.py index 9a55c26227..f0ecf63b5a 100644 --- a/conduitpylib/viz/__init__.py +++ b/conduitpylib/viz/__init__.py @@ -1,5 +1,6 @@ """Visualization tools.""" +from ._align_marker import align_marker from ._annotate_spearman import annotate_spearman from ._apply_symmetric_axes import apply_symmetric_axes from ._beleaguerment_regplot import beleaguerment_regplot @@ -34,6 +35,7 @@ # adapted from https://stackoverflow.com/a/31079085 __all__ = [ + "align_marker", "apply_symmetric_axes", "annotate_spearman", "beleaguerment_facetplot", diff --git a/conduitpylib/viz/_align_marker.py b/conduitpylib/viz/_align_marker.py new file mode 100644 index 0000000000..ce43ea22cd --- /dev/null +++ b/conduitpylib/viz/_align_marker.py @@ -0,0 +1,70 @@ +import typing + +from matplotlib import markers as mpl_markers +from matplotlib.path import Path as mpl_Path + + +# adapted from https://stackoverflow.com/a/26726237 +def align_marker( + marker: str, + halign: typing.Literal["left", "center", "right"] = "center", + valign: typing.Literal["top", "middle", "bottom"] = "middle", + pad: float = 1.0, +) -> mpl_Path: + """Create markers with specified alignment. + + Parameters + ---------- + marker : a valid marker specification. + See mpl.markers + halign : string, float {'left', 'center', 'right'} + Specifies the horizontal alignment of the marker. *float* values + specify the alignment in units of the markersize/2 (0 is 'center', + -1 is 'right', 1 is 'left'). + valign : string, float {'top', 'middle', 'bottom'} + Specifies the vertical alignment of the marker. *float* values + specify the alignment in units of the markersize/2 (0 is 'middle', + -1 is 'top', 1 is 'bottom'). + + Returns + ------- + marker_array : numpy.ndarray + A Nx2 array that specifies the marker path relative to the + plot target point at (0, 0). + + Notes + ----- + The mark_array can be passed directly to ax.plot and ax.scatter, e.g.:: + + ax.plot(1, 1, marker=align_marker('>', 'left')) + """ + + if isinstance(halign, str): + halign = { + "right": -pad, + "middle": 0.0, + "center": 0.0, + "left": pad, + }[halign] + + if isinstance(valign, str): + valign = { + "top": -pad, + "middle": 0.0, + "center": 0.0, + "bottom": pad, + }[valign] + + # Define the base marker + bm = mpl_markers.MarkerStyle(marker) + + # Get the marker path and apply the marker transform to get the + # actual marker vertices (they should all be in a unit-square + # centered at (0, 0)) + m_arr = bm.get_path().transformed(bm.get_transform()).vertices + + # Shift the marker vertices for the specified alignment. + m_arr[:, 0] += halign / 2 + m_arr[:, 1] += valign / 2 + + return mpl_Path(m_arr, bm.get_path().codes) diff --git a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py index f2f41bb4ff..5d55bcc2fd 100644 --- a/conduitpylib/viz/_calc_performance_semantics_axis_lims.py +++ b/conduitpylib/viz/_calc_performance_semantics_axis_lims.py @@ -68,7 +68,7 @@ def calc_performance_semantics_axis_lims( ymin = min(0.4, ymin) # make room for rugplot elements - xmax *= 1.1 + xmax *= 1.3 ymax *= 3 return xmin, xmax, ymin, ymax diff --git a/conduitpylib/viz/_draw_edge_markers.py b/conduitpylib/viz/_draw_edge_markers.py index 616a8761f6..a8cd71993f 100644 --- a/conduitpylib/viz/_draw_edge_markers.py +++ b/conduitpylib/viz/_draw_edge_markers.py @@ -2,9 +2,13 @@ import typing from frozendict import frozendict +import numpy as np from matplotlib.axes import Axes as mpl_Axes from matplotlib.collections import PathCollection as mpl_PathCollection +from matplotlib.container import ErrorbarContainer as mpl_ErrorbarContainer + +from ._align_marker import align_marker def draw_edge_marker( @@ -26,8 +30,7 @@ def draw_edge_marker( The x and y coordinates of the point. """ xlim, ylim = ax.get_xlim(), ax.get_ylim() - edge_x, edge_y, marker, annotation = x, y, None, "" - ha, va, xytext = "left", "center", (5, 0) # default alignment and offset + edge_x, edge_y, markers = x, y, list() xwidth = -operator.__sub__(*xlim) ywidth = -operator.__sub__(*ylim) @@ -36,39 +39,23 @@ def draw_edge_marker( if x < xlim[0]: amount = int((xlim[0] - x) / xwidth) backslash = "\\" - edge_x, marker, annotation, ha = ( - xlim[0] - xoff, - f"$◅{backslash * amount}$", - f"{x:.0f}", - "right", - ) + edge_x = xlim[0] - xoff + markers.append(f"$◅{backslash * amount}$") elif x > xlim[1]: amount = int((x - xlim[1]) / xwidth) - edge_x, marker, annotation, ha = ( - xlim[1] + xoff, - rf"$| \!\! \leftrightarrow \!\!|{{\times}}{amount}\rangle\!\rangle\!\rangle$", - f"{x:.0f}", - "left", - ) + m = rf"$| \!\! \leftrightarrow \!\!|{{\times}}{amount}\rangle\!\rangle\!\rangle$" + edge_x = xlim[1] + xoff + # markers.append(align_marker(m, halign="left")) + markers.append(align_marker(m, halign="right", pad=1.3)) if y < ylim[0]: - edge_y, marker, annotation, va, xytext = ( - ylim[0] - yoff, - "^", - f"{y:.2f}" if not annotation else f"({annotation}, {y:.2f})", - "bottom", - (0, 5), - ) + edge_y = ylim[0] - yoff + markers.append("^") elif y > ylim[1]: - edge_y, marker, annotation, va, xytext = ( - ylim[1] + yoff, - "v", - f"{y:.2f}" if not annotation else f"({annotation}, {y:.2f})", - "top", - (0, -5), - ) + edge_y = ylim[1] + yoff + markers.append("v") - if marker: + for marker in markers: ax.plot( edge_x, edge_y, @@ -84,17 +71,6 @@ def draw_edge_marker( **marker_kwargs, }, ) - ax.annotate( - annotation, - (edge_x, edge_y), - **{ - "ha": ha, - "va": va, - "textcoords": "offset points", - "xytext": xytext, - **annotation_kwargs, - }, - ) return edge_x, edge_y @@ -118,13 +94,11 @@ def draw_edge_markers( for collection in ax.collections: if isinstance(collection, mpl_PathCollection): # Extract points from the line - points = list(collection.get_offsets()) - new_offsets = [] - for x, y in points: + for x, y in collection.get_offsets(): # Draw edge marker if the point is out of bounds if x < xlim[0] or x > xlim[1] or y < ylim[0] or y > ylim[1]: - x_, y_ = draw_edge_marker( + x, y = draw_edge_marker( ax, x, y, @@ -132,5 +106,38 @@ def draw_edge_markers( marker_kwargs=marker_kwargs, offset=offset, ) - else: - new_offsets.append((x, y)) + new_offsets.append((x, y)) + + collection.set_offsets(new_offsets) + collection.set(clip_on=False) + + x_width = -operator.__sub__(*xlim) + x_thresh = xlim[1] + x_offset = x_thresh + x_width * offset + for container in ax.containers: + if isinstance(container, mpl_ErrorbarContainer): + # Unpack the container + ( + plotline, # Line2D instance of x, y plot markers and/or line + caplines, # A tuple of Line2D instances of the error bar caps + # A tuple of LineCollection with the horizontal and vertical + # error ranges. + barlinecols, + ) = container + + # Adjust each error bar + for barlinecol in barlinecols: + segments = barlinecol.get_segments() + new_segments = [] + for segment in segments: + (x0, y0), (x1, y1) = segment + if x0 > x_thresh: + assert x0 == x1 + x0, x1 = x_offset, x_offset + print(f"{x0=}, {x1=}") + print(f"{y0=}, {y1=}") + new_segment = [(x0, y0), (x1, y1)] + new_segments.append(new_segment) + + barlinecol.set_segments(new_segments) + barlinecol.set(clip_on=False) diff --git a/conduitpylib/viz/_performance_semantics_scatterplot.py b/conduitpylib/viz/_performance_semantics_scatterplot.py index 4925e61dff..fb6f53b7be 100644 --- a/conduitpylib/viz/_performance_semantics_scatterplot.py +++ b/conduitpylib/viz/_performance_semantics_scatterplot.py @@ -1,3 +1,4 @@ +import contextlib from difflib import restore import itertools as it import sys @@ -452,6 +453,14 @@ def remove_alpha(handle, orig) -> None: which="both", ) + with contextlib.suppress(AttributeError): + jointgrid.ax_joint.ticklabel_format( + axis="x", style="sci", scilimits=(-2, 3) + ) + with contextlib.suppress(AttributeError): + jointgrid.ax_joint.ticklabel_format( + axis="y", style="sci", scilimits=(-2, 3) + ) compact_xaxis_units(ax=jointgrid.ax_joint, base_unit="s") if legend == "only": From b66b956965e400a4822f41eeb28d689084314532 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Mon, 20 Nov 2023 00:39:29 -0500 Subject: [PATCH 117/145] Add marker helper (not currently used) --- conduitpylib/viz/_build_quasiroman_arrow.py | 22 +++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 conduitpylib/viz/_build_quasiroman_arrow.py diff --git a/conduitpylib/viz/_build_quasiroman_arrow.py b/conduitpylib/viz/_build_quasiroman_arrow.py new file mode 100644 index 0000000000..924baf36aa --- /dev/null +++ b/conduitpylib/viz/_build_quasiroman_arrow.py @@ -0,0 +1,22 @@ +def build_quasiroman_arrow(n: int) -> str: + # Simple Roman numeral conversion using only I, V, and X + roman_parts = [] + num = n + roman_parts.extend(["M"] * (num // 1000)) # Add 'X' for each multiple of 10 + num %= 1000 + roman_parts.extend(["D"] * (num // 500)) # Add 'X' for each multiple of 10 + num %= 500 + roman_parts.extend(["C"] * (num // 100)) # Add 'X' for each multiple of 10 + num %= 100 + roman_parts.extend(["L"] * (num // 50)) # Add 'X' for each multiple of 10 + num %= 50 + roman_parts.extend(["X"] * (num // 10)) # Add 'X' for each multiple of 10 + num %= 10 + roman_parts.extend(["V"] * (num // 5)) # Add 'V' for each multiple of 5 + num %= 5 + roman_parts.extend([r"/"] * num) # Add 'I' for the remainder + + # Join with " \! " to form the arrow-like structure + res = "$" + r" \! ".join(roman_parts) + r" \! $-$\!\!\guilsinglright$" + print(n, res) + return res From 87ea1eff89e518bdc262b9000e9c3cf682a35ae1 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 15:49:30 +0000 Subject: [PATCH 118/145] Set higher keyname chop threshold --- binder/execute_notebooks.sh | 2 ++ third-party/requirements.in | 2 +- third-party/requirements.txt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 07cb95ff9e..89758aafcb 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -28,6 +28,8 @@ echo "--------------------------------------" ################################################################################ shopt -s nullglob +export KEYNAME_CHOP_CHUNK_SIZE=255 +echo "KEYNAME_CHOP_CHUNK_SIZE ${KEYNAME_CHOP_CHUNK_SIZE}" for notebook in "${script_dir}/"*.ipynb; do echo "notebook ${notebook}" diff --git a/third-party/requirements.in b/third-party/requirements.in index 1764e8c509..9428903489 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -1,5 +1,5 @@ git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient -keyname==0.5.3 +keyname==0.5.4 numpy==1.23.5 pandas==1.1.2 frozendict==1.2 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index 777000a63d..da1a9dba06 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -78,7 +78,7 @@ jupyter_client==6.1.12 # via # -r requirements.in # ipykernel -keyname==0.5.3 +keyname==0.5.4 # via # -r requirements.in # nbmetalog From c1217d01fae6e9e28450d8cda1d41bb7865a3770 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 15:49:51 +0000 Subject: [PATCH 119/145] Disable notebook causing timeout --- ...t=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=weak-scaling/{a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_} (100%) diff --git a/binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_ similarity index 100% rename from binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=weak-scaling/a=beleaguerment+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_ From 845266bd204bcb326ce6dba86b140cf019673a7d Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:09:54 +0000 Subject: [PATCH 120/145] Bump keyname version for bugfix --- third-party/requirements.in | 2 +- third-party/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index 9428903489..fbaa3576c1 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -1,5 +1,5 @@ git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient -keyname==0.5.4 +keyname==0.5.5 numpy==1.23.5 pandas==1.1.2 frozendict==1.2 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index da1a9dba06..6c296fe73b 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -78,7 +78,7 @@ jupyter_client==6.1.12 # via # -r requirements.in # ipykernel -keyname==0.5.4 +keyname==0.5.5 # via # -r requirements.in # nbmetalog From c9c9eac4e769727184eb6387729d2bf292ea4094 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:20:11 +0000 Subject: [PATCH 121/145] Try parallelizing the notebook job with larger runner --- .github/workflows/CI.yml | 4 +++- binder/execute_notebooks.sh | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7fd26a81d6..752738e842 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,7 +44,9 @@ jobs: binder: name: Notebooks - runs-on: ubuntu-20.04 + runs-on: + group: ubuntu-runners + labels: ubuntu-20.04-16core needs: - docker-build container: diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 89758aafcb..34417542e8 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -38,7 +38,7 @@ for notebook in "${script_dir}/"*.ipynb; do jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ - "${notebook}" + "${notebook}" & done shopt -u nullglob @@ -52,7 +52,9 @@ echo "-------------------------" shopt -s nullglob for script in "${script_dir}/"*/execute_notebooks.sh; do - "${script}" "$@" + "${script}" "$@" & done shopt -u nullglob + +wait From c01f8351f637d0bec196c004dcea9d235fbf7c55 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:24:28 +0000 Subject: [PATCH 122/145] Pin notebook container to skip build-per-commit --- .github/workflows/CI.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 752738e842..b125193f69 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -47,10 +47,8 @@ jobs: runs-on: group: ubuntu-runners labels: ubuntu-20.04-16core - needs: - - docker-build container: - image: mmore500/conduit:GITHUB_ACTION_${{ github.run_number }} + image: mmore500/conduit:GITHUB_ACTION_684 # github actions requires root to access mounted volumes options: --user root steps: From 3878d1f14008f6ca822c8e8d8e57d9fd479bb4e0 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:33:33 +0000 Subject: [PATCH 123/145] Revert "Try parallelizing the notebook job with larger runner" This reverts commit 8559cffcf787cdb8a247a82453e7114de738c917. --- .github/workflows/CI.yml | 6 +++--- binder/execute_notebooks.sh | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b125193f69..0fc5bd7b46 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,9 +44,9 @@ jobs: binder: name: Notebooks - runs-on: - group: ubuntu-runners - labels: ubuntu-20.04-16core + runs-on: ubuntu-20.04 + needs: + - docker-build container: image: mmore500/conduit:GITHUB_ACTION_684 # github actions requires root to access mounted volumes diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 34417542e8..89758aafcb 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -38,7 +38,7 @@ for notebook in "${script_dir}/"*.ipynb; do jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ - "${notebook}" & + "${notebook}" done shopt -u nullglob @@ -52,9 +52,7 @@ echo "-------------------------" shopt -s nullglob for script in "${script_dir}/"*/execute_notebooks.sh; do - "${script}" "$@" & + "${script}" "$@" done shopt -u nullglob - -wait From 025c28ca326265c03dd49d8ba7d486b42de0767a Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:20:11 +0000 Subject: [PATCH 124/145] Try parallelizing the notebook job with larger runner --- .github/workflows/CI.yml | 4 +++- binder/execute_notebooks.sh | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 0fc5bd7b46..94a0c956cd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,7 +44,9 @@ jobs: binder: name: Notebooks - runs-on: ubuntu-20.04 + runs-on: + group: ubuntu-runners + labels: ubuntu-20.04-16core needs: - docker-build container: diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 89758aafcb..34417542e8 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -38,7 +38,7 @@ for notebook in "${script_dir}/"*.ipynb; do jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ - "${notebook}" + "${notebook}" & done shopt -u nullglob @@ -52,7 +52,9 @@ echo "-------------------------" shopt -s nullglob for script in "${script_dir}/"*/execute_notebooks.sh; do - "${script}" "$@" + "${script}" "$@" & done shopt -u nullglob + +wait From 7d2897aab6bdececd454614bf02d898fa51d9c56 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:24:28 +0000 Subject: [PATCH 125/145] Pin notebook container to skip build-per-commit --- .github/workflows/CI.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 94a0c956cd..b125193f69 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -47,8 +47,6 @@ jobs: runs-on: group: ubuntu-runners labels: ubuntu-20.04-16core - needs: - - docker-build container: image: mmore500/conduit:GITHUB_ACTION_684 # github actions requires root to access mounted volumes From d8149b7fca21a4b7be5f1c1d0cf7648241eb7a80 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:33:33 +0000 Subject: [PATCH 126/145] Revert "Try parallelizing the notebook job with larger runner" This reverts commit 8559cffcf787cdb8a247a82453e7114de738c917. --- .github/workflows/CI.yml | 6 +++--- binder/execute_notebooks.sh | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b125193f69..0fc5bd7b46 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,9 +44,9 @@ jobs: binder: name: Notebooks - runs-on: - group: ubuntu-runners - labels: ubuntu-20.04-16core + runs-on: ubuntu-20.04 + needs: + - docker-build container: image: mmore500/conduit:GITHUB_ACTION_684 # github actions requires root to access mounted volumes diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 34417542e8..89758aafcb 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -38,7 +38,7 @@ for notebook in "${script_dir}/"*.ipynb; do jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ - "${notebook}" & + "${notebook}" done shopt -u nullglob @@ -52,9 +52,7 @@ echo "-------------------------" shopt -s nullglob for script in "${script_dir}/"*/execute_notebooks.sh; do - "${script}" "$@" & + "${script}" "$@" done shopt -u nullglob - -wait From 16ae1f36ae17472f66888c75c444c9d102ccbf7f Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:40:35 +0000 Subject: [PATCH 127/145] Use non-recursive approach to parallelize nb execution --- binder/execute_notebooks.sh | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 89758aafcb..9331cce835 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -31,28 +31,17 @@ shopt -s nullglob export KEYNAME_CHOP_CHUNK_SIZE=255 echo "KEYNAME_CHOP_CHUNK_SIZE ${KEYNAME_CHOP_CHUNK_SIZE}" -for notebook in "${script_dir}/"*.ipynb; do - echo "notebook ${notebook}" - export NOTEBOOK_NAME="$(basename "${notebook%.*}")" - export NOTEBOOK_PATH="$(realpath "${notebook}")" +# Find all .ipynb files and use xargs to run nbconvert in parallel, within the directory of each notebook +find "${script_dir}/" -maxdepth 1 -name "*.ipynb" -print0 | xargs -0 -n 1 -P 2 -I {} bash -c '{ + notebook="{}" + notebook_dir=$(dirname "$notebook") + notebook_base=$(basename "$notebook") + echo "Processing notebook ${notebook_base} in directory ${notebook_dir}" + cd "${notebook_dir}" jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ - "${notebook}" -done - -shopt -u nullglob - -################################################################################ -echo -echo "recurse to subdirectories" -echo "-------------------------" -################################################################################ - -shopt -s nullglob - -for script in "${script_dir}/"*/execute_notebooks.sh; do - "${script}" "$@" -done + "$notebook_base" +}' shopt -u nullglob From ff77899b4e07861e6f47a6bbac309b518ca9cc29 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:48:30 +0000 Subject: [PATCH 128/145] Don't use source inside container, clone it instead --- .github/workflows/CI.yml | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 0fc5bd7b46..14b37a09b7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -52,28 +52,18 @@ jobs: # github actions requires root to access mounted volumes options: --user root steps: + - uses: actions/checkout@v2 + # with: + # submodules: 'recursive' + - run: python3 -m pip install -r requirements.txt # Adapted from https://askubuntu.com/a/524368 - - run: cd /opt/conduit/binder && ./execute_notebooks.sh - - run: git config --global --add safe.directory /__w/conduit/conduit - - run: git init - - uses: fregante/setup-git-user@v1 - - run: git commit --allow-empty -m "Initial commit" - - run: cp -r /opt/conduit/ deploy/ + - run: cd binder && ./execute_notebooks.sh + # adapted from https://unix.stackexchange.com/a/545630 + - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; - uses: JamesIves/github-pages-deploy-action@4.0.0 with: + folder: . branch: binder # The branch the action should deploy to. - folder: deploy # The folder the action should deploy. - - run: mkdir -p deploy-artifacts/ - - run: cp -r /opt/conduit/binder/. deploy-artifacts/binder/ - # adapted from https://unix.stackexchange.com/a/107647 - - run: find deploy-artifacts/binder/ -type f ! \( -name '*.csv' -o -name '*.png' -o -name '*.jpg' -o -name '*.pdf' -o -name '*.json' -o -name '*.meta' -o -name '*.txt' -o -name '*.out' -o -name '*.ipynb' \) -delete - # delete symlinks (Overleaf is not compatible with symlinks) - # adapted from https://superuser.com/a/586948 - - run: find deploy-artifacts/binder -type l -delete - - uses: JamesIves/github-pages-deploy-action@4.0.0 - with: - branch: binder-artifacts # The branch the action should deploy to. - folder: deploy-artifacts # The folder the action should deploy. unit: name: Unit Tests From 1ddf836479daaa613689c2038e9d739ccb390d6e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 11:50:37 -0500 Subject: [PATCH 129/145] Drop build dependency --- .github/workflows/CI.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 14b37a09b7..eea5815df5 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -45,8 +45,6 @@ jobs: binder: name: Notebooks runs-on: ubuntu-20.04 - needs: - - docker-build container: image: mmore500/conduit:GITHUB_ACTION_684 # github actions requires root to access mounted volumes From c4f6e6a747af7c5a78376435665f531ee47ec1ae Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 11:53:28 -0500 Subject: [PATCH 130/145] Remove broken pip install --- .github/workflows/CI.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index eea5815df5..3b9722a99a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -53,7 +53,6 @@ jobs: - uses: actions/checkout@v2 # with: # submodules: 'recursive' - - run: python3 -m pip install -r requirements.txt # Adapted from https://askubuntu.com/a/524368 - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 From 1aad5aebdbb2e5a44bdc1f37496dbede6332277e Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 16:57:37 +0000 Subject: [PATCH 131/145] Fix execute notebook nb discovery recursion --- binder/execute_notebooks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 9331cce835..9ccfee9392 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -32,7 +32,7 @@ export KEYNAME_CHOP_CHUNK_SIZE=255 echo "KEYNAME_CHOP_CHUNK_SIZE ${KEYNAME_CHOP_CHUNK_SIZE}" # Find all .ipynb files and use xargs to run nbconvert in parallel, within the directory of each notebook -find "${script_dir}/" -maxdepth 1 -name "*.ipynb" -print0 | xargs -0 -n 1 -P 2 -I {} bash -c '{ +find "${script_dir}/" -name "*.ipynb" -print0 | xargs -0 -n 1 -P 2 -I {} bash -c '{ notebook="{}" notebook_dir=$(dirname "$notebook") notebook_base=$(basename "$notebook") From a2f6d94a257a7111c1169b360b83395df78428b5 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:05:07 +0000 Subject: [PATCH 132/145] Disable broken notebook --- ...s+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/{a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb => a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_} (100%) diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_ similarity index 100% rename from binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb rename to binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_ From bf84201b553f88cf8620d4c3412496ae6e40ae12 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:09:19 +0000 Subject: [PATCH 133/145] Try staying in root directory --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3b9722a99a..d7bcf6b4be 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -54,7 +54,7 @@ jobs: # with: # submodules: 'recursive' # Adapted from https://askubuntu.com/a/524368 - - run: cd binder && ./execute_notebooks.sh + # - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; - uses: JamesIves/github-pages-deploy-action@4.0.0 From f45602267869dc5bda24cbfdd88971b01fbbbef1 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:11:08 +0000 Subject: [PATCH 134/145] Run git repo/user setup on deploy --- .github/workflows/CI.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index d7bcf6b4be..c4da27bda7 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,6 +57,9 @@ jobs: # - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; + - run: git init + - uses: fregante/setup-git-user@v1 + - run: git commit --allow-empty -m "Initial commit" - uses: JamesIves/github-pages-deploy-action@4.0.0 with: folder: . From 2098679832764170b8bdc809e0dec6a65066ab31 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:15:34 +0000 Subject: [PATCH 135/145] Fix safe directory exception --- .github/workflows/CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c4da27bda7..055d2caf1f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,6 +57,7 @@ jobs: # - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; + - run: git config --global --add safe.directory / - run: git init - uses: fregante/setup-git-user@v1 - run: git commit --allow-empty -m "Initial commit" From 90b22f1a8cd75d60862669d20e25d357c4b283ce Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:19:26 +0000 Subject: [PATCH 136/145] Bugfix: mark current directory safe for git --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 055d2caf1f..bc93175799 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,7 +57,7 @@ jobs: # - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; - - run: git config --global --add safe.directory / + - run: git config --global --add safe.directory . - run: git init - uses: fregante/setup-git-user@v1 - run: git commit --allow-empty -m "Initial commit" From b64d24b7c3c2f62e4c8525f9099f1b309e01ea47 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:29:27 +0000 Subject: [PATCH 137/145] Try setting safe directory to glob --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index bc93175799..016d5a9ff0 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,7 +57,7 @@ jobs: # - run: cd binder && ./execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; - - run: git config --global --add safe.directory . + - run: git config --global --add safe.directory "*" - run: git init - uses: fregante/setup-git-user@v1 - run: git commit --allow-empty -m "Initial commit" From 548e2845ca16d4737b992858b340036e0bbd3e88 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:31:34 +0000 Subject: [PATCH 138/145] Re-enable notebook evaluation --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 016d5a9ff0..ddb3d5a97c 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -54,7 +54,7 @@ jobs: # with: # submodules: 'recursive' # Adapted from https://askubuntu.com/a/524368 - # - run: cd binder && ./execute_notebooks.sh + - run: ./binder/execute_notebooks.sh # adapted from https://unix.stackexchange.com/a/545630 - run: find -type f -name "*.pdf" -exec bash -c 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dBATCH -dQUIET -sOutputFile="new.pdf" "{}"; rm "{}"; mv "new.pdf" "{}";' {} \; - run: git config --global --add safe.directory "*" From 2b483884ccd8642698dd96fea24c5576a48ae657 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 12:37:39 -0500 Subject: [PATCH 139/145] Try setting KEYNAME_CHOP_CHUNK_SIZE inside eval job --- binder/execute_notebooks.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/binder/execute_notebooks.sh b/binder/execute_notebooks.sh index 9ccfee9392..4d6f67937b 100755 --- a/binder/execute_notebooks.sh +++ b/binder/execute_notebooks.sh @@ -28,8 +28,6 @@ echo "--------------------------------------" ################################################################################ shopt -s nullglob -export KEYNAME_CHOP_CHUNK_SIZE=255 -echo "KEYNAME_CHOP_CHUNK_SIZE ${KEYNAME_CHOP_CHUNK_SIZE}" # Find all .ipynb files and use xargs to run nbconvert in parallel, within the directory of each notebook find "${script_dir}/" -name "*.ipynb" -print0 | xargs -0 -n 1 -P 2 -I {} bash -c '{ @@ -38,6 +36,8 @@ find "${script_dir}/" -name "*.ipynb" -print0 | xargs -0 -n 1 -P 2 -I {} bash -c notebook_base=$(basename "$notebook") echo "Processing notebook ${notebook_base} in directory ${notebook_dir}" cd "${notebook_dir}" + export KEYNAME_CHOP_CHUNK_SIZE=255 + echo "KEYNAME_CHOP_CHUNK_SIZE ${KEYNAME_CHOP_CHUNK_SIZE}" jupyter nbconvert \ --to notebook --execute --inplace \ --ExecutePreprocessor.timeout=600 \ From e714f2c93dec975e6b3af2cdeacd767a84b02bb4 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 17:39:40 +0000 Subject: [PATCH 140/145] Bump keyname pin for better error diagnostics --- third-party/requirements.in | 2 +- third-party/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/third-party/requirements.in b/third-party/requirements.in index fbaa3576c1..c644a00e70 100644 --- a/third-party/requirements.in +++ b/third-party/requirements.in @@ -1,5 +1,5 @@ git+git://github.com/mmore500/osfclient@9e2e14d#egg=osfclient -keyname==0.5.5 +keyname==0.5.6 numpy==1.23.5 pandas==1.1.2 frozendict==1.2 diff --git a/third-party/requirements.txt b/third-party/requirements.txt index 6c296fe73b..539fc3ca6d 100644 --- a/third-party/requirements.txt +++ b/third-party/requirements.txt @@ -78,7 +78,7 @@ jupyter_client==6.1.12 # via # -r requirements.in # ipykernel -keyname==0.5.5 +keyname==0.5.6 # via # -r requirements.in # nbmetalog From 0fab056f236dd32d2498d73befead62a35dade4c Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 13:13:22 -0500 Subject: [PATCH 141/145] Bump container for newer python deps --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ddb3d5a97c..aab5626454 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -46,7 +46,7 @@ jobs: name: Notebooks runs-on: ubuntu-20.04 container: - image: mmore500/conduit:GITHUB_ACTION_684 + image: mmore500/conduit:GITHUB_ACTION_703 # github actions requires root to access mounted volumes options: --user root steps: From 856a625cdfc958894dbd89a2dcbc940a6085f06b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 18:47:29 +0000 Subject: [PATCH 142/145] Disable broken notebook --- ...t=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=weak-scaling/{a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb => a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_} (100%) diff --git a/binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb b/binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_ similarity index 100% rename from binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb rename to binder/date=2021+project=72k5n/a=weak-scaling/a=performance_semantics+what=weak-scaling+compute-work=0+simels_per_cpu=2048+ext=.ipynb_ From 4c865472bed3b671701f3cde0155e0bbd5d203d2 Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 14:06:26 -0500 Subject: [PATCH 143/145] Add ghostscript to container --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 0424e4246d..ca578b89ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,6 +53,7 @@ RUN \ fonts-liberation \ gconf-service \ gdb \ + ghostscript \ gpg-agent \ gzip \ g++-9 \ From 19da8ff9e586a730e2a37772dbff518b8a3589df Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 14:07:29 -0500 Subject: [PATCH 144/145] Bump container pin to get ghostscript --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index aab5626454..95d6f5d26d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -46,7 +46,7 @@ jobs: name: Notebooks runs-on: ubuntu-20.04 container: - image: mmore500/conduit:GITHUB_ACTION_703 + image: mmore500/conduit:GITHUB_ACTION_706 # github actions requires root to access mounted volumes options: --user root steps: From a6cdbe9216d22d802d976b03c70eac5dd592e91b Mon Sep 17 00:00:00 2001 From: Matthew Andres Moreno Date: Thu, 30 Nov 2023 14:18:10 -0500 Subject: [PATCH 145/145] Restore notebook, wasn't broken --- ...cs+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/{a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_ => a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb} (100%) diff --git a/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_ b/binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb similarity index 100% rename from binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb_ rename to binder/date=2021+project=72k5n/a=multithreading-vs-multiprocessing/a=performance_semantics+what=threadproc+compute-work=0+simels_per_cpu=1+ext=.ipynb