Notifies Lawine eindämmen

Begonnen von noansi, 12 Juni 2016, 01:23:39

Vorheriges Thema - Nächstes Thema

noansi

Hallo Rudolf,

über die NotifyFn werden in FHEM ja "interessierte" Module über eine Statusänderung an Readings informiert.

Ich kenne es bisher in der Form, dass alle NotifyFn aller devices bei einer Reading Änderung aufgerufen werden und die NotifyFn dann schaut, ob die Änderung "interessant" ist.

Werden in der NotifyFn eines Moduls wiederum Readings aktualisiert, steigen die NotifyFn Aufrufe in FHEM rasant an.
Damit steigt auch der Rechenzeitbedarf überproportional mit zunehmender Anzahl von Modulen.

Hier Zeit zu sparen bringt dann einiges.

Für 91_watchdog.pm habe ich daher folgenden Vorschlag:

Hiermit lässt sich in watchdog_Notify Rechnenzeit sparen, wenn die RegExps DeviceNamen filtern:
#####################################
sub
watchdog_Notify($$)
{
  my ($watchdog, $dev) = @_;
 
  $n   = $dev->{NAME};
 
  return "" if (!defined($watchdog->{helper}{SensorsL}{$n})); # is it one of our devices?

  my $ln = $watchdog->{NAME};
  return "" if(IsDisabled($ln));
...



Die {SensorsL} muss natürlich gefüllt werden, daher in watchdog_Define:

...
  $watchdog->{RE1} = $re1;
  $watchdog->{RE2} = $re2;
  $watchdog->{TO}  = $to;
  $watchdog->{CMD} = $cmd;

  # fill our device lookup list to speedup NotifyFn
  $watchdog->{helper}{SensorsL}{$name} = 1;
  my $hhs = $watchdog->{helper}{SensorsL};
  my $devicecheck = $re1.' '.$re2;
  foreach my $d (keys %defs) {
    $hhs->{$d} = 1 if ($devicecheck =~ m/$d/);
  }
  delete($watchdog->{helper}{SensorsL}{$name});

  if($re1 eq ".") {
...


Da ich viele watchdogs benutze, um den Lebenszustand von Sensoren zu überwachen, macht sich dies stark bemerkbar.
Insbesondere mit Blick auf das HM Timing bei CUL weshalb ich auf diesen Gedanken gekommen bin. x.x Sekunden "Störfeuer" für zufällig gerade eintreffende Sensorwerte sind da kontraproduktiv.

Bei der Verwendung von Namen muss man natürlich aufpassen, damit das mit den RegExps nicht kollidiert und umgekehrt wohl auch.

Bei anderen Modulen mit NotifyFn macht dieses Hash Verfahren ebenso Sinn, denn schon die übliche verwendete Methode des String Vergleichs bei dem DeviceNamen Vergleich ist langsamer als die Hash Methode.
Zusätzlich lässt sich auf diesem Wege auch ein direkter Aufruf einer Auswertefunktion realisieren, wenn man statt 1 zuzuweisen einen Funktionsnamen verwendet und damit eine Funktionsreferenz in der NotifyFn aufruft.


Vermutlich noch fixer würde es gehen, wenn FHEM eine Art Notify Vewaltung erhalten würde, mit der nur die "interessierten" Module mit dem Notify eines Devices versorgt würden. Über den NotifyFn Rückgabewert könnte man an device Nachrichten interessierte Module ermitteln und sammeln.

Gruß, Ansgar.

Markus Bloch

Hallo Ansgar,

es gibt bereits eine Art "Notify-Verwaltung" um die Flut an Notify-Prüfungen einzudämmen. Das ganze nennt sich $hash->{NOTIFYDEV}, welches im Definitions-Hash gesetzt werden kann um eine kommaseparierte Liste an Definitionsnamen angeben zu können, von denen die jeweilige Definition Events erwünscht. Dadurch kann eine Definition den Aufruf ihrer NotifyFn auf das notwendigste minimieren. Dies wird bereits in aktuell 45 Modulen verwendet. FHEM hat intern eine Zuordnungstabelle von welche Definition an welche Definition Events dispatched werden. Durch NOTIFYDEV wird diese Zuordnungstabelle natürlich erheblich kleiner, da nur wenige Zuordnungen je nach gewünschten Definitionen erzeugt werden.

Im Watchdog wurde NOTIFYDEV bisher noch nicht verbaut, da es hier etwas komplizierter ist und entsprechend 2 Regexps zu parsen sind. Es gibt bereits eine Funktion notifyRegexpChanged() in FHEM, welche eine Regexp prüft, und ggf. ein NOTIFYDEV erzeugt. Dies funktioniert aktuell nur bei Regexp die einen eindeutigen Definitionsnamen enthalten (keine Wildcard wie .* usw.). Man könnte dies generell auf Wildcards ausweiten, das ist kein Problem. Das geht allerdings dann auch nur bei Regexp wie bspw:

Wohnzimmer_.*:on

Es geht jedoch nicht bei:

(Wohnzimmer_Lampe1:on|Wohnzimmer_Lampe2:on)
Wohnzimmer_(Lampe1|Lampe2):on


Wir hatten es bereits früher versucht diesen Mechanismus etwas intelligenter zu gestalten. Allerdings kann man dann beliebige Regexps konstruieren, wo dann der gesamte Mechanismus wieder versagt und ein NOTIFYDEV auf eine Definition gesetzt wurde, obwohl noch weitere mit da rein müssten.

Was ich anbieten könnte, wäre ein Patch für notifyRegexpChanged der auch Definition-Wildcards erkennt und wenn die Liste der Definitionsnamen kleiner gleich 5 ist, diese als NOTIFYDEV setzt. Dies gilt aber nur für Regexps wie

Wohnzimmer_.*:on

Gruß
Markus

Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

noansi

#2
Hallo Markus,

danke für den Hinweis auf NOTIFYDEV.

Ich lebe noch mit einer älteren fhem.pl, in der das noch nicht als Komma separierte Liste drin ist. Schon mal ungünstig...

ZitatAllerdings kann man dann beliebige Regexps konstruieren, wo dann der gesamte Mechanismus wieder versagt und ein NOTIFYDEV auf eine Definition gesetzt wurde, obwohl noch weitere mit da rein müssten.
Wenn man denn das "beliebige" nicht einschränken möchte, so dass eine NOTIFYDEV Liste ertellbar ist, dann sind die RegExps wohl zu komplex, da muss ich Dir leider zustimmen.
Ein eindeutiger Trenner (':') zwischen Devicenamenanteil und Eventanteil muss wohl Pflicht sein, um das zu ermöglichen. Dann kann man alle Devices zumindest durchtesten, ob sie in die NOTIFYDEV Liste eines Devices müssen.
Der Aufschrei des Entsetzen ist dann wohl sicher, wenn solch eine Einschränkung eingeführt würde...

Der Gedanke mit der Rückmeldung aus NotifyFn hat sich damit auch erledigt, da ich nicht an den Eventanteil gedacht habe.

Alternativ sähe ich noch eine Syntaxvariation/-alternative in watchdog.
Bisherige Definitionsform: keine NOTIFYDEV Liste -> volle Zeitstrafe
Neue Definitionsform mit Trennungszwangs: NOTIFYDEV Liste möglich -> Zeitoptimierung  :)

Gruß, Ansgar.

Markus Bloch

#3
Hallo Ansgar,

ganz so einfach ist es leider nicht. Das ganze ist unabhängig vom watchdog. Generell funktioniert das setzen von NOTIFYDEV nur dann, wenn die Definitionsnamen keinerlei Wildcards oder andere Regexp-Features enthalten. Würde man bei einer Regexp mit Wildcards alle möglichen Definitionsnamen über eine Prüfung von $defs durchführen, würden neue Definitionen die angelegt werden und darauf passen würden/sollten/müssen nicht mehr berücksichtigt. In so einem Fall müsste jedes Watchdog/notify/FileLog/... die Regexp neu gegen $defs prüfen um wieder alle Definitionen zu erfassen.

Das ganze würde auch nur bei einer kleinen Ergebnismenge (bspw. 5 Stück) Sinn machen, Bei 30 Definitionen oder mehr rechtfertigt der Aufwand zur Ermittlung aller Definitionen nicht mehr die Zeitersparnis durch NOTIFYDEV.

Das ganze ist daher nicht so ganz einfach ;-).

Ich habe aber mal einen Patch für NOTIFYDEV mit Regexp-Wizard-basierenden Regexp's gebaut: https://forum.fhem.de/index.php/topic,54536.0.html

Gruß
Markus



Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

NOTIFYDEV wird ja jetzt schon nicht direkt verwendet sondern bei jedem define, rename und delete schon neu in einen hash übersetzt der dann verwendet wird.

vermutlich könnte man beim erstellen dieses hash zusätzlich auf einen direkten vergleich auf die device namen auch per regex matchen. in readingsGroup mache ich so etwas zur zeit auch schon mit einem notify auf global DEFINED, RENAME und DELETE.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

Zitat von: justme1968 am 12 Juni 2016, 15:41:27
vermutlich könnte man beim erstellen dieses hash zusätzlich auf einen direkten vergleich auf die device namen auch per regex matchen. in readingsGroup mache ich so etwas zur zeit auch schon mit einem notify auf global DEFINED, RENAME und DELETE.

Das stimmt, das Problem ist eher die zweifelsfreie Erkennung aller definitionsrelevanten Teile der Regexp. Nicht immer sind Definitions-Teil und Event-Teil klar getrennt. Man muss keine Trennung zwischen Namen und Event machen. Man müsste sehr detaillierte Prüfungen machen um sich absolut sicher sein zu können, das man alle relevanten Teile der Regexp erkannt hat.

Diesen Aufwand möchte ich persönlich nicht machen. ;-)

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

noansi

Hallo Markus, hallo Andre,

Zitatdas Problem ist eher die zweifelsfreie Erkennung aller definitionsrelevanten Teile der Regexp
Gerade deswegen der Gedanke, die Trennung durch eine andere Syntax zu erzwingen.

Die Frage wäre, braucht man die derzeitige "Nichttrennung" oder kann man darauf verzichten?
Derzeit könnte ich für meinen Bedarf darauf verzichten.
Aber da ich nun ein wenig darüber gegrübelt habe, würde eine Trennung doch die Möglichkeiten arg einschränken.

ZitatDiesen Aufwand möchte ich persönlich nicht machen.
Das kann ich nachvollziehen. ;-)

Ohne tiefgreifende regexp Analyse bleibt es wohl bei dem Wunsch.

Danke für den Patch!

Gruß, Ansgar.

Markus Bloch

Zitat von: noansi am 12 Juni 2016, 18:21:11
Die Frage wäre, braucht man die derzeitige "Nichttrennung" oder kann man darauf verzichten?
Derzeit könnte ich für meinen Bedarf darauf verzichten.

Du musst es andersherum betrachten. Aktuell gibt es keine Regel die vorschreibt, dass die Regexp mit : getrennt sein MUSS. Die Commandref für notify schreibt nur vor dass eine übergebene Regexp auf folgende 2 Möglichkeiten matchen muss:

devicename

devicename:event


Das bedeutet im Umkehrschluss aber auch, dass folgende Regexp auf matchen würden (Definitionsname: "test123"):

test123.*on
test1.*on

test\d*.*on


Hier kann ich keinerlei Rückschlüsse auf Definitions-Anteil und Event-Anteil machen. Und gerade diese Regexp werden von Anfängern gerne genutzt weil sie es irgendwo mal gesehen haben und .* natürlich einfacher ist als test123:power:.on zu verwenden.

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

noansi

#8
Hallo Markus,

ZitatDu musst es andersherum betrachten.
Das habe ich schon und daher den Aufwand verstanden, der dahinter steckt.
Ich würde mal grob schätzen, Parsen, nach "ODER" und "UND" Knoten Klassifizieren, Umstellen, Ausklammern etc. und daraus versuchen einen Match zu generieren mit dem man die definierten Devices matchen kann. Das ist weit von mal eben entfernt.
Oder es fällt jemandem was ein, das es in der Perl Welt schon passend gibt.

EDIT: Mit passenden Devicenamen und dem Wunsch mehrere mit einer RegExp zu erfassen lassen sich sicherlich auch pathologische RegExp Fälle konstruieren, bei denen jeder Algorithmus versagen muss, weil eine eindeutige Trennung zwischen Devicename und Event nicht mehr gegeben ist, respektive sich nur noch bei Betrachtung der Devicenamen im System erschließt.

Dein Patch hilft schon mal an anderen Stellen. Danke!

Für den watchdog kann ich es nach meinen Bedürfnissen anpassen. Das hilft nur nicht generell.

Gruß, Ansgar.