Skip to content

perf(push_child): defer unparent until evaluation#78

Open
ernisto wants to merge 2 commits into
centau:mainfrom
ernisto:optimize-push-child
Open

perf(push_child): defer unparent until evaluation#78
ernisto wants to merge 2 commits into
centau:mainfrom
ernisto:optimize-push-child

Conversation

@ernisto

@ernisto ernisto commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@ernisto ernisto changed the title perf(push_child): defer unparent until evaluatekeeping unchanged ordered parents perf(push_child): defer unparent until evaluation Jul 7, 2026
@Olaroll

Olaroll commented Jul 8, 2026

Copy link
Copy Markdown

Did a quick test with this. Improves my performance a lot, but I did encounter a new error for some reason. I'll leave the traceback, in case it helps. I can try looking into what specific type of graph causes the issue later today. It's a specific source update where it happens consistently, but all other sources seem fine ¯\_(ツ)_/¯

Also I'm using alicesaidhi's fork with types, but I hope that's not relevant because the graph code is pretty much unchanged compared to centau's.

Here's the traceback:

ReplicatedStorage.Src.Packages..pesde.alicesaidhi+vide.0.4.1-testing.4.vide.src.graph:105: invalid argument #1 to 'find' (table expected, got nil)  -  Client - graph:105
Stack Begin  -  Studio
Script 'ReplicatedStorage.Src.Packages..pesde.alicesaidhi+vide.0.4.1-testing.4.vide.src.graph', Line 105 - function evaluate_node  -  Studio - graph:105
Script 'ReplicatedStorage.Src.Packages..pesde.alicesaidhi+vide.0.4.1-testing.4.vide.src.graph', Line 271 - function update_descendants  -  Studio - graph:271
Script 'ReplicatedStorage.Src.Packages..pesde.alicesaidhi+vide.0.4.1-testing.4.vide.src.source', Line 24 - function update_source  -  Studio - source:24
Script 'ReplicatedStorage.Src.UI.UiUtils', Line 34  -  Studio - UiUtils:34
Stack End  -  Studio

@ernisto

ernisto commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

how did u merge them ? id like see exactly the code. I will take a look here, but would be useful a minimal repro

Comment thread src/graph.luau
local parents = node.parents
for i = node.pushing_parent_index+1, #parents do
-- assert(parent.pushing_parent_index ~= TEMPORALLY_UNPARENTED)
-- if do error here, a stack overflow error would error later

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably this is the minimal repro of the error you get there, but there maybe you have a condition before the infinite re-entrancy happen

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ernisto ernisto left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@centau let me know if i should remove this long comment, or any format adjust

@Olaroll

Olaroll commented Jul 9, 2026

Copy link
Copy Markdown

Hey @ernisto, finally got time to make a repro for the error I had. It could probably be simplified further, but I think this is enough to get you on the right track. Also, this time I tested with the the main repo Vide, your code exactly, and the issue is still present.

Vide.root(function()
	local currentTime = Vide.source(time())
	RunService.Heartbeat:Connect(function() currentTime(time()) end)

	local tblSrc = Vide.source({})
	local i = 0
	local function addItem()
		i += 1
		local tbl = tblSrc()
		tbl[`Entry{i}`] = "Hello There"
		tblSrc(tbl)
	end

	Vide.cleanup(task.spawn(function()
		while task.wait(1) do
			addItem()
		end
	end))

	Vide.effect(function() print(tblSrc()) end)

	Vide.indexes(tblSrc, function(_v, k)
		local function removeThis()
			local tbl = tblSrc()
			tbl[k] = nil
			tblSrc(tbl)
		end

		local finishedAt = currentTime() + 0.5
		local isFinished = Vide.derive(function() return currentTime() >= finishedAt end)

		Vide.effect(function()
			if isFinished() then removeThis() end
		end)
	end)
end)

@ernisto

ernisto commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

the commit i made yesterday doesnt really fix the issue, just make clearer the real issue

@ernisto

ernisto commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author
  	local tbl = tblSrc()
  	tbl[k] = nil
  	tblSrc(tbl)

vide doesnt have deep equal table check, so it does the infinite re-entrant updates. Even on vide almost sure it will error stack overflow, so for your specific case, you could fix this by using

local tbl = vide.untrack(tblSrc)
tbl[k] = nil
tblSrc(tbl)

@Olaroll

Olaroll commented Jul 10, 2026

Copy link
Copy Markdown

Oh right, can't believe I missed the untrack there 🤦

In that case, I'm more surprised by my code not erroring on the main branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants