A few measurements of stat()'s speed

Jonathan Marler johnnymarler at gmail.com
Tue Mar 26 23:28:00 UTC 2019


On Tuesday, 26 March 2019 at 20:09:52 UTC, Andrei Alexandrescu 
wrote:
> On 3/26/19 2:36 PM, H. S. Teoh wrote:
>> Does caching the contents of import directories cause 
>> significant
>> overhead?  If not, why not just cache it anyway, regardless of 
>> whether
>> the import happens across network mounts.
>
> Because testing takes 10 minutes and implementation takes one 
> day or more. We want to make sure there's impact.
>
>> On a slightly different note, why are we paying so much 
>> attention to
>> import speeds anyway?
>
> You destroy your own opening point: work should be put where 
> there's potential for impact, not "regardless".
>
>> We can optimize import speeds to hell and back
>> again until they cost practically zero time, yet the act of 
>> actually
>> *using*  one of those imports -- ostensibly the reason you'd 
>> want to
>> import anything in the first place -- immediately adds a huge 
>> amount of
>> overhead that by far overshadows those niggly microseconds we 
>> pinched.
>> Ergo:
>> 
>> 	import std.regex;
>> 	void main() {
>> 		version(withRegex)
>> 			auto re = regex("a");
>> 	}
>> 
>> This takes about 0.5 seconds to compile without 
>> -version=withRegex on my
>> machine. With -version=withRegex, it takes about *4.5 seconds* 
>> to
>> compile.  We have a 4 second bottleneck here and yet we're 
>> trying to
>> shave off microseconds elsewhere.  Why does instantiating a
>> single-character regex add FOUR SECONDS to compilation time?  
>> I think
>> *that*  is the question we should be answering.
>
> There's a matter of difficulty. I don't have a good attack on 
> dramatically improving regexen. If you do, it would be of 
> course a high impact project. There's also a matter of paying 
> for what you don't use. Unused imports are, well, unused. Used 
> imports should be paid for in proportion. Agreed, 4.5 seconds 
> is not quite proportionate.

I've included a script below to generate and run a performance 
test.  Save it to your box as "gen", then run "./gen" to generate 
then test, then "./build" to run it.

I tried changing the "stat" calls to use "access" instead, but 
with around 70,000 system calls (found out using strace), it 
didn't make any noticeable difference.  With "stat" it was around 
2.2 seconds and was about the same with "access". So the issue is 
not with how much memory stat is returning, it the overhead of 
performing any system call.


#!/usr/bin/env python3
# Run "./gen" to generate file for performance test
# Run "./build" to run the test
import os
import stat

mod_count = 1000
path_count = 20

def mkdir(dir):
     if not os.path.exists(dir):
         os.mkdir(dir)

mkdir("out")
for i in range(0, path_count):
     mkdir("out/lib{}".format(i))

mkdir("out/mods")
for i in range(0, mod_count):
     with open("out/mods/mod{}.d".format(i), "w") as file:
     	for j in range(0, mod_count):
             file.write("import mod{};\n".format(j))

with open("out/main.d", "w") as file:
     for i in range(0, mod_count):
         file.write("import mod{};\n".format(i))
     file.write('void main() { import 
std.stdio;writeln("working"); }')

with open("build", "w") as file:
     file.write("#!/usr/bin/env bash\n")
     file.write('[ "$DMD" != "" ] || DMD=dmd\n')
     file.write("set -x\n")
     file.write("time $DMD \\\n")
     for i in range(0, path_count):
         file.write("  -I=out/lib{} \\\n".format(i))
     file.write("  -I=out/mods out/main.d $@")
os.chmod("build", stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | 
stat.S_IXOTH)


More information about the Digitalmars-d mailing list