Pixie Node Overview
Dashboard shows the pods on the selected node along with their CPU usage, memory consumption, and network traffic stats. 
To learn how to monitor infrastructure health using Pixie, see the [tutorial](https://docs.px.dev/tutorials/pixie-101/infra-health/).
Dashboard shows the pods on the selected node along with their CPU usage, memory consumption, and network traffic stats. To learn how to monitor infrastructure health using Pixie, see https://docs.px.dev/tutorials/pixie-101/infra-health/
{
  "__inputs": [
    {
      "name": "DS_PIXIE_GRAFANA DATASOURCE PLUGIN",
      "label": "Pixie Grafana Datasource Plugin",
      "description": "",
      "type": "datasource",
      "pluginId": "pixie-pixie-datasource",
      "pluginName": "Pixie Grafana Datasource Plugin"
    }
  ],
  "__requires": [
    {
      "type": "datasource",
      "id": "pixie-pixie-datasource",
      "name": "Pixie Grafana Datasource Plugin",
      "version": "0.0.9"
    },
    {
      "type": "panel",
      "id": "table",
      "name": "Table",
      "version": ""
    },
    {
      "type": "panel",
      "id": "timeseries",
      "name": "Time series",
      "version": ""
    }
  ],
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "target": {
          "limit": 100,
          "matchAny": false,
          "tags": [],
          "type": "dashboard"
        },
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "graphTooltip": 0,
  "id": null,
  "iteration": 1657153861516,
  "links": [],
  "panels": [
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {
            "align": "auto",
            "displayMode": "auto",
            "inspect": false
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "phase"
            },
            "properties": [
              {
                "id": "custom.displayMode",
                "value": "color-text"
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "ready"
            },
            "properties": [
              {
                "id": "custom.displayMode",
                "value": "color-text"
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "start_time"
            },
            "properties": [
              {
                "id": "custom.align",
                "value": "right"
              }
            ]
          },
          {
            "matcher": {
              "id": "byName",
              "options": "pod"
            },
            "properties": [
              {
                "id": "links",
                "value": [
                  {
                    "title": "",
                    "url": "/d/_t3foxCnz/px-pod?orgId=1&${pixieCluster:queryparam}&var-pixiePod=${__data.fields.pod}"
                  }
                ]
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 13,
        "w": 16,
        "x": 0,
        "y": 0
      },
      "id": 2,
      "options": {
        "footer": {
          "fields": "",
          "reducer": [
            "sum"
          ],
          "show": false
        },
        "showHeader": true
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = pods_for_node(start_time, node)\noutput.phase = px.pluck(output.status, \"phase\") \noutput.ready = px.pluck(output.status, \"ready\") \n\n\noutput = output[['pod', 'phase', 'ready', 'start_time', 'containers']]\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Pods",
      "type": "table"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "CPU Usage",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "percentunit"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 13,
        "w": 8,
        "x": 16,
        "y": 0
      },
      "id": 3,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = resource_timeseries(start_time, node, '$groupby')\n#output.phase = px.pluck(output.status, \"phase\") \n#output.ready = px.pluck(output.status, \"ready\") \noutput = output[['time_', 'cpu_usage','groupby_col']]\n\n#output = output[['pod', 'phase', 'ready', 'start_time', 'containers']]\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "CPU Usage",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Bytes Read",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "KBs"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 12,
        "w": 8,
        "x": 0,
        "y": 13
      },
      "id": 4,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = resource_timeseries(start_time, node, '$groupby')\n#output.phase = px.pluck(output.status, \"phase\") \n#output.ready = px.pluck(output.status, \"ready\") \noutput.bytes_read = output.total_disk_read_throughput * px.pow(10,9) / px.pow(2,10)\noutput = output[['time_', 'bytes_read','groupby_col']]\n\n#output = output[['pod', 'phase', 'ready', 'start_time', 'containers']]\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Bytes Read",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Bytes Written",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "KBs"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 12,
        "w": 8,
        "x": 8,
        "y": 13
      },
      "id": 5,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = resource_timeseries(start_time, node, '$groupby')\n#output.phase = px.pluck(output.status, \"phase\") \n#output.ready = px.pluck(output.status, \"ready\") \noutput.bytes_written = output.total_disk_write_throughput * px.pow(10,9) / px.pow(2,10)\noutput = output[['time_', 'bytes_written','groupby_col']]\n\n#output = output[['pod', 'phase', 'ready', 'start_time', 'containers']]\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Bytes Written",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Bytes Read",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "KBs"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 12,
        "w": 8,
        "x": 16,
        "y": 13
      },
      "id": 6,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = network_stats(start_time, node, '$groupby')\noutput.sent_data = output.tx_bytes_per_ns * px.pow(10,9) / px.pow(2,10)\noutput = output[['time_', 'sent_data','groupby_col']]\n\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Bytes Read",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Received Data",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "KBs"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 11,
        "w": 8,
        "x": 0,
        "y": 25
      },
      "id": 7,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = network_stats(start_time, node, '$groupby')\noutput.received_data = output.rx_bytes_per_ns * px.pow(10,9) / px.pow(2,10)\noutput = output[['time_', 'received_data','groupby_col']]\n\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Received Network Traffic",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Resident Memory Usage",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "deckbytes"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 11,
        "w": 8,
        "x": 8,
        "y": 25
      },
      "id": 8,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = resource_timeseries(start_time, node, '$groupby')\noutput.rss = output.rss / px.pow(2,10)\noutput = output[['time_', 'rss','groupby_col']]\n\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Resident Set Size",
      "type": "timeseries"
    },
    {
      "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
      "description": "",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "axisLabel": "Virtual Memory Usage",
            "axisPlacement": "auto",
            "barAlignment": 0,
            "drawStyle": "line",
            "fillOpacity": 0,
            "gradientMode": "none",
            "hideFrom": {
              "legend": false,
              "tooltip": false,
              "viz": false
            },
            "lineInterpolation": "linear",
            "lineWidth": 1,
            "pointSize": 5,
            "scaleDistribution": {
              "type": "linear"
            },
            "showPoints": "auto",
            "spanNulls": false,
            "stacking": {
              "group": "A",
              "mode": "none"
            },
            "thresholdsStyle": {
              "mode": "off"
            }
          },
          "mappings": [
            {
              "options": {
                "Failed": {
                  "color": "red",
                  "index": 5
                },
                "Pending": {
                  "color": "yellow",
                  "index": 6
                },
                "Running": {
                  "color": "green",
                  "index": 0
                },
                "Succeeded": {
                  "color": "green",
                  "index": 4
                },
                "Terminated": {
                  "color": "red",
                  "index": 3
                },
                "Unknown": {
                  "color": "red",
                  "index": 7
                },
                "Waiting": {
                  "color": "yellow",
                  "index": 8
                },
                "false": {
                  "color": "red",
                  "index": 2
                },
                "true": {
                  "color": "green",
                  "index": 1
                }
              },
              "type": "value"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green"
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "deckbytes"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 11,
        "w": 8,
        "x": 16,
        "y": 25
      },
      "id": 9,
      "options": {
        "legend": {
          "calcs": [],
          "displayMode": "list",
          "placement": "bottom"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "pluginVersion": "7.5.1",
      "targets": [
        {
          "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
          "queryBody": {
            "pxlScript": "# Copyright 2018- The Pixie Authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n\n''' Node Overview\n\nThis view summarizes the process and network stats for a given input node in a cluster.\nIt computes CPU, memory consumption, as well as network traffic statistics.\nIt also displays a list of pods that were on that node during the time window.\n\n'''\nimport px\n\nns_per_ms = 1000 * 1000\nns_per_s = 1000 * ns_per_ms\n# Window size to use on time_ column for bucketing.\nwindow_ns = px.DurationNanos(10 * ns_per_s)\n\n# $pixieCluster - work around for grafana to update panel on variable change\nnode = '$node'\nstart_time = __time_from\n\ndef pods_for_node(start_time: int, node: px.Node):\n    ''' Gets a list of pods running on the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df.pod = df.ctx['pod_name']\n    df.container = df.ctx['container_name']\n    df = df.groupby(['pod', 'container']).agg()\n    df = df.groupby('pod').agg(containers=('container', px.count))\n    df.start_time = px.pod_name_to_start_time(df.pod)\n    df.status = px.pod_name_to_status(df.pod)\n    return df[['pod', 'start_time', 'containers', 'status']]\n\n\ndef resource_timeseries(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the windowed process stats (CPU, memory, etc) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='process_stats', start_time=start_time)\n    df = df[df.ctx['node_name'] == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate CPU usage by process (UPID) in each k8s_object\n    # over all windows.\n    df = df.groupby(['upid', 'timestamp', groupby]).agg(\n        rss=('rss_bytes', px.mean),\n        vsize=('vsize_bytes', px.mean),\n        # The fields below are counters, so we take the min and the max to subtract them.\n        cpu_utime_ns_max=('cpu_utime_ns', px.max),\n        cpu_utime_ns_min=('cpu_utime_ns', px.min),\n        cpu_ktime_ns_max=('cpu_ktime_ns', px.max),\n        cpu_ktime_ns_min=('cpu_ktime_ns', px.min),\n        read_bytes_max=('read_bytes', px.max),\n        read_bytes_min=('read_bytes', px.min),\n        write_bytes_max=('write_bytes', px.max),\n        write_bytes_min=('write_bytes', px.min),\n        rchar_bytes_max=('rchar_bytes', px.max),\n        rchar_bytes_min=('rchar_bytes', px.min),\n        wchar_bytes_max=('wchar_bytes', px.max),\n        wchar_bytes_min=('wchar_bytes', px.min),\n    )\n    # Next calculate cpu usage and memory stats per window.\n    df.cpu_utime_ns = df.cpu_utime_ns_max - df.cpu_utime_ns_min\n    df.cpu_ktime_ns = df.cpu_ktime_ns_max - df.cpu_ktime_ns_min\n    df.actual_disk_read_throughput = (df.read_bytes_max - df.read_bytes_min) / window_ns\n    df.actual_disk_write_throughput = (df.write_bytes_max - df.write_bytes_min) / window_ns\n    df.total_disk_read_throughput = (df.rchar_bytes_max - df.rchar_bytes_min) / window_ns\n    df.total_disk_write_throughput = (df.wchar_bytes_max - df.wchar_bytes_min) / window_ns\n\n    # Then aggregate process individual process metrics.\n    df = df.groupby(['timestamp', groupby]).agg(\n        cpu_ktime_ns=('cpu_ktime_ns', px.sum),\n        cpu_utime_ns=('cpu_utime_ns', px.sum),\n        actual_disk_read_throughput=('actual_disk_read_throughput', px.sum),\n        actual_disk_write_throughput=('actual_disk_write_throughput', px.sum),\n        total_disk_read_throughput=('total_disk_read_throughput', px.sum),\n        total_disk_write_throughput=('total_disk_write_throughput', px.sum),\n        rss=('rss', px.sum),\n        vsize=('vsize', px.sum),\n    )\n\n    # Finally, calculate total (kernel + user time)  percentage used over window.\n    df.cpu_usage = px.Percent((df.cpu_ktime_ns + df.cpu_utime_ns) / window_ns)\n    df['time_'] = df['timestamp']\n    df.groupby_col = df[groupby]\n    return df.drop(['cpu_ktime_ns', 'cpu_utime_ns', 'timestamp', groupby])\n\n\ndef network_stats(start_time: int, node: px.Node, groupby: str):\n    ''' Gets the network stats (transmitted/received traffic) for the input node.\n\n    Args:\n    @start_time Starting time of the data to examine.\n    @node: The full name of the node to filter on.\n    '''\n    df = px.DataFrame(table='network_stats', start_time=start_time)\n    df = df[px.pod_id_to_node_name(df.pod_id) == node]\n    df[groupby] = df.ctx[groupby]\n    df.timestamp = px.bin(df.time_, window_ns)\n\n    # First calculate network usage by node over all windows.\n    # Data is sharded by Pod in network_stats.\n    df = df.groupby(['timestamp', 'pod_id', groupby]).agg(\n        rx_bytes_end=('rx_bytes', px.max),\n        rx_bytes_start=('rx_bytes', px.min),\n        tx_bytes_end=('tx_bytes', px.max),\n        tx_bytes_start=('tx_bytes', px.min),\n        tx_errors_end=('tx_errors', px.max),\n        tx_errors_start=('tx_errors', px.min),\n        rx_errors_end=('rx_errors', px.max),\n        rx_errors_start=('rx_errors', px.min),\n        tx_drops_end=('tx_drops', px.max),\n        tx_drops_start=('tx_drops', px.min),\n        rx_drops_end=('rx_drops', px.max),\n        rx_drops_start=('rx_drops', px.min),\n    )\n\n    # Calculate the network statistics rate over the window.\n    # We subtract the counter value at the beginning ('_start')\n    # from the value at the end ('_end').\n    df.rx_bytes_per_ns = (df.rx_bytes_end - df.rx_bytes_start) / window_ns\n    df.tx_bytes_per_ns = (df.tx_bytes_end - df.tx_bytes_start) / window_ns\n    df.rx_drops_per_ns = (df.rx_drops_end - df.rx_drops_start) / window_ns\n    df.tx_drops_per_ns = (df.tx_drops_end - df.tx_drops_start) / window_ns\n    df.rx_errors_per_ns = (df.rx_errors_end - df.rx_errors_start) / window_ns\n    df.tx_errors_per_ns = (df.tx_errors_end - df.tx_errors_start) / window_ns\n\n    # Add up the network values per node.\n    df = df.groupby(['timestamp', groupby]).agg(\n        rx_bytes_per_ns=('rx_bytes_per_ns', px.sum),\n        tx_bytes_per_ns=('tx_bytes_per_ns', px.sum),\n        rx_drop_per_ns=('rx_drops_per_ns', px.sum),\n        tx_drops_per_ns=('tx_drops_per_ns', px.sum),\n        rx_errors_per_ns=('rx_errors_per_ns', px.sum),\n        tx_errors_per_ns=('tx_errors_per_ns', px.sum),\n    )\n    df.groupby_col = df[groupby]\n    df['time_'] = df['timestamp']\n    return df.drop(['timestamp', groupby])\n\n\ndef stacktraces(start_time: int, node: str):\n    df = px.DataFrame(table='stack_traces.beta', start_time=start_time)\n\n    df.namespace = df.ctx['namespace']\n    df.pod = df.ctx['pod']\n    df.container = df.ctx['container']\n    df.cmdline = df.ctx['cmdline']\n\n    # Compute node using _exec_hostname() instead of `df.ctx['node']`\n    # We do this so it works for non-k8s processes too.\n    # This is important for determining total number of stack trace samples per node,\n    # as we need to include the non-K8s processes in the computation.\n    df.node = px.Node(px._exec_hostname())\n\n    # When computing percentages below, we want CPU percentages, not Node percentages.\n    # Since a node may have multiple CPUs, the formula is:\n    #    percentage = num_samples_symbol / (num_samples_node / num_cpus )\n    # So grab the number of CPUs and pipe it down to the percentage computation.\n    df.num_cpus = px._exec_host_num_cpus()\n\n    # Filter on the node.\n    df = df[df.node == node]\n\n    # Get stack trace totals for this node.\n    # Do this before any additional filtering.\n    node_agg = df.groupby([\"node\"]).agg(\n        count=('count', px.sum),\n        num_cpus=('num_cpus', px.any)\n    )\n\n    # Filter out non-k8s processes.\n    df = df[df.pod != '']\n\n    # Combine flamegraphs from different intervals into one larger framegraph.\n    df = df.groupby(['node', 'namespace', 'pod', 'container', 'cmdline', 'stack_trace_id']).agg(\n        stack_trace=('stack_trace', px.any),\n        count=('count', px.sum)\n    )\n\n    # Compute percentages.\n    df = df.merge(\n        node_agg,\n        how='inner',\n        left_on=\"node\",\n        right_on=\"node\",\n        suffixes=['', '_x']\n    )\n    df.percent = 100.0 * df.count * df.num_cpus / df.count_x\n    return df.drop('node_x')\n\noutput = resource_timeseries(start_time, node, '$groupby')\noutput.vsize = output.vsize / px.pow(2,10)\noutput = output[['time_', 'vsize','groupby_col']]\n\npx.display(output)"
          },
          "queryType": "run-script",
          "refId": "A"
        }
      ],
      "title": "Virtual Memory Size",
      "type": "timeseries"
    }
  ],
  "schemaVersion": 27,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": [
      {
        "current": {},
        "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
        "definition": "Clusters",
        "hide": 0,
        "includeAll": false,
        "multi": false,
        "name": "pixieCluster",
        "options": [],
        "query": {
          "queryType": "get-clusters"
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "type": "query"
      },
      {
        "current": {},
        "datasource": "${DS_PIXIE_GRAFANA DATASOURCE PLUGIN}",
        "definition": "Node",
        "hide": 0,
        "includeAll": false,
        "multi": false,
        "name": "node",
        "options": [],
        "query": {
          "queryBody": {
            "clusterID": "$pixieCluster"
          },
          "queryType": "get-nodes"
        },
        "refresh": 2,
        "regex": "",
        "skipUrlSync": false,
        "sort": 0,
        "type": "query"
      },
      {
        "current": {
          "selected": false,
          "text": "node",
          "value": "node"
        },
        "description": "",
        "hide": 0,
        "includeAll": false,
        "multi": false,
        "name": "groupby",
        "options": [
          {
            "selected": true,
            "text": "node",
            "value": "node"
          },
          {
            "selected": false,
            "text": "service",
            "value": "service"
          },
          {
            "selected": false,
            "text": "pod",
            "value": "pod"
          },
          {
            "selected": false,
            "text": "namespace",
            "value": "namespace"
          }
        ],
        "query": "node,service,pod,namespace",
        "queryValue": "",
        "skipUrlSync": false,
        "type": "custom"
      }
    ]
  },
  "time": {
    "from": "now-15m",
    "to": "now"
  },
  "timepicker": {},
  "timezone": "",
  "title": "Pixie Node Overview",
  "description": "Dashboard shows the pods on the selected node along with their CPU usage, memory consumption, and network traffic stats. ",
  "uid": "tcpoz_jnz",
  "version": 1,
  "weekStart": "",
  "gnetId": 17000
}