+ Notes and rules about a program, and the one that is allowed to change the machine - #147
Open
Hawkynt wants to merge 6 commits into
Open
+ Notes and rules about a program, and the one that is allowed to change the machine#147Hawkynt wants to merge 6 commits into
Hawkynt wants to merge 6 commits into
Conversation
… query Cycles, the ideal processor and the TEB pointer. All three sat unticked under a heading saying the engine enumerates threads on both platforms, and each was missing for a different reason - which is the whole of the unknown-is-a-value rule in one row. Cycles are not another spelling of CPU time. Time is what the clock says a thread held a processor for; cycles are what the processor actually retired. On a machine whose frequency moves - every laptop - a thread on a core parked at 800 MHz reads exactly as busy by time as one at 4.8 GHz, and only the cycle count says which. Linux reports n/i and not n/a: the kernel will charge cycles to a task through perf_event_open, subject to kernel.perf_event_paranoid, so the absence is ours. The ideal processor sits beside the last-CPU column on purpose. Affinity is where a thread is allowed, last CPU is where it ran, and this is where the scheduler would put it given a free choice; a thread preferred on processor 2 that keeps running on 7 is being bounced off its own cache, and no one of the three columns says that alone. Flattened across processor groups like every other processor number here, because on a machine with more than sixty-four processors, processor 3 of group 1 and processor 3 of group 0 are different processors. The TEB is the address only. What is inside one is another process memory and reading it means attaching, which the no-driver rule refuses along with the driver, so the box stays partial. The pass costs a handle per thread, so it runs for the one process somebody has open and never over the table: four hundred processes carry several thousand threads, and three syscalls each for a page nobody opened is the reading that has to be asked for rather than taken. The bulk query now says "not sampled yet" for the three rather than "not supported" - the readings exist and that call is simply not the one that takes them. Checked against the kernel on pid 1: 319041 / 57453 voluntary and involuntary switches, affinity 0-15, and 12273 + 12612 ticks of user and kernel time all match /proc/1/stat and /proc/1/status exactly, with cycles n/i and the other two n/a beside them.
…nge the machine rules.tsv beside the settings, following them wherever --settings, PROCMAN_SETTINGS or a portable marker put them - the shape the usage record already has, and for the same two reasons: it is a list that grows rather than a set of preferences, and somebody throwing away every note they wrote should not lose the rest of their settings with it. A rule attaches a note, a colour, a category and an expected publisher, and recognises a program by path, digest, name, command line or signer. Order decides and the first match wins - not "the most specific", which sounds better and cannot be defined: is a path more specific than a digest, or a command line than a signer? A file read top to bottom is a rule somebody can predict by looking at it. The pattern language is * and ? and nothing else. A rule file is edited by hand by somebody who wants to say "anything under /usr/bin", and every character of a path - the dots, the plus in a package name, the brackets a build system leaves behind - is a metacharacter in a regular expression and an ordinary character here. A digest is compared and never globbed: an asterisk in a hash is a typo, and treating it as a wildcard would quietly turn one rule into a rule about most of the machine. A rule keyed on a reading nobody took is a third answer and not a no. The digest and the signer are read on request rather than every sample, so a hash rule against a table that has not hashed anything has not failed to match. Calling it "no" would silently drop every hash rule and leave a person watching their rule do nothing with nothing to tell them why. The dangerous part is the applier, so the opt-in is per rule. Recording that a backup job ought to run at idle priority is a note; reniceing it is this program reaching out and changing the machine because of a line in a file. apply is a column rather than a global preference, anything that is not an explicit yes leaves the machine alone, and a file written by a version without that column cannot start acting because a field was missing. Once per process and never again for that process. Somebody who lowers a priority by hand after the rule ran has overruled it, and a program putting it back every second would be fighting them with no way to win. Keyed on the identity pair, so a recycled pid is a new process rather than one already handled. Reachable from all three. The note, the category and the publisher comparison are rows on the overview page every front-end builds from; the colour is a row background in the window, where it beats the derived category - one is what this program worked out and the other is what a person decided - and still yields to a high-contrast desktop. Both front-ends run the applier, or a rule would act depending on which program you happened to open. The publisher is a comparison rather than a value. "Expected: Mozilla Corporation" beside a signer field somebody has to scroll back to is two facts a reader has to join, and whether they agree is the question they were asking. Where the signature has not been read it says so: a publisher nobody checked and a publisher that did not match are opposite conclusions. The colour reader moved into Core on the way past. Two things read colours out of files now, and a hash meaning one thing in the settings file and another in the rules file is the drift the field catalogue was put in one place to prevent. Checked against the kernel and not against the suite. A rule matching *sleep 200* with apply=yes and 15 / 0-1 / idle took a real process from nice 0 to 15, affinity 0-15 to 0,1 and I/O class none to idle, read back out of /proc/[pid]/stat, taskset and ionice. The same rule with apply=no left all three exactly as they were.
… and what has happened Both were described in the checklist as "a filter rather than a feature" and "one call away rather than a feature away". They were. Strings shows the ASCII, UTF-8 and UTF-16 runs of this process own image, offset and encoding beside each, scanned when the tab is opened rather than when the window is and once rather than per tick. It is the one reading in this window whose cost is the size of the file - every other page reads a few kilobytes of structure. Bounded to the first 16 MB and the bound is said out loud when it bites, because this runs on the thread that draws the window and the binary inspector is where somebody goes to read a whole file on purpose. Scanning the process own memory stays refused. process_vm_readv and /proc/[pid]/mem are both governed by PTRACE_MODE_ATTACH, which Yama declines by default for anything this program did not start, and a memory reverse-engineering suite is the first non-goal. That half is a decision and not a gap, which is why the box is partial rather than ticked. Timeline is the window own event ring filtered to this pid, newest first, refilled on the tick because the whole point is that something happened while somebody was looking. The ring is handed in rather than made here: one log per program and not one per properties window, or there would be two bounds, two start times and two chances to disagree about what happened. Three states and three sentences, because the first two are the same empty table and mean opposite things - nothing is recording, nothing has been recorded yet, and nothing has happened to this process while n things happened to others. A blank list with no heading reads as the third when it is the first. Both pages can legitimately come up empty, so both are in the capture log by heading rather than by count: an empty rectangle and "nothing has been recorded yet" are the same picture. The shot proves it - 8,936 runs out of 1,973,888 bytes with the symbol names legible, and the timeline saying nothing happened to this process while three things happened to others. Nineteen tabs is more than 1280 pixels of strip holds and the capture shows the last of them behind the scroll arrows. Not a fault, and recorded rather than left for somebody to find by looking for a tab that is off the edge.
…e cursor W lists every unit and its state; b lists what runs at login and what will not. The window has had both since the services and startup views were written, and the terminal had only the unit a process belongs to - which is a different question. "What is running under this pid" is not "what is on this machine", and a capability reachable from one front-end and not the other is exactly the drift the one-catalogue rule exists to stop. Both are read when asked for rather than on the tick. Enumerating every unit on the machine once a second would be the monitor becoming the thing worth monitoring, and unit state does not move at the rate a process table does. Units are grouped running, then ran-and-exited, then inactive: the order the question comes in for somebody who opened this after something broke. There is no "failed" heading and that is not an omission - the manager keeps a failed unit state in its own memory and writes it to no file, so a failed unit looks inactive from out here, and a heading that could never have anything under it is worse than no heading. The words are the ones the window already uses, so the two cannot describe one unit differently. Autostart is split into what will run and what will not, and the second half is the point: a list that does not say which entries are switched off is a list of things somebody will assume are running. The reason travels with the entry, because "hidden" and "only shown in GNOME" are different problems and only one of them is a mistake. A machine where everything runs gets no second heading - an empty "will not" group reads as a list that failed to load rather than as good news. Nothing back is a sentence in both, because a machine with no service manager and a machine whose units this user may not read are the same empty box and opposite conclusions. Checked against the machine. 377 units with 22 running, which is what systemctl list-units --state=running counts, and four sampled main PIDs match systemctl show -p MainPID exactly - all off disk and the cgroup tree, no D-Bus, nothing spawned. 24 autostart entries and 14 that will run: 23 .desktop files in /etc/xdg/autostart plus one systemd user unit sitting in default.target.wants, which systemctl --user is-enabled calls disabled because it answers a different question - whether the user enabled it, not whether it runs. A second assertion came out of writing this: no two actions share a default key. A duplicate is a binding that silently never fires.
…ices GetServices answered with an empty list, so the view existed on Windows and had no rows in it. That is not a view of a machine with nothing running; it is a feature nobody wrote, wearing the appearance of one. EnumServicesStatusEx for the list, then QueryServiceConfig and QueryServiceConfig2 per service. Read-only by construction: the handles are asked for SERVICE_QUERY_CONFIG and SERVICE_QUERY_STATUS and nothing else, so this path cannot start or stop anything even by accident - commanding a service is IServiceControl job and asks for its own rights when it is used. Nothing needs elevation, and it is read on demand rather than on the tick, for the same reason the systemd side is: two queries per service several hundred times a second is the monitor becoming the thing worth monitoring. Drivers are rows on purpose. The driver-service indicator is a column that can only exist if they are, and a view that silently omitted half the service control manager would answer a narrower question than the one it appears to. The state map does not invent a systemd word for a Windows state. A pending start reports as running because that is what the manager said and where it is going; paused reports as unknown, because Windows has a state systemd does not and folding it into either of the other two would say something untrue about a service that is neither. Splitting ImagePath is text rather than syscalls, so it is in Core with no platform attribute and runs on every CI leg. It is emphatically not a split on the first space: most Windows program paths have one, so that would name C:\\Program for the majority of services on the machine, and the wrong program is worse than no program because it looks like an answer. Quoted first, then the first .exe, then the first space for a driver that has no extension at all. It does not try to resolve the unquoted-path ambiguity Windows resolves by trying each prefix - reporting what the registry says is a reading, and deciding what the loader would pick is a claim about a filesystem nobody looked at. The Windows half is covered by a gated fixture whose assertions are about distinguishing things rather than about counting them: something runs and something does not, something starts by itself and something does not, at least some gave up a command line and an account. A reader that got the start type wrong would most likely report one answer for every row, and every simpler assertion would pass. AOT publish stays at zero warnings with the new imports.
…iting on them exit.time had nowhere for its answer to live, the exited-highlight had nothing to highlight, and the Exited colour had been in the palette and the legend since they were written with nothing ever producing it. keep.exited in the settings file, in seconds, off by default. A table that keeps its dead is showing something that is not there: a considered thing to ask for and a bad thing to assume, and on a machine that churns through processes it doubles the table for nobody who was not looking for one that ended. With it off, exit.time is a dash everywhere, which is the honest rendering of a question nobody has arranged to be able to answer. A kept row carries the last reading that was taken and every rate over it is unsampled. A row that has stopped moving must not go on reporting the rate it had when it stopped - that draws a dead process using a processor. Exited is classified ahead of New, because a short-lived process can be born and buried inside one frame and "it has gone" is the more urgent of the two things to say. A death is announced once. A tombstone left in the previous-sample index would go unmatched every sample and report the same exit for as long as the row was kept, which would put one death in a timeline sixty times a minute. Two bounds, because they fail differently: the duration is what somebody asked for, and a cap of two thousand rows is what stops a build machine ending a thousand processes a second from making the table unreadable. A recycled pid is a new row beside the old one rather than a resurrection. exit.code is the column this asked for and it is honest: NotPermitted everywhere, because neither kernel tells a bystander what a process it did not start exited with - the status goes to the parent through wait on Unix and needs a handle held across the exit on Windows. Nought is the code that means success, which makes it the one value that must never be invented; a defaulted counter here would report every process on the machine as having exited cleanly. A defect the tests caught and a reader would not have. The delta sizes its per-row arrays to the snapshot the probe left, which is before the kept rows are appended - so a kept row was in the table, looked correct, and threw the moment any front-end asked it for a percentage. The delta is extended after the append now. Checked on the machine and not only in the suite: a process started and left to end came back in --list as a row with a true exit time three seconds after it was gone, and a dash under the code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
§66 in full, and §91's row for it. Stacked on #146 — the first commit is that PR.
rules.tsvbeside the settings, following them wherever--settings,PROCMAN_SETTINGSor a portable marker put them: the same shape §44's usage record has, and for the same two reasons. It is a list that grows rather than a set of preferences, and somebody throwing away every note they wrote should not lose the rest of their settings with it.A rule attaches a note, colour, category and expected publisher, and recognises a program by path, digest, name, command line or signer.
Order decides, first match wins — not "the most specific", which sounds better and cannot be defined: is a path more specific than a digest, or a command line than a signer? A file read top to bottom is a rule somebody can predict by looking at it.
The pattern language is
*and?and nothing else. A rule file is edited by hand by somebody who wants to say "anything under /usr/bin", and every character of a path — the dots, the plus in a package name, the brackets a build system leaves behind — is a metacharacter in a regular expression and an ordinary character here. A digest is compared and never globbed: an asterisk in a hash is a typo, and treating it as a wildcard would quietly turn one rule into a rule about most of the machine.A rule keyed on a reading nobody took is a third answer. The digest and the signer are read on request rather than every sample (§5.4), so a hash rule against a table that has not hashed anything has not failed to match —
RuleVerdict.Unknown, and the collection reports it. Calling it "no" would silently drop every hash rule and leave a person watching their rule do nothing with nothing to tell them why (§72.3).The third box is the dangerous one
Recording that a backup job ought to run at idle priority is a note; reniceing it is this program reaching out and changing the machine because of a line in a file. So:
applyis a column, not a global preference — twenty notes, one of them actingyesleaves the machine alone, so a file written by a version without that column cannot start acting because a field was missingVerification, from the kernel rather than the suite
A rule matching
*sleep 200*withapply=yesand15 / 0-1 / idle, against a real process:0-150,1read back out of
/proc/[pid]/stat,taskset -pcandionice -p. The same rule withapply=noleft all three exactly as they were.Reach
The note, category and publisher comparison are rows on the overview page all three front-ends build from; the colour is a row background in the window, where it beats the derived category — one is what this program worked out and the other is what a person decided — and still yields to a high-contrast desktop (§45.9, §74). Both front-ends run the applier, or a rule would act depending on which program you happened to open (§58).
The publisher is shown as a comparison rather than a value: "expected X" beside a signer field somebody has to scroll back to is two facts a reader has to join. Where the signature has not been read it says so — a publisher nobody checked and a publisher that did not match are opposite conclusions.
The colour reader moved into Core on the way past: two things read colours out of files now, and a hash meaning one thing in the settings file and another in the rules file is the drift the field catalogue was put in one place to prevent.
Suite 2646 passed, 2 skipped, 0 warnings;
--self-test37/37.