1 module bench; 2 import std.algorithm : count, filter, map, sum; 3 import std.array : array, split; 4 import std.datetime.stopwatch : StopWatch, AutoStart, Duration; 5 import std.file : exists, readText; 6 import std.format : format; 7 import std.stdio : stderr, writeln, writefln; 8 import ada.url; 9 10 @safe: 11 12 immutable string[11] urlExamples = [ 13 "https://www.google.com/webhp?hl=en&ictx=2&sa=X&ved=0ahUKEwil_oSxzJj8AhVtEFkFHTHnCGQQPQgI", 14 "https://support.google.com/websearch/?p=ws_results_help&hl=en-CA&fg=1", 15 "https://en.wikipedia.org/wiki/Dog#Roles_with_humans", 16 "https://www.tiktok.com/@aguyandagolden/video/7133277734310038830", 17 "https://business.twitter.com/en/help/troubleshooting/how-twitter-ads-work.html?ref=web-twc-ao-gbl-adsinfo&utm_source=twc&utm_medium=web&utm_campaign=ao&utm_content=adsinfo", 18 "https://images-na.ssl-images-amazon.com/images/I/41Gc3C8UysL.css?AUIClients/AmazonGatewayAuiAssets", 19 "https://www.reddit.com/?after=t3_zvz1ze", 20 "https://www.reddit.com/login/?dest=https%3A%2F%2Fwww.reddit.com%2F", 21 "postgresql://other:9818274x1!!@localhost:5432/otherdb?connect_timeout=10&application_name=myapp", 22 "http://192.168.1.1", 23 "http://[2606:4700:4700::1111]", 24 ]; 25 26 struct BenchmarkData 27 { 28 const(string)[] urls; 29 size_t totalBytes; 30 31 static BenchmarkData fromFile(string filename) @trusted 32 { 33 if (!filename.exists) 34 { 35 stderr.writeln("File not found: ", filename); 36 return BenchmarkData(urlExamples, urlExamples.array.map!(s => s.length).sum); 37 } 38 39 auto urls = filename.readText.split; 40 return BenchmarkData(urls, urls.map!(s => s.length).sum); 41 } 42 43 static BenchmarkData defaultData() 44 { 45 return BenchmarkData(urlExamples, urlExamples.array.map!(s => s.length).sum); 46 } 47 48 size_t countInvalidUrls() const @trusted 49 { 50 return urls.filter!(url => !AdaUrl(ParseOptions(url)).isValid).count; 51 } 52 } 53 54 struct BenchmarkResults 55 { 56 Duration totalTime; 57 double bytesPerSecond; 58 double urlsPerSecond; 59 double timePerByte; 60 double timePerUrl; 61 size_t paramCount; 62 string toString() const 63 { 64 return format("Benchmark results:\n" ~ 65 "Total time: %s\n" ~ 66 "Speed: %.2f bytes/s\n" ~ 67 "URLs processed: %.2f urls/s\n" ~ 68 "Time per byte: %.9f s\n" ~ 69 "Time per URL: %.9f s", 70 totalTime, 71 bytesPerSecond, 72 urlsPerSecond, 73 timePerByte, 74 timePerUrl); 75 } 76 } 77 78 BenchmarkResults runBenchmark(const BenchmarkData data) @trusted 79 { 80 size_t paramCount; 81 auto sw = StopWatch(AutoStart.yes); 82 foreach (url_string; data.urls) 83 { 84 auto url = AdaUrl(ParseOptions(url_string)); 85 if (url.isValid) 86 { 87 auto params = url.getSearchParams(url.getSearch); 88 paramCount += params.length; 89 } 90 } 91 92 sw.stop(); 93 immutable duration = sw.peek(); 94 immutable double seconds = duration.total!"nsecs" / 1_000_000_000.0; 95 96 return BenchmarkResults( 97 duration, 98 data.totalBytes / seconds, 99 data.urls.length / seconds, 100 seconds / data.totalBytes, 101 seconds / data.urls.length, 102 paramCount 103 ); 104 } 105 106 void main(string[] args) 107 { 108 auto data = args.length > 1 ? BenchmarkData.fromFile( 109 args[1]) : BenchmarkData.defaultData(); 110 writefln("Loaded %d URLs, totaling %d bytes.", data 111 .urls.length, data.totalBytes); 112 writefln("Found %d invalid URLs.", data.countInvalidUrls()); 113 114 auto results = runBenchmark(data); 115 writeln(results); 116 }