Aller au contenu

Performance des commandes "Fibaro"


jjacques68

Messages recommandés

hello !! 

 

Je me pose la question suivante, niveau performances (rapidité d'exécution, réactivité, autres ...) :

j'essaye de prendre des précautions dans les termes choisi...

 

faudrait-il mieux utiliser

 

par exemple : 

api.post("/devices/xxx/action/turnOn", {})

ou 

fibaro.call(xxx, "turnOn")

 

autre exemple

api.get("/devices/xxx").properties.value

ou

fibaro.getValue(xxx, "value")

 

je demande ça car j'ai l'impression qu'il y a une différence au niveau de la "latence" ou "réactivité", certes très légère...

Mais quand les script commencent à devenir lourd, ça peut peut-être avoir son importance non ?

 

J'ai envie de dire que passer par l'API semble plus rapide qu'utiliser les fonctions Fibaro !

Je me trompe ? c'est juste une impression ?

 

Y a t il une règle spécifique ?

 

Qu'en pensez vous ?

Lien vers le commentaire
Partager sur d’autres sites

Je pense que tu as raison, car les commandes fibaro font appel à l'API il me semble bien. Donc ça rajoute une encapsulation.

 

Le seul moyen de le savoir, c'est de faire un benchmark.

Tu fais une boucle qui répète 1000 fois la même action, et tu mesures la durée d'exécution avec os.clock()

Tu fais tourner chaque boucle 2 ou 3 fois pour absorber les variations, et tu compares les 2 résultats des différentes commandes

Lien vers le commentaire
Partager sur d’autres sites

oh ben merde ! je m'y attendais pas à ça !!!!

 

function QuickApp:button1(event)
    local t1 = os.time()
    self:trace("Start GET with API")
    for i = 1, 1000 do res = api.get("/devices/38").properties.value end
    self:trace("Get with API : ", os.difftime(os.time(),t1), "secondes")
end

function QuickApp:button2(event)
    local t1 = os.time()
    self:trace("Start GET with FIBARO")
    for i = 1, 1000 do res = fibaro.getValue(38, "value") end
    self:trace("Get with FIBARO : ", os.difftime(os.time(),t1), "secondes")
end

résultat : 

 

[06.06.2020] [11:38:57] [TRACE] [QUICKAPP600]: Start GET with API
[06.06.2020] [11:39:10] [TRACE] [QUICKAPP600]: Get with API : 13.0 secondes
[06.06.2020] [11:39:13] [TRACE] [QUICKAPP600]: Start GET with FIBARO
[06.06.2020] [11:39:16] [TRACE] [QUICKAPP600]: Get with FIBARO : 3.0 secondes

 

Lien vers le commentaire
Partager sur d’autres sites

Hum, étonnant.

 

Cela me rappelle un vieux Benchmark développé par Steven lors du passage à la v4 sur HC2, qui démontrait que la HC3 en v3 était plus performante que la v4 : En page 7 de ce topic :

 

 

 

 

Tu crois que tu pourrais le porter pour un QuickApp sur HC3 ?

Et le même dans une scène, pour comparer les performances.

 

D'ailleurs c'est pareil pour ton test, il faudrait le faire tourner dans une scène pour voir s'il subsiste une différence comme sur la HC2

Lien vers le commentaire
Partager sur d’autres sites

et pour le CALL

 

function QuickApp:button3(event)
    local t1 = os.time()
    self:trace("Start CALL with API")
    for i = 1, 1000 do res = api.post("/devices/203/action/turnOn",{}) end
    self:trace("CALL with API : ", os.difftime(os.time(),t1), "secondes")
end

function QuickApp:button4(event)
    local t1 = os.time()
    self:trace("Start CALL with FIBARO")
    for i = 1, 1000 do res = fibaro.call(203, "turnOn") end
    self:trace("CALL with FIBARO : ", os.difftime(os.time(),t1), "secondes")
end

résultat

[06.06.2020] [11:48:05] [TRACE] [QUICKAPP600]: Start CALL with API
[06.06.2020] [11:49:30] [TRACE] [QUICKAPP600]: CALL with API : 85.0 secondes
[06.06.2020] [11:49:36] [TRACE] [QUICKAPP600]: Start CALL with FIBARO
[06.06.2020] [11:51:04] [TRACE] [QUICKAPP600]: CALL with FIBARO : 88.0 secondes

 

donc ça c’était depuis un QA, je vais essayer depuis une scène...

Lien vers le commentaire
Partager sur d’autres sites

Alors dans une scène

 

déjà la fonction os.difftime() est pas dispo :( par grave, j'ai contourné...

 

voilà le résultat

 

[06.06.2020] [12:03:01] [TRACE] [TEST SCENE]: Start GET with API
[06.06.2020] [12:03:21] [TRACE] [TEST SCENE]: Get with API : 20 secondes

[06.06.2020] [12:03:21] [TRACE] [TEST SCENE]: Start GET with FIBARO
[06.06.2020] [12:03:24] [TRACE] [TEST SCENE]: Get with FIBARO : 3 secondes

----------------------------------------------------------------------------

[06.06.2020] [12:03:24] [TRACE] [TEST SCENE]: Start CALL with API
[06.06.2020] [12:04:58] [TRACE] [TEST SCENE]: CALL with API : 94 secondes

[06.06.2020] [12:04:58] [TRACE] [TEST SCENE]: Start CALL with FIBARO
[06.06.2020] [12:06:15] [TRACE] [TEST SCENE]: CALL with FIBARO : 77 secondes

 

Lien vers le commentaire
Partager sur d’autres sites

@Lazer : j'ai repris le code de @Steven comme tu proposais

 

os.clock() n'existe pas, il me retourne une erreur, je l'ai donc enlevé :( dommage...

 

-- Parameters --
local NameScene = "Test"
local id_exist = 600
local global_exist = "DelayVmc"
local nbIteration = 1000

-- Do not touch please ---
local id_not_exist = 100056
local global_not_exist = "AABBCCDDEEFFGGHHIIFFF"

function log(name, start)
  	if (start) then
		fibaro.trace(NameScene,string.format("%s instruction time : %ds", name, os.time()-start))
	else
		fibaro.trace(NameScene,string.format("%s", name))
    end
end

function execute(name, func)
  if not pcall(function() 
        local start = os.time()
        for i= 1, nbIteration do func() end
        log(name, start)
    end) then 
        fibaro.warning(NameScene, "ERROR : " .. name)
    end
end  

log("Nb runs : " .. nbIteration .. " | id : " .. id_exist .. " | G.Variable : " .. global_exist)
log("----------------------------------------------")
log("")

-- Tests ---
execute("getValue Exist_________________:", function() fibaro.getValue(id_exist, "value") end)
execute("getValue Not Exist_____________:", function() fibaro.getValue(id_not_exist, "value") end)
execute("turnOn_________________________:", function() fibaro.call(id_exist, "turnOn") end)
execute("getGlobalVariable Exist________:", function() fibaro.getGlobalVariable(global_exist) end)
execute("getGlobalVariable Not Exist____:", function() fibaro.getGlobalVariable(global_not_exist) end)
execute("setGlobalVariable______________:", function() fibaro.setGlobalVariable(global_exist, fibaro.getGlobalVariable(global_exist)) end)
execute("getType________________________:", function() fibaro.getType(id_exist) end)
execute("getName________________________:", function() fibaro.getName(id_exist) end)
execute("getRoomID______________________:", function() fibaro.getRoomID(id_exist) end)
execute("getRoomName____________________:", function() fibaro.getRoomName(fibaro.getRoomID(id_exist)) end)
execute("getSunrise_____________________:", function() fibaro.getValue(1, "sunsetHour") end)

log("")
log("----------------------------------------------")
log("ALL DONE")

 

Résultat

 

[06.06.2020] [17:31:04] [TRACE] [TEST]: Nb runs : 1000 | id : 600 | G.Variable : DelayVmc
[06.06.2020] [17:31:04] [TRACE] [TEST]: ----------------------------------------------
[06.06.2020] [17:31:04] [TRACE] [TEST]:
[06.06.2020] [17:31:08] [TRACE] [TEST]: getValue Exist_________________: instruction time : 4s
[06.06.2020] [17:31:11] [TRACE] [TEST]: getValue Not Exist_____________: instruction time : 3s
[06.06.2020] [17:32:11] [TRACE] [TEST]: turnOn_________________________: instruction time : 60s
[06.06.2020] [17:32:11] [TRACE] [TEST]: getGlobalVariable Exist________: instruction time : 0s
[06.06.2020] [17:32:11] [TRACE] [TEST]: getGlobalVariable Not Exist____: instruction time : 0s
[06.06.2020] [17:32:11] [TRACE] [TEST]: setGlobalVariable______________: instruction time : 0s
[06.06.2020] [17:32:25] [TRACE] [TEST]: getType________________________: instruction time : 14s
[06.06.2020] [17:32:37] [TRACE] [TEST]: getName________________________: instruction time : 12s
[06.06.2020] [17:32:50] [TRACE] [TEST]: getRoomID______________________: instruction time : 13s
[06.06.2020] [17:33:07] [TRACE] [TEST]: getRoomName____________________: instruction time : 17s
[06.06.2020] [17:33:10] [TRACE] [TEST]: getSunrise_____________________: instruction time : 3s
[06.06.2020] [17:33:10] [TRACE] [TEST]:
[06.06.2020] [17:33:10] [TRACE] [TEST]: ----------------------------------------------
[06.06.2020] [17:33:10] [TRACE] [TEST]: ALL DONE

 

Lien vers le commentaire
Partager sur d’autres sites

Top ça, merci :)

 

Sur mon HC3, qui semble un peu plus rapide que la tienne, surement parce qu'elle est moins chargée, elle ne me sert que pour du développement.

[06.06.2020] [19:04:35] [TRACE] [TEST LUA PERF]: Nb runs : 1000 | id : 22 | G.Variable : Test
[06.06.2020] [19:04:35] [TRACE] [TEST LUA PERF]: ----------------------------------------------
[06.06.2020] [19:04:35] [TRACE] [TEST LUA PERF]: 
[06.06.2020] [19:04:37] [TRACE] [TEST LUA PERF]: getValue Exist_________________: instruction time : 2s
[06.06.2020] [19:04:39] [TRACE] [TEST LUA PERF]: getValue Not Exist_____________: instruction time : 2s
[06.06.2020] [19:05:10] [TRACE] [TEST LUA PERF]: turnOn_________________________: instruction time : 31s
[06.06.2020] [19:05:10] [TRACE] [TEST LUA PERF]: getGlobalVariable Exist________: instruction time : 0s
[06.06.2020] [19:05:10] [TRACE] [TEST LUA PERF]: getGlobalVariable Not Exist____: instruction time : 0s
[06.06.2020] [19:05:10] [TRACE] [TEST LUA PERF]: setGlobalVariable______________: instruction time : 0s
[06.06.2020] [19:05:22] [TRACE] [TEST LUA PERF]: getType________________________: instruction time : 12s
[06.06.2020] [19:05:35] [TRACE] [TEST LUA PERF]: getName________________________: instruction time : 13s
[06.06.2020] [19:05:47] [TRACE] [TEST LUA PERF]: getRoomID______________________: instruction time : 12s
[06.06.2020] [19:06:02] [TRACE] [TEST LUA PERF]: getRoomName____________________: instruction time : 15s
[06.06.2020] [19:06:03] [TRACE] [TEST LUA PERF]: getSunrise_____________________: instruction time : 1s
[06.06.2020] [19:06:03] [TRACE] [TEST LUA PERF]: 
[06.06.2020] [19:06:03] [TRACE] [TEST LUA PERF]: ----------------------------------------------
[06.06.2020] [19:06:03] [TRACE] [TEST LUA PERF]: ALL DONE

 

Pour info sur mon HC2 :

[DEBUG] 11:39:36: Nb runs : 1000 | id : 11 | G.Variable : SMS 
[DEBUG] 11:39:36: ---------------------------------------------- 
[DEBUG] 11:39:36:  
[DEBUG] 11:39:40: getValue Exist : instruction time : 4s | cpu time : 1.726s 
[DEBUG] 11:39:44: getValue Not Exist : instruction time : 4s | cpu time : 1.40616s 
[DEBUG] 11:39:55: setValue : instruction time : 11s | cpu time : 3.4183s 
[DEBUG] 11:39:58: getGlobal Exist : instruction time : 3s | cpu time : 1.73315s 
[DEBUG] 11:40:01: getGlobal Not Exist : instruction time : 3s | cpu time : 1.41096s 
[DEBUG] 11:40:46: setGlobal : instruction time : 45s | cpu time : 3.78558s 
[DEBUG] 11:40:56: getType : instruction time : 10s | cpu time : 6.68276s 
[DEBUG] 11:41:06: getName : instruction time : 10s | cpu time : 6.87206s 
[DEBUG] 11:41:16: getRoomID : instruction time : 10s | cpu time : 6.71876s 
[DEBUG] 11:41:29: getRoomName : instruction time : 12s | cpu time : 8.48164s 
[DEBUG] 11:41:32: getSunrise : instruction time : 4s | cpu time : 1.69301s 
[DEBUG] 11:41:32:  
[DEBUG] 11:41:32: ---------------------------------------------- 
[DEBUG] 11:41:32: ALL DONE 

 

Les résultats sont pour le moins surprenants : dans l'ensemble, mon HC2 de prod, donc avec déjà une bonne activité (gestion des modules Z-Wave, VD, Scènes, ....) est plus performante que la HC3 !!!

 

Ça c'est pas banal.... :huh:

 

Imagine la HC2 en v3 comment ça décoiffait, elle explose tout le monde :3:

 

 

  • Like 1
  • Haha 1
Lien vers le commentaire
Partager sur d’autres sites

Je suis en train de penser à autre chose en regardant les CPU de la HC3.

Elle a 4 coeurs, tandis que la HC2 n'en avait que 2.

Chaque QuickApp ou scène est monothreadé, c'est à dire que son code ne s'exécute que sur un seul cœur.

Donc ce benchmark est limité par la puissance d'un cœur.

En fait c'est même plus compliqué, car il fait appel à l'API et aux fonctions Fibaro qui sont exécutées dans d'autres processus, sur d'autres cœurs.

Bref, il ne permet pas de comparer les performances d'une HC2 avec une HC3.

 

Mais le raisonnement reste valable pour optimiser son propre code LUA :)

 

Lien vers le commentaire
Partager sur d’autres sites

pas moyen de savoir quel cœur est utilisé ?

 

je me suis posé ces questions de performances, suite à mes problèmes liés au manque de multi instances des scènes.

Un gars sur le fofo officiel m'a proposé d'utilité l'API RefreshStates.

Qui recense tous les événements.

Je l'interroge toutes les 200 ms.

selon des filtres que j'ai mis en place, je lance des fonctions dans des QA.

Du coup, avec ce procédé, je ne passe plus par des scènes triggées.

Et j'ai donc résolu le problème d'événements "loupé" ou plutôt d'actions non effectuées.

 

Mais ! je constate une légère latence dans les actions... :( 

Lien vers le commentaire
Partager sur d’autres sites

Non pas vraiment, et de toute façon ça n'aurait que peu d'intérêt, le scheduleur dans le noyau de l'OS affecte les threads d'exécution dynamiquement aux coeurs, en fonction de la charge. C'est le principe même d'un OS multithreadé (par opposition à.... MS-DOS :2:)

 

Tu peux regarder l'onglet CPU du panneau de Diagnostiques pendant l'exécution de ta scène de Benchmark, tu verras que tous les cœurs travaillent, justement parce que l'OS équilibre au mieux l'activité. Ce qu'il faut plusieurs dizaines de fois par seconde, donc c'est invisible à l'échelle humaine.

 

image.thumb.png.17d0a09cfbc7d71345e798e2b041a793.png

 

Lien vers le commentaire
Partager sur d’autres sites

Le 06/06/2020 à 11:08, Lazer a dit :

les commandes fibaro font appel à l'API il me semble bien.

C'est tout à fait ça... Et certainement encore le cas sur HC3

 

Les fonctions fibaro ne sont qu'une surcouche sur des fonctions LUA internes qui utilisent des libs lua, dans le but de simplifier la vie de monsieur tout le monde.

 

Par ex pour un getValue le parcours est le suivant:

 

  1. <-> fibaro.getValue
  2. <-> fibaro:get + des vérifications + conversion des valeurs retournées (string: valeur + modification)
  3. <-> api.get
  4. <-> http:GET() => pas possible de descendre plus bas sauf en root
  5. <-> lib

@jjacques68

 

Petite piste d'optimisation :)

 

Le api.get dans le cas d'un getValue devrait être :

api.get("/devices/{deviceID}/properties/{propertyName}")

et pas 

api.get("/devices/{deviceID}").properties.value

Tu vas comprendre :)

 

http://hc3-00000000/api/devices/27/properties/value retourne

 

{
  "value": 0,
  "modified": 1591920284
}

http://hc3-00000000/api/devices/27 retourne l’intégralité de l'objet


  "id": 27,
  "name": "27",
  "roomID": 220,
  "view": [
    {
      "assetsPath": "/dynamic-plugins/com.fibaro.multilevelSwitch/assets",
      "jsPath": "/dynamic-plugins/com.fibaro.multilevelSwitch",
      "name": "com.fibaro.multilevelSwitch",
      "translatesPath": "/dynamic-plugins/com.fibaro.multilevelSwitch/i18n",
      "type": "ts"
    }
  ],
  "type": "com.fibaro.multilevelSwitch",
  "baseType": "com.fibaro.binarySwitch",
  "enabled": true,
  "visible": true,
  "isPlugin": false,
  "parentId": 492,
  "viewXml": false,
  "configXml": false,
  "interfaces": [
    "deviceGrouping",
    "levelChange",
    "light",
    "power",
    "zwave",
    "zwaveSwitchAll"
  ],
  "properties": {
    "parameters": [
      {
        "id": 1,
        "lastReportedValue": 255,
        "lastSetValue": 255,
        "size": 1,
        "value": 255
      },
      {
        "id": 6,
        "lastReportedValue": 0,
        "lastSetValue": 0,
        "size": 1,
        "value": 0
      },
      {
        "id": 7,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 8,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 9,
        "lastReportedValue": 5,
        "lastSetValue": 5,
        "size": 1,
        "value": 5
      },
      {
        "id": 10,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 11,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 12,
        "lastReportedValue": 99,
        "lastSetValue": 99,
        "size": 1,
        "value": 99
      },
      {
        "id": 13,
        "lastReportedValue": 2,
        "lastSetValue": 2,
        "size": 1,
        "value": 2
      },
      {
        "id": 14,
        "lastReportedValue": 0,
        "lastSetValue": 0,
        "size": 1,
        "value": 0
      },
      {
        "id": 15,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 16,
        "lastReportedValue": 1,
        "lastSetValue": 1,
        "size": 1,
        "value": 1
      },
      {
        "id": 17,
        "lastReportedValue": 0,
        "lastSetValue": 0,
        "size": 1,
        "value": 0
      },
      {
        "id": 18,
        "lastReportedValue": 0,
        "lastSetValue": 0,
        "size": 1,
        "value": 0
      },
      {
        "id": 19,
        "lastReportedValue": 0,
        "lastSetValue": 0,
        "size": 1,
        "value": 0
      },
      {
        "id": 20,
        "lastReportedValue": 110,
        "lastSetValue": 110,
        "size": 1,
        "value": 110
      },
      {
        "id": 30,
        "lastReportedValue": 3,
        "lastSetValue": 3,
        "size": 1,
        "value": 3
      },
      {
        "id": 39,
        "lastReportedValue": 600,
        "lastSetValue": 600,
        "size": 2,
        "value": 600
      }
    ],
    "pollingTimeSec": 0,
    "zwaveCompany": "Fibargroup",
    "zwaveInfo": "3,3,20",
    "zwaveVersion": "1.4",
    "categories": [
      "lights"
    ],
    "configured": true,
    "dead": false,
    "deadReason": "",
    "deviceControlType": 23,
    "deviceGroup": [
      
    ],
    "deviceGroupMaster": 0,
    "deviceIcon": 15,
    "emailNotificationID": 3,
    "emailNotificationType": 0,
    "endPointId": 0,
    "isLight": true,
    "log": "",
    "logTemp": "",
    "manufacturer": "",
    "markAsDead": true,
    "model": "",
    "nodeId": 8,
    "parametersTemplate": "1",
    "power": 0.0,
    "powerConsumption": 80,
    "productInfo": "1,15,1,0,1,4,1,4",
    "pushNotificationID": 4,
    "pushNotificationType": 0,
    "remoteGatewayId": 0,
    "saveLogs": true,
    "serialNumber": "",
    "showEnergy": true,
    "smsNotificationID": 3,
    "smsNotificationType": 0,
    "state": false,
    "switchAllMode": "SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY",
    "useTemplate": true,
    "userDescription": "",
    "value": 0
  },
  "actions": {
    
  },
  "created": 1591920284,
  "modified": 1591920284,
  "sortOrder": 5
}

Donc si tu veux réellement gagner du CPU, économiser la mémoire et améliorer les temps de réponse je crois que tu sais ce qu'il te reste à faire.

 

Dans le cas d'un fibaro.call bien que cela puisse paraître dingue ceci https://www.domotique-fibaro.fr/topic/14144-script-custom-callaction/ est vraisemblablement la méthode la plus souple et la plus efficace en matière de performance mais à mettre dans la balance avec les lignes de codes en sus à charger à l'appel d'une scène ou en mémoire pour un QA, tout est toujours une affaire de compromis et une solution adaptée a un cas d'usage ;)

 

 

  • Like 2
Lien vers le commentaire
Partager sur d’autres sites

Il y a 14 heures, Krikroff a dit :

Le api.get dans le cas d'un getValue devrait être :


api.get("/devices/{deviceID}/properties/{propertyName}")

Alors peut on accéder de la même manière à d'autre info qui ne sont pas dans "properties" ?

comme par exemple le roomID d'un device ?

 

J'ai essayé ça mais ça ne marche pas

local RoomID = api.get("/devices/203/roomID")

 

Lien vers le commentaire
Partager sur d’autres sites

×
×
  • Créer...