Skip to content

hal-histogram: drop BLT for Tcl/Tk 9, add race-free histobinstream comp#4090

Merged
BsAtHome merged 3 commits into
LinuxCNC:masterfrom
grandixximo:histogram-lh-chart
Jun 1, 2026
Merged

hal-histogram: drop BLT for Tcl/Tk 9, add race-free histobinstream comp#4090
BsAtHome merged 3 commits into
LinuxCNC:masterfrom
grandixximo:histogram-lh-chart

Conversation

@grandixximo
Copy link
Copy Markdown
Contributor

Summary

Two related changes for hal-histogram, with one shared piece reused by
latency-histogram:

  1. Replace BLT with a Tk-canvas chart so the tool runs on Tcl/Tk 9.
  2. Add histobinstream, a streaming histogram comp that takes an atomic
    snapshot, removing the RT/non-RT data race of the existing histobins.

See the individual commit messages for the details of each change.

Motivation

BLT has no Tcl/Tk 9 port, so hal-histogram could not run on Tcl 9 systems
(e.g. Fedora 42+). latency-histogram was already ported to a canvas widget;
I extract that widget into lib/hallib/lh_chart.tcl so both tools share it.

histobins transfers one bin per servo cycle over the index/check
handshake, so its histogram is smeared across many milliseconds and its
statistics can drift out of sync with the bins. latencybinstream already
solved this for latency-histogram; histobinstream brings the same HAL
stream approach to hal-histogram, which now uses it by default and falls
back to histobins with --legacy.

histobins left unchanged on purpose

I deliberately leave histobins as it is, including two latent bugs, so the
--legacy path stays a faithful contrast to the corrected streaming comp:

  • invalue == maxvalue lands in bin[nbins], a write past the array at
    nbins == 200 and reachable with integer pins. histobinstream index-tests
    the high tail and counts it as positive overflow instead.
  • The mean/variance update is skipped on the first sample with mean still
    seeded to 0, biasing the running statistics. histobinstream seeds from
    the first sample.

Testing

Tested locally:

  • lh_chart renders under Xvfb on Tk 8.6; screenshot capture works through the
    ImageMagick fallback (the native image -format window path is Tk 8.7+/9).
  • histobinstream validated end-to-end under halrun: input 25 falls in the
    expected bin, input 50 (== maxvalue) goes to the positive tail with no
    out-of-bounds write, input -3 goes to the negative tail; stream_error
    stays clear and the statistics are correct.
  • hal-histogram run against a live LinuxCNC instance with the streaming comp
    on a real-time thread; the GUI updates correctly.
  • Both scripts parse cleanly; histobinstream.comp carries the same -Wextra
    hygiene as the recent histobins cleanup.

BLT has no Tcl/Tk 9 port. Extract the canvas-based lh_chart widget and
window-capture helper into lib/hallib/lh_chart.tcl, shared by both
tools. latency-histogram now sources it instead of carrying an inline
copy; hal-histogram drops blt::barchart, blt::bitmap and blt::winop
snap along with the hard BLT and Tclx requirements, so both run on
Tcl/Tk 8.6 and 9 alike.

Also remove the obsolete base_thread_fp advice from hal-histogram: the
HAL uses_fp flag is deprecated and ignored, so all threads are
FP-capable and no motmod option is needed.
histobins transfers one bin per cycle, so its snapshot is smeared
across many milliseconds and the statistics can desync from the bins.
Add histobinstream, the streaming counterpart modeled on
latencybinstream: on the rising edge of the stream pin it pushes the
whole histogram (negative tail, bins, positive tail) through a HAL
stream and latches the scalar statistics, giving a consistent atomic
snapshot. hal-histogram uses it by default and falls back to histobins
with --legacy.

The bin classification compares invalue against minvalue for the
negative tail, because integer truncation of a negative quotient rounds
toward zero and would otherwise land such samples in bin 0. It tests
the computed bin index against nbins for the positive tail, avoiding
the bin[nbins] out-of-bounds write that histobins performs when
invalue == maxvalue.
@BsAtHome
Copy link
Copy Markdown
Contributor

Your implementation of histobinstream is not one that I'd accept. Quite a bit of legacy implementation that has been wrong for some time... Let me hack one together that fixes most of the issues I see in your version ;-)

@grandixximo
Copy link
Copy Markdown
Contributor Author

Had a feeling it wouldn't fly...

@BsAtHome
Copy link
Copy Markdown
Contributor

Had a feeling it wouldn't fly...

Wasn't too bad, but I'm picky :-)

Try to take a look at the attached version. See if that works. (attached with extra .txt extension because someone insanely stupid with a great hang to pure theater thinks that you can improve security by naming it differently)
histobinstream.comp.txt

@BsAtHome
Copy link
Copy Markdown
Contributor

And please fix my "Cache som pins" typo (make it 'some').

Replace the comp implementation with the version Bertho Stultiens posted
in review of PR LinuxCNC#4090: cache the volatile input pins once per cycle, use
real_t, keep input_error sticky until reset, and update the last_*
trackers right after the accumulate block. The bin classification and
first-sample seeding are unchanged. Also fixes his "som" -> "some"
comment typo.
@grandixximo
Copy link
Copy Markdown
Contributor Author

grandixximo commented May 31, 2026

Adopted your version as a commit on top so the rework is easy to diff against the original, and fixed the "som" typo. Verified it builds and the classification still holds (25 to bin 2, 50 to the positive tail with no overflow, -3 to the negative tail), and tested it in RIP against a running machine.

should have caught the _fp myself ...

@BsAtHome BsAtHome merged commit d37a3da into LinuxCNC:master Jun 1, 2026
15 checks passed
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