public inbox for goredo-devel@lists.stargrave.org Atom feed
* Potentially unnecessary redoing of targets @ 2026-01-12 9:02 Niklas Böhm 2026-01-12 12:53 ` spacefrogg 0 siblings, 1 reply; 6+ messages in thread From: Niklas Böhm @ 2026-01-12 9:02 UTC (permalink / raw) To: goredo-devel Hello, I noticed that there is some behavior with ood detection that can lead to unnecessary redoing of a target. If you have the two simple files: 1.do: echo 1 2.do: redo-ifchange 1 sleep 3 echo 2 then calling `redo-ifchange 2` will run them, as intended. When adding a comment to 1.do and again calling `redo-ifchange 2`, it will correctly redo the file `1` and afterwards redo itself. This is kind of the crucial point. If you Ctrl-C the redoing process while it's sleeping during execution of `2.do`, then it will (correctly, in my opinion) not redo the file `2` in a subsequent call to `redo-ifchange 2` since all of the dependencies are unchanged. To me, this behavior could also be extended to be performed during execution of redo itself. In this example, this would mean to check, again, if the dependencies have differing output before then starting the process of redoing `2`. I acknowledge that this is not a trivial change in itself, though the additional computation time should be negligible, as the hash of `1` is already computed. It would mean to change the ood detection to not declare `2` ood only based on `1.do` differing, but instead to check this after redoing `1`. Let me know what you think about this proposed change! Greetings Nik ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Potentially unnecessary redoing of targets 2026-01-12 9:02 Potentially unnecessary redoing of targets Niklas Böhm @ 2026-01-12 12:53 ` spacefrogg 2026-01-12 15:12 ` Niklas Böhm 0 siblings, 1 reply; 6+ messages in thread From: spacefrogg @ 2026-01-12 12:53 UTC (permalink / raw) To: goredo-devel You are describing two different cases. In the first, the execution of `2.do` has already started (due to OOD). This could result in anything, even in dropping `1` as a dependency entirely. The assumption that `redo-ifchange 1` resulting in an unchanged output ALSO results in not changing the output of `2` is just wrong. Anything could happen depending on what the content of `1` means in the context of executing `2.do`. It could even result in never running `1.do`. The (implicit) contract is that ONLY `2.do` may decide what the content of `1` means. In addition, there is also the (implicit) assumption that the meaning of `1` should only depend on the current content of `1` and not on whether/how it has changed from the previous run. In the second case, OOD has just determined that there is nothing to do. You only reached that case by (nearly) compromising the build flow, which is (or should be) out of scope for the design of redo. Actually, you would have reached the same case by running `redo-ifchange 1; redo-ifchange 2`. There, the first `redo-ifchange` also "clears" the OOD state of `1`. So, to make the distinction clear: In your case, which was running `redo-ifchange 2`, `2` being OOD because of `1` just results in running `2.do`. That's it. Whether that means to also run `1.do` is entirely up to the program in `2.do`. Running `1.do` is not the result of `1` being determined OOD but of the command `redo-ifchange 1` being part of `2.do`. The two cases have nothing in common, really. Kind regards, Michael ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Potentially unnecessary redoing of targets 2026-01-12 12:53 ` spacefrogg @ 2026-01-12 15:12 ` Niklas Böhm 2026-01-12 16:26 ` spacefrogg 2026-01-13 8:23 ` Sergey Matveev 0 siblings, 2 replies; 6+ messages in thread From: Niklas Böhm @ 2026-01-12 15:12 UTC (permalink / raw) To: goredo-devel Thanks for your response. In general, I want to say that `2` is not ood because `1` did not change after completion of `1.do`, hence we would never have to start it. The state when `2.do` is executing is in fact not ood, but because we determined `1` to be ood (as 1.do that changed), we run `2.do` anyways. What I would suggest is to check, once more, if the targets actually did change their content before launching `2.do`. I see that currently the problem is that the ood checking goes as follows (with redo-ifchange -d): [48985] dbg ood: 2 checking [48985] dbg ood: 2 -> 2.do: checking [48985] dbg ood: 2 -> 2.do: same inode [48985] dbg ood: 2 -> 2.do: is source [48985] dbg ood: 2 -> 1: checking [48985] dbg ood: 2 -> 1: inode differs [48985] dbg ood: 2 -> 1: same hash [48985] dbg ood: . 1 checking [48985] dbg ood: . 1 -> 1.do: checking [48985] dbg ood: . 1 -> 1.do: inode differs [48985] dbg ood: . 1 -> 1.do: hash differs [48985] dbg ood: . 1: true [48985] dbg ood: 2 -> 1: ood [48985] dbg ood: 2: true I want to make the claim that `2` is not necessarily ood at that point, as we could first redo `1` and then check if the output differs before determining `2` to be ood. As the build file `2.do` did not change, we know that its dependencies do not change; hence in my opinion it is a forgone conclusion to say that `2` is ood only because `1.do` has a differing hash, but actually `1` itself does not. I'll admit that it might be an involved change in the code base and will also make redo itself change its behavior (as you lose the transitivity property for ood detection), but in my eyes it would be correct to check the direct targets of the .do file, instead of cascading the ood property. This would also make the build system minimal Anyways, thanks for reading all of this text, I hope my point became a little clearer. Cheers Nik ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Potentially unnecessary redoing of targets 2026-01-12 15:12 ` Niklas Böhm @ 2026-01-12 16:26 ` spacefrogg 2026-01-13 8:23 ` Sergey Matveev 1 sibling, 0 replies; 6+ messages in thread From: spacefrogg @ 2026-01-12 16:26 UTC (permalink / raw) To: goredo-devel On 2026-01-12 15:12, Niklas Böhm wrote: > Thanks for your response. In general, I want to say that `2` is not > ood because `1` did not change after completion of `1.do`, hence we > would never have to start it. The state when `2.do` is executing is in > fact not ood, but because we determined `1` to be ood (as 1.do that > changed), we run `2.do` anyways. What I would suggest is to check, > once more, if the targets actually did change their content before > launching `2.do`. Thanks, I see the case you are constructing. But you are misjudging the task that you've given redo to do in the first place. What I was trying to convey in my previous message was, in essence, that: 1) `redo-ifchange 1; redo-ifchange 2` and 2) `redo-ifchange 2` are two separate cases that you are conflating with each other. You are trying to turn case 2) into case 1), which is not what redo is about. > I see that currently the problem is that the ood checking goes as > follows (with redo-ifchange -d): > [48985] dbg ood: 2 checking > [48985] dbg ood: 2 -> 2.do: checking > [48985] dbg ood: 2 -> 2.do: same inode > [48985] dbg ood: 2 -> 2.do: is source > [48985] dbg ood: 2 -> 1: checking > [48985] dbg ood: 2 -> 1: inode differs > [48985] dbg ood: 2 -> 1: same hash > [48985] dbg ood: . 1 checking > [48985] dbg ood: . 1 -> 1.do: checking > [48985] dbg ood: . 1 -> 1.do: inode differs > [48985] dbg ood: . 1 -> 1.do: hash differs > [48985] dbg ood: . 1: true > [48985] dbg ood: 2 -> 1: ood > [48985] dbg ood: 2: true This is exactly as it should go, because what you are trying to execute is case 2). In case 2), the only decision redo has to make is whether or not to execute `2.do`. It does NOT decide whether to execute `1.do`. As I explained in my last message, executing `2.do` could result in removing `1` (and by transitivity `1.do`) from its dependency graph entirely. So, executing `1.do` just to find out whether you have to execute `2.do` or, even worse, cancelling the execution of `2.do` after the line `redo-ifchange 1` just because you've determined it no longer to be OOD, is the wrong move. Prematurely executing `1.do` before `2.do` (which is precisely turning case 2) into case 1)) can be wrong for the following reasons: - it could be removed from `2`'s dependency graph on the next run of `2.do`. So it would be a waste of effort. - it could be an after-dependency that is only to be executed after most of `2.do` has run (I use after-dependencies to collect dependencies from .tex files processes, for example). So running it eagerly would potentially operate on old data. And even if not, it is up to the user to place `redo-ifchange` calls in .do files. By running them early, you virtually move them all to the front of the file, which could change the results in non-obvious ways. This "feature" would also be very hard to communicate. > I want to make the claim that `2` is not necessarily ood at that point, > as we could first redo `1` and then check if the output differs before > determining `2` to be ood. As the build file `2.do` did not change, we > know that its dependencies do not change; hence in my opinion it is a > forgone conclusion to say that `2` is ood only because `1.do` has a > differing hash, but actually `1` itself does not. This is where you are mixing things up. Let me say the concluding statement of my last message again: The call that produced above trace was `redo-ifchange 2`. It's purpose is to determine, whether or not to run `2.do`. That's it. For that decision, it uses the currently known dependency graph of `2` as a starting point. According to this graph, `2` IS OOD and `2.do` must be run. This does not mean anything with regards to `1` or `1.do`, even if the alteration of `1.do` was the cause. But the only way to get rid of this outdated knowledge (that `1` is still a dependency of `2`) is to execute `2.do` and to find out. > I'll admit that it might be an involved change in the code base and > will also make redo itself change its behavior (as you lose the > transitivity property for ood detection), but in my eyes it would be > correct to check the direct targets of the .do file, instead of > cascading the ood property. This would also make the build system > minimal As I was trying to clarify, such a system would be very different from redo and would not allow for free placement of `redo-ifchange ...` calls throughout .do files. Or, at least, these calls would have a different meaning, depending on whether you run the .do file for the first time or because it was determined to be OOD. Believe me, I see, what you are trying to achieve, but with that change, the semantics of redo and redo-ifchange calls become weird and non-obvious. Kind regards, Michael ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Potentially unnecessary redoing of targets 2026-01-12 15:12 ` Niklas Böhm 2026-01-12 16:26 ` spacefrogg @ 2026-01-13 8:23 ` Sergey Matveev 2026-01-13 19:04 ` Niklas Böhm 1 sibling, 1 reply; 6+ messages in thread From: Sergey Matveev @ 2026-01-13 8:23 UTC (permalink / raw) To: goredo-devel [-- Attachment #1: Type: text/plain, Size: 971 bytes --] Greetings! *** Niklas Böhm [2026-01-12 16:12]: >What I would suggest is to check, once more, if the targets >actually did change their content before launching `2.do`. redo just do not work that way. If it determines that "2" is OOD (because it depends on "1", that depends on altered "1.do"), then it runs 2.do. It does not run 1.do, but 2.do, that *may* run 1.do. Even if we saw that result of "1" target was not changed, we already executing 2.do anyway, maybe somewhere in the middle of its code, with various steps already done before encountering "redo-ifchange 1" in it. spacefrogg perfectly explained all of that (and other issues, like premature "1.do" execution) in details indeed. Here is the crucial difference in behaviour between Make and redo: Make, if 2 is OOD, will run 1(.do). Redo will run 2.do, that may run 1.do. -- Sergey Matveev (http://www.stargrave.org/) LibrePGP: 12AD 3268 9C66 0D42 6967 FD75 CB82 0563 2107 AD8A [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 265 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Potentially unnecessary redoing of targets 2026-01-13 8:23 ` Sergey Matveev @ 2026-01-13 19:04 ` Niklas Böhm 0 siblings, 0 replies; 6+ messages in thread From: Niklas Böhm @ 2026-01-13 19:04 UTC (permalink / raw) To: goredo-devel Hi again, alright, I think I see the point now. I agree that the behavior would definitely not seem intuitive and I suppose I am just not thinking of some corner cases where this could be very confusing. My point is that `2.do` specifically did not change; hence the dependencies should stay the same, depending only on whether `1` changes or not. If the hash stays the same, then there is no need to even start the execution of `2.do`. In case the contents of `1` do change then all bets are off, so I agree that it does not make sense to change the behavior of redo. Personally, I actually think that it would be nice to have `redo-ifchange 1; redo-ifchange 2` and only `redo-ifchange 2` work the same, although that would also lead to trouble when you rely on one of those to produce files that are not properly tracked by redo. In any case, thanks for the discussion and explanations. Cheers Nik ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-01-13 19:05 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-01-12 9:02 Potentially unnecessary redoing of targets Niklas Böhm 2026-01-12 12:53 ` spacefrogg 2026-01-12 15:12 ` Niklas Böhm 2026-01-12 16:26 ` spacefrogg 2026-01-13 8:23 ` Sergey Matveev 2026-01-13 19:04 ` Niklas Böhm