[Device Support Request] - SIN-4-FP-21_EQU

Problem description
I have a Pilot wire heating module (Leroy Merlin version) and I want to control it via ZHA.
Brand : ADEO
Model : SIN-4-FP-21_EQU

At the moment we don't have mode handling, only On and Off (Hors Gel) with power measurement.
Some people seems to have handle this module with Z2M but not ZHA.
https://www.zigbee2mqtt.io/devices/SIN-4-FP-21_EQU.html
https://github.com/Koenkk/zigbee2mqtt/issues/19169
Solution description
We need to have mode handling. There are 6 modes : confort, confort -1, confort -2, eco, Hors Gel, Off.
Screenshots/Video
Screenshots/Video

Device signature
Device signature
{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4727, maximum_buffer_size=82, maximum_incoming_transfer_size=500, server_mask=11264, maximum_outgoing_transfer_size=500, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0051",
      "input_clusters": [
        "0x0000",
        "0x0003",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0702",
        "0x1000",
        "0xfc00"
      ],
      "output_clusters": [
        "0x0019"
      ]
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0066",
      "input_clusters": [
        "0x0021"
      ],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "Adeo",
  "model": "SIN-4-FP-21_EQU",
  "class": "zigpy.device.Device"
}

Diagnostic information
Diagnostic information
{
  "home_assistant": {
    "installation_type": "Home Assistant Supervised",
    "version": "2023.11.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.6",
    "docker": true,
    "arch": "aarch64",
    "timezone": "Europe/Paris",
    "os_name": "Linux",
    "os_version": "6.1.24-v8+",
    "supervisor": "2023.11.3",
    "host_os": "Debian GNU/Linux 11 (bullseye)",
    "docker_version": "24.0.7",
    "chassis": "",
    "run_as_root": true
  },
  "custom_components": {
    "hacs": {
      "version": "1.33.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.36.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.106",
      "zigpy-deconz==0.21.1",
      "zigpy==0.59.0",
      "zigpy-xbee==0.19.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.6",
      "universal-silabs-flasher==0.0.14",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 41678,
    "manufacturer": "Adeo",
    "model": "SIN-4-FP-21_EQU",
    "name": "Adeo SIN-4-FP-21_EQU",
    "quirk_applied": false,
    "quirk_class": "zigpy.device.Device",
    "quirk_id": null,
    "manufacturer_code": 4727,
    "power_source": "Mains",
    "lqi": 176,
    "rssi": -56,
    "last_seen": "2023-11-27T16:20:28",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4727, maximum_buffer_size=82, maximum_incoming_transfer_size=500, server_mask=11264, maximum_outgoing_transfer_size=500, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0051",
          "input_clusters": [
            "0x0000",
            "0x0003",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0702",
            "0x1000",
            "0xfc00"
          ],
          "output_clusters": [
            "0x0019"
          ]
        },
        "242": {
          "profile_id": "0xa1e0",
          "device_type": "0x0066",
          "input_clusters": [
            "0x0021"
          ],
          "output_clusters": [
            "0x0021"
          ]
        }
      },
      "manufacturer": "Adeo",
      "model": "SIN-4-FP-21_EQU"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "button.chauffage_chambres_identifier",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "sensor.chauffage_chambres_demande_instantanee",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "sensor.chauffage_chambres_summation_delivered",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "switch.chauffage_chambres_commutateur",
        "name": "Adeo SIN-4-FP-21_EQU"
      },
      {
        "entity_id": "select.chauffage_chambres_comportement_au_demarrage",
        "name": "Adeo SIN-4-FP-21_EQU"
      }
    ],
    "neighbors": [
      {
        "device_type": "Coordinator",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x0000",
        "permit_joining": "Unknown",
        "depth": "0",
        "lqi": "154"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x1E44",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "114"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x2D56",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "122"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x56B7",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "108"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x88C4",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "88"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0x9E18",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "109"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xCF76",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "125"
      },
      {
        "device_type": "Router",
        "rx_on_when_idle": "On",
        "relationship": "Sibling",
        "extended_pan_id": "**REDACTED**",
        "ieee": "**REDACTED**",
        "nwk": "0xD40F",
        "permit_joining": "Unknown",
        "depth": "15",
        "lqi": "123"
      }
    ],
    "routes": [
      {
        "dest_nwk": "0x0000",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x0000"
      },
      {
        "dest_nwk": "0xAB2E",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0xAB2E"
      },
      {
        "dest_nwk": "0xCF76",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x1E44"
      },
      {
        "dest_nwk": "0x56B7",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0x56B7"
      },
      {
        "dest_nwk": "0xD40F",
        "route_status": "Active",
        "memory_constrained": false,
        "many_to_one": false,
        "route_record_required": false,
        "next_hop": "0xD40F"
      }
    ],
    "endpoint_names": [
      {
        "name": "SMART_PLUG"
      },
      {
        "name": "COMBO_BASIC"
      }
    ],
    "user_given_name": "Chauffage Chambres",
    "device_reg_id": "50237090f1dac5121b7c9eb9b8bdf801",
    "area_id": "chambre",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "SMART_PLUG",
          "id": 81
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "Adeo"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "SIN-4-FP-21_EQU"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0003": {
            "endpoint_attribute": "identify",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0x0000": {
                "attribute_name": "on_off",
                "value": 1
              },
              "0x4003": {
                "attribute_name": "start_up_on_off",
                "value": 255
              }
            },
            "unsupported_attributes": {}
          },
          "0x0702": {
            "endpoint_attribute": "smartenergy_metering",
            "attributes": {
              "0x0000": {
                "attribute_name": "current_summ_delivered",
                "value": 39737
              },
              "0x0304": {
                "attribute_name": "demand_formatting",
                "value": 19
              },
              "0x0302": {
                "attribute_name": "divisor",
                "value": 1000
              },
              "0x0400": {
                "attribute_name": "instantaneous_demand",
                "value": 1028
              },
              "0x0306": {
                "attribute_name": "metering_device_type",
                "value": 0
              },
              "0x0301": {
                "attribute_name": "multiplier",
                "value": 1
              },
              "0x0200": {
                "attribute_name": "status",
                "value": 0
              },
              "0x0303": {
                "attribute_name": "summation_formatting",
                "value": 59
              },
              "0x0300": {
                "attribute_name": "unit_of_measure",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0100": {
                "attribute_name": "current_tier1_summ_delivered"
              },
              "0x0102": {
                "attribute_name": "current_tier2_summ_delivered"
              },
              "0x0104": {
                "attribute_name": "current_tier3_summ_delivered"
              },
              "0x0106": {
                "attribute_name": "current_tier4_summ_delivered"
              },
              "0x0108": {
                "attribute_name": "current_tier5_summ_delivered"
              },
              "0x010a": {
                "attribute_name": "current_tier6_summ_delivered"
              }
            }
          },
          "0x1000": {
            "endpoint_attribute": "lightlink",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0xfc00": {
            "endpoint_attribute": "manufacturer_specific",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      },
      "242": {
        "device_type": {
          "name": "COMBO_BASIC",
          "id": 102
        },
        "profile_id": 41440,
        "in_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs
Logs
[Paste the logs here]

Custom quirk
Custom quirk
[Paste your custom quirk here]

Additional information
No response

Hello, i have those devices since a couple of days. I'm using Deconz (Phoscon) to add device to my zigbee network: devices are recognized as Lamp in Phoscon and i can only On and Off but without power measurement. So there is also no Power Measurement in Home Assistant (ZHA).
What have you done to see power measurement?

Hello,
I just paired modules to Home Assistant and they were recognized as a socket and the consumption information came automatically

Ok thanks. I finally removed DeconZ and i replaced it with ZHA. I have now "Commutateur", "Demande instantanée" and "Summation delivered" but not "Consommation chauffage". Is it usefull?

Oh yes sorry this one is a manual entry to know how much consumption I have each day

I'm also interested. It will be interesting to check if the device is the same with SIN-4-fp-21 because they are both made by nodon
Ce post m'intéresse aussi. Il serait intéressant de voir si un développement peut permettre de faire fonctionner la référence du fabricant Nodon: la sin-4-fp-21

Great! Can you explain me how to do that please?

Into parameters, in entries tab, create a new one, you need to choose a utiliy meter (water, electricity) in french its "Compteur de services publics (eau, gaz, électricité…)" and set the same parameters as the screenshot

I'm also interested. It will be interesting to check if the device is the same with SIN-4-fp-21 because they are both made by nodon
Ce post m'intéresse aussi. Il serait intéressant de voir si un développement peut permettre de faire fonctionner la référence du fabricant Nodon: la sin-4-fp-21

I think it's the same, I see somewhere else on github that people reference the SIN-4-FP-21 as the same device as the SIN-4-FP-21_EQU.

Great! Can you explain me how to do that please?

Into parameters, in entries tab, create a new one, you need to choose a utiliy meter (water, electricity) in french its "Compteur de services publics (eau, gaz, électricité…)" and set the same parameters as the screenshot

Thnaks!!

Any news on this ?
Is everything working with ZHA ?

Any news on this ? Is everything working with ZHA ?

Hi,
I asked directly the manufecturer for information. For Z2M the integration will be available in late January but for ZHA it will be available later.

I flag here to follow. I have several of these modules on my heaters and I would like more that consumption and on/off. :)

hi,
I am also interested in this integration under ZHA: the SIN-4-FP-21 boxes seem very good, I am waiting to be able to control my radiators with them.

Same issue here. added yesterday to HA through ZHA, it shows a switch toggle,  and consumption, but no control to the heater.
I aslo have to mention that the "switch" part of the module has no effect on y heater, which is kind of weird to me.

Hi i've asked to Nodon's support and they told me the ZHA intégration is on
the pipe and it will be released in the coming weeks.
Seb
Le ven. 1 mars 2024, 10:10, laur3nt95 @.***> a écrit :

Same issue here. added yesterday to HA through ZHA, it shows a switch
toggle, and consumption, but no control to the heater.
I aslo have to mention that the "switch" part of the module has no effect
on y heater, which is kind of weird to me.
—
Reply to this email directly, view it on GitHub
https://github.com/zigpy/zha-device-handlers/issues/2777#issuecomment-1972799249,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/A6BFTUPNNVFWJL37I4AENT3YWBAXHAVCNFSM6AAAAAA74GUVVWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNZSG44TSMRUHE
.
You are receiving this because you are subscribed to this thread.Message
ID: @.***>

Hi,
I have a SIN-4-FP-21 (the one from Nodon), and I am able to use it with ZHA, via zha_toolkit, with the help of https://github.com/Koenkk/zigbee2mqtt/issues/19169#issuecomment-1801181411 .
You can use zha_toolkit.scan_device to scan your zigbee device for all its informations, and look at the "Manufacture specific" cluster_id:
        "0xfc00": {
          "cluster_id": "0xfc00",
          "title": "Manufacturer Specific",
          "name": "manufacturer_specific",
          "attributes": {
            "0x0000": {
              "attribute_id": "0x0000",
              "attribute_name": "0",
              "value_type": [
                "0x20",
                "uint8_t",
                "Analog"
              ],
              "access": "READ|WRITE|REPORT",
              "access_acl": 7,
              "manf_id": 4747,
              "attribute_value": 1
            }
          },
          "commands_received": {},
          "commands_generated": {}
        }

Now you can send command to the module:
service: zha_toolkit.attr_write
data:
  ieee: xx:xx:xx:xx:xx:xx # your sin-4-fp-21 module id
  manf: 4747 # 0x128b, nodon
  endpoint: 1
  cluster: 64512 # 0xfc00
  attribute: 0 # which attribute we want to write, only 0 / 0x0000 is available in this cluster
  attr_val: "1" # 1: Confort, 2: Eco, 3: Hors Gel, see https://github.com/Koenkk/zigbee2mqtt/issues/19169#issuecomment-1801181411

Et voila©®, you can now integrate it in custom configuration in HA.
I hope this can help you, until Nodon/ZHA-device-handlers integrate this natively :)

They just changed their support page with devices compatibility... Bad news for SIN-4-FP-21, it seems that HA is through Z2M only...

Does anybody know if the information above can be used to write a Quirk for ZHA? Btw. Thanks a lot @Skunnyk for finding this information!

I've posted a quirk in #3040 that may also support ADEO variant.
Feel free to test.

Hello I made some adaptations of Nodon quirk in #3040 to make it working with Adeo device.
Here is the code of custom quirk working for me:
"""Adeo SIN-4-FP-21_EQU pilot wire module."""
from typing import Any, Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef,
    WriteAttributesStatusRecord,
    Status
)

from zigpy.zcl import ClusterType

import zigpy.types as t

import logging
_LOGGER = logging.getLogger(__name__)

class NodonPilotWireMode(t.enum16):
    OFF = 0x00
    COMFORT = 0x01
    ECO = 0x02
    FROST_PROTECTION = 0x03
    COMFORT_MINUS_1 = 0x04
    COMFORT_MINUS_2 = 0x05

NODON_PILOT_WIRE_CLUSTER_ID = 0xfc00  #64512

class NodonPilotWireCluster(CustomCluster):
    """NodOn pilot wire manufacturer-specific cluster."""

    cluster_id: Final = NODON_PILOT_WIRE_CLUSTER_ID
    name: Final = "Pilot Wire"
    ep_attribute: Final = "pilot_wire_cluster"
    manufacturer_id_override: Final = 4747

    class AttributeDefs(BaseAttributeDefs):
        pilot_wire_mode: Final = ZCLAttributeDef(
            id=0x0000,
            type=NodonPilotWireMode,
            access="r"
        )

    class ClientCommandDefs(BaseCommandDefs):
        setMode: Final = ZCLCommandDef(
            id=0x0000,
            schema={"mode": NodonPilotWireMode},
            direction=True,
            is_manufacturer_specific=True
        )

    async def write_attributes(
        self, attributes: dict[str | int, Any], manufacturer: int | None = None
    ) -> list:
        """Override writes to the pilot_wire_mode attribute."""
        if "pilot_wire_mode" in attributes:
            await self.client_command(0, attributes.get("pilot_wire_mode"), manufacturer=4747)
            await self.read_attributes(attributes)
            return [[WriteAttributesStatusRecord(Status.SUCCESS)]]
        return await super().write_attributes(attributes, manufacturer=4747)

    async def read_attributes(
        self,
        attributes: list[int | str],
        allow_cache: bool = False,
        only_cache: bool = False,
        manufacturer: int | t.uint16_t | None = None,
    ) -> Any:
        return await super().read_attributes(attributes, allow_cache=False, only_cache=False, manufacturer=4747)

(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("Adeo","SIN-4-FP-21_EQU")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

Will test it ASAP! THANKS!

Hello I made some adaptations of Nodon quirk in #3040 to make it working with Adeo device. Here is the code of custom quirk working for me:
"""Adeo SIN-4-FP-21_EQU pilot wire module."""
from typing import Any, Final
from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, EntityType, EntityPlatform
from zigpy.zcl.foundation import (
    BaseAttributeDefs,
    BaseCommandDefs,
    ZCLAttributeDef,
    ZCLCommandDef,
    WriteAttributesStatusRecord,
    Status
)

from zigpy.zcl import ClusterType

import zigpy.types as t

import logging
_LOGGER = logging.getLogger(__name__)

class NodonPilotWireMode(t.enum16):
    OFF = 0x00
    COMFORT = 0x01
    ECO = 0x02
    FROST_PROTECTION = 0x03
    COMFORT_MINUS_1 = 0x04
    COMFORT_MINUS_2 = 0x05

NODON_PILOT_WIRE_CLUSTER_ID = 0xfc00  #64512

class NodonPilotWireCluster(CustomCluster):
    """NodOn pilot wire manufacturer-specific cluster."""

    cluster_id: Final = NODON_PILOT_WIRE_CLUSTER_ID
    name: Final = "Pilot Wire"
    ep_attribute: Final = "pilot_wire_cluster"
    manufacturer_id_override: Final = 4747

    class AttributeDefs(BaseAttributeDefs):
        pilot_wire_mode: Final = ZCLAttributeDef(
            id=0x0000,
            type=NodonPilotWireMode,
            access="r"
        )

    class ClientCommandDefs(BaseCommandDefs):
        setMode: Final = ZCLCommandDef(
            id=0x0000,
            schema={"mode": NodonPilotWireMode},
            direction=True,
            is_manufacturer_specific=True
        )

    async def write_attributes(
        self, attributes: dict[str | int, Any], manufacturer: int | None = None
    ) -> list:
        """Override writes to the pilot_wire_mode attribute."""
        if "pilot_wire_mode" in attributes:
            await self.client_command(0, attributes.get("pilot_wire_mode"), manufacturer=4747)
            await self.read_attributes(attributes)
            return [[WriteAttributesStatusRecord(Status.SUCCESS)]]
        return await super().write_attributes(attributes, manufacturer=4747)

    async def read_attributes(
        self,
        attributes: list[int | str],
        allow_cache: bool = False,
        only_cache: bool = False,
        manufacturer: int | t.uint16_t | None = None,
    ) -> Any:
        return await super().read_attributes(attributes, allow_cache=False, only_cache=False, manufacturer=4747)

(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("Adeo","SIN-4-FP-21_EQU")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

Shouldn't the last part with "QuirkBuilder" be like this?
(

    QuirkBuilder("ADEO", "SIN-4-FP-21_EQU")
    .also_applies_to("NodOn","SIN-4-FP-21")
    .replaces(NodonPilotWireCluster)
    .enum("pilot_wire_mode",NodonPilotWireMode,NODON_PILOT_WIRE_CLUSTER_ID,
        ClusterType.Server,1,EntityType.STANDARD,EntityPlatform.SELECT,False,True)
    .add_to_registry()
)

I’m not sure the manufacturer override works for nodon device.
Furthermore the name of manufacturer in signature is Adeo not ADEO on my setup. I don’t it is always the case or not.

Hi! It took me a while but I tested the quirk right now.
Quirk execute with no issue. My warmers are well discovered and use the quirk. I guess that as a lot of attribute names changed.

Nothing about changing the pilot-wire setup from eco to something else.
I'm not sure the quirk was doing this, either. But I hoped :)

FYI: https://github.com/zigpy/zha-device-handlers/pull/3364 got merged. It supports both NodOn and Adeo. The code should become part of the 2024.12 release. Unfortunately, the change comes with only ZHA attributes (one which changes via "Manage Zigbee Device") and not with enum in the HA interface due to concerns from maintainers.

To anyone interested in a temporary workaround based on the recent #3364
Here is a template Select allowing you to change mode directly within HA.
Unfortunately, I do not found a way to read the attribute value yet. If anyone as a clue about how i can sync it with se template select state, i'll take it !
template:
  - select:
        name: "Mode seche serviette"
        icon: mdi:radiator
        unique_id: "select_mode_seche_serviette"
        options: >-
            {{
            [
                "Off",
                "Confort",
                "Eco",
                "Hors Gel",
                "Confort -1",
                "Confort -2"
            ]
            }}
        state: >-
            {% set cluster_value = state_attr('zha.d4:48:67:ff:fe:aa:33:e0', 'cluster_0xfc00_in_0x0000')|default('0') %}
            {% set modes = {
            '0x00': 'Off',
            '0x01': 'Confort',
            '0x02': 'Eco',
            '0x03': 'Hors Gel',
            '0x04': 'Confort -1',
            '0x05': 'Confort -2'
            } %}
            {{ modes[cluster_value|string] }}
        select_option:
            - service: zha.set_zigbee_cluster_attribute
              data:
                cluster_type: "in"
                endpoint_id: 1
                cluster_id: 64512
                ieee: "d4:48:67:ff:fe:aa:33:e0"
                attribute: 0
                value: >-
                    {% set modes = {
                    'Off': 'NodOnPilotWireMode.Off',
                    'Confort': 'NodOnPilotWireMode.Comfort',
                    'Eco': 'NodOnPilotWireMode.Eco',
                    'Hors Gel': 'NodOnPilotWireMode.FrostProtection',
                    'Confort -1': 'NodOnPilotWireMode.ComfortMinus1',
                    'Confort -2': 'NodOnPilotWireMode.ComfortMinus2'
                    } %}
                    {{ modes[option] }}

To anyone interested in a temporary workaround based on the recent https://github.com/zigpy/zha-device-handlers/pull/3364
Here is a template Select allowing you to change mode directly within HA.
Unfortunately, I do not found a way to read the attribute value yet. If anyone as a clue about how i can sync it with se template select state, i'll take it !
template:
  - select:
        name: "Mode seche serviette"
        icon: mdi:radiator
        unique_id: "select_mode_seche_serviette"
        options: >-
            {{
            [
                "Off",
                "Confort",
                "Eco",
                "Hors Gel",
                "Confort -1",
                "Confort -2"
            ]
            }}
        state: ""
        select_option:
            - service: zha.set_zigbee_cluster_attribute
              data:
                cluster_type: "in"
                endpoint_id: 1
                cluster_id: 64512
                ieee: "<device-address>"
                attribute: 0
                value: >-
                    {% set modes = {
                    'Off': 'NodOnPilotWireMode.Off',
                    'Confort': 'NodOnPilotWireMode.Comfort',
                    'Eco': 'NodOnPilotWireMode.Eco',
                    'Hors Gel': 'NodOnPilotWireMode.FrostProtection',
                    'Confort -1': 'NodOnPilotWireMode.ComfortMinus1',
                    'Confort -2': 'NodOnPilotWireMode.ComfortMinus2'
                    } %}
                    {{ modes[option] }}


CI Integration

Still need to bring gitlab yaml into this and do some CI integration.
Best to resolve it first in the typescript-demo-lib though.

Done with #11.

Done with #11.


All pycodestyle issues disappeared after upgrade

I was on my way fixing some pycodestyle issues and then upgraded my ide-python to the latest 0.8.0. However, all the pycodestyle issues that I was trying to fix disappeared in my code. Is anyone else having this issue? Let me know if you need more information to reproduce this.

@lgeiger I saw you added this commit: https://github.com/lgeiger/ide-python/commit/97cb04bfee25713fa3b3a18b990388ebe7343181
However,  it seems like select and ignore should be of string type instead of array? Please correct me if I am wrong since I am not really familiar with pycodestyle.

There was a bug in an earlier version of python-langiage-server. Could you update to the latest version and try again?

Thanks. It works now again!


[BugFix] Avoid copying model in losses

I think we still need to copy the model, otherwise we may end up in complicated situations where one model is de-populated from its params and the collector (which uses the same model) ends up with a stateless model.


Bug with offline wallet setup

Very good hardware wallet, congratulations to the team!
But I just figured out a bug, I tried to create my wallet offline without any connexion to ensure nothing related to my private key is sent during this process.
It does work only for the primary card, impossible to add the backup card.
The normal behavior should be to offer to bypass the online certificate check for the backup card as it is offered for the primary card. But as you can see in this video, it's not offered. The only way to configure the backup card is to go back online.
https://github.com/user-attachments/assets/fe77050a-862f-42d3-aeb2-cf700df2facf

You don't need an internet connection to generate/import the seed phrase, thus, a phone without Wi-Fi or a SIM card can be used at this step. However, an internet connection is necessary when creating a backup to download the certificates. Even so, you can initiate the seed phrase import on one device and proceed with the backup on another device that has internet access.
It is irrelevant whether there is an internet connection on the phone, as the seed phrase is generated directly on the device and does not require an internet connection. Nonetheless, some users express concerns about security, fearing that the seed could be transmitted from the phone. We would like to clarify that this is not the case. The seed is not stored in any location. Instead, it is used to generate a private key, which is subsequently transferred to the card.
More information can be found here:
https://tangem.com/en/blog/post/how-tangem-wallet-backs-up-private-keys/
https://tangem.com/en/blog/post/setup-without-seed-phrase/


Ansibilize Horton Bot

HI JOHN
Ok here's an initial working set of playbooks for deploying the bot. Some notes below:

I'm targeting master in bot.yml, so to test you'll need to pass in this branch as follows:

$ ansible-playbook setup.yml --ask-vault-pass --extra-vars "ansistrano_git_branch=ansibilize"

In before_symlink you'll see i have become: no which I know is normally redundant. But in this case the hook is inheriting yes upstream and so I had to explicitly set it to no here so the vagrant user could access it's installed bundler binary

In puma.service I'm passing in the slack token via ENVIRONMENT. I'm especially curious what you think about this. It works, but is obviously writing the token into the service file. If there's a better place/way to set the variable let me know.

The vault password is in LastPass in Shared-DevOps/Library Slack Bot - Vault Password

Fixes: #24 #5

The only show stoppers I have seen:

the ansistrano_git_branch pointing to not-master.
Using hosts: in a play is ignored. You need connection: local to prevent running on the remote host, and the run_once: true to ensure the timestamp is generated only once even when pushing to multiple hosts.

Placing become: between   name: and the module itself is personally distasteful to me, but not enough of a show stopper to demand fixing.
This PR also bumps ruby to 2.4.2, which I don't think is in the master branch yet.

I think it is pointing to master already? https://github.com/ucsdlib/horton-bot/pull/51/files#diff-e32d9925e6709cfcec416425566787f6R28

Will to. Tbh, I pulled the initial version of this from the horton/notch8 playbook.. so eek. But I'll update it!

@jhriv - let me know if https://github.com/ucsdlib/horton-bot/pull/51/commits/a6c5a1fe3ac6ed1b7b6f38e67a6dcfedbcaf18d5 addresses the issues with that task. Thanks!

@jhriv - any other changes you want to see here? If not, merge please? :)


vendor: Update tfortools to version v0.1.0

This new version of tfortools contains methods to help us clean up
our help messages in ciao-cli.
Signed-off-by: Mark Ryan<EMAIL_ADDRESS>

Coverage remained the same at 65.915% when pulling 86d2daa1bc0dd720f3b992848ffbef98ff93c69a on markdryan:tfortools0.1.0 into 086750f820eead4f154a78f726995ec1751ef5ed on ciao-project:master.

Coverage remained the same at 65.915% when pulling 86d2daa1bc0dd720f3b992848ffbef98ff93c69a on markdryan:tfortools0.1.0 into 086750f820eead4f154a78f726995ec1751ef5ed on ciao-project:master.

Coverage increased (+0.004%) to 65.927% when pulling ba0e1933c252df92cf872acbe47ad9e5ea0112d4 on markdryan:tfortools0.1.0 into 6e244e54ed5347da9b02d6efc35d8a3a0138e518 on ciao-project:master.


FastAPI response model issue with SQLalchemy 1.4

Checks

[x] I added a descriptive title to this issue
[x] I have searched (google, github) for similar issues and couldn't find anything
[x] I have read and followed the docs and still think this is a bug

Not sure if this is the correct place for this, if not please notify where it would be better suited.
Bug
When using SQLAlchemy 1.3 with FastAPI and pydantic you could do this:

def get_users(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.User).offset(skip).limit(limit).all()

class UserBase(BaseModel):
    email: str

class User(UserBase):
    id: int
    is_active: bool
    items: List[Item] = []

    class Config:
        orm_mode = True

@app.get("/users/", response_model=List[schemas.User])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_users(db, skip=skip, limit=limit)
    return users

The result as expected is as follows:
[
  {
    "email": "string",
    "id": 1,
    "is_active": true,
    "items": []
  }
]

But when you upgrade to SQLAlchemy 1.4 the response_model breaks.
async def get_users(db: AsyncSession, skip: int = 0, limit: int = 100):
    db_execute = await db.execute(select(models.User).offset(skip).limit(limit))
    return db_execute.all()

@app.get("/users/", response_model=List[schemas.User])
async def read_users(skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db)):
    crud_users = await crud.get_users(db, skip=skip, limit=limit)
    return crud_users

INFO:     <IP_ADDRESS>:60298 - "GET /users/?skip=0&limit=100 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 389, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/fastapi/applications.py", line 179, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc from None
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/exceptions.py", line 82, in __call__
    raise exc from None
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/routing.py", line 227, in handle
    await self.app(scope, receive, send)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/starlette/routing.py", line 41, in app
    response = await func(request)
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/fastapi/routing.py", line 190, in app
    response_data = await serialize_response(
  File "/Users/user/code-utils/test_env/lib/python3.9/site-packages/fastapi/routing.py", line 111, in serialize_response
    raise ValidationError(errors, field.type_)
pydantic.error_wrappers.ValidationError: 6 validation errors for User
response -> 0 -> email
  field required (type=value_error.missing)
response -> 0 -> id
  field required (type=value_error.missing)
response -> 0 -> is_active
  field required (type=value_error.missing)
response -> 1 -> email
  field required (type=value_error.missing)
response -> 1 -> id
  field required (type=value_error.missing)
response -> 1 -> is_active
  field required (type=value_error.missing)

A quick fix I found:
async def get_users(db: AsyncSession, skip: int = 0, limit: int = 100):
    db_execute = await db.execute(select(models.User).offset(skip).limit(limit))
    return_items = []
    for item in db_execute.all():
        return_items.append(item[0].__dict__)
    return return_items

Entire example can be found here: https://github.com/tiangolo/fastapi/pull/2331
Again I'm not sure if this is the correct repository for this, so please notify where would it be better suited.

See my comment on the other issue, this isn't a pydantic issue


Question: Similar to DuckDB Node JS API

Hello @auxten
I am talking with a few enthusiasts and we are considering to add a few things that will improve the developers' experience on CHDB.
We could work on a proof of concept but first we would like to know if you would be interested to have similar to DuckDB Node JS API - ref: https://duckdb.org/docs/api/nodejs/overview
Something like this that would make it easier when building queries:
db.all('SELECT ?::INTEGER AS fortytwo, ?::VARCHAR AS hello', 42, 'Hello, World', function(err, res) {
  if (err) {
    console.warn(err);
    return;
  }
  console.log(res[0].fortytwo)
  console.log(res[0].hello)
});

Nice, you are right. This style is more Node JS style. I will try to sort it out how to do that. But frankly speaking, I'm not a JS expert. If you would like to help on this and I could do the C/C++ part ;)


Support Native Private Field Emission

Suggestion

🔍 Search Terms

Private field emission
✅ Viability Checklist

My suggestion meets these guidelines:

[X] This wouldn't be a breaking change in existing TypeScript/JavaScript code
[X] This wouldn't change the runtime behavior of existing JavaScript code
[X] This could be implemented without emitting different JS based on the types of the expressions
[X] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
[X] This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion
In Node 15+ (v8 8.x), the runtime provides complete support for native private fields, and methods. This additionally includes static level fields/methods as well. Node 12+ includes some support, but does not completely cover the private field specification.
Currently, the compilation target ESNext produces the WeakMap implementation, which incurs performance overhead.  It would be ideal to be able to emit native code when possible, even if its behind a feature flag.
💻 Use Cases
More efficient code, and better runtime performance, by offloading complexity to the underlying engine.

Chrome/V8 also has support for private fields and private methods/accessors: https://v8.dev/features/class-fields

Currently, the compilation target ESNext produces the WeakMap implementation

This is not true for TypeScript 4.2: Playground link

The playground appears to be behaving oddly, when I pull up the link above, I see the output target as ES3.
Additionally, I had an override locally that I had missed, and setting the output to ESNext does indeed seem to preserve the native private syntax.  This means this is working as intended and can be closed.


Reports on medical_event collection with PowerBI

[x] Create MongoDB ODBC Connection to Power BI on Dev

[ ] Create Reports with DEV PowerBI

[ ] Deploy on prod

[ ] Run test reports on PROD

Blocked by:
[SOLVED] https://github.com/edenlabllc/ehealth.api/issues/3275

As we already deployed mongodb connector. @danakonovalenko or @IrinaRevutska can proceed with generating reports.


These 4 params are the next candidate for Class because

watts, t_average, duty, dbi: They are quite repetitive params to many of our functions and very often co-occuring.
https://github.com/zimolzak/fcc-rf-formulas/blob/fa27937e5ade94f9b8a644283199846cecf0def9/fcc.py#L147

Closed by e2c63328570d695fec6ec1913fe3142090681f02


[Feature] Hide [...] tab on android device

Device
Phone/Tablet
Operating System
Android
Browser
Kiwi Browser
Suggestion
I'm using the android app, I used to use the kiwi browser prior to thats release.
I have an idea to remove the [...] tab that is always present on the screen. Maybe there could be a setting in options (so people could opt in if interested) to add a user pinch gesture that can hide/show that button. I'm pretty sure this button is being rendered inside of /src/modules/stream/stream-ui.ts.
On a laptop I can remove the button by using the dev console, isolating the button, and setting display: none;. I'm really just looking to add an option that will let me do this on my android device.
I'm not familiar with TS so I'm unsure where this button is being styled within the app - if you point me in that direction I'd be happy to make a POC branch.
Thank you for your time and this app is awesome.

Which button are you referring?

This button

You can hide it since version 1 of the script https://better-xcloud.github.io/features/#hide-system-menus-icon

Wow, thanks for letting me know! Like I said, awesome app. Cheers.


[SPARK-38767][SQL] Support ignoreCorruptFiles and ignoreMissingFiles in Data Source options

What changes were proposed in this pull request?
Support ignoreCorruptFiles and ignoreMissingFiles in Data Source options for both V1 and V2 file-based data sources.
spark.read...option("ignoreCorruptFiles", "true")...
spark.read...option("ignoreMissingFiles", "true")...

Why are the changes needed?
Improve UX
Does this PR introduce any user-facing change?
Yes.
Previously:
spark.sql("set spark.sql.files.ignoreCorruptFiles=true")
spark.sql("set spark.sql.files.ignoreMissingFiles=true")
spark.read...
spark.read...

Now:
spark.read...option("ignoreCorruptFiles", "true")...
spark.read...option("ignoreMissingFiles", "true")...

How was this patch tested?
Enhance existing UTs for ignoreMissingFiles + ignoreCorruptFiles

cc: @cloud-fan appreciate it if you can take a look whenever you have time, thanks!

Can one of the admins verify this patch?

@cloud-fan Addressed your comments, thanks for that! also, add a test in FileBasedDataSourceSuite.

Thank you, @Yaohua628 and @cloud-fan .

I updated the Affected Version of this improvement JIRA to 3.4.0 from 3.2.1.
I left one minor comment for the naming about parsedOptions.

Thanks for fixing Affected Version! Also, renamed to options.

we would have to document it at https://github.com/apache/spark/blob/master/docs/sql-data-sources-generic-options.md

Thanks! Added doc and updated examples.
cc: @cloud-fan

Merged to master for Apache Spark 3.4.0.
Thank you, @Yaohua628 , @cloud-fan , @HyukjinKwon

Welcome to the Apache Spark community, @Yaohua628 .
I added you to the Apache Spark contributor group and SPARK-38767 is assigned to you.

@dongjoon-hyun Thank you!! 🎉
(btw I think you assigned to the wrong person "Yaohua Cui", should be "Yaohua Zhao", :-P. I know, it's confusing)

Oh.. Sorry. Now I fixed it. BTW, this is the previous my worklog. Although I chose 1 for Yaohua Zhao and it showed you correctly in the log, it seems that Apache Spark script had some bug for those two IDs. Maybe, I can take a look at that later. BTW, thank you for informing that.
JIRA is unassigned, choose assignee
[1] Yaohua Zhao (Reporter)
Enter number of user, or userid, to assign to (blank to leave unassigned):1
=== JIRA SPARK-38767 ===
summary		Support ignoreCorruptFiles and ignoreMissingFiles in Data Source options
assignee	Yaohua Zhao
status		In Progress
url		https://issues.apache.org/jira/browse/SPARK-38767

Enter comma-separated fix version(s) [3.4.0]:
Successfully resolved SPARK-38767 with fixVersions=['3.4.0']!

Oh.. Sorry. Now I fixed it. BTW, the following is the previous my worklog. Although I chose 1 for Yaohua Zhao and it showed you correctly in the log, it seems that Apache Spark script had some bug for those two IDs. Maybe, I can take a look at that later. BTW, thank you for informing that.
JIRA is unassigned, choose assignee
[1] Yaohua Zhao (Reporter)
Enter number of user, or userid, to assign to (blank to leave unassigned):1
=== JIRA SPARK-38767 ===
summary		Support ignoreCorruptFiles and ignoreMissingFiles in Data Source options
assignee	Yaohua Zhao
status		In Progress
url		https://issues.apache.org/jira/browse/SPARK-38767

Enter comma-separated fix version(s) [3.4.0]:
Successfully resolved SPARK-38767 with fixVersions=['3.4.0']!

Ah got it! Not a problem. Thank you so much for the help on this PR!!

it seems that Apache Spark script had some bug for those two IDs.

might relate to this one, a JIRA python client bug: https://github.com/pycontribs/jira/issues/1049

@dongjoon-hyun hi Dongjoon, just realize I probably need to fix here by passing the options in InMemoryFileIndex, where ignoreMissingFiles is used, right? Please correct me if I misunderstand this part! Thanks a lot!

@cloud-fan @dongjoon-hyun Hi folks, do you know when the doc changes will be deployed? https://spark.apache.org/docs/latest/sql-data-sources-generic-options.html? Thanks!

@Yaohua628  As I commented https://github.com/apache/spark/pull/36069#issuecomment-1097149876 , this is Apache Spark 3.4.0 for next year. What you are referring is Apache Spark 3.3, isn't it?
For Apache Spark 3.4.0, we just started to discuss about the release plan in the dev mailing list.

https://lists.apache.org/thread/0dt1n6rhhhvsyj48y8bfq3sxvxvlpn57

FYI, Apache Spark 3.4 code freeze was March 15th, 2022. This patch simply arrived one month later after code freeze deadline.

https://spark.apache.org/versioning-policy.html

@dongjoon-hyun Oh yeah, you are right! Thanks for your clarification!


AIY Vision kit 1.1 Pi WH - Cannot use Picamera() inside a function or a loop

Hi there!
I have been fiddling around the Picamera module a little bit and I noticed that when using Picamera() inside a function or a loop I would consistently get this error message.
mmal: mmal_vc_port_enable: failed to enable port vc.null_sink:in:0(OPQV): ENOSPC
mmal: mmal_port_enable: failed to enable connected port (vc.null_sink:in:0(OPQV))0x13a49b0 (ENOSPC)
mmal: mmal_connection_enable: output port couldn't be enabled
Traceback (most recent call last):
  File "funSetup_v3.py", line 388, in <module>
    main()
  File "funSetup_v3.py", line 385, in main
    camera = PiCamera()
  File "/usr/lib/python3/dist-packages/picamera/camera.py", line 433, in __init__
    self._init_preview()
  File "/usr/lib/python3/dist-packages/picamera/camera.py", line 513, in _init_preview
    self, self._camera.outputs[self.CAMERA_PREVIEW_PORT])
  File "/usr/lib/python3/dist-packages/picamera/renderers.py", line 558, in __init__
    self.renderer.inputs[0].connect(source).enable()
  File "/usr/lib/python3/dist-packages/picamera/mmalobj.py", line 2212, in enable
    prefix="Failed to enable connection")
  File "/usr/lib/python3/dist-packages/picamera/exc.py", line 184, in mmal_check
    raise PiCameraMMALError(status, prefix)
picamera.exc.PiCameraMMALError: Failed to enable connection: Out of resources

I checked the cables. All good. I have the most recent update, upgrade and firmware update available.
sudo apt-get update
sudo apt-get upgrade
sudo rpi-update

I even run this for good measure.
sudo apt --fix-broken install
I tried increasing the memory, by different increment up to 256. It didn't work.
I also rebooted every time I had this error message.
Between each attempt I also did
pkill python3
Then...
I tried the 'with' way.
def timelapse():
    with picamera.PiCamera() as camera:

I also tried to define the camera outside my function.
camera = Picamera()
def recordVideo():
    camera.resolution = (1640, 922)  # Full Frame, 16:9 (Camera v2)

Then Python told me the variable was accessed before it was created.
I also tried to give the camera global scope.
global camera
camera = Picamera()
def recordVideo():
    camera.resolution = (1640, 922)  # Full Frame, 16:9 (Camera v2)

Any workaround I missed about this?

It's definitely not related to inside/outside function or loop. Can you check camera using raspivid or raspistill command line tools? Did you disable JoyDemo service running in background (it uses the camera and camera cannot be shared between processes)?

Hi @dmitriykovalev !
I disabled the JoyDemo (First thing I do on a fresh install, those beeps drive me nuts lol). I will take your word on the scope part because since then I have been going about it differently. I did check the raspivid and raspistill command line tools and got the same error.
Coming back to the fact that the camera cannot be shared between processes... I know there's the splitter in the doc for streaming and recording at the same time, but what about when the script crashes (e.g. because of a lack of memory) or in the event of a KeyboardInterrupt (without a try/catch). How would you free the camera? The pkill python3 doesn't seem to work 100% of the time. Is there a way to free the camera? Also, Is there a way to unload the inference models? Can inference.close() be used?

Regarding close() functions: camera.close() frees all camera resources and stops camera, inference.close() frees inference resources (unloads model from the bonnet) and stops inferences. That's why you should typically use "with picamera.PiCamera() as camera" or "with CameraInference() as inference" to have these close() functions called automatically.
Can you try our example code (e.g. face_detection_camera.py), does it work on your setup?

Hi Dmitry! Thanks for your comment.
I tried the face_detection_camera.py.
If I call the Python script from a bash script though it won't work.

Take this snippet as an example.
```
while true; do
    if [ -f /home/pi/failsafe ]; then
        echo "Failsafe turned on!" > exit.log
        break
    fi
    echo $$ > mainShPid.log
    echo "Starting the Python Script"
    echo `date`
    ./face_camera_trigger.py
    wait
    echo "Python Script terminated"
done
```
I got this result
```
Starting the Python Script
Fri 15 Jun 14:18:42 EDT 2018
WARNING:root:LoadModel: Model 'FaceDetection' is already loaded.
Python Script terminated
Starting the Python Script
Fri 15 Jun 14:19:02 EDT 2018
^CTraceback (most recent call last):
  File "/opt/aiy/projects-python/src/aiy/_drivers/_spicomm.py", line 137, in transact
    fcntl.ioctl(self._dev, SPICOMM_IOCTL_TRANSACT, buf)
OSError: [Errno 14] Bad address

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./face_camera_trigger.py", line 40, in <module>
    main()
  File "./face_camera_trigger.py", line 30, in main
    for result in inference.run():
  File "/opt/aiy/projects-python/src/aiy/vision/inference.py", line 76, in run
    yield self._engine.camera_inference()
  File "/opt/aiy/projects-python/src/aiy/vision/inference.py", line 257, in camera_inference
    return self._communicate(request).inference_result
  File "/opt/aiy/projects-python/src/aiy/vision/inference.py", line 187, in _communicate
    response.ParseFromString(self._transport.send(request.SerializeToString()))
  File "/opt/aiy/projects-python/src/aiy/_drivers/_transport.py", line 33, in send
    return self._spicomm.transact(request)
  File "/opt/aiy/projects-python/src/aiy/_drivers/_spicomm.py", line 137, in transact
    fcntl.ioctl(self._dev, SPICOMM_IOCTL_TRANSACT, buf)
KeyboardInterrupt

```
It says that the model is already loaded and therefore it doesn't take a picture when there's a face.
I also tried to call the `inference.close()` from within with `CameraInference(face_detection.model()) as inference:` without any luck. I
```
def main():
    with PiCamera() as camera:
        # Configure camera
        camera.resolution = (1640, 922)# Full Frame, 16:9 (Camera v2)
        camera.start_preview()
        # Do inference on VisionBonnet
        with CameraInference(face_detection.model()) as inference:
            for result in inference.run():
                if len(face_detection.get_faces(result)) >= 1:
                    filename = dt.datetime.now().strftime("%Y-%m-%d_%H.%M.%S.jpg")
                    camera.capture(filename)
                    camera.resolution = (640, 480)
                    camera.start_recording(dt.datetime.now().strftime("%Y-%m-%d_%H.%M.%S.h264"))
                    camera.wait_recording(600)
                    camera.stop_recording()
                    send(filename) # Send the JPG by email.
                    break
            inference.close() #Not working
        camera.stop_preview()
        camera.close()
```
This script also when called from a bash script or as a function called within a Python While loop, it doesn't free the mmal ressources. I will read the doc about that 'with' statement until your next reply.

You don't need to call inference.close() explicitly because of with CameraInference(...) construction. Otherwise it's going to call inference.close() twice and the second one would fail.  You also don't need to call camera.close() explicitly for the same reason.
CameraInference is a helper class which loads and unloads model: https://github.com/google/aiyprojects-raspbian/blob/e48363018e37b1fdc22d5ddc4b221db97c2cf47b/src/aiy/vision/inference.py#L68
Having WARNING:root:LoadModel: Model 'FaceDetection' is already loaded. is fine, that's just a warning.

Thank you Dmitri! I just looked over this bit of code differently because of that conversation.

@davesdere No problem! Closing this for now.


[RFC][BYOC] Marvell ML/AI Accelerator Integration

Integrate Marvell’s ML/AI accelerator with TVM BYOC framework in order to bring the TVM ecosystem to Marvell customers.

We have also posted a pre-RFC at https://discuss.tvm.apache.org/t/pre-rfc-byoc-marvell-ml-ai-accelerator-integration/11691.
Plus, we have up-streamed our POC code changes in:  PR-9730 (https://github.com/apache/tvm/pull/9730). We have resolved a Mrvl.cmake issue but we are now waiting for tips from the TVM community in order to make the PR's Jenkins task_rust.sh to pass.
Note1: we have not spend much time on driver/runtime integration and therefore can be missing changes for rust cargo. We are trying to catch up here.
Note2: we do run TVM-Jenkinsfile-like build & tests locally but we have skipped the task_rust.sh script during our locally run.

Hello,
How can we request a reviewer to review our RFC?
Also, we have followed the RFC template and listed several unresolved questions, which need help from reviewer and/or TVM community to resolve?
The first few issues are related TVM Jenkins build's rust/cargo failure. I.e., we like to add two more build config flags (use_mrvl and use_mrvl_runtime) in tvm/rust/ setups but need help to update the cargo.io's tvm-build package -- BTW tvm-build seems to be owned by OctoML GitHub. Also, there are other tvm/tests/scripts/task_rush.sh errors. Can a reviewer provide additional information or pointers explain how we should debug the task_rush.sh run to find and resolve issues due to new changes?
Thanks,

Joe

@areusch @jroesch
Is there some aging process to follow in the TVM Open Source so issues get looked at and advanced without getting stale for weeks? As there are timelines that get affected by such delays.
Thanks

@areusch - Thanks for replying.
Please see my comments below regarding your questions.

Question: device planning, which I think maybe you're doing outside the typical TVM flow?
*   If I understand your question correctly: Yes and no.
*   We are using TVM relay flow to generate JSON meta files and IR sub-graphs of the network model
*   We like to use TVM code-gen and runtime flow to generate binary to run inference for “llvm-part” of the network model
*   But we also like to use our build-from-outside-TVM-flow, Marvell accelerator backend/code-gen component to generate binary for “Marvell-part” of the network model (to be run on Marvell accelerator)
i.      Not right now, but in a future RFC, we can and like to provide APIs and library files so that we can embed Marvell backend/code-gen component into libtvm.so and within the typical TVM flow

 *   Not right now, but in a future RFC, when Marvell driver APIs and TVM-Marvell runtime & driver hookups are ready, we like to use the typical TVM flow (with Marvell modifications) to run “Marvell-part” computes of the network on Marvell HW accelerator directly and llvm-part of computes

Question: executor, which I think you may have re-implemented here.
*   I believe that we implemented specializations of the current executor code in order to generate Marvell JSON meta files.
*   It is possible that others may have also implemented “parts of” similar specializations in the last 6 months – if this is the case (and we can use them), we like to know how we can merge codebase
Question: to provide code links into your PoC if that would help me understand--I can do some targeted reading
*   As listed in the RFC, our POC changes have been up-streamed to the TVM GitHub’s PR-9730.
If you like to, you should also be able to git clone from https://github.com/ccjoechou/tvm.git and checkout & use the “byoc-mrvl” branch.
Question: it would also be great to spell out a plan for tests here--it seems like it might be possible to checkin your compiler/simulator into our CI, but could you be more explicit about your plans there?
*   We have added infrastructure code and a test_mrvl suite to run the POC TVM-BYOC-Marvell flow
*   Currently, there is a code-gen test, which can be run to use a pre-trained a ssd-resnet50 model - please see tvm/tests/python/contrib/test_mrvl/ test_mrvl_codegen.py and its test_ssd_resnet50_aot_json_codegen function
*   Should also be able to run regular docker steps below to exercise the BYOC-Marvell flow to compile a ssd-resnet50 network to generate JSON meta files for Marvell accelerator:

./docker/bash.sh --name tvm_mrvl tlcpack/ci-cpu:v0.79 ./tests/scripts/task_config_build_cpu.sh
./docker/bash.sh --name tvm_mrvl tlcpack/ci-cpu:v0.79 ./tests/scripts/task_build.sh build -j10
./docker/bash.sh --name tvm_mrvl tlcpack/ci-cpu:v0.79 ./tests/scripts/task_ci_setup.sh
./docker/bash.sh --name tvm_mrvl tlcpack/ci-cpu:v0.79 ./tests/scripts/task_python_integration.sh

 *   For the last task_python_integration.sh suite, can edit the file in order to skip steps to run other test suites but focus on running only tests/python/contrib/test_mrvl:

sudo pip3 install gluoncv
run_pytest ctypes ${TVM_INTEGRATION_TESTSUITE_NAME}-contrib tests/python/contrib/test_mrvl
Pleas also see my comments in-line below.
Let me raise a difference here:

The TVM partition’s sub-graph seems to represent a relay function, which can include multiple frontend operators captured by utilizing the relay merge-composite patten
The Marvell sub-graph is a connected graph of multiple relay merge-composite functions – I did not know how to include a Figure in the RFC file before (now I do). But if you look at the listed pre-RFC link, we did include figures at end of the corresponding pre-RFC on the discuss forum – please check the end of pre-RFC and its figure to see whether they can help explaining the definition of Marvell sub-graphs here. https://discuss.tvm.apache.org/t/pre-rfc-byoc-marvell-ml-ai-accelerator-integration/11691].

Thanks again and please let us know, if you like to discuss more.

Joe

From: Andrew Reusch @.>
Sent: Tuesday, January 18, 2022 12:48 PM
To: apache/tvm-rfcs @.>
Cc: Joe Chou @.>; Mention @.>
Subject: [EXT] Re: [apache/tvm-rfcs] [RFC][BYOC] Marvell ML/AI Accelerator Integration (PR #48)
External Email

@areusch requested changes on this pull request.
@ssdurakohttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_ssdurako&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=d2Phi5OhJYC30chQlDSTXGdBUHLcKOytTeAstHx3XVU&e= @ccjoechouhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_ccjoechou&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=WZdEJI-EoLFqhJJcO9YZeCcSYSSC-s48_LgSB5F5K1c&e= apologies for the long delay! i think we missed this one since it was mailed during TVMCon and also just before we all took off for the holidays. I'll try to be a bit better about reviewing this.
Overall I have some understanding of your approach with this RFC. I'd like to further discuss some of the rationale behind:

device planning, which I think maybe you're doing outside the typical TVM flow?
executor, which I think you may have re-implemented here.

I'm a bit low on bandwidth to read your full PoC PR. would you mind clarifying the RFC as a starting point (or feel free to provide code links into your PoC if that would help me understand--I can do some targeted reading, I'm just fairly busy for a full read-through right now)
it would also be great to spell out a plan for tests here--it seems like it might be possible to checkin your compiler/simulator into our CI, but could you be more explicit about your plans there?
also cc @comaniachttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_comaniac&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=5likf9V3g5a6XmvwPAr-ais9kJ9tL1Oe3UCcdIReMIQ&e= @mbs-octomlhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_mbs-2Doctoml&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=e3YsFOFCwaZu1YZYwMB9BPZ3m6b0Ne-2byTRo1cYgvQ&e= @Mousiushttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_Mousius&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=mqoZGl7ZzAvBheq3qBAww4oxaItbLwRtTPxO_jkI7w4&e= @junrushao1994https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_junrushao1994&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=MuKxC3uDBMZAx2b6eewBCqm_vk3zVN29bCKxGNYf8a0&e= for further comments on BYOC, device planning, and support for custom executors

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787106344&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=R7fm2C2KsgY7__XRfP-OLUzHCTDIV2vV74gcKzdXtns&e=:

 conv2d + add + batch_norm + tuple.getitem(0) + relu

For the first Marvell-BYOC revision, at most one for-accelerator Mrvl subgraph and at most one for-TVM-target

 non-Mrvl subgraph (let's call this sub-graph B) can be identified; plus, the for-accelerator Mrvl subgraph can

 only use input tensor(s) of given pre-trained network as its subgraph’s input tensors

+* Do code-gen step for each for-accelerator Mrvl subgraph:

Marvell-BYOC-specific attributes are introduced for each composite-merged/fused Call node so that a Nodes-JSON

 file and a Constants-JSON file are produced for the Mrvl subgraph

+STEP (2) Run Mrvl-ML/AI Backend Compiler to generate model binary for each Mrvl subgraph

+* The Mrvl-ML/AI backend compiler will be distributed as an executable in the OCTEON SDK; and it can be used to read

in Nodes-JSON and Constants-JSON files of each Mrvl subgraph as input meta-data in order to generate final instructions,

in model binary file

+* Note: Mrvl-ML/AI backend compiler, which does accelerator-specific optimization and code generation, is not included
what's the test plan for this RFC? Would it be possible to add the Marvell backend compiler and simulator to our ci images and run against it in CI?
[ccjoechou writes: for this BYOC-Marvell RFC, the POC PR codebase only contains code to generate JSON meta files. We have up-streamed our test_mrvl test suite but only contains JSON codegen. In our next RFC, we will provide runtime & driver hookups. We are working on a Marvell backend package with Marvell backend code-gen and Marvell software simulator, which mimics a cycle-approximate Marvell HW accelerator. This package can become available later for external usage.
Currently, we are having problems run TVM rust/cargo and can’t find useful document to debug issues – plus, tvm-build is owned by OctoML (not GitHub TVM, right?)]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787107277&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=dTFGJaoaEmF7zEr2T3eNCq4rM8GuJUGIcBCKJwUjp7I&e=:

+STEP (2) Run Mrvl-ML/AI Backend Compiler to generate model binary for each Mrvl subgraph

+* The Mrvl-ML/AI backend compiler will be distributed as an executable in the OCTEON SDK; and it can be used to read

in Nodes-JSON and Constants-JSON files of each Mrvl subgraph as input meta-data in order to generate final instructions,

in model binary file

+* Note: Mrvl-ML/AI backend compiler, which does accelerator-specific optimization and code generation, is not included

to upstream

+STEP (3a) or (3b) Run inference on the software Simulator or on the Mrvl ML/AI HW accelerator for the Mrvl subgraph

+* The Mrvl Software Simulator of the Mrvl ML/AI HW accelerator will be distributed as an executable in a Mrvl-ML/AI tar

ball; and it can be used to read in input file(s) and the model binary to run inference for the Mrvl subgraph

+* Note: Mrvl ML/AI accelerator can run inference in either float16 mode or int8 quantization mode. For this RFC, we will

focus only on float16 inference run

just checking if this was the end of the sentence here
[ccjoechou writes: yes]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787114611&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=ENAAXEINGM7EwToNOLBW3SyS_1du7HQF34XpbsKcVwc&e=:

     /* en_id=599 */) /* ty=Tensor[(256, 1568), float32] */;

 %11 = nn.dense(%9, %10, units=None, out_dtype="float32", /* en_id=600 */) /* ty=Tensor[(1, 256), float32] */;

 %12 = add(%11, meta[relay.Constant][5] /* ty=Tensor[(256), float32] */,

     /* en_id=601 */) /* ty=Tensor[(1, 256), float32] */;

 %13 = nn.relu(%12, /* en_id=602 */) /* ty=Tensor[(1, 256), float32] */;

 %14 = transpose(meta[relay.Constant][6] /* ty=Tensor[(256, 10), float32] */, axes=[1, 0],

     /* en_id=675 */) /* ty=Tensor[(10, 256), float32] */;

 %15 = nn.dense(%13, %14, units=None, out_dtype="float32", /* en_id=676 */) /* ty=Tensor[(1, 10), float32] */;

 add(%15, meta[relay.Constant][7] /* ty=Tensor[(10), float32] */, /* en_id=677 */) /* ty=Tensor[(1, 10), float32] */

+}

+```

+* We can get to the following one Mrvl subgraph by applying the default strategy.

in the mrvl.py file: the compute_two_subgraphs() function of the class MrvlIRGraphUtils is used

 to create mod_mrvl_subgraph and mod_non_mrvl_subgraph for

could you clarify this sentence?
[ccjoechou writes: did not know how to include a Figure in the RFC file – but I did include figures at end of the corresponding pre-RFC on the discuss forum – please check the end of pre-RFC and its figure to see whether they can help explaining the definition of Marvell sub-graphs here. https://discuss.tvm.apache.org/t/pre-rfc-byoc-marvell-ml-ai-accelerator-integration/11691]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787115633&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=NMd2x1139DrgTciUNgZ8CD9PiwmazbEys_2ZMegmtEU&e=:

 %13 = nn.relu(%12, /* en_id=602 */) /* ty=Tensor[(1, 256), float32] */;

 %14 = transpose(meta[relay.Constant][6] /* ty=Tensor[(256, 10), float32] */, axes=[1, 0],

     /* en_id=675 */) /* ty=Tensor[(10, 256), float32] */;

 %15 = nn.dense(%13, %14, units=None, out_dtype="float32", /* en_id=676 */) /* ty=Tensor[(1, 10), float32] */;

 add(%15, meta[relay.Constant][7] /* ty=Tensor[(10), float32] */, /* en_id=677 */) /* ty=Tensor[(1, 10), float32] */

+}

+```

+* We can get to the following one Mrvl subgraph by applying the default strategy.

in the mrvl.py file: the compute_two_subgraphs() function of the class MrvlIRGraphUtils is used

 to create mod_mrvl_subgraph and mod_non_mrvl_subgraph for

+```

def @main(%permute_input: Tensor[(1, 1, 28, 28), float32]) -> Tensor[(1, 10), float32] {

 %0 = @tvmgen_mrvl_main_0(%permute_input, /* en_id=4136 */) /* ty=Tensor[(1, 28, 28, 1), float32] */;

above, the RFC discusses having exactly one Marvell and non-Marvell subcgraph, but here I see 8 different function calls. do you mean that there are two targets, and you partition the graph into 8 subgraphs, but each subgraph is assigned to one or the other target? (reading further, I can see this is not the case, but it would help with reader comprehension to clarify this example)
[ccjoechou writes: We are talking about different definitions of “(sub-)graphs” here. In the TVM partition pass, TVM’s graph or sub-graph is a merge-composite IR function, which can contain a pre-define pattern of original frontend operators. In BYOC-Marvell RFC’s definition, a sub-graph is a connected graph of Marvell-merge-composite functions. For instance, a tvmgen_mrvl_main_4 (see below in original email), it is a TVM-partition sub-graph, which is a Marvell merge-composite function containing frontend operators: conv, add, batchnorm, tuple-get-item, relu. But a Marvell sub-graph contains, in the given test case, several Marvell merge-composite functions.]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787117464&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=9V5lRxYmfESbgL3yM5Ilb_xMOPZt-l7-zSzW5591Rko&e=:

 %3 = @tvmgen_mrvl_main_3(%2, /* en_id=4139 */) /* ty=Tensor[(1, 14, 14, 32), float32] */;

 %4 = @tvmgen_mrvl_main_4(%3, /* en_id=4140 */) /* ty=Tensor[(1, 7, 7, 32), float32] */;

 %5 = @tvmgen_mrvl_main_5(%4, /* en_id=4141 */) /* ty=Tensor[(1, 1568), float32] */;

 %6 = @tvmgen_mrvl_main_6(%5, /* en_id=4142 */) /* ty=Tensor[(1, 256), float32] */;

 @tvmgen_mrvl_main_7(%6, /* en_id=4143 */) /* ty=Tensor[(1, 10), float32] */

}

+```

+* In the above Mrvl subgraph, it is formed by "not-yet optimized Marvell (backend) layers". For example,

tvmgen_mrvl_main_0 to tvmgen_mrvl_main_7 are composited/fused Marvell layers.

In the mrvl.mrvl_pattern_table() function, fusing patterns have been defined in order to composite

 original IR nodes into Marvell backend layers.

For example, the following 3 IR call nodes (nn.conv2d + nn.bias_add + nn.relu) in the original IR graph

 are composited into one Marvell layer: tvmgen_mrvl_main_1, conceptually speaking.

+```

 # from original IR graphs

this process looks rather similar to the device planning pass used in tvm.relay.build. are they the same? if not, could you motivate why you don't want to reuse that one?
[ccjoechou: sorry I am not sure what you meant by “device planning pass”? We have been following what others did in tvm/python/tvm/relay/op/contrib by utilizing relay passes (for example, ConvertLayout, MergeComposite, AnnotateTarget, and etc.). Please note that in this RFC, we only want to generate JSON meta files and we are not ready to propose/up-stream our runtime & driver hookups yet).]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787129775&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=mipKEVzGwI-kUn_2n_Pb71FU6tS4AsBlfYeJzyoNlJg&e=:

 %0 = @tvmgen_mrvl_main_0(%permute_input, /* en_id=4136 */) /* ty=Tensor[(1, 28, 28, 1), float32] */;

 %1 = @tvmgen_mrvl_main_1(%0, /* en_id=4137 */) /* ty=Tensor[(1, 28, 28, 64), float32] */;

 %2 = @tvmgen_mrvl_main_2(%1, /* en_id=4138 */) /* ty=Tensor[(1, 14, 14, 64), float32] */;

 %3 = @tvmgen_mrvl_main_3(%2, /* en_id=4139 */) /* ty=Tensor[(1, 14, 14, 32), float32] */;

 %4 = @tvmgen_mrvl_main_4(%3, /* en_id=4140 */) /* ty=Tensor[(1, 7, 7, 32), float32] */;

 def @tvmgen_mrvl_main_0(%mrvl_0_i0: Tensor[(1, 1, 28, 28), float32], Inline=1, Compiler="mrvl",

     global_symbol="tvmgen_mrvl_main_0", Primitive=1) -> Tensor[(1, 28, 28, 1), float32] {

   layout_transform(%mrvl_0_i0, src_layout="NCHW", dst_layout="NHWC",

       /* en_id=3334 */) /* ty=Tensor[(1, 28, 28, 1), float32] */

 }

+```

+* Currently, in order for the following Marvell classes/functions to identify a Mrvl subgraphs and a non-Mrvl

subgraph from the layout-converted, composited/fused IR graph, we are utilizing the unique en_id attribute

could you motivate the naming of en_id a bit? i recognize this is a common thing, but it might be nice to choose a slightly more specific name
[ccjoechou writes: en_id as ExprNode ID. It is an extra field, which has been defined in the include/./tvm/ir/expr.h file for the RelayExprNode or just ExprNode class.]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787130884&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=Ew6gvJZix-z7H4QsP5VlpdhjQ4fJ-0-iezoY2L2FyAk&e=:

       mod = seq(mod)

   return mod

mod_new = tvm.IRModule(mod_mrvl.functions, mod_mrvl.type_definitions)

mod_new["main"] = MrvlSubgraphToRevert(mrvl_layers_in_mrvl_subgraph, mod_mrvl).visit(mod_mrvl["main"])

mod_new = relay.transform.RemoveUnusedFunctions()(mod_new)

mod_new = relay.transform.InferType()(mod_new)

mod_new = run_opt_pass(mod_new, relay.transform.DefuseOps())

mod_new = run_opt_pass(mod_new, relay.transform.ConvertLayout({"nn.conv2d": ["NCHW", "OIHW"], "nn.max_pool2d": ["NCHW"]}))

mod_new = run_opt_pass(mod_new, relay.transform.SimplifyExpr())

mod_new = run_opt_pass(mod_new, relay.transform._ffi_api.DropNoopTranspose())

mod_new = run_opt_pass(mod_new, relay.transform.InferType())

return mod_new

+```

+* Marvell-specific graph executor codegen, We have defined call backs and extension functions in the following files:
could you motivate this further? it's hard to understand why you need to output your own JSON format without some explanation here.
[ccjoechou writes: the above code block is not to output our own JSON format; instead, it is to “revert” a sub-graph, which went over Marvell passes (e.g., ConvertLayout, MergeComposite, AnnotateTarget, and etc), back to its original, say, llvm-IR graph. Hence, we are: defuse-ops (opposing to Merge-Composite), reverted ConvertLayout, and etc. Motivation for reverting back to this llvm-part subgraph is to allow this llvm-part subgraph to go through TVM llvm-flow to generate runtime binary.]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787131656&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=rToD4fZ9EIg8eIkLKttKsDNIv0v45-SouZi0No4Qt5g&e=:

+```

+* the need to link between pre-trained model and final Marvell backend layer - for instance, through tvm_custom

We did not include prototype code in PR-9730 but intend to provide our sample changes in another RFC and PR.

+# Drawbacks
+[drawbacks]: #drawbacks

+* We haven't identified any major not do items. Several other designs are by choices - that is we understand that

there are benefits for doing or benefits for not-doing.

+# Rationale and alternatives
+[rationale-and-alternatives]: #rationale-and-alternatives

+* We follow the TVM BYOC framework to enable BYOC Marvell flow without impacting any TVM core features.
it seems like there has been some impact to the GraphExecutor, and I think one point of confusion here is whether it was necessary to do that or whether you could have handled the additional runtime complexity inside a Marvell-specific runtime.Module. could you explain a bit further here?
[ccjoechou writes: I do not see GraphExecutor term in above. Please provide an example or point us to a TVM file so we can understand your comment a bit more. Thanks.]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787132217&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=JRaYKexNQLso0O88polwIXQyGMTNHhdyLbV1bKRfSrM&e=:

bypassing the tvm/Jenkinsfile's tests/scripts/task_rust.sh step. We will need help to re-enable the step.

+* We like to duplicate the Jenkins environment in order to run tvm/Jenkinsfile as is, but, we ran into many issues.

Currently, we have a tvm-like Jenksinsfile environment to only run a subset of test suites using a modified

Jenkinsfile.

+* We have identified a need to allow a call-back function to be registered when generating Mrvl-BYOC-specific

Nodes-JSON file. We are trying to follow TVM Python/CPP-CB style as much as possible. But, since our callback

function tvm/src/relay/backend/contrib/mrvl/graph_executor_codegen_mrvl.cc::GetExternalJSON() function is using

non-simple argument types, we need help from TVM community to provide suggestions/guidelines in order to make

new CB code better to meet TVM community requirements here.

+* For one Mrvl-BYOC relay transformation pass, we have identified a need to inject a (global) expr node ID for the

RelayExprNode class and its derived classes: Tuple and CallNode, so that during the transformation pass, we can

uniquely identify each Tuple or CallNode object. Again, we need help from TVM community to provide

suggestions/guidelines here in order to know whether this is one of the best ways to achieve the Mrvl-BYOC need.

i think it would help to spell out why you guys need to be able to identify each expression here.
[ccjoechou writes: yes but not just us but a data-scientist customer who is using TVM flow may like to know, for example, the linkages between the runtime performance #s and their corresponding user frontend model’s operators (e.g., each expression).]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787132545&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=dIcIPdSahtIX9piD7O2f_UhKljEWi-K6XvL8MI3svgY&e=:

RelayExprNode class and its derived classes: Tuple and CallNode, so that during the transformation pass, we can

uniquely identify each Tuple or CallNode object. Again, we need help from TVM community to provide

suggestions/guidelines here in order to know whether this is one of the best ways to achieve the Mrvl-BYOC need.

+* We also identified a need to maintain linkages between (operator-)information described in the original, given

pre-trained network model and the code-gen JSON files so that the compiler backend will be able to report user-level

(e.g., meaningful-to-user) messages regarding the given pre-trained network. For instance, in the

tvm/python/tvm/relay/frontend/onnx.py and common.py files, we can see user-level information being captured using

“tvm_custom” related code as in original onnx.py file for the given pre-trained network; but, in common.py, the code

later drops the linkage, via attrs.pop(“tvm_custom”), and does not pass the linkage onto the initial relay IR graph.

We have a draft solution to maintain linkages between the given pre-trained network model and its relay IR graph

(using expr node ID and tvm custom ID, plus, a few utility functions), but would like to know whether the TVM

community has any better or work-in-progress resolution.

+* When using TVM RPC code to exercise and run inference on a remote-hosted Mrvl ML/AI HW accelerator for the Mrvl

subgraph, we ran into one minor issue and have made local TVM RPC enhancement so that, when a TVM RPC client sends

could you explain the nature of the problem that requires the client to know the absolute path?
[ccjoechou writes: First, the TVM RPC server choses path for any uploaded file under tmp randomly (which can be good to reduce possible security problem). But, in our use case, we like to have the TVM RPC client to send a “runtime” command to the RPC server side to pre-process the just uploaded file before the file can be consumed autonomously by the RPC server using pre-defined script. We can’t find a way or via a TVM example, which shows how this can be done.]

In rfcs/0048-BYOC-Marvell-ML-accelerator-integration.mdhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23discussion-5Fr787133542&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=9sG9W_t_KkSawUyjosauynkwCGnYieI8qZo2TOrwXQU&e=:

pre-trained network model and the code-gen JSON files so that the compiler backend will be able to report user-level

(e.g., meaningful-to-user) messages regarding the given pre-trained network. For instance, in the

tvm/python/tvm/relay/frontend/onnx.py and common.py files, we can see user-level information being captured using

“tvm_custom” related code as in original onnx.py file for the given pre-trained network; but, in common.py, the code

later drops the linkage, via attrs.pop(“tvm_custom”), and does not pass the linkage onto the initial relay IR graph.

We have a draft solution to maintain linkages between the given pre-trained network model and its relay IR graph

(using expr node ID and tvm custom ID, plus, a few utility functions), but would like to know whether the TVM

community has any better or work-in-progress resolution.

+* When using TVM RPC code to exercise and run inference on a remote-hosted Mrvl ML/AI HW accelerator for the Mrvl

subgraph, we ran into one minor issue and have made local TVM RPC enhancement so that, when a TVM RPC client sends

a file to the remote server, the TVM RPC client can know where the remote server saves the file on the remote machine.

Since this is not directly related to this Mrvl-BYOC PR, we will find time to contribute this enhance back in another

TVM PR soon.

+* In order for us to generate the constants-JSON file, we must “NOT” remove external params, which were stored in
why is this? params passed in MetadataModule are meant for consumption only by the runtime.Module which defines them. it seems like perhaps you need to consume them at the executor level. could you explain that?
[ccjoechou writes: We are using relay to generate JSON meta files representing the given network model in a way our backend code can process directly (e.g., only the marvell-part sub-graph(s). If we have include 100% of our backend code in the TVM codebase, then, we do not need to dump constants in JSON mega file; but, due to our backend code is built outside the typical TVM flow and can do other compile-time optimization including manipulating constants, we need constants JSON.]
—
Reply to this email directly, view it on GitHubhttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_apache_tvm-2Drfcs_pull_48-23pullrequestreview-2D855912667&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=L2xG3uKvJ4yJ_ixp1fyRD1bRTpZgR-yWZtSVJPsEHLo&e=, or unsubscribehttps://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_notifications_unsubscribe-2Dauth_AM636PACHANYNAATB4KA7B3UWXGYFANCNFSM5KJYF53A&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=NB9WVT4nlWSlIeHit8jurEkvilrrj22R7iAhBtdylbI&e=.
Triage notifications on the go with GitHub Mobile for iOShttps://urldefense.proofpoint.com/v2/url?u=https-3A__apps.apple.com_app_apple-2Dstore_id1477376905-3Fct-3Dnotification-2Demail-26mt-3D8-26pt-3D524675&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=-StSSo5XOXXHK4bMwp_B8eLiRGQ0DXvLD_42vrZOwyQ&e= or Androidhttps://urldefense.proofpoint.com/v2/url?u=https-3A__play.google.com_store_apps_details-3Fid-3Dcom.github.android-26referrer-3Dutm-5Fcampaign-253Dnotification-2Demail-2526utm-5Fmedium-253Demail-2526utm-5Fsource-253Dgithub&d=DwMFaQ&c=nKjWec2b6R0mOyPaz7xtfQ&r=84zI-iH2xz28Q_xujSGbjYaq38CgcRgl_vGzCtF6TwQ&m=VNqzldKdQt96drtn_9Nfv7pyo4q1twvxtd6wMIR7FYI4cpvEKxaaVtBsanbms18J&s=HJ1qy1TGjh0KDSnnPWyF-MoI-UYA3X9I_er2DAq4ICs&e=.
You are receiving this because you were mentioned.Message ID: @.***>

@areusch: Thanks again for your latest responses. Don't worry about timing (we all have our real jobs to do too).
I am going to update the RFC #48 doc based on many of your feedback in the next few days -- including to add figures by following the example you gave and to add descriptions to clarify many good questions of reviewers.
Once that is done, we will reply to your latest responses individually. For changing the en_id name to exprnode_id, we will update our POC-up-streamed TVM PR accordingly first.
Btw, in our RFC flow, we mentioned that we need to call the relay defused-op pass convert merge-composition-ed Relay IR back to w/o-composition Relay IR. We found a bug in the Relay Defuses-op pass and had up-streamed a fix and a test case to TVM (see TVM PR-10069 for details).

@areusch: Forgot to answer your first question.
Yes, for now, we like to generate external JSON files, only for the accelerator sub graph(s), in the BuildResult step so that we can pass them to our not-(yet-)in-TVM-general-flow, external-accelerator-specific compiler backend program to do further AOT for-inference-run optimization in order to generate more optimized ISA code to run inference for the accelerator sub graph(s).
For the llvm sub graphs (let me use llvm here to distinguish them from those for-accelerator sub graphs), we will and do follow the TVM general flow to generate the .so lib files.
When the Model Library format and flow become stable, plus, they can be specialized to include extra external accelerator and memory allocations & communications, we definitely like to see how we can advance the BYOC-Marvell flow to use them (with llvm .so lib files together).

@ccjoechou great thanks! i'll take another look here when you're done with the updates.

Hi @areusch:
I have updated RFC-#48 based on most of your feedback. New RFC md file and 4 new figures have been uploaded.
Please take a look again (in a view document mode I can see new figures being displayed inside RFC).
We are taking couple of your TIR-related advices and will start reviewing RFC-0010 and TVM TIR files.
For our TVM PR-9730 POC code, I have renamed en_id to exprnode_id for our changes and update that PR soon.

@ccjoechou hey I think you may have had a bad merge--I see a bunch of unrelated RFCs listed as changed underneath "Files changed." Could you take a look and rebase/re-merge?

@ccjoechou hey I think you may have had a bad merge--I see a bunch of unrelated RFCs listed as changed underneath "Files changed." Could you take a look and rebase/re-merge?

Let me check.

@areusch: You are correct that I must did something wrong the last time and now I lost the linkage between my GitHub forked byoc-mrvl branch and this tvm-rfc PR-#48. Therefore, my changes done a week ago are still staying on my personal GitHub forked byoc-mrvl branch and did not get push to the tvm-rfc PR-#48.
Any suggestion for me to do?
I can see my byoc-mrvl branch is good to be merged automatically with the tvm-rfc PR-#48 but I do not see any bottom to click to make it happen.

@areusch:
Hello, I believe I have cleaned up the PR's commits now (reset a few commits and re-add changes).
Sorry about that.
Can you take a look again (my latest changes are with this commit: 8a7fd01)?
Thanks.

@ccjoechou sorry for the delay--i've gotten pretty busy with something and will hopefully have some bandwidth towards the end of the week.
cc @jroesch @mbs-octoml in case they have cycles

@areusch: No worries. I saw lots TVM emails coming from you & others working on other also important stuffs. We will wait for your feedback.

@areusch:
Yes, using one or two zoom sessions to go over some questions of yours and some questions of ours will definitely be very, very helpful. This way we can sync up quicker.
I am open tomorrow (2/25) as well as Monday (2/28) in the afternoons from 1:30 pm to 6 pm Pacific time zone.
Will you be available?
My company email address is<EMAIL_ADDRESS>Please feel free to schedule a zoom meeting using my email.

@ccjoechou Summarizing our discussion a bit:

Marvell is interested in being able to arbitrarily partition a Relay graph into hardware-accelerated and non-hardware-acclerated parts

The boundaries between these parts are to be determined by Marvell backend; therefore, some additional control is needed over the default behavior provided by MergeComposite
@mbs-octoml suggests that they use the StopFusion annotation to manually enforce the boundaries. These annotations could be added programmatically via a Relay IRModule pass. StopFusion is used in FuseOps pass to avoid fusion.
Using this approach, the Marvell partitioning pass defined here could be simplified and the existing fusion pass could be used.

Marvell needs to be able to determine which:

Imported ONNX operator is responsible for a given Relay node
Relay node is responsible for a TIR CallNode

This needs to happen at two times:

At compile time, to serve as a reference to the boundary nodes between a hardware-accelerated and non-hardware-accelerated subgraph
At runtime, to determine which backend operator to call

A follow-up question here from me: at runtime, couldn’t you just emit the call to the correct backend operator? I wonder if the reason this mapping was needed was due to previous difficulties configuring the TVM partitioner (it would sometimes fuse across a desired boundary). Is it possible to avoid the need for this reference at runtime given the improved partitioning approach mentioned above?
That doesn't solve the problem of needing to identify a Relay node at compile time. However, if we can reduce this need to a purely compile-time need, perhaps we can develop an alternate way to refer to a Relay node given Relay source code other than adding an id to the IR. cc @tqchen @junrushao1994 in case they have ideas here.

Marvell proposes to add a Relay attribute exprnode_id and export this from the compiled artifact to identify the relay nodes which are fused into a particular subgraph
More broadly, source maps (e.g. mapping TIR to Relay to frontend operator) would help here.

Right now the RFC proposes to create a new GraphExecutorCodegen. It might not be necessary to do this if we could export the exprnode_id for Relay operators passed to BYOC. A suggestion is to create a Marvell-specific runtime::Module modeled after CUDAModule which contains several distinct pieces of generated code. The exprnode_ids could be kept separate from any binary instructions if encoded this way. This pattern is common amongst GPU-offloaded runtime::Module.

Additionally, note the SaveToFile override which is invoked when Module.save() is called from Python. This can allow you walk the runtime::Module tree from Python and collect the various exprnode_ids into a single e.g. JSON blob.

@jroesch to comment on rust CI failures

Marvell would like to contribute a simulator which can run in TVM CI to test their accelerator. We discussed either adding the sim to ci-cpu or a new ci-marvell, the method to do this, and limitations of TVM CI.

Marvell runs a patched version of the TVM CI internally. A primary reason why patching is needed is because many tests in the TVM CI require an internet connection to e.g. download models, but their CI is run in a sandbox. It would be particularly helpful to mark such tests e.g. via pytest.mark in order to make these easy to skip. We also discussed pre-populating the download_testdata cache and patching pytest.skip into download_testdata on their internal fork. cc @leandron @driazati @konturn for visibility and in case they have ideas here.