I've posted more on the subject here.
http://www.wiremod.com/forum/ideas-suggestions/35567-attaching-sensors-entities.html
I need that for my maglevs to lag the server less when playing on train maps.
For 8 rangers in total I am getting vast increase in performance ( 110 ops for the wiremod sensor and 70 ops for mine )
This may be put in ..entities/wire_expression2/core/custom/flash_sensors.lua
https://github.com/dvdvideo1234/ScriptsWireE2/blob/master/Bridges/flash_sensors.lua
What do you guys think, may I create a patch for it ?
I believe the majority of the performance impact on the server comes from the util.TraceLine function, which is likely effectively hundreds of ops, rather than from lua primitive array instantiation. In either case, if you truly wanted to "cache" a trace request object, your sampleTrace(s) function could just be two lines:
local trData = findSensor(...)
util.TraceLine(trData)
Which I could see some value in... But to be accepted into official wire, it should use the same E2 types and methods as regular traces. Your variable reuse in findSensor is also rather troubling, just return false if any input parameter is missing, and then return the whole chain in one operation.
For 8 rangers in total I am getting vast increase in performance ( 110 ops for the wiremod sensor and 70 ops for mine )
E2 ops are not a useful measure of performance - we could just manually set every function to 0 ops. Can you provide actual performance benchmarking?
We could set some E2 functions to negative ops, and then, obviously, executing those functions will make the server run faster.
@immibis ...wat
@TomyLobo If reducing the number of ops that functions take makes them faster (hint: it doesn't), then why don't we set them to negative ops?
1) Assuming that you are talking about "e2function void entity:smpTracer(string sKey)"
I think all the input parameters must be checked before proceeding to the sampling
2) For the official wire traces what should I use?
wire/lua/entities/gmod_wire_expression2/core/ranger.lua
"local function ranger(self, rangertype, range, p1, p2, hulltype, mins, maxs, traceEntity )"
3) What is this "variable reuse" you speak of, assuming that you talk about "local Sensor = arrSensors". If it does not find a sensor with the given name it just returns nil, because it is needed to index by all three values ( type, entity, name )
The whole idea is to "attach" a sensor to the entity using a local position and direction, so for example for a maglev to be easier to manage the sensors.
https://www.youtube.com/watch?v=zijOm4JU2Gs
The E2 source used for testing
@name Tracer Test
@inputs
@outputs Dist Tct Cre Est Time
@persist E:entity Len End Time Tct Rep Cre Est Tst
@trigger
@model models/props_phx/gears/bevel9.mdl
runOnTick(1)
if(first() || dupefinished())
{
Rep = 200 # Run that many time the whole thing
Tst = 100 # Run the whole cycle that many times
End = 50 # Cycle counts
Len = 15
Est = 0
Cre = Rep
E = entity()
E:addTracer("TEST",vec(0,0,0),vec(0,0,-1),Len)
}
if(Cre)
{
if(Tct)
{
T = systime()
Cnt = End
while(Cnt > 0)
{
# BEGIN
# Flash Sensors
# E:smpTracer("TEST")
# Dist = E:getTracerDistance("TEST")
# Wire ranger
Dist = rangerOffset(Len,E:pos(),E:up()):distance()
# END
Cnt--
}
Time = Time + (systime() - T)
Tct--
}else{
Tct = Tst
if(Time > 0)
{
Est = Est + Time
Cre--
if(!Cre){ print("Elapsed: "+ (Est/Rep)) }
Time = 0
}
}
}
Flash sensors: 0.10629411670619
Wire ranger: 0.18506070641881
Well using the high accurate time is still ... 80% faster
Conceptual notes:
ranger functions could internally act on a ranger object similar to those created by your library. (There's also inconsistent terminology - the current ones are called rangers, and you call ranger to trace them, your ones are called tracers and you call smpTracer to trace them.)rangerIgnoreWorld, rangerFlags or any other things you can do with a global ranger.entity(1):addTracer(...), which is silly.runOnTick(1); entity():addTracer(toString(I++)) would eat the server's memory. (This isn't necessarily a huge issue because we probably are susceptible to this in many other places, and there are nastier ways to kill a server.)smpTracer as fast as possible, there's still more that could be done. If you wanted to be extreme, then you could avoid the local-space to world-space conversions by having an invisible point entity parented to the one you want to trace from. I'm not actually suggesting that you should do that - but there are smaller gains to be made. There's multiple unnecessary field accesses to trData.start and trData.endpos, and the use of sType adds hypothetical future flexibility at the result of an extra table lookup. And you could do the trick with local util_TraceLine = util.TraceLine at the top of the file to avoid yet more table accesses. Finally, you could slightly improve things with a tail call.So with 50 traces you're getting a 0.08 second increase in speed? That means (if my math is correct) that with 8 traces (like your maglev has), that'll be approximately 0.0126 seconds faster.
Not sure if you'll get a noticeable performance increase from this. If you want to do this because your maglev lags the server, I think you need to fix all the other code in your E2 before thinking about traces.
Well, in that case I was thinking to code a sampler of a ranger with local coordinates to the entity. What do you guys think
if(first() || dupefinished())
{
runOnTick(1)
Chip = entity()
RD = rangerOffset(Length,Position,Direction)
}
# Sample the ranger start/endpos relative to the entity given
# If no entity is given, then traces are using data provided when created
# In ranger:sample(Entity/Void) there will be a traceLine() finction
RD:sample(Chip)
# Get the distance
D = RD:distance()
So in the above example, that means the only performance increase you'll
get is from running toWorld in Lua instead of in E2? That's not going to be
a lot. However, if we do add that, let me modify your idea a tiny bit. We
could instead add "entity:rangerOffset(...)" which would have all the same
arguments and overloads as the regular rangerOffset, except all the
positions and directions would be local to the entity.
On Tue, May 24, 2016 at 10:06 AM, Deyan Dobromirov <[email protected]
wrote:
Well, in that case I was thinking to code a sampler of a ranger with local
coordinates to the entity. What do you guys thinkif(first() || dupefinished())
{
runOnTick(1)
Filter = entity()
RD = rangerOffset(Position,Direction,Length)
}Sample the ranger start/endpos relative to the entity given
If no entity is given, then traces are using (Position,Direction,Length)
In ranger:sample(Entity/Void) there will be a traceLine() finction
RD:sample(Filter)
Get the distance
D = RD:distance()
—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/wiremod/wire/issues/1123#issuecomment-221195716
But isn't it going to create a new ranger every iteration like before, though the Idea is quite good.
In my maglev I have:
##### Ranger data
# Getting data from UD Rangers
UfrPos = RangerUDOffset:x()*Fwd + RangerUDOffset:y()*Rgh + RangerUDOffset:z()*Up + MC
UflPos = UfrPos - 2 * RangerUDOffset:y() * Rgh
UbrPos = UfrPos - 2 * RangerUDOffset:x() * Fwd
UblPos = UflPos - 2 * RangerUDOffset:x() * Fwd
Ufl = rangerOffset(RangerLen:y(),UflPos,-Up):distance()
Ufr = rangerOffset(RangerLen:y(),UfrPos,-Up):distance()
Ubl = rangerOffset(RangerLen:y(),UblPos,-Up):distance()
Ubr = rangerOffset(RangerLen:y(),UbrPos,-Up):distance()
# Getting Data from LR Rangers
DfrPos = RangerLROffset:x()*Fwd + RangerLROffset:y()*Rgh + RangerLROffset:z()*Up + MC
DflPos = DfrPos - 2 * RangerLROffset:y() * Rgh
DbrPos = DfrPos - 2 * RangerLROffset:x() * Fwd
DblPos = DflPos - 2 * RangerLROffset:x() * Fwd
Dfl = rangerOffset(RangerLen:x(),DflPos,-Rgh):distance()
Dfr = rangerOffset(RangerLen:x(),DfrPos, Rgh):distance()
Dbl = rangerOffset(RangerLen:x(),DblPos,-Rgh):distance()
Dbr = rangerOffset(RangerLen:x(),DbrPos, Rgh):distance()
And I think for now there will not gonna be workaround for creating a new sensor with the modified position and angle. I mean I still have to calculate the position and direction, which will create some garbage collected objects later on instead of declaring the ranger as a persist and crate it once then sampling.
What do you think ?
So does yours. What's the difference?
EDIT: Ah, I see. Yours reuses the RangerData table, so that you don't specify the positions and directions again. This is what you've been getting at the whole time, I see that now. Sure, that would increase performance, by a tiny amount. Is it really a large enough increase to be worth it though? As I said earlier, 0.0126 seconds sounds like so small you're probably better off fixing the other parts of your code first.
On Tue, May 24, 2016 at 11:21 AM, Deyan Dobromirov <[email protected]
wrote:
But isn't it going to create a new ranger every iteration, though the Idea
is quite good.—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/wiremod/wire/issues/1123#issuecomment-221213378
Allocates and initialize memory for the ranger once by calling E:addTracer("Down").
Gather all the data of the already allocated once sensor by calling E:smpTracer("Down") and only refreshing the allocated sensor with the coordinate system of the entity.
Read the distance associated with that sensor name getTracerDistance("Down")
In the main loop only sampling and distance persists .. and the goal is only to update the given ranger with the new origin ;) (E:pos(), E:ang())
EDIT: The idea is somehow to remove the:
# Getting data from UD Rangers
UfrPos = RangerUDOffset:x()*Fwd + RangerUDOffset:y()*Rgh + RangerUDOffset:z()*Up + MC
UflPos = UfrPos - 2 * RangerUDOffset:y() * Rgh
UbrPos = UfrPos - 2 * RangerUDOffset:x() * Fwd
UblPos = UflPos - 2 * RangerUDOffset:x() * Fwd
And it will be done by Lua and replace it like:
# Getting data from UD Rangers
DRDfr = RDfr:distance()
DRDfl = RDfl:distance()
DRDbr = RDbr:distance()
DRDbl = RDbl:distance()
EDIT-1.5: By looking it to the scale of the elapsed time it's actually 80% faster, thus I still have to test that E:rangerOffset(...) will give the similar result.
EDIT-2: Should I try this method with the E:rangerOffset(...) ?
I've written a better system and this PR is not needed
Most helpful comment
We could set some E2 functions to negative ops, and then, obviously, executing those functions will make the server run faster.