Transient ranges

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Tue May 31 05:42:23 PDT 2016


On 5/30/16 11:46 AM, Andrei Alexandrescu wrote:
> On 05/30/2016 11:22 AM, Steven Schveighoffer wrote:
>> On Monday, 30 May 2016 at 15:12:41 UTC, Andrei Alexandrescu wrote:
>>> On 05/30/2016 09:30 AM, Steven Schveighoffer wrote:
>>>> My iopipe library is 2x as fast.
>>>
>>> Cool! What is the trick to the speedup? -- Andrei
>>
>> Direct buffer access and not using FILE * as a base.
>
> So what primitives do you use? The lower-level descriptor-based
> primitives open() and friends? http://linux.die.net/man/2/open

Yes. That is not the focus of my library, though. I have a very crude 
and basic I/O type that just wraps the system calls into a nice API.

> What do you mean by direct buffer access?

I mean instead of pulling data out one character at a time from another 
buffer into your buffer, you have direct access, using all the speedups 
that CPUs provide when accessing arrays.

I'm also allowing the compiler to inline as much as possible because all 
the code is available.

> What is the relative contributions of these (and possibly other) design
> decisions to the overall speed?

I don't know. I started with a vastly different design and it ended up 
being twice as fast. So it's difficult to say for certain what are the 
major factor that is slowing down std.stdio.

At DConf, Adrian Matoga presented his very similar flod library, and I 
was surprised when it was faster than mine at processing lines, even 
though he was still using std.stdio.File. So I found a few reasons why 
mine was slower and fixed them. The things that made it much faster were:

1. Switched to direct pointer access (i.e. doing while(*ptr++ != 
lineTerminator) {} ) when the buffer type was an array.
2. I was stupidly accessing the member of the struct which held the 
terminator instead of allocating a stack variable for it. After doing 
that (and making it immutable), the compiler was much better informed on 
how to optimize.

There may even be more opportunities for speedup, but I'm pretty 
satisfied with it at the moment.

> How can we integrate some of these in std.stdio without breaking
> backward compatibility,

There are 2 main issues with FILE *:

1) it does not provide buffer access, so you must rely on things like 
getline if they exist. But these have their own problems (i.e. do not 
support unicode, require C-malloc'd buffer)

2) All calls are opaque, so no inlining can occur. This is especially 
painful if you have to call fgetc in a tight loop. This goes back to the 
buffer access issue -- FILE * only lets you look ahead one character.

So I think the only real way to provide a decent performance improvement 
without breaking C compatibility is to write code that is aware of the 
implementation details of the opaque FILE * type. Just like getline.

> or offer additional artifacts that integrate
> seamlessly and don't need to be compatible?

I had a grand plan to replace stdio with something that "evolves" to 
faster D based i/o when you did D-like things. But it's very complex, 
and each addition of code to stdio makes things more complex.

In reality, I think we only need to be C compatible for stdout (possibly 
only via write[f][ln]), and possibly stdin. There's no reason we need to 
use C i/o for any other uses. What makes things difficult is that 
everything in Phobos uses std.stdio.File for all i/o and that uses C i/o.

-Steve


More information about the Digitalmars-d mailing list