As requested in the JSR223 performance thread I’ll post my code as an example to see if there is some room for improvements. I found that jython is ~160 times faster than xTend in a simple example.
The code here is for analyzing and to find out if there are possibilities in xTend to make it run faster.
What does it do:
I have six led strips in my room. Two in front of me, two to the left and two to the right. On is always facing up and one is facing down. I use this setup to illuminate the room when there is movement but also to signal various events:
- washing mashine is done
- I forgot to close the window and is getting cold
- today is trash day and I have to remember to take it out
- etc.
So there are various fades which can overlay each other and run at the same time. To make it more complicated, some fades run only on some led strips. Washing machine runs only on the lower strips, window only on the front lower but movement only on the upper strips.
To achieve this comfortably I wrote a fade scheduler. Unfortunately the code is very slow on the pi2. My goal was to get a refresh rate of 50ms so I can have really smooth fades. At the moment I have between 150ms and 750ms per fade step - so this is way to slow.
I am posting my code for analysis. Be aware that the code is very complex and is best viewed in the designer. If you want to run the code and you don’t have the dmx-binding just delete the dmx part. It should run fine without.
items
Group gWohnzimmerFADEs "Fades"
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
// DMX Auswahl
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
Number Wohnzimmer_Fade_Zeit "Fade Zeit ms [%d]"
Group g_Licht_Wohnzimmer (gWohnzimmerFADEs)
Group g_Licht_Wohnzimmer_Oben (g_Licht_Wohnzimmer)
Color Wohnzimmer_Vorne_Oben "Wohn V O" (g_Licht_Wohnzimmer_Oben) {dmx="CHANNEL[81/3], ON[FADE|5000:255,255,200:0], OFF[FADE|2000:0,0,0:0]"}
Color Wohnzimmer_Rechts_Oben "Wohn R O" (g_Licht_Wohnzimmer_Oben) {dmx="CHANNEL[73/3], ON[FADE|5000:255,255,200:0], OFF[FADE|2000:0,0,0:0]"}
Color Wohnzimmer_Hinten_Oben "Wohn H O" (g_Licht_Wohnzimmer_Oben) {dmx="CHANNEL[65/3], ON[FADE|5000:255,255,200:0], OFF[FADE|2000:0,0,0:0]"}
Group g_Licht_Wohnzimmer_Unten (g_Licht_Wohnzimmer)
Color Wohnzimmer_Vorne_Unten "Wohn V U" (g_Licht_Wohnzimmer_Unten) { dmx="CHANNEL[85/3],ON[FADE|5000:255,255,200:0],OFF[FADE|2000:0,0,0:0]" }
Color Wohnzimmer_Rechts_Unten "Wohn V U" (g_Licht_Wohnzimmer_Unten) { dmx="CHANNEL[77/3],ON[FADE|5000:255,255,200:0],OFF[FADE|2000:0,0,0:0]" }
Color Wohnzimmer_Hinten_Unten "Wohn V U" (g_Licht_Wohnzimmer_Unten) { dmx="CHANNEL[69/3],ON[FADE|5000:255,255,200:0],OFF[FADE|2000:0,0,0:0]" }
Group g_Wohnzimmer_Fade_History
Color Wohnzimmer_Vorne_Oben_0 (g_Wohnzimmer_Fade_History)
Color Wohnzimmer_Rechts_Oben_0 (g_Wohnzimmer_Fade_History)
Color Wohnzimmer_Hinten_Oben_0 (g_Wohnzimmer_Fade_History)
Color Wohnzimmer_Vorne_Unten_0 (g_Wohnzimmer_Fade_History)
Color Wohnzimmer_Rechts_Unten_0 (g_Wohnzimmer_Fade_History)
Color Wohnzimmer_Hinten_Unten_0 (g_Wohnzimmer_Fade_History)
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
// DMX-Fades
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
Switch Wohnzimmer_Fade_Bewegung_Tag "Bewegungsmelder Tag" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Bewegung_Nacht "Bewegungsmelder Nacht" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Waschmaschine "Waschmaschine fertig" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Schalter "Funkschalter" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Muell "Muell raus bringen" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Schlafzimmerfenster "Schlafzimmerfenster offen" (gWohnzimmerFADEs)
Switch Wohnzimmer_Fade_Alle_Aus "Alle aus" (gWohnzimmerFADEs)
Switch Wohnzimmer_FADE_Luigi_online "Luigi online" (gWohnzimmerFADEs)
Switch Wohnzimmer_FADE_Luigi_offline "Luigi offline" (gWohnzimmerFADEs)
code:
// Imports
import org.joda.time.*
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.util.LinkedHashMap
import java.util.HashMap
import java.util.Map
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
var Lock to_copy_lock = new ReentrantLock()
var boolean to_copy_state = false
var Lock fades_lock = new ReentrantLock()
var int fades_anz = 0
var HashMap<String, Object> fade_soll_map =
newLinkedHashMap(
"Vorne_Oben" -> null as HSBType,
"Rechts_Oben" -> null as HSBType,
"Hinten_Oben" -> null as HSBType,
"Vorne_Unten" -> null as HSBType,
"Rechts_Unten" -> null as HSBType,
"Hinten_Unten" -> null as HSBType,
"Wait" -> false as Boolean,
"" -> null as Object
) as LinkedHashMap<String, Object>
rule "Fade Bewegungsmelder Tag an"
when
Item Wohnzimmer_Fade_Bewegung_Tag received update ON
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
fade_soll_map.put( "Vorne_Oben", new HSBType( "0,0,100"))
fade_soll_map.put( "Rechts_Oben", new HSBType( "0,0,100"))
fade_soll_map.put( "Hinten_Oben", new HSBType( "0,0,100"))
Wohnzimmer_Fade_Zeit.sendCommand(3000)
end
rule "Fade Bewegungsmelder Nacht an"
when
Item Wohnzimmer_Fade_Bewegung_Nacht received update ON
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
fade_soll_map.put( "Vorne_Oben", new HSBType( "30,100,3"))
fade_soll_map.put( "Rechts_Oben", new HSBType( "30,100,3"))
fade_soll_map.put( "Hinten_Oben", new HSBType( "30,100,3"))
Wohnzimmer_Fade_Zeit.sendCommand(3000)
end
rule "Bewegungsmelder Fade aus"
when
Item Wohnzimmer_Fade_Bewegung_Tag received update OFF or
Item Wohnzimmer_Fade_Bewegung_Nacht received update OFF
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
fade_soll_map.put( "Wait", true as Boolean)
fade_soll_map.put( "Vorne_Oben", new HSBType( "0,0,0"))
fade_soll_map.put( "Rechts_Oben", new HSBType( "0,0,0"))
fade_soll_map.put( "Hinten_Oben", new HSBType( "0,0,0"))
Wohnzimmer_Fade_Zeit.sendCommand(2000)
end
rule "Bewegungsmelder Wohnzimmer_Fade_Schalter"
when
Item Wohnzimmer_Fade_Schalter received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_Fade_Schalter.state
if( state == OFF) {
fade_soll_map.put( "Wait", true as Boolean)
fade_soll_map.put( "Vorne_Oben", new HSBType( "0,0,0"))
fade_soll_map.put( "Rechts_Oben", new HSBType( "0,0,0"))
fade_soll_map.put( "Hinten_Oben", new HSBType( "0,0,0"))
fade_soll_map.put( "Vorne_Unten", new HSBType( "0,0,0"))
fade_soll_map.put( "Rechts_Unten", new HSBType( "0,0,0"))
fade_soll_map.put( "Hinten_Unten", new HSBType( "0,0,0"))
}
else {
fade_soll_map.put( "Vorne_Oben", new HSBType( "0,0,100"))
fade_soll_map.put( "Rechts_Oben", new HSBType( "0,0,100"))
fade_soll_map.put( "Hinten_Oben", new HSBType( "0,0,100"))
fade_soll_map.put( "Vorne_Unten", new HSBType( "0,0,100"))
fade_soll_map.put( "Rechts_Unten", new HSBType( "0,0,100"))
fade_soll_map.put( "Hinten_Unten", new HSBType( "0,0,100"))
}
Wohnzimmer_Fade_Zeit.sendCommand(2000)
end
rule "Fade Bewegungsmelder Waschmaschine"
when
Item Wohnzimmer_Fade_Waschmaschine received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_Fade_Waschmaschine.state
var HSBType next = null
if( state == ON) next = new HSBType( "130,100,100")
else next = new HSBType( "130,100,0")
fade_soll_map.put( "Vorne_Unten", next)
fade_soll_map.put( "Rechts_Unten", next)
fade_soll_map.put( "Hinten_Unten", next)
if( state == OFF) fade_soll_map.put( "Wait", true as Boolean)
Wohnzimmer_Fade_Zeit.sendCommand(3000)
end
rule "Fade Wohnzimmer_Fade_Schlafzimmerfenster"
when
Item Wohnzimmer_Fade_Schlafzimmerfenster received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_Fade_Schlafzimmerfenster.state
var HSBType next = null
if( state == ON) next = new HSBType( "230,90,100")
else next = new HSBType( "230,90,0")
fade_soll_map.put( "Vorne_Unten", next)
if( state == OFF) {
fade_soll_map.put( "Wait", true as Boolean)
}
Wohnzimmer_Fade_Zeit.sendCommand(1000)
end
rule "Fade Wohnzimmer_Fade_Muell"
when
Item Wohnzimmer_Fade_Muell received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_Fade_Muell.state
var HSBType next = null
if( state == ON) next = new HSBType( "307,83,100")
else next = new HSBType( "307,83,0")
fade_soll_map.put( "Vorne_Unten", next)
fade_soll_map.put( "Rechts_Unten", next)
fade_soll_map.put( "Hinten_Unten", next)
if( state == OFF)fade_soll_map.put( "Wait", true as Boolean)
Wohnzimmer_Fade_Zeit.sendCommand(3000)
if( state == ON){
createTimer(now.plusSeconds(90)) [|
Wohnzimmer_Fade_Muell.postUpdate(OFF)
]
}
end
rule "Fade Wohnzimmer_FADE_Luigi_online"
when
Item Wohnzimmer_FADE_Luigi_online received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_FADE_Luigi_online.state
var HSBType next = null
if( state == ON) next = new HSBType( "131,88,100")
else next = new HSBType( "131,88,0")
if( state == OFF) fade_soll_map.put( "Wait", true as Boolean)
fade_soll_map.put( "Hinten_Unten", next)
Wohnzimmer_Fade_Zeit.sendCommand(3000)
end
rule "Fade Wohnzimmer_FADE_Luigi_offline"
when
Item Wohnzimmer_FADE_Luigi_offline received update
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val state = Wohnzimmer_FADE_Luigi_offline.state
var HSBType next = null
if( state == ON) next = new HSBType( "17,87,100")
else next = new HSBType( "17,87,0")
if( state == OFF) fade_soll_map.put( "Wait", true as Boolean)
fade_soll_map.put( "Hinten_Unten", next)
Wohnzimmer_Fade_Zeit.sendCommand(2000)
end
rule "Fade Wohnzimmer_Fade_Alle_Aus"
when
Item Wohnzimmer_Fade_Alle_Aus received update ON
then
var boolean wait = true
do{
to_copy_lock.lock()
wait = to_copy_state
if( !to_copy_state) to_copy_state = true
to_copy_lock.unlock()
if( wait) Thread::sleep(100)
}
while(wait)
val HSBType VO = Wohnzimmer_Vorne_Oben.state as HSBType
val HSBType RO = Wohnzimmer_Rechts_Oben.state as HSBType
val HSBType HO = Wohnzimmer_Hinten_Oben.state as HSBType
val HSBType VU = Wohnzimmer_Vorne_Unten.state as HSBType
val HSBType RU = Wohnzimmer_Rechts_Unten.state as HSBType
val HSBType HU = Wohnzimmer_Hinten_Unten.state as HSBType
//Aus wartet immer
fade_soll_map.put( "Wait", true as Boolean)
if( VO.brightness > 0) fade_soll_map.put( "Vorne_Oben", new HSBType(VO.hue, VO.saturation, new PercentType(0)))
if( RO.brightness > 0) fade_soll_map.put( "Rechts_Oben", new HSBType(RO.hue, RO.saturation, new PercentType(0)))
if( HO.brightness > 0) fade_soll_map.put( "Hinten_Oben", new HSBType(HO.hue, HO.saturation, new PercentType(0)))
if( VU.brightness > 0) fade_soll_map.put( "Vorne_Unten", new HSBType(HO.hue, HO.saturation, new PercentType(0)))
if( RU.brightness > 0) fade_soll_map.put( "Rechts_Unten", new HSBType(RU.hue, RU.saturation, new PercentType(0)))
if( HU.brightness > 0) fade_soll_map.put( "Hinten_Unten", new HSBType(HU.hue, HU.saturation, new PercentType(0)))
Wohnzimmer_Fade_Zeit.sendCommand(2000)
end
rule "test"
when
Item test changed or
System started
then
val tsstart = DateTimeUtils::currentTimeMillis()
var HashMap<String, String> map_soll = newLinkedHashMap( "" -> "") as LinkedHashMap<String, String>
var i = 0
do {
map_soll.put( String::format("%d", i), String::format("%d", i))
i = i + 1
}
while( i < 100000)
logInfo( "Wohnzimmer", String::format( "Dauer %dms", DateTimeUtils::currentTimeMillis() - tsstart))
end
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
// Fade Wohnzimmer init
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Fade Wohnzimmer init"
when
Item Initialize received update ON or
System started
then
Wohnzimmer_Vorne_Oben.sendCommand( "0,0,0")
Wohnzimmer_Rechts_Oben.sendCommand( "0,0,0")
Wohnzimmer_Hinten_Oben.sendCommand( "0,0,0")
Wohnzimmer_Vorne_Unten.sendCommand( "0,0,0")
Wohnzimmer_Rechts_Unten.sendCommand( "0,0,0")
Wohnzimmer_Hinten_Unten.sendCommand( "0,0,0")
Wohnzimmer_Fade_Zeit.postUpdate(0)
fades_lock.lock()
fades_anz = 0
fades_lock.unlock()
to_copy_lock.lock()
to_copy_state = false
to_copy_lock.unlock()
end
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
// Execute Fade
//-----------------------------------------------------------------------------------------------------------------------------------------------------------
rule "Execute Fade"
when
Item Wohnzimmer_Fade_Zeit received update
then
var Integer steps = (Wohnzimmer_Fade_Zeit.state as DecimalType / 50).intValue()
if( steps <= 0) {
to_copy_lock.lock()
to_copy_state = false
to_copy_lock.unlock()
return false
}
logDebug( "Wohnzimmer", String::format( "%15s | 1", "Fade"))
val keys = newArrayList("Vorne_Oben", "Rechts_Oben", "Hinten_Oben", "Vorne_Unten", "Rechts_Unten", "Hinten_Unten")
var long start = DateTimeUtils::currentTimeMillis()
var HashMap<String, Object> map_soll = newLinkedHashMap( "" -> null as Object) as LinkedHashMap<String, Object>
//Copy locally
for( key : keys) {
map_soll.put( key, fade_soll_map.get(key))
fade_soll_map.put( key, null)
}
map_soll.put( "Wait", fade_soll_map.get("Wait"))
fade_soll_map.put( "Wait", false as Boolean)
//Available for copiing again
to_copy_lock.lock()
to_copy_state = false
to_copy_lock.unlock()
//Bei Wait warten, bis alle Fades fertig sind
val boolean wait = if( map_soll.get("Wait") as Boolean) true else false
if( wait) {
var int tmp = 1
while (tmp > 0) {
fades_lock.lock()
tmp = fades_anz
fades_lock.unlock()
if( tmp > 0) Thread::sleep(250)
}
}
//Anzahl erhöhen
fades_lock.lock()
fades_anz = fades_anz + 1
val fade_id = fades_anz
fades_lock.unlock()
if( wait) {
logDebug( "Wohnzimmer", String::format( "%15s | Wait complete %dms", "Fade" + fade_id.toString(), DateTimeUtils::currentTimeMillis() - start))
start = DateTimeUtils::currentTimeMillis()
}
logDebug( "Wohnzimmer", String::format( "%15s | Start %dms", "Fade" + fade_id.toString(), DateTimeUtils::currentTimeMillis() - start))
//initialisieren
var HashMap<String, LinkedHashMap<String, Object>> fade_data = newLinkedHashMap(
"Vorne_Oben" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Vorne_Oben as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>,
"Rechts_Oben" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Rechts_Oben as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>,
"Hinten_Oben" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Hinten_Oben as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>,
"Vorne_Unten" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Vorne_Unten as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>,
"Rechts_Unten" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Rechts_Unten as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>,
"Hinten_Unten" -> newLinkedHashMap(
"Do" -> false as Boolean,
"Item" -> Wohnzimmer_Hinten_Unten as Object,
"Dummy" -> null as Object
) as LinkedHashMap<String, Object>
)
var boolean do_sth = false
for( key : keys) {
var Object soll_obj = (map_soll.get( key)) as Object
if( soll_obj != null) {
var soll = soll_obj as HSBType
var data = fade_data.get( key)
var item = (data.get("Item")) as org.openhab.core.items.GenericItem
var ist = item.state as HSBType
data.put( "Do", true as Boolean)
data.put( "Soll", soll as HSBType)
var float diff_H = (soll.hue - ist.hue).floatValue() / steps
var float diff_S = (soll.saturation - ist.saturation).floatValue() / steps;
var float diff_B = (soll.brightness - ist.brightness).floatValue() / steps
//If we start from 0 brightness set color corectly!
if( ist.brightness == 0) {
diff_H = 0.floatValue()
diff_S = 0.floatValue()
item.sendCommand( new HSBType( soll.hue, soll.saturation, ist.brightness))
}
if( diff_H != 0 || diff_S != 0 || diff_B != 0) do_sth = true
data.put( "Step Hue", diff_H)
data.put( "Step Saturation", diff_S)
data.put( "Step Brightness", diff_B)
logDebug( "Wohnzimmer", String::format( "%15s | %13s Step Hue: %3.1f", "Fade" + fade_id.toString(), key, diff_H))
logDebug( "Wohnzimmer", String::format( "%15s | %13s Step Saturation: %3.1f", "Fade" + fade_id.toString(), key, diff_S))
logDebug( "Wohnzimmer", String::format( "%15s | %13s Step Brightness: %3.1f", "Fade" + fade_id.toString(), key, diff_B))
//Fade History
postUpdate( item.name + "_0", item.state.toString())
}
}
if( !do_sth){
fades_lock.lock()
fades_anz = fades_anz - 1
fades_lock.unlock()
return false
}
logDebug( "Wohnzimmer", String::format( "%15s | initialized: %dms", "Fade" + fade_id.toString(), DateTimeUtils::currentTimeMillis() - start))
var long step_duration_ts = DateTimeUtils::currentTimeMillis()
var int step_sleep = 0
//Fade Execution
while (steps > 0) {
step_duration_ts = DateTimeUtils::currentTimeMillis()
for( key : keys) {
var data = fade_data.get( key)
if( data.get("Do") as Boolean) {
var item = (data.get("Item")) as org.openhab.core.items.GenericItem
var HSBType ist = item.state as HSBType
var double new_H = ist.hue.floatValue() + (data.get("Step Hue") as Float)
var double new_S = ist.saturation.floatValue() + (data.get("Step Saturation") as Float)
var double new_B = ist.brightness.floatValue() + (data.get("Step Brightness") as Float)
//Boundry-Check!!!
if( new_H > 360.0) new_H = 360.0
if( new_S > 100.0) new_S = 100.0
if( new_B > 100.0) new_B = 100.0
if( new_H < 0.0) new_H = 0.0
if( new_S < 0.0) new_S = 0.0
if( new_B < 0.0) new_B = 0.0
val String str_H = String::format("%.3f", new_H).replace(",", ".")
val String str_S = String::format("%.3f", new_S).replace(",", ".")
val String str_B = String::format("%.3f", new_B).replace(",", ".")
//logDebug( "Wohnzimmer", "Command: " + str_H + "," + str_S + "," + str_B)
item.sendCommand( str_H + "," + str_S + "," + str_B)
}
}
step_sleep = 50 - (DateTimeUtils::currentTimeMillis() - step_duration_ts).intValue
if( step_sleep > 0) Thread::sleep( step_sleep)
//logDebug( "Wohnzimmer", String::format( "%15s | sleep: %dms", "Fade" + fade_id.toString(), step_sleep))
steps = steps - 1
}
//Anzahl verringern
fades_lock.lock()
fades_anz = fades_anz - 1
fades_lock.unlock()
logDebug( "Wohnzimmer", String::format( "%15s | finished: %dms", "Fade" + fade_id.toString(), DateTimeUtils::currentTimeMillis() - start))
end