Skip to content

Instantly share code, notes, and snippets.

@gumdropsteve
Last active February 3, 2020 23:04
Show Gist options
  • Save gumdropsteve/a069b48112ca7ddb1791a3069f8dc4d6 to your computer and use it in GitHub Desktop.
Save gumdropsteve/a069b48112ca7ddb1791a3069f8dc4d6 to your computer and use it in GitHub Desktop.
Test pool vs no pool performance with BlazingSQL
import os
import urllib
from blazingsql import BlazingContext
# set number of times to run each query
n_runs = 3
# let user know
print(f'nruns = {n_runs}')
'''CHECK FOR DATA
'''
# tag base url, file name & relative data folder
base_url = 'https://blazingsql-colab.s3.amazonaws.com/netflow_data/'
fn = 'nf-chunk2.csv'
# do we already have the data?
if not os.path.isfile(fn):
# no, so let us know then download it
print(f'Downloading {base_url + fn} to {fn}')
urllib.request.urlretrieve(base_url + fn, fn)
'''CLEAR BSQL MEMORY
'''
# remove existing RAL & algebra logs
try:
os.system('rm RAL.0.log')
except:
print('no RAL log to remove')
try:
os.system('rm algebra.log')
except:
print('no algebra log to remove')
'''START TESTING
'''
# connect to BlazingSQL
bc = BlazingContext(pool=False)
# determine path to data
path = os.getcwd() + '/nf-chunk2.csv'
# create table
bc.create_table('netflow', path, header=0)
# define the query
query = '''
SELECT
a.firstSeenSrcIp as source,
a.firstSeenDestIp as destination,
count(a.firstSeenDestPort) as targetPorts,
SUM(a.firstSeenSrcTotalBytes) as bytesOut,
SUM(a.firstSeenDestTotalBytes) as bytesIn,
SUM(a.durationSeconds) as durationSeconds,
MIN(parsedDate) as firstFlowDate,
MAX(parsedDate) as lastFlowDate,
COUNT(*) as attemptCount
FROM
netflow a
GROUP BY
a.firstSeenSrcIp,
a.firstSeenDestIp
'''
# query the table 3 times
for i in range(n_runs):
bc.sql(query)
# This query against the logs will tell you the average execution time for every query.
log_query = """
SELECT
MAX(end_time) AS end_time, SUM(query_duration)/COUNT(query_duration) AS avg_time,
MIN(query_duration) AS min_time, MAX(query_duration) AS max_time, COUNT(query_duration) AS num_times,
relational_algebra
FROM (
SELECT
times.end_time as end_time, times.query_id, times.avg_time,
times.max_time as query_duration, times.min_time, ral.relational_algebra as relational_algebra
FROM (
SELECT
query_id, MAX(log_time) AS end_time, SUM(duration)/COUNT(duration) AS avg_time,
MIN(duration) AS min_time, MAX(duration) AS max_time
FROM
bsql_logs
WHERE
info = 'Query Execution Done'
GROUP BY
query_id ) AS times
INNER JOIN (
SELECT
query_id,
SUBSTRING(info, 13, 2000) AS relational_algebra
FROM
bsql_logs
WHERE
info LIKE 'Query Start%'
GROUP BY
query_id, info ) AS ral
ON
times.query_id = ral.query_id
ORDER BY
times.end_time DESC) AS temp GROUP BY relational_algebra
"""
# save results to CSV
bc.log(log_query).to_csv('false_pool_runtimes.csv', index=False)
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Pool vs No Pool\n",
"In this notebook we will compare BlazingSQL performance with and without memory pool."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import numpy as np\n",
"from blazingsql import BlazingContext\n",
"import matplotlib.pyplot as plt; plt.rcdefaults()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"BlazingContext ready\n"
]
},
{
"data": {
"text/plain": [
"<pyblazing.apiv2.context.BlazingTable at 0x7fdafb703d30>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# identify path to data\n",
"path = os.getcwd() \n",
"\n",
"# start up BlazingSQL\n",
"bc = BlazingContext()\n",
"\n",
"# create tables for pool & no pool performance\n",
"bc.create_table('yes_pool', path + '/true_pool_runtimes.csv', header=0)\n",
"bc.create_table('no_pool', path + '/false_pool_runtimes.csv', header=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Visualize Results"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pool is 24.6350% faster\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAnEAAAHJCAYAAADq/G+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdeXhN5/7//9fOHJmMESGIeYqZmoMqNYfWVEV0cjpGlQ/VOrQ1Fq1qy9FqDZ30qOEYew4lSlGtmlJppZpBEUMRMyH394/+sn62DBJTuuL5uK59XXKve93rfe9N8+oa7u0wxhgBAADAVlzyugAAAADkHiEOAADAhghxAAAANkSIAwAAsCFCHAAAgA0R4gAAAGyIEAcAAGBDhDgAAAAbIsQBAADYECEOyKccDoccDocKFSqkU6dOZdpnzJgxcjgcmjhx4l2pafv27Wrbtq0KFixo1ZeQkKDo6Gg5HA5FRkbelTpuRXrd6S8XFxcVLFhQzZs31+zZs5VXX4LjcDhUtmzZPDl2bkRGRlrv3dy5czPtk5CQIIfDoSpVqtzRWlq2bJnh8/T19VXNmjU1atQonT59+o4e/0Z1JSQk5MnxYR9ueV0AgDvr1KlTevvtt/Xaa6/d0eOULVtWiYmJWYaYM2fOqEuXLjp8+LBatmypkJAQ65emHQ0YMECSdPXqVe3fv1/fffedNm3apG+++UZffPFFHldnD2PHjtWjjz4qN7e8/VXUrl07BQUFSZIOHjyozZs3a+zYsfrqq6+0efNmFSpUKE/rA7JCiAPyMRcXF7m5uWnatGkaPHhwnv4y+uGHH3To0CH169dP8+fPz7M6bpfrzyKtWbNGHTp00IIFC9S3b1916tQpbwqzCW9vb+3fv1/z58/XY489lqe1jBgxQi1btrR+jo+PV+vWrfXLL79o3LhxmjJlSt4VB2SDy6lAPubu7q4nnnhCp0+f1ltvvZWntfzxxx+SpHLlyuVpHXfKAw88oH79+kmSli5dmsfV/P09/fTTkv46G3flypU8rsZZaGiodeaazxJ/Z4Q4IJ8bOXKkPD099c477+jEiRM53s8Yo3nz5qlFixYqWLCgvL29VbNmTU2ZMkWpqalWv/T72RITEyU53zNWtmxZ6/6m9MuPr732mrU9J/fAXblyRe+++67q1asnX19f+fr6qmHDhpo5c6auXr3q1HfAgAFyOBzasGGDU/tXX33ldA/etaZMmSKHw6H3338/x+9NVurUqSNJOnDggFP7+fPn9cYbb6hGjRry9vZWQECAWrRooQULFmQ51oEDBzRo0CCVKVNGnp6eCgwMVPfu3fXDDz/ccp2dO3eWw+HQ119/nen2y5cvq3DhwvL29na6L+z7779Xt27drJqCgoLUsGFDvfzyyzp79myuamjQoIE6duyo+Pj4LO+Ny8qqVav0wAMPqFChQvLy8lLlypU1YsSILO/9vBlZfZaS9Mknn6hZs2by9/dXgQIFVLNmTU2YMEEXL17MdKyb+fyBnCDEAflcyZIl9eSTT+rMmTOaOnVqjvZJS0tTr169FBkZqV27dql+/fpq166djh07pmHDhikiIkJpaWmSpKCgIA0YMEA+Pj6S/gpS6a+HH35Yvr6+GjBggJo2bSpJqlWrlrW9WbNm2dZx9epVde3aVS+88IJ+++03tWnTRm3atNEvv/yiZ555Rj169LDqkGRdElu/fr3TONHR0Zn++dqfw8PDc/TeZOfMmTOSJE9PT6e2Fi1a6J///KeOHj2qTp06qWnTptq2bZv69OmjwYMHZxhnz549qlu3rj744AMVKFBA3bt3V8WKFbVkyRI1adJECxcuvKU6+/btK0n67LPPMt2+atUqnTx5Up07d5a/v78kaeXKlWrSpImWL1+usmXLqnv37qpdu7aOHz+uiRMn6vjx47muY8yYMZKkcePGOf2PQXYmTJigjh07Kjo6WvXq1VNERITOnz+vSZMm6b777tORI0dyXUdmMvssJWnQoEHq37+/tm/frubNm6tjx446fPiwRo4cqdatW+vChQsZxsnt5w/kmAGQL0kynp6exhhjDh48aLy8vIyfn585fvy41Wf06NFGkpkwYYLTvpMmTTKSzAMPPGCOHj1qtZ89e9Z07tzZSDLvvfee0z5lypQx2f0nZc6cOUaSGT16dIZt69evN5LMgAEDnNqnTJliJJmwsDBz5MgRq/3QoUOmcuXKRpJ5//33rfbff//dSDLh4eFO41SvXt1UrFjReHh4OB3j6tWrJiAgwBQtWtSkpaVlWfu1JGU6z7S0NNO4cWMjybzyyitW+3PPPWckmTZt2pgzZ85Y7bGxsSYwMNBIMitXrnQaJywszEgyL7/8slNdCxcuNC4uLsbPz88kJydnqKtMmTI5msP58+eNr6+v8fX1NefOncuwvUePHkaSWbp0qdUWHh5uHA6H+fHHHzP0//77783p06dzdOwBAwYYSeaLL74wxhjr79OsWbOsPvHx8UaSqVy5stO+27Zts+b//fffW+0XL160au7Ro0eO6kifkySzfv36DNtGjBhhJJmmTZtabV999ZWRZEqWLGni4uKs9pSUFNOsWTMjyQwbNsxpnNx+/tfWFR8fn+O54N5EiAPyqWtDnDHGvPDCC0aSGTFihNWWWYhLTU01RYsWNX5+fubYsWMZxk1OTjaenp4mLCzMqf1OhLjSpUsbSeabb77JsM+yZcsy/UVfunRp4+npaS5cuGCMMebYsWPG4XCY559/3jRt2tQp6Pz4449GknnooYeyrPt614e4K1eumH379pnIyEjrPf/tt9+MMX+FXm9vb+Pi4mL27duXYazp06cbSaZdu3ZW27p164wkExoaaq5cuZJhn+7du2cavHMT4owxpl+/fk5hKt3p06eNt7e3KVSokLl06ZLVXrVqVVOwYMEcj5+V60Pc9u3bjSRTunRp63hZhbj+/fsbSWbUqFEZxj1y5Ij1Xv/xxx85qiWzEHfw4EEzZcoU4+HhYSSZTz/91NrWokULI8l89NFHGcbavXu3cTgcxs/Pz5rHzXz+19ZFiMONcDkVuEeMGDFCXl5eeu+997K99LVjxw4dP35czZo1U9GiRTNsL168uCpWrKiYmJgMl45up6SkJCUlJSkoKEitW7fOsL1Tp04qWLCgfv31Vx07dsxqDw8P16VLl7R161ZJ0oYNG2SMUcuWLdWyZUslJiZa98XdyqXU9Hvs3NzcVKlSJc2dO1d+fn764osvVL58eUl/rYt34cIFNWzYUBUrVswwRvqDEN999521NMvGjRslSb169ZKrq2uW+6T3u1npl1Q///xzp/YlS5bowoUL6tGjhzw8PKz2evXq6dSpU3r88ccVExNzS8e+Vt26ddW1a1clJSXp448/zrZv+pzTa79WYGCg2rZtq7S0NG3evDlXNbRq1cr6PEuWLKmhQ4cqNTVVI0eOtI6VmpqqrVu3yuFw6JFHHskwRlhYmGrWrKkzZ85o165dkm7u8wdygxAH3CNKlCihf/zjHzp79qwmT56cZb/0gLN69eoMC6Gmv2JiYmSMydWDErl16NAhScpyAVuHw6EyZco49ZX+//vi0gNa+oMX4eHhmW67dp/cSL+vb+DAgYqKitLs2bOVmJiobt265XgOBQsWVEBAgM6ePWs9QHCjfdLbr53zzWjTpo2KFy+ur7/+2ulzTA911wel8ePHq1atWvr4448VFhamYsWKqWvXrpozZ44uXbp0S7WkLzo9fvx4Xb58Oct+hw4dcvrcr3ez7027du00YMAARUZG6umnn9bUqVO1b98+jRs3zurz559/6vLlyypevLi8vLxydPyb+fyB3GCdOOAeMnz4cM2aNUvvv/++hg4dmmmf9Cc+K1asqCZNmmQ73vU3fd8JDocjV33Sz6qlB7QNGzYoLCxMRYoUUdOmTeXh4aHo6Gj1799fmzZtUpEiRVSjRo1c15WbJypzO4ec7JOTMbPj6uqqXr16afr06Vq4cKEGDRqkY8eO6ZtvvlFISIiaN2/u1D8kJEQ//vij1q1bpxUrVmjDhg1avny5li1bpjfffPOWFsWtXbu2IiIitGTJEs2ePVsdOnS4pbnl9r25fp24Wx07t59lTvsA1+NMHHAPCQoK0tNPP61z587pzTffzLRPqVKlJEk1atTQ3Llzs31ldrn1dgkODpb018KrWUlKSpL011nGdOXLl1dISIi2bt2qgwcPKiYmxvoF7e3trQYNGig6Olo7d+7UqVOn1KJFizv2C/RGc0hJSVFKSop8fHzk5+eXo33Sl3K5ds436/qnVL/88ktduXJFjzzySKbviZubm9q2bavp06dr165dSkhIsBbFvdWvbrv2bFxWZ/aCg4NljLHeg+vdzvfmekWKFJGHh4eSk5OzvI3g+uPfzOcP5AYhDrjHDB8+XAUKFNCMGTMyXY6hQYMGCggI0Pr163N1iSf9/qnbtXBr6dKlVbp0aSUnJ2vdunUZtq9cuVInT55U5cqVVaxYMadt6ffFTZo0ScYYtWrVytqWfl9c+pm0m7mUmlP16tWTt7e3tm3bpri4uAzbP/30U0lSs2bNrNCUfgbsyy+/zLAO3rX7XH+m7Gak36u1adMmJSUlZXkpNSulS5fW8OHDJf21LMqtqFmzprp3766DBw/qww8/zLRP+pwzWxrl2LFj+t///icXF5cbnkG+Ge7u7mrUqJGMMZl+rVpMTIx27dolPz8/1apVS9LNff5AbhDigHtMYGCgnnnmGZ0/f17z5s3LsN3T01NDhw7VqVOn9NBDD2V61mP37t368ssvndrSzzr8+uuvt63W559/XpL04osvOj28kJycrGHDhjn1uVb6JdUPP/xQDodDLVq0sLalh7b0oHAnQ5yPj48ee+wxpaWl6dlnn9W5c+esbfv27dPYsWMlOc+hZcuWCgsLU3x8vP75z3863fC+dOlSLV68WL6+vjlaKDknHnnkERljNGHCBG3ZskU1atRQWFhYhn5vv/12pqE/fcHg0qVL33It6WfjZsyYken2Z599Vi4uLnrnnXf0448/Wu2XL1/W888/r/Pnz6t79+4qWbLkLdeSmfTPafTo0fr999+t9jNnzui5556TMUaDBg2y/ofmZj5/IFfy6rFYAHeWrlti5FpHjx41Pj4+1nIZ1y9XcfXqVdOnTx9rjMaNG5tevXqZ+++/34SGhhpJpmvXrk77TJ061UgyxYsXN7179zaPP/64GT58uLX9ZpYYuXLlimnfvr2RZAICAky3bt1MRESE8fPzM5JMRESEuXr1aobx4uLirLnVqlXLadu5c+es5SMKFy6c4/Xh0kmZrxOXldOnT5t69eoZSSYwMND06NHDdOjQwXh5eRlJ5oUXXsiwz+7du02RIkWMJFO1alXTp08f07RpUyPJuLm5mX//+9+Z1pWbJUbS7du3z5qTJDNx4sRM+wUEBBgXFxdTp04d07NnT9OjRw9rrb6iRYtay6rcyPVLjFwvfb03ZbLEiDHGjBs3znof2rRpY3r37m1CQkKMJFOxYsUM6+dlJ7t14rLy1FNPGUnG29vbdOzY0fTo0cMUK1bMSDKNGjXKsO7ezXz+LDGCnCLEAflUdiHOGGP+7//+L8sQl+6rr74yDz74oClatKhxd3c3JUqUMI0aNTJjxowxv/zyi1Pf1NRU8+qrr5ry5csbd3f3DKHiZkJc+rjvvPOOqVOnjilQoIApUKCAqV+/vnn//fczXUctXalSpYwkExUVlWFbeiCKiIjIcv+s5DbEGfPXemGvvfaaqVatmvH09DR+fn6mWbNm5vPPP89yn8TERPPkk0+akJAQ4+7ubooWLWoiIiKcFrm9vq6bCXHGGNOgQQMjyTgcDpOYmJhpn/nz55tHHnnEVK5c2fj5+Rk/Pz9TrVo1M3ToUHPo0KEcH+tGIS4mJsa4uLhkGeKMMWbFihXm/vvvNwEBAcbDw8NUqFDB/N///Z85ceJEjusw5uZCnDF/vRdNmjQxvr6+xsvLy1SvXt2MGzfOnD9/PtP+uf38CXHIKYcxLE4DAABgN9wTBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIbe8LgB3Rlpamg4dOiQ/Pz++zgUAAJswxujMmTMKDg6Wi0v259oIcfnUoUOHFBISktdlAACAm3DgwAGVKlUq2z6EuHzKz89P0l9/Cfz9/fO4GgAAkBOnT59WSEiI9Xs8O4S4fCr9Eqq/vz8hDgAAm8nJrVA82AAAAGBDhDgAAAAbIsQBAADYECEOAADAhghxAAAANkSIAwAAsCFCHAAAgA0R4gAAAGyIEAcAAGBDhDgAAAAbIsQBAADYECEOAADAhghxAAAANkSIAwAAsCG3vC4Ad1aX2S/Kzdsjr8sAANwha5+emdclII9wJg4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbIgQBwAAYEOEOAAAABsixAEAANgQIQ4AAMCGCHEAAAA2RIgDAACwIUIcAACADRHiAAAAbMgtrwvAnbXsibfl7++f12UAAIDbjDNxAAAANkSIAwAAsCFCHAAAgA0R4gAAAGyIEAcAAGBDhDgAAAAbIsQBAADYECEOAADAhghxAAAANsQ3NgAA7rqrV68qNTU1r8sA8oSHh4dcXG79PBohDgBw1xhjlJycrFOnTuV1KUCecXFxUWhoqDw8PG5pHEIcAOCuSQ9wgYGBKlCggBwOR16XBNxVaWlpOnTokA4fPqzSpUvf0r8BQhwA4K64evWqFeCKFCmS1+UAeaZYsWI6dOiQrly5Ind395sehwcbAAB3Rfo9cAUKFMjjSoC8lX4Z9erVq7c0DiEOAHBXcQkV97rb9W+AEAcAAGBDhDgAAO6iDz74QCEhIXJxcdG0adNuy5gJCQlyOBzauXPnTe3fr18/jR8//rbUkhsOh0NLly6968e9HTp16qQZM2bkaQ082AAAyFNtZj59V4+39umZueofGRmpefPmSZLc3NxUuHBh1axZU3369FFkZGSu1vs6ffq0nnvuOb311lt66KGHFBAQkKtacio6OlqtWrXSyZMnVbBgwWz77t69WytXrszzQJIb134mWTHG3NEa/vnPf6pz586KjIzMs/s8ORMHAMANPPjggzp8+LASEhK0evVqtWrVSlFRUerUqZOuXLmS43GSkpKUmpqqjh07qkSJEn+Lhzzee+899ejRQ35+fnldSo698847Onz4sPWSpDlz5mRou97ly5dvWw0NGzZU0aJF9eWXX962MXOLEAcAwA14enoqKChIJUuWVN26dTVy5Ej95z//0erVqzV37lyrX0pKip566ikFBgbK399frVu31q5duyRJc+fOVVhYmCSpXLlycjgc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+2zfvl09e/ZU7969tWfPHo0ZM0ajRo3S3Llzc3Usb29vSVJqaqqMMYqIiNCJEye0YcMGrVmzRvv371evXr2s/kuWLFFUVJReeuklxcTEaNCgQRo4cKDWr1+f42N+++23ql+/fqbbhg0bpilTpuiHH35QYGCgunTpotTU1BzPOTIyUj/++KOWLVumLVu2yBijDh06WGNcb+PGjfL19c32NX78+BzP7fz58xo6dKh+/PFHrV27VmlpaXrooYeUlpaWaf+RI0dq3759Wr16tWJjYzVjxgwVKVJEknT27Fm1bNlSBQsW1MaNG7Vx40Z5eXmpffv2unLlijVGw4YNFR8fn+XflduFe+IAAMiBbt26qXbt2ho9erQ++uijDNvfeust3X///Ro1apQkqVKlStq7d68mT56syMjIHB3jjz/+0OTJk1WqVClVqlRJa9eu1e7duxUfH6+QkBBJ0ieffKLq1avrhx9+UIMGDTRlyhRFRkZaX8g+ZMgQbd26VVOmTFGrVq1ydNyEhAQFBwdnum306NF64IEHJEnz5s1TqVKltGTJEvXs2fOGc46Li9OyZcv03XffqUmTJpKkzz77TCEhIVq6dKl69OiR4Xj169fXzp07s623cOHCTj+vWLFCvr6+1s/t27fXwoULJSnDMWbPnq3g4GDt27dPVapUyTB2UlKS6tSpY4Xaa+8R/Pzzz+Xt7a0PPvjAaps3b54CAgL07bffqnXr1pKkkiVLSpISExNVqlSpbOdyKzgTBwBADk2aNEnz5s3T3r17M2yLjY1V06ZNndqaNm2quLi4bO9vS0lJka+vr3x8fBQSEqLLly9r8eLF8vDwUGxsrEJCQqwAJ0nVqlVTwYIFFRsbm+1x07fnxIULF+Tl5ZXptmsvsRYuXFiVK1e+4bHT5xwbGys3Nzfdd9991vYiRYo4jXE9b29vVahQIdvX9SGuVatW2rlzp/WaPn26te23335Tnz59VK5cOfn5+alixYqSlOESaLpnnnlGn376qerWravhw4dr69at1rbt27frl19+cTorWKRIEV2+fFn79+93moP011nAO4kzcQAA5FCLFi3Url07jRw5MsPZNWOMHA5HhrYb8fPz008//SQXFxcVL15cPj4+2Y6ZWXtmx81sv6wULVo0Vw9tpI99ozlnNf/s6tu4caPat2+f7fFHjhypkSNHWj/7+Phk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Hj2qdu3aKTg4WH5+frf9GDkxdOhQDRo0SD179tSuXbu0bds2NW/eXF27dtV77713x4+fmpp6x48BAADsLdchrk2bNgoKCtKECROy7bd582a1aNFC3t7eCgkJ0QsvvKBz585Jklq2bKnExES9+OKLcjgccjgcio6OtkJb69atrbbMzJw5U+XLl5eHh4cqV66sTz75xNr20ksvqXPnztbP06ZNk8Ph0MqVK622ypUra9asWZmOvXXrVk2dOlWTJ0/W0KFDVaFCBVWtWlXjxo3T4MGDNWTIEB04cECSNGbMGNWuXdtp/2nTpqls2bJObXPmzFHVqlXl5eWlKlWqaMaMGda2hIQEORwO/fvf/1bLli3l5eWlDz74QP7+/vrqq6+cxlm+fLl8fHx05syZTGsHAAD3jlyHOFdXV40fP17vvvuu/vjjj0z77NmzR+3atVP37t21e/duffnll9q0aZOee+45SdLixYtVqlQpvf766zp8+LAOHz6sJk2a6Ndff5UkLVq0yGq73pIlSxQVFaWXXnpJMTExGjRokAYOHKj169dL+isgbty4UWlpaZKkDRs2qGjRotqwYYMkKTk5Wfv27VN4eHimtX/xxRfy9fXVoEGDMmx76aWXlJqaqkWLFuX4/frwww/1yiuvaNy4cYqNjdX48eM1atQozZs3z6nf8OHD9cILLyg2NlbdunVT7969NWfOHKc+c+bM0cMPP5xnZygBAMDfh9vN7NStWzfVrl1bo0eP1kcffZRh++TJk/XII49o8ODBkqSKFStq+vTpCg8P18yZM1W4cGG5urrKz89PQUFB1n6BgYGSpMKFCzu1X2vKlCmKjIzUM888I0kaMmSItm7dqilTpqhVq1Zq0aKFzpw5ox07dqhu3brauHGjhg4dqsWLF0uS1q9fr+LFi6tKlSqZjr9v3z7rLN/1goODFRAQoH379uX4vXrjjTc0depUde/eXZIUGhqqvXv3atasWRowYIDVb/DgwVYfSXriiSfUpEkTHTp0SMHBwTp+/LhWrFihNWvWZHqcS5cu6dKlS9bPp0+fznGNAADAfm766dRJkyZp3rx52rt3b4Zt27dv19y5c+Xr62u92rVrp7S0NMXHx99SwbGxsWratKlTW9OmTRUbGytJCggIUO3atRUdHa09e/bIxcVFgwYN0q5du3TmzBlFR0dneRYuJ4wxmQa8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\n",
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# focus results to runtime\n",
"n_pool_performance = list(bc.sql('select avg_time from no_pool')['avg_time']) \n",
"y_pool_performance = list(bc.sql('select avg_time from yes_pool')['avg_time']) \n",
"\n",
"# set bar chart details\n",
"objects = (['Netflow Query'])\n",
"y_pos = np.arange(len(objects))\n",
"bar_width = 0.05\n",
"\n",
"# horizontal bar chart of query performances\n",
"pool_true = plt.barh(y_pos+bar_width*1.5, y_pool_performance, bar_width, align='center', \n",
" label=\"Default (pool=True)\", color='seagreen', alpha=0.9)\n",
"\n",
"pool_false = plt.barh(y_pos, n_pool_performance, bar_width, align='center', \n",
" label=\"No Pool (pool=False)\", color='darkslateblue', alpha=0.9)\n",
"\n",
"# format chart\n",
"plt.yticks(y_pos, objects)\n",
"plt.xlabel('Runtime (ms)')\n",
"plt.title('Netflow Pool vs No Pool', size=15)\n",
"plt.legend()\n",
"\n",
"# how much of a speedup have we achieved\n",
"speed_up = ((sum(n_pool_performance) / sum(y_pool_performance))-1)*100\n",
"print(f'Pool is {str(speed_up)[:7]}% faster')\n",
"\n",
"# display\n",
"plt.show()"
]
}
],
"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.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
import os
import urllib
from blazingsql import BlazingContext
# set number of times to run each query
n_runs = 3
# let user know
print(f'nruns = {n_runs}')
'''CHECK FOR DATA
'''
# tag base url, file name & relative data folder
base_url = 'https://blazingsql-colab.s3.amazonaws.com/netflow_data/'
fn = 'nf-chunk2.csv'
# do we already have the data?
if not os.path.isfile(fn):
# no, so let us know then download it
print(f'Downloading {base_url + fn} to {fn}')
urllib.request.urlretrieve(base_url + fn, fn)
'''CLEAR BSQL MEMORY
'''
# remove existing RAL & algebra logs
try:
os.system('rm RAL.0.log')
except:
print('no RAL log to remove')
try:
os.system('rm algebra.log')
except:
print('no algebra log to remove')
'''START TESTING
'''
# connect to BlazingSQL
bc = BlazingContext(pool=True)
# determine path to data
path = os.getcwd() + '/nf-chunk2.csv'
# create table
bc.create_table('netflow', path, header=0)
# define the query
query = '''
SELECT
a.firstSeenSrcIp as source,
a.firstSeenDestIp as destination,
count(a.firstSeenDestPort) as targetPorts,
SUM(a.firstSeenSrcTotalBytes) as bytesOut,
SUM(a.firstSeenDestTotalBytes) as bytesIn,
SUM(a.durationSeconds) as durationSeconds,
MIN(parsedDate) as firstFlowDate,
MAX(parsedDate) as lastFlowDate,
COUNT(*) as attemptCount
FROM
netflow a
GROUP BY
a.firstSeenSrcIp,
a.firstSeenDestIp
'''
# query the table 3 times
for i in range(n_runs):
bc.sql(query)
# This query against the logs will tell you the average execution time for every query.
log_query = """
SELECT
MAX(end_time) AS end_time, SUM(query_duration)/COUNT(query_duration) AS avg_time,
MIN(query_duration) AS min_time, MAX(query_duration) AS max_time, COUNT(query_duration) AS num_times,
relational_algebra
FROM (
SELECT
times.end_time as end_time, times.query_id, times.avg_time,
times.max_time as query_duration, times.min_time, ral.relational_algebra as relational_algebra
FROM (
SELECT
query_id, MAX(log_time) AS end_time, SUM(duration)/COUNT(duration) AS avg_time,
MIN(duration) AS min_time, MAX(duration) AS max_time
FROM
bsql_logs
WHERE
info = 'Query Execution Done'
GROUP BY
query_id ) AS times
INNER JOIN (
SELECT
query_id,
SUBSTRING(info, 13, 2000) AS relational_algebra
FROM
bsql_logs
WHERE
info LIKE 'Query Start%'
GROUP BY
query_id, info ) AS ral
ON
times.query_id = ral.query_id
ORDER BY
times.end_time DESC) AS temp GROUP BY relational_algebra
"""
# save results to CSV
bc.log(log_query).to_csv('true_pool_runtimes.csv', index=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment