On 28 October 2014 22:51, Steven Schveighoffer via Digitalmars-d <[email protected]> wrote: > On 10/27/14 8:01 PM, Manu via Digitalmars-d wrote: >> >> 28 October 2014 04:40, Benjamin Thaut via Digitalmars-d >> <[email protected]> wrote: >>> >>> Am 27.10.2014 11:07, schrieb Daniel Murphy: >>> >>>> "Benjamin Thaut" wrote in message news:[email protected]... >>>>> >>>>> >>>>> I'm planning on doing a pull request for druntime which rewrites every >>>>> toString function within druntime to use the new sink signature. That >>>>> way druntime would cause a lot less allocations which end up beeing >>>>> garbage right away. Are there any objections against doing so? Any >>>>> reasons why such a pull request would not get accepted? >>>> >>>> >>>> >>>> How ugly is it going to be, since druntime can't use std.format? >>> >>> >>> >>> They wouldn't get any uglier than they already are, because the current >>> toString functions within druntime also can't use std.format. >>> >>> An example would be to toString function of TypInfo_StaticArray: >>> >>> override string toString() const >>> { >>> SizeStringBuff tmpBuff = void; >>> return value.toString() ~ "[" ~ >>> cast(string)len.sizeToTempString(tmpBuff) ~ "]"; >>> } >>> >>> Would be replaced by: >>> >>> override void toString(void delegate(const(char)[]) sink) const >>> { >>> SizeStringBuff tmpBuff = void; >>> value.toString(sink); >>> sink("["); >>> sink(cast(string)len.sizeToTempString(tmpBuff)); >>> sink("]"); >>> } >> >> >> The thing that really worries me about this synk API is that your code >> here produces (at least) 4 calls to a delegate. That's a lot of >> indirect function calling, which can be a severe performance hazard on >> some systems. >> We're trading out garbage for low-level performance hazards, which may >> imply a reduction in portability. > > > I think given the circumstances, we are better off. But when we find a > platform that does perform worse, we can try and implement alternatives. I > don't want to destroy performance on the platforms we *do* support, for the > worry that some future platform isn't as friendly to this method.
Video games consoles are very real, and very now. I suspect they may even represent the largest body of native code in the world today. I don't know if 'alternatives' is the right phrase, since this approach isn't implemented yet, and I wonder if a slightly different API strategy exists which may not exhibit this problem. >> But in any case, I think all synk code like this should aim to call >> the user supplied synk delegate at most *once* per toString. >> I'd like to see code that used the stack to compose the string >> locally, then feed it through to the supplied synk delegate in fewer >> (or one) calls. > > > This is a good goal to have, regardless. The stack is always pretty high > performing. However, it doesn't scale well. If you look above, the function > already uses the stack to output the number. It would be trivial to add 2 > chars to put the "[]" there also so only one sink call occurs. It would be trivial, and that's precisely what I'm suggesting! :) > But an aggregate which relies on members to output themselves is going to > have a tough time following this model. Only at the lowest levels can we > enforce such a rule. I understand this, which is the main reason I suggest to explore something other than a delegate based interface. > Another thing to think about is that the inliner can potentially get rid of > the cost of delegate calls. druntime is a binary lib. The inliner has no effect on this equation. >> Ideally, I guess I'd prefer to see an overload which receives a slice >> to write to instead and do away with the delegate call. Particularly >> in druntime, where API and potential platform portability decisions >> should be *super*conservative. > > > This puts the burden on the caller to ensure enough space is allocated. Or > you have to reenter the function to finish up the output. Neither of these > seem like acceptable drawbacks. Well that's why I open for discussion. I'm sure there's room for creativity here. It doesn't seem that unreasonable to reenter the function to me actually, I'd prefer a second static call in the rare event that a buffer wasn't big enough, to many indirect calls in every single case. There's no way that reentry would be slower. It may be more inconvenient, but I wonder if some API creativity could address that...? > What would you propose for such a mechanism? Maybe I'm not thinking of your > ideal API. I haven't thought of one I'm really happy with. I can imagine some 'foolproof' solution at the API level which may accept some sort of growable string object (which may represent a stack allocation by default). This could lead to a virtual call if the buffer needs to grow, but that's not really any worse than a delegate call, and it's only in the rare case of overflow, rather than many calls in all cases.
