- 10 Jan, 2020 3 commits
-
-
Eric Myhre authored
Hopefully to become final. I'm going to try to copy the contents out to the root dir to become the new interfaces at the end of this. I copied most of the node.go file and it's probably best to read that as a diff from the live one. Mostly, it adds the NodeStyle type and the documentation around that. The nodebuilder.go file still devolved into some commentstorms and incomplete parts, but is probably honing in on minimally-unsatisfying compromises. I used a couple symlinks to "copy" the types for Path, etc, from the live main package, just to get more things compiling together. Those features aren't showing any cracks and aren't up for review due to any transitive interactions that are in question, so, this treatment is sufficient to move things along. Links aren't present in the package yet. I may or may not do some reconsiderations on those to match the "style" naming pattern, as the 'nodestyle' research package already briefly probed; or, it might be out of scope and something for later (if at all). This is a presently a compile error until I handle it one way or the other. The long-story-made-short of the remaining commentstorm is: handling map keys generically just absolutely sucks. There is basically no way to do it without massive allocation penalties for boxing. Any and all alternative tradeoffs I can think of are baroque and not pleasing. I'm still hoping for another idea to strike, but at this point it's looking like it's time to bite some bullet (any bullet) and move on. Signed-off-by: Eric Myhre <hash@exultant.us>
-
Eric Myhre authored
Signed-off-by: Eric Myhre <hash@exultant.us>
-
Eric Myhre authored
Not all of these compile. I'm going to try to blaze through this and the rest of the experiments until we get to a result quickly, and probably then promptly remove most of these directories. Meanwhile, since we're under a path prefix beginning with an underscore, build and test commands using the "./..." don't trip here. There's at least one thing seriously wrong with each of these drafts, and each of them also devolves into comments rather than completion, but I think they're getting closer to circling around something useful. Signed-off-by: Eric Myhre <hash@exultant.us>
-
- 07 Dec, 2019 2 commits
-
-
Eric Myhre authored
See the comment blocks at the top of the file for reasons why. See the comment blocks at the bottom for some remarks on the outcomes. tl;dr it's certainly *differently* frustrating than the current interface, if nothing else! Better? I dunno. Maybe!
-
Eric Myhre authored
I'm still scratching out prototypes in another directory to make it easier to focus on the details I'm interested in rather than get wrapped up with the kerfuffling details of the existing full interfaces... as well as easier to try out different interfaces. And at some point, of course, we want *codegen* for these things, while what I'm plunking about with here is a sketch of the expected *output*. So, this is a large step removed from the final code... but it's easier to sketch this way and "imagine" where the templating can later appear. This solution approach seems to be going largely well. And we have some tests which count allocs very carefully to confirm the desired result! Still a lot to go. There's large hunks of comments and unresolved details still in this commit; I just need a checkpoint. Some things around creation of maps are still looking tricky to support optimizations for. Research needed there. A comment hunk describes the questions, but so far there's no tradeoff-free answer. Perhaps most usefully: here's also a checkpoint of the "HACKME_memorylayout" document! It also still has a few todos, but it's the most comprehensive block of prose I've got in one place so far. Hopefully it will be useful reading for anyone else wanting to get up to speed on the in-depth in "why" -- it's awfully, awfully hard to infer this kind of thing from the eschatology of just observing where pointers are in a finished product! Signed-off-by: Eric Myhre <hash@exultant.us>
-
- 03 Dec, 2019 2 commits
-
-
Eric Myhre authored
As you can see from the directory name ("multihoisting"), when I began exploring this topic, I didn't know they were called that. :/ This thus turned out to very much be one of those occasions where knowing the *right two words* to put into a search engine would've saved a fairly enormous number of hours. Once I finally found the right term, some perfectly lovely documentation appeared. But alas. (Like the previous commits, this stuff is coming from a while ago; roughly Oct 25. It uncovers a lot of stuff that gets us much closer to being able to make correct and performant designs to minimize and amortize the number of allocations that will be required to make our node trees work in codegen (though with that said, there will also still be plenty of details in need of refinement after this, too).) Still working on a "HACKME_memorylayout.md" doc, which will appear in the codegen directories in the near future and contain a summary of these learnings and how they balance against other design concerns. Meanwhile, a couple of other notes in their rough form: - basically, don't use non-pointer methods. - turns out value receivers tend to mean "copy it", and pointer receivers *don't* mean "heap alloc it" (they just mean "consider escape, maybe"). - so overall you're tying the compilers hands when you use a value receiver, and you're *not* when you use a pointer receiver. - taking pointers to things already being passed around in pointer form or already having heap-escaped seems to be free. - it might demand something become heap alloc if it wasn't already... - but this turns out to be fairly amortizable. - because if you write nearly-everthing to be pointers, then, there you go. - and if you're lucky and something is shortlived (provably doesn't escape), then even whole stacks of ptr-receiver methods will still probably inline and collapse to no heap action. - the analysis on this seems to reach much further than i thought it would. - `-gcflags '-m -m'` was extremely revealing on this point. - tl;dr: - more pointers not less in all functions and passing; - but do have one struct that's the Place of Residence of the data without pointers. - this pair of choices probably leads to the best outcomes. - hokay so. applied to topic: two sets of embeds. - builders might as well have their own big slab of embed too. - logically nonsense to embed them, but incredibly rare you're not gonna use the memory, so! And a couple important incantations, which can help understand What's Really Going On Here in a bunch of ways: - `-gcflags '-S'` -- gives you assembler dump - `-gcflags '-m'` -- gives you escape analysis (minimally informative and hard to read) - `-gcflags '-m -m'` -- gives you radically more escape analysis, in stack-form (actually useful!!) - `-gcflags '-l'` -- disables inlining! I learned about the '-m -m' thing by grepping the Go compiler source, incidentally. It's a wildly under-documented feature. No joke: I encountered it via doing a `grep "Debug['m']` in go/src; there is currently no mention of it in `go tool compile -d help`. Once I found the magic string, and could submit it to search engines, I started to find a few other blogs which mention it... but I'd seen none of them (and had not found queries that turned them up) until having this critical knowledge already in-hand. >:I So chalking up another score for "the right words would've been nice". Performance work is fun!
-
Eric Myhre authored
It's been, broadly speaking, "tricky" to plan out and design some of this project. It's been doubly tricky to do it while understanding the holistic performance implications of the detailed choices. And while "premature optimization, evil", etcetera... I've gone through the performance rodeo in this vincinity at least once before (in the form of the refmt libraries): and resultingly, I'm going to claim a slightly-better-than-zero intuition for what's premature and what's utterly critical to keep track of as early as possible lest ye be doomed to a rewrite after learning things the hard way. (Arguably, half this codebase **is** the rewrite after learning things the hard way. But I digress.) So: to combat this "trickiness", I've started writing a lot of "research" code and experimental benchmarks. This is still certainly fraught with peril -- in fact, one of the major things I've learned overall is just *how* dangerously misleading microbenchmarks can be (and to combat this, I've now started regularly reading the assembler output to make sure the optimizer is doing exactly what I think it is, neither more nor less) -- but it's much more informative than *not* doing it, and trying to suss out the mess later once you've built a whole system. And that's what it's time to start committing. (I should've started a while ago, honestly.) This "rsrch" directory will get some more content momentarily in coming commits, because there's a *lot* of stuff on my localhost. Some of it was so preliminary I'm not going to bother to preserve it; a lot of things are potentially pretty interesting, as educational and archeological material, if nothing else: those I'm going to commit. (It's possible all this will end up `git rm` again at some time in the future, too. But honestly, it's darn hard to remember "why didn't you just do X?" sometimes. Notes need to get committed *somewhere*, at least briefly enough that it's possible to dig them out again.) So! To start: here are some research benchmarks into what strongly- natively-typed builders might look like in our codegen outputs. These are from about Oct 13th, as best I can suss localhost mtimes. I think most of these concepts are ones I'm (frustratingly) backing away from now, because I've learned a *lot* more about performance in the meanwhile, and I don't think these are gonna do well. But the worked exploration into ergonomics is still potentially interesting and worth review! Signed-off-by: Eric Myhre <hash@exultant.us>
-