Skip to content

Conversation

@osnr
Copy link
Collaborator

@osnr osnr commented Aug 1, 2025

Major changes:

  • Multithreaded evaluator: multiple threads (usually 1 active thread roughly = 1 CPU) can execute Folk/Tcl code at the same time. The database is now implemented in pure C with a mix of locks and atomic-retry and reference counting, so it's thread-safe and any thread can write/read it. When a statement is added, triggered When bodies (and destructors) are scheduled out to any available thread (CPU) using a work-stealing scheduler.
    • image
  • No convergence & no 'ticks': there is no consistent world-state; for example, the renderer just displays whatever statements are in-database when it checks. This is probably the most controversial design choice in folk2. I'm curious if it'll hold up, but it seems necessary to me to hold off the system from getting arbitrarily slow as new programs get added. Thoughts/arguments welcome.
    • An unfortunate number of sort-of-arbitrary time-to-live keep 10ms, keep 8ms, etc times have been added to various places in the system. I want to think about ways to get rid of most/all of these (can we have receivers say they want to use either the current statement or the previous matching one? can we retain previous versions of statements by default?), or at least to have some more principled discipline of where they should go and why they should have that length
  • Draws happen to per-page canvases (drawable-onto GPU textures) instead of to the screen
    • This allows for big reductions in statement traffic and draw calls, since many draws don't change at all from frame to frame with respect to the page
  • Regions are gone; you'll be drawing to a per-page texture and probably using page-local meter coordinates (should fix Refactor all user-facing units to be in real-world (e.g. cm/m) units #202)
  • Statements::findMatches (which was sort of a hacky escape valve) is being promoted to Query! and ForEach!, which are more first-class
  • All imperative commands (Hold, Assert, Retract) now have ! suffix
    • If you have a setup.folk, you need to change any Asserts in it to be Assert!s (ideally, make one an alias/wrapper/shim for the other)
    • Hold is being replaced with Hold! -- you can give it either a code block or a Claim/Wish to hold, and it takes -on and -key options
  • Global variables and procs will not work, because blocks of code may run in completely different CPUs/threads/interpreters. All sharing of code/data has to happen through statements (or, as an escape hatch, through unsafe C).
    • A new version of fn, a new C module system, and a new Tcl module system (to be documented) make it reasonably easy to share code.
  • C is slightly different: invoke with [C] instead of [c create], and $cc compile returns a library object that you then call methods on instead of dumping the compiled functions into global namespace. (then this library object can be safely shared over statements and invoked from any thread)
  • collected matches have been renamed to collected results (because Match is a specific datatype internally that I don't want to confuse)
  • Notify: and Subscribe: have been added for point events (keypresses, print requests)

Known issues:

  • camera slice works but is quite buggy. I think it's pushing the texture loading/unloading and the destructor implementation pretty hard. You'll get bugs where it causes other pages to blink in and out, where the camera slices get really laggy when projected, where it leaks MBs of memory and causes RAM exhaustion, and where the system crashes because the GPU-side texture storage is exhausted (presumably because we leaked camera slice textures?)
    • (update: exhaustion seems to be fixed in e897364)
    • (update: camera slice blinking and other-page blinking mostly fixed)
      • camera slices still laggier/choppier than I'd like!
    • also probably implies animation is buggy/broken
    • https://youtu.be/R6ZYPGkWd8w
  • There are some random other memory leaks to dig into (not much worse than folk1, but still).
  • Freeze/lock-in bug where page outlines sometimes lock in as ghosts when you leave the system on for a while (you'll see the stale detection/quad statements stuck in the database with a relatively lower statement id, also)
  • (also see README.md)
  • lots of functionality yet to port: high-level draw operations, points-at/other geometric operations, halo/title/other text operations, audio, terminal, web editor can't outline out of the box
  • reset exposure setting post-calibration? it's probably underexposed in most cases since the user is setting it for a fully-illuminated projection area / sometimes system doesn't work post-calibration
    • calibrate also can leave the system in a weird state when canceled or completed

The design of folk2 is overall probably more complicated than folk1, but not enormously so: the core is now fixed C modules that are compiled ahead-of-time, since we barely touched them anyway, so boot times are faster and the whole thing is a single ./folk binary like a 'normal' PL runtime, instead of leaning on tclsh8.6.

It runs in one process that you can kill instead of a mess of forked processes.

There is one multithreaded Folk system instead of multiple federated ones on the machine, so you don't need to worry about Start process and statement sharing.

folk2 uses the Jim Tcl interpreter instead of Tcl 8.6, and it vendors Jim Tcl, so we can take more control over it and drop the external dependency.


Nice new things:

  • It's noticeably much, much faster. Judging by calibration latency metric, this is about twice as fast in end-to-end latency as folk1, but that might be an underestimate.
    • Calibration feels much faster, much more 'live'
    • The editor also feels much faster, more like a usable/real editor
    • Calibration should be faster but also more accurate: partly because it's faster, partly because it now refines the individual homographies while calibrating (and uses better algorithm to compute the homographies) (fixes Apriltag corrupts while sliding the calibration board #183)
  • Calibration comes with camera image preview (including AprilTag detect results) of each pose. (Fixes /calibrate: Tag detection feedback overlay on camera preview #197.)
  • You can do blocking operations (like exec curl or sleep) in the middle of programs, or hit Folk web endpoints like / or /camera-frame from another computer, or write an infinite loop, without blocking the rest of the system. It should be harder for 'naive' programming to take down Folk, just like in any other preemptive OS.
    • The implementation of many Folk subsystems becomes a lot clearer: camera, AprilTag detector, GPU, etc are all just infinite loops that block on the device and then do some work when ready, no forking a process out and setting up communications channels, it's all just statements :-)
    • The process subsystem (Start process, On process) has been removed; you can do bare When { ... } instead of Start process { ... } if you want to not block the current execution context
  • Because of the canvas design (you draw on canvas with real-world coordinates), text is now universally measured in meters and will scale properly to stay the same real-world size/shape as you lift/skew a page, because it's being set in real-world coordinates.
  • Jim Tcl comes with some nice bonuses: $(...) shorthand for expressions, x(y) shorthand for dicts, better stack traces, some OO stuff, some lexical scope stuff.
  • More powerful/C-compatible destructor system: statements can have a destructor which is guaranteed to be pinned until all downstream statements/When bodies are gone, so you can use the destructor to free memory or other unsafe operations like that and be guaranteed not to have a use-after-free (nice for heap-allocated camera images, GPU textures, other C objects)
  • -serially modifier for When that makes only one of that When run at a time (for stuff like camera frames where you don't want to blow up the CPU with too much work and it's OK to miss one)
  • -keep modifier for Claim/Hold that keeps it around for a few milliseconds past its expiration to reduce blinking and keep downstream statements alive while you wait for the successor statement to come in (in case the downstream statement would be some really expensive operation that you don't want to wastefully/unnecessarily redo)
  • settle parameter for Collect (which is used to stabilize graphics -- don't draw until the display list has been stable for a few milliseconds)
  • A whole Tracy profiler module has been added, tracy, which lets you low-overhead record zones, allocations, stack traces, events. Incredibly useful for performance monitoring, evaluator monitoring, blink debugging
    • Address Sanitizer support has also been added, although haven't tested recently
    • (these should also propagate into dynamically compiled C)


Next steps:

  • Test it on your system
  • I want to test @smj-edison 's branch that should allow much more intense object sharing and save us a lot of serialize/deserialize time (I think most of the work the system does in folk2 right now is literally just making and unmaking strings every time a When block runs, and these objects are immutable, so we should be able to just share the Tcl data...)
  • Cleanup unused cache.c and other stuff
  • Port missing functionality and programs (animation, sound), fix web editor so it makes quads, port live-usb, update documentation
  • More breaking changes: collected matches -> collected results, maybe nicer Hold syntax, maybe keep messing with the GPU/canvas/quad interfaces to make them cleaner, maybe rename On unmatch
  • Do a more extensive writeup

README.md Outdated

## todo

- event statements?
Copy link
Collaborator

Choose a reason for hiding this comment

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

Event statements would be amazing to ensure delivery (I've been thinking that asserts are for describing the universe as it currently is, so old state is no longer useful, but a message must be processed even if it is old). It's not necessary to get the current system working though.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this still being used?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

nope! it might be a good idea to bring back, though -- it was just more broken / causing more problems than I thought and performance is still pretty good without it. it's sort of fulfilling the same role as your branch

osnr added 7 commits August 29, 2025 15:53
This was causing keyboard and music to often not work, because read()
in jim-exec would hang on the zombie child process (because the child
process was not closing its end of the pipe for some reason?)
Just tentative, but very useful for animation frames and display.
@subelsky
Copy link
Contributor

subelsky commented Sep 1, 2025

folk2 works for me! Calibration was much easier, and I really like the "flash" effect. The only issues I had were:

  1. My Ubuntu server couldn't resolve the linux-perf package, so I had to modify the Makefile remote-setup task to skip it.

  2. Tiny issue with the Makefile use of FOLK_REMOTE_NODE (will submit PR)

I got a new projector and am still fiddling with the position, hence the keystone errors:

IMG_4249

osnr and others added 30 commits November 19, 2025 13:50
Synthesize new-style editors on keyboards in the same way we were
old-style editors.
Longer keep time for the actual semantic point statement to reduce
blinking. New bug: now the pointers are really blinky.
Goal is to be able to filter out nav items that have mandatory
parameters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

6 participants