{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import os\n", "import json\n", "\n", "import matplotlib.pyplot as plt\n", "from dataclasses import dataclass\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "this_dir = os.path.dirname(os.path.abspath(''))\n", "# results is in \"../results\"\n", "results_dir = os.path.join(this_dir, \"results\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "experiment_folder = \"casestudy_example\"\n", "experiment_name = \"cs_example_edf\"\n", "\n", "experiment_file = os.path.join(results_dir, experiment_folder, experiment_name + \".json\")\n", "if not os.path.exists(experiment_file):\n", " print(\"Experiment file not found: \", experiment_file)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "with open(experiment_file) as f:\n", " experiment_data_raw = json.load(f)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of records: 12055\n", "First record: {'entry': {'operation': 'start_work', 'chain': 0, 'node': 'node_0', 'count': 500, 'next_release_us': 99890}, 'time': 0.0001}\n", "Operation types: ['get_next_executable', 'end_work', 'next_deadline', 'wait_for_work', 'start_work']\n" ] } ], "source": [ "def pre_process_data(data):\n", " for record in data:\n", " record[\"time\"] = int(record[\"time\"])\n", "\n", " min_time = min([record[\"time\"] for record in data])\n", " for record in data:\n", " record[\"time\"] -= min_time\n", " record[\"time\"] /= (1000 * 1000)\n", "\n", " if record[\"entry\"][\"operation\"] == \"next_deadline\":\n", " #print(\"Record: \", record)\n", " record[\"entry\"][\"deadline\"] = int(record[\"entry\"][\"deadline\"])\n", " record[\"entry\"][\"deadline\"] -= min_time\n", " record[\"entry\"][\"deadline\"] /= (1000 * 1000)\n", "\n", " # data = sorted(data, key=lambda x: x[\"time\"])\n", " return data\n", "\n", "experiment_data = pre_process_data(experiment_data_raw)\n", "\n", "print(\"Number of records: \", len(experiment_data))\n", "print(\"First record: \", experiment_data[0])\n", "operation_types = list(set([record[\"entry\"][\"operation\"] for record in experiment_data]))\n", "print(\"Operation types: \", operation_types)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "@dataclass\n", "class Record:\n", " start_time: float\n", " end_time: float\n", " node_name: str\n", "\n", "@dataclass\n", "class RecordLine:\n", " node_name: str\n", " count: int\n", "\n", " def __eq__(self, other):\n", " return self.node_name == other.node_name and self.count == other.count\n", "\n", " def __hash__(self):\n", " return hash((self.node_name, self.count))\n", "\n", "def get_records(data) -> list[Record]:\n", " # used to match start_work and end_work records\n", " current_records: dict[RecordLine, Record] = {}\n", " records = []\n", " for record in data:\n", " if record[\"entry\"][\"operation\"] == \"start_work\":\n", " current_record = Record(start_time=record[\"time\"], node_name=record[\"entry\"][\"node\"], end_time=None)\n", " current_record_line = RecordLine(node_name=record[\"entry\"][\"node\"], count=record[\"entry\"][\"count\"])\n", " if current_record_line in current_records:\n", " raise Exception(\"Overlapping records\")\n", " current_records[current_record_line] = current_record\n", " elif record[\"entry\"][\"operation\"] == \"end_work\":\n", " current_record_line = RecordLine(node_name=record[\"entry\"][\"node\"], count=record[\"entry\"][\"count\"])\n", " if current_record_line not in current_records:\n", " raise Exception(\"No start record\")\n", " current_record = current_records[current_record_line]\n", " current_record.end_time = record[\"time\"]\n", " records.append(current_record)\n", " del current_records[current_record_line]\n", " return records\n", "\n", "records = get_records(experiment_data)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of nodes: 4\n" ] } ], "source": [ "num_nodes = len(set([record.node_name for record in records]))\n", "print(\"Number of nodes: \", num_nodes)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "98aed7649afd4e958ddfe602039f901b", "version_major": 2, "version_minor": 0 }, "image/png": "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UVVV9ZHWAwAYKEoegE1NTdHY2BgLFy6MVatWxbvvvhs33nhjzJ49O2bMmBERETfddFNce+21MWPGjLj44otj3bp1sXXr1pg4cWJ+nhUrVsTixYujpqYmmpubo6enJzZv3hyvv/56n6t0R/LKK6/EnDlz4swzz4x77703/ud//if/ufHjxxfnwAEABoiSB2Aul4snnngivvzlL8ell14aQ4YMiebm5rjvvvvyYxYsWBBdXV2xZMmSOHToUHzuc5+LRYsWxZNPPpkfc91118XJJ58c99xzT9xyyy0xatSoaGxsjK985SvH3UN7e3u89NJL8dJLL8Xpp5/e53NFeE0MAMCAUpRXAaei2K8iGsivhhuIr1Ss5FffeRWw9Q6Pq9TnnlcBV/7XoULM5VXAlSPJ/woOACBlgzIA29ra+vx6mA/e5s6dW+7tAQCU1aD8v4BvuOGGmD9//hE/N3LkyBLvBgBgYBmUAVhbW+u/dQMAOIpB+SNgAACOTgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkZli5N8DRZVlhxhRyrlKvV8i5rGe9gbxeIecq13rHG1vpx1eJcw329fjoXAEEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASMywcm+Ao8vl3v8zy44/pr/jSjGmktc7PK6S1yvEvqxX+vUKOVc51suy4z+XT2SuYynnc+FYYwv1d7mQc5XruVeouY63bz46VwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAElMxAdja2hrnnXdeubcBAFDxKiYAC23//v2xcOHCqK6ujrFjx0ZLS0u8+eab5d4WAEDRJRuACxcujK1bt0Z7e3t8//vfj//4j/+IL33pS+XeFgBA0RUlAOfMmROLFy+OJUuWRG1tbYwfPz5aW1vzn9+5c2fMmzcvRo8eHdXV1TF//vzYu3dvnznuuuuuGDduXIwZMyZaWlri0KFDH1pnzZo1MWXKlBgxYkRMnjw57r///n7tr7OzM/7t3/4t1qxZEzNnzoxLLrkk7rvvvnj00Udj9+7dH+vYAQAGuqJdAVy7dm2MGjUqOjo64u67747bb7892tvbo7e3N+bNmxf79++PDRs2RHt7e2zfvj0WLFiQv+/69eujtbU12traYvPmzVFXV/ehuFu3bl0sW7Ys7rjjjujs7Iy2trZYunRprF279rh727hxY4wdOzZmzJiR/1hTU1MMGTIkOjo6jnq/np6e6O7u7nMDAKg0w4o18bRp02L58uUREXH22WfHd77znXj66acjIuKFF16IHTt2RENDQ0REPPLII3HOOefEs88+G+eff36sWrUqWlpaoqWlJSIiVq5cGU899VSfq4DLly+Pb33rW/HZz342IiImTJgQ27ZtiwceeCCuueaaY+5tz549cdppp/X52LBhw6K2tjb27Nlz1PvdeeedsWLFihM8EwAAA0vRrgBOmzatz/t1dXWxb9++6OzsjIaGhnz8RURMnTo1xo4dG52dnRHx/o9oZ86c2ef+s2bNyr/91ltvRVdXV7S0tMTo0aPzt5UrV0ZXV1exDiluu+22OHjwYP62a9euoq0FAFAsRbsCOHz48D7v53K56O3tLcjch1+tu3r16g+F4tChQ497//Hjx8e+ffv6fOzdd9+N/fv3x/jx4496v6qqqqiqqvoIOwYAGDhK/irgKVOmxK5du/pcPdu2bVscOHAgpk6dmh/z//8t3qZNm/Jvjxs3Lurr62P79u0xadKkPrcJEyYcdw+zZs2KAwcOxHPPPZf/2L//+79Hb2/vh4ISAGCwKdoVwKNpamqKxsbGWLhwYaxatSrefffduPHGG2P27Nn5F2XcdNNNce2118aMGTPi4osvjnXr1sXWrVtj4sSJ+XlWrFgRixcvjpqammhubo6enp7YvHlzvP7663HzzTcfcw9TpkyJ5ubmuP766+Pv//7v45133om/+qu/ii984QtRX19f1OMHACi3kl8BzOVy8cQTT8Qpp5wSl156aTQ1NcXEiRPjsccey49ZsGBBLF26NJYsWRLTp0+P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M888k0VE9vLLLxdm0xWoFOf54MGDWURkTz31VGE2XaGKda5/85vfZL//+7+fvfjii9mZZ56ZfAAW4zxfc8012bx584qy38HOj4CL6O23347nnnsumpqa8h8bMmRINDU1xcaNG494n40bN/YZHxHxR3/0R/nxO3bsiD179vQZU1NTEzNnzjzqnINdMc4zR1aqc33w4MHI5XIxduzYguy70pTiPL/99tvx4IMPRk1NTZx77rmF23yFKda57u3tjauuuipuueWWOOecc4qz+QpSzOf0T37ykzjttNPi05/+dCxatChee+21wh/AICQAi+jVV1+N9957L8aNG9fn4+PGjYs9e/Yc8T579uw55vjDf57InINdMc4zR1aKc33o0KG49dZb44tf/GJR/gP4SlDM8/z9738/Ro8eHSNGjIhvf/vb0d7eHqeeemphD6CCFOtcf/Ob34xhw4bF4sWLC7/pClSs89zc3ByPPPJIPP300/HNb34zNmzYEHPnzo333nuv8AcxyAwr9wYADnvnnXdi/vz5kWVZ/N3f/V25tzMoXXbZZbFly5Z49dVXY/Xq1TF//vzo6OiI0047rdxbGzSee+65+Nu//dv4r//6r8jlcuXezqD2hS98If92Y2NjTJs2Lc4666z4yU9+EpdffnkZdzbwuQJYRKeeemoMHTo09u7d2+fje/fujfHjxx/xPuPHjz/m+MN/nsicg10xzjNHVsxzfTj+Xn755Whvb0/26l9Ecc/zqFGjYtKkSXHhhRfG9773vRg2bFh873vfK+wBVJBinOuf/vSnsW/fvjjjjDNi2LBhMWzYsHj55Zfjr//6r+OTn/xkUY5joCvV1+mJEyfGqaeeGi+99NLH3/QgJwCL6KSTTorp06fH008/nf9Yb29vPP300zFr1qwj3mfWrFl9xkdEtLe358dPmDAhxo8f32dMd3d3dHR0HHXOwa4Y55kjK9a5Phx/v/rVr+Kpp56KT3ziE8U5gApRyud0b29v9PT0fPxNV6hinOurrroqfv7zn8eWLVvyt/r6+rjlllviySefLN7BDGClek7/5je/iddeey3q6uoKs/HBrNyvQhnsHn300ayqqip7+OGHs23btmVf+tKXsrFjx2Z79uzJsizLrrrqquzrX/96fvzPfvazbNiwYdm9996bdXZ2ZsuXLz/ir4EZO3Zs9sQTT2Q///nPs3nz5vk1MEU4z6+99lr2/PPPZz/4wQ+yiMgeffTR7Pnnn89++9vflvz4BpJCn+u33347u/LKK7PTTz8927JlS59f59DT01OWYxwICn2e33zzzey2227LNm7cmP3617/ONm/enP35n/95VlVVlb344otlOcaBohhfP/4/rwIu/Hl+4403sq997WvZxo0bsx07dmRPPfVU9gd/8AfZ2WefnR06dKgsx1hJBGAJ3HfffdkZZ5yRnXTSSdkFF1yQbdq0Kf+52bNnZ9dcc02f8evXr88+9alPZSeddFJ2zjnnZD/4wQ/6fL63tzdbunRpNm7cuKyqqiq7/PLLs1/+8pelOJQBrdDn+aGHHsoi4kO35cuXl+BoBrZCnuvDv2bnSLcf//jHJTqigamQ5/l3v/td9qd/+qdZfX19dtJJJ2V1dXXZlVdemT3zzDOlOpwBrdBfP/4/Afi+Qp7n//3f/82uuOKK7Pd+7/ey4cOHZ2eeeWZ2/fXX54OSY8tlWZaV59ojAADl4N8AAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAk5v8AT4r/JDEMlw4AAAAASUVORK5CYII=", "text/html": [ "\n", "