Some LinksetData functions, especially llLinksetDataGetKeys and llLinksetDataFindKeys are slower than expected
under review
RavieDragon SLSGC
Edited post with some further information.
Some linkset data functions are slower than one would expect. I first noticed slowdowns on April 11th and looked in detail about it. It's taking some additional frames to do linkset writes in a region that is all but empty.
I have a script to repro with results on top comment attached to this ticket as well as the regions I tested this in including RACore (Skill Gaming region), Rabbits Landing (Full Region), and Chicory Field (Linden Home Region).
Log In
Maestro Linden
marked this post as
under review
Maestro Linden
Hi RavieDragon SLSGC, thanks for the repro script. Testing in a fairly idle Second Life Server 2026-01-28.21455867889 region (with >20ms of spare time), I see similar results to what you report. I also tried with a version of your script modified to pause for 30 seconds between each benchmark phase and to poll the frame number directly (shown in child comment). This had similar results:
Took 8 frames to write 1000 new entries.
Took 646 frames to list 1000 individual entry keys.
Took 5 frames to read 1000 values.
Took 6 frames to replace 1000 existing entries.
Took 883 frames to read, increment, overwrite 1000 entries.
It seems that writing new entries and reading entries is extremely fast, but that listing individual keys with
llLinksetDataListKeys
and updating existing keys in a read/increment/write cycle is a bit slower - a bit less than a single simulation frame, per key. It might be possible to speed things up, but nothing has changed in simulators in the past week. Linkset data operates locally on the simulator, and we have not updated the main simulator channel for a few months, now.Maestro Linden
default
{
state_entry()
{
float cooldown = 30; // time to wait between tests
llLinksetDataReset();
integer frameA1 = (integer)llGetEnv("frame_number");
// write 1000 LSD entries:
integer n;
while (n++ < 1000)
{
llLinksetDataWrite((string)n, (string)((integer)llFrand(1000)));
}
integer frameA2 = (integer)llGetEnv("frame_number");
llSleep(cooldown);
// list entry keys:
integer frameB1 = (integer)llGetEnv("frame_number");
n = 0;
string dataKey;
while (dataKey = (string)llLinksetDataListKeys(n++, 1))
{
// do nothing here
}
integer frameB2 = (integer)llGetEnv("frame_number");
llSleep(cooldown);
// read entry values:
integer frameC1 = (integer)llGetEnv("frame_number");
n = 0;
while (n++ < 1000)
{
string dataValue = llLinksetDataRead((string)n);
}
integer frameC2 = (integer)llGetEnv("frame_number");
llSleep(cooldown);
// replace 1000 existing entries:
integer frameD1 = (integer)llGetEnv("frame_number");
n = 0;
while (n++ < 1000)
{
llLinksetDataWrite((string)n, (string)((integer)llFrand(1000)));
}
integer frameD2 = (integer)llGetEnv("frame_number");
llSleep(cooldown);
// read entry key, read entry value, increment and write value:
integer frameE1 = (integer)llGetEnv("frame_number");
n = 0;
while (dataKey = (string)llLinksetDataListKeys(n++, 1))
{
string dataValue = llLinksetDataRead(dataKey);
llLinksetDataWrite(dataKey, (string)((integer)dataValue + 1));
}
integer frameE2 = (integer)llGetEnv("frame_number");
llOwnerSay("Took " + (string)(frameA2 - frameA1) + " frames to write 1000 new entries.\n"
+ "Took " + (string)(frameB2 - frameB1) + " frames to list 1000 individual entry keys.\n"
+ "Took " + (string)(frameC2 - frameC1) + " frames to read 1000 values.\n"
+ "Took " + (string)(frameD2 - frameD1) + " frames to replace 1000 existing entries.\n"
+ "Took " + (string)(frameE2 - frameE1) + " frames to read, increment, overwrite 1000 entries.");
}
}
Maestro Linden
I also added a benchmark to increment each of the values with protected writes:
// read entry key, read entry value, increment and **protected** write value:
integer frameF1 = (integer)llGetEnv("frame_number");
n = 0;
while (dataKey = (string)llLinksetDataListKeys(n++, 1))
{
string dataValue = llLinksetDataRead(dataKey);
llLinksetDataWriteProtected(dataKey, (string)((integer)dataValue + 1), dataValue);
}
integer frameF2 = (integer)llGetEnv("frame_number");
llOwnerSay("Took " + (string)(frameF2 - frameF1) + " frames to read, increment, protected-overwrite 1000 entries.");
This one is about 3x slower than the non-protected case:
[5:06 PM] LSD Benchmark: Took 871 frames to read, increment, overwrite 1000 entries.
[5:15 PM] LSD Benchmark: Took 23011 frames to read, increment, protected-overwrite 1000 entries.
llLinksetDataWriteProtected should definitely be slower than llLinksetDataWrite due to the extra read, but I was surprised by it being _that_ much slower.
RavieDragon SLSGC
It's worth noting the llLinksetDataGetKeys and FindKeys ARE a little slower than they should have been but the issue concerning the REALLY long delays was an error on my part. As such editing this canny to sound less drastic, as the overall issue isn't as severe.
RavieDragon SLSGC
Script to attempt repro. Sorry I'm having all kinds of issues getting this into this canny.