Comments (15)
@TheAngryByrd Sorry meant to say, your last most recent run of trie router on Debian was actually significantly faster than osx, really pronounced on longer routes and ones with parsing (one route is +200% faster then vanilla Giraffe!?!)
This output nicely shows that we can get +26% performance boost on TaskCont ( 17% Task CE, 9% Continuation), and another +39% with basic trie router (+76% from vanilla giraffe). I have built another radix/token tree implementation that should be little faster again (will test when all 3 done) and am now developing a cpu-caching focused one that lays entire map onto a 1-dimensional struct array, minimizing hops and utilises prebuilt index key maps to eliminate lookups.
Giraffe | TaskCont | TaskContTrie | Gir/Cont | Gir/Trie | Cont/Trie | Urls |
---|---|---|---|---|---|---|
88102 | 107562 | 110822 | +22% | +26% | +3% | / |
88501 | 107966 | 105799 | +22% | +20% | -2% | /about |
63268 | 81826 | 106559 | +29% | +68% | +30% | /auth/dashboard |
64892 | 73544 | 103903 | +13% | +60% | +41% | /auth/helpdesk |
63812 | 80834 | 108368 | +27% | +70% | +34% | /auth/inbox |
34609 | 46247 | 96658 | +34% | +179% | +109% | /auth/manager/accesscode/57646878 |
32088 | 40954 | 98299 | +28% | +206% | +140% | /auth/manager/executive/area/globaloperationcentral |
35423 | 51014 | 105696 | +44% | +198% | +107% | /auth/manager/executive/finance |
37659 | 50092 | 103655 | +33% | +175% | +107% | /auth/manager/executive/mis |
36439 | 48145 | 102607 | +32% | +182% | +113% | /auth/manager/executive/operations |
48084 | 64472 | 104357 | +34% | +117% | +62% | /auth/manager/payroll |
28899 | 33543 | 62715 | +16% | +117% | +87% | /auth/manager/teambravosales5345545.34544 |
46385 | 61851 | 101565 | +33% | +119% | +64% | /auth/manager/teamview |
46846 | 62551 | 104378 | +34% | +123% | +67% | /auth/manager/timesheets |
31418 | 37319 | 66035 | +19% | +110% | +77% | /auth/parsefirstlong987654321stringssecondandthirdIntegers |
42309 | 54735 | 101076 | +29% | +139% | +85% | /authtoken/as8d7f098adsf897asdf7a09dfasd7f9as7df987 |
60940 | 75203 | 98367 | +23% | +61% | +31% | /data/sunnydrycold/weather |
80472 | 107941 | 109810 | +34% | +36% | +2% | /delivery |
84192 | 102317 | 111883 | +22% | +33% | +9% | /ourstory |
84951 | 100414 | 103441 | +18% | +22% | +3% | /products |
87425 | 109061 | 115006 | +25% | +32% | +5% | /test |
56922 | 72761 | 101775 | +28% | +79% | +40% | /value/thisisavaluethatisbeingpassed |
86496 | 107979 | 112136 | +25% | +30% | +4% | /wheretofindus |
1330132 | 1678331 | 2334910 | +26% | +76% | +39% | Grand Total |
from giraffe.
I have built 3 "working" routers
- Trie (char tree nodes)
- Token/Radix (substring token tree nodes)
- Flat rolled tree (cpu caching optimized)
The Trie one is slow relative to other two, unfortunately the flat one was only 5% faster then token one to my surprise. I can tweak it to squeeze a little more but it's a lot less then I had hoped given the exponentially more complicated logic & execution.
I have spent/wasted last few weeks trying to fix boxing problem such that SRTP would be able to build partial application parser that pushed parsed values into function stack, avoiding boxing but it's just a bridge too far for now (I will come back to this).
For maintainability & simplicity I figured I'd release the token router first so I have created a branch token-router
in my fork and all original routing now in BasicRouter
module with token one in TokenRouter
.
I then went and copied all HttpHandlerTests
into a TokenRouterTests
such that HttpHandlerTests
uses BasicRouter
namespace, and new tests test token router on same tests.
7 tests have failed to my surprise and despite my basic tests all working... so that's where I am now, just need to figure out bug in 7 tests and good to merge. most appear to relate to nested subroutes (how dev lays/dupes routes). I have labelled failing tests with comment //<<FAIL
in repo.
I may need to change how trees mapped as with token implementation there is a tree built for each router(choose) whereas with the flat router I managed to suck entire app into one optimised tree.
Either way should be released this week.
NB: I am not including any case-insensitive matching in performance router as its a perf big slowdown and rarely causes a routing issue, users should turn caps lock off. BasicRouter
will always be there for those who need it and performance isn't an issue.
from giraffe.
New token router live and merged #114 on develop branch so now closing issue
from giraffe.
Awesome work and I like those suggestions. Let me know how I can help you with progressing on this issue !
from giraffe.
I think routing can be optimize without involving IO, we should probably look into http://benchmarkdotnet.org/ or expecto's wrapper for it use https://github.com/haf/expecto#benchmarkdotnet-usage
from giraffe.
@TheAngryByrd I was only realising the same thing about an hour ago, you're absolutely right, a pattern matching algo can be run & tested outside the server with a dummy HttpHandler class, does not need to be tested inside server every time. I have 2/3 variants of algo/tree I want to test so makes way more sense to do it this way if I am micro-tweaking the performance. Thanks as always !! I'll try use the expecto wrapper (but I've never used before).
@dustinmoris Thanks, will do, it's just a case of testing a few variants of my algo/tree structure now to see which performs best. The problem with using structs for the nodes is that you usually have to recursively construct entire nodes on initialisation which calls for more complex construction algo ... or duplicating work by creating in Obj/Dictionary form first and then mapping. Will keep you posted.
If anyone has any ideas on most performant structures/algo please do share and we can implement & test.
from giraffe.
@gerardtoconnor great news!
from giraffe.
I am going to close this issue as this one has been superseded by #53 and #69
from giraffe.
I think this is a separate issue/feature request but fine closing as I can integrate into continuation/task PR.
I finished my attempt at faster router but despite being 10x more complex was only 3% faster ... which is disappointing and pushes me to go for radix tree hybrid version that is almost as fast but far simplier to maintain.
from giraffe.
Can we re-open this until the new router PR is submitted? This is separate to both continuations & task CE as it implements a (radix-style) tree router with hand rolled parsers for max performance.
I would like to reopen as there are a few design questions I would like to ask & performance metrics to share etc?
from giraffe.
I have been bit delayed deploying this given I have been trying to re-design the parameter application structure to avoid boxing.
Given the high-frequency of parsing of URLs in web apps with a large slowdown in req/sec proportional to the amount of parsing, there is unneeded overhead in boxing parse values onto the heap, grouped together by a ref Tuple, more GC pressure.
By using partial application instead, (fun a b c ->
), we should be able to push parsed value types right onto the stack without boxing, so the calling parse handler can just pop off values, not even touching the heap (string obj still on heap but without boxing & additional ref lookup).
So far method overloading having an issue matching initial curried function signature taken from (fmt:StringFormat<'T,HttpHandler> , fn: 'T )
so trying to figure out how to hack around this.
for routef "foo/%i/bar/%s" (fun i s -> ...)
, type 'T is int -> string -> HttpHandler
matching our parse handler funtion fun i s next ctx -> ...
if I cannot figure a way around boxing after this weekend, will probably just release now with boxing, and put boxing issue on todo list.
from giraffe.
@gerardtoconnor did you ever find any time to work on this? Is there a way we can help you out?
from giraffe.
Actually, the token router is 580 lines vs Array routers 700 lines so not sure either fit into the "maintainability & simplicity" bucket. 😳
Feel free start reviewing process now as not too much will change with bug fixing... or just take my word for it and avoid burning your eyes on my spaghetti code 😏 .
In case anyone is lost as to what the code is doing, its building & then navigating a hybrid radix tree where nodes can have functions attached that dictate how to process/continue the match/parse process.
Some weird optimisations are included which may look bizarre but help JIT.
from giraffe.
There is one test I cannot get to pass
Failed Giraffe.TokenRouterTests.GET "/foo/blah blah/bar" returns "blah blah"
Error Message:
Expected: blah%20blah
Actual: blah blah
I will submit PR and maybe @dustinmoris can perhaps throw a fresh set of eyes on it?
Basically, it expects the written response of parsed path to be url encoded, but given we are using NSubstitute and not the server, not seeing where the encoding is done in the prior version!?
from giraffe.
Live now: https://github.com/dustinmoris/Giraffe/releases/tag/v0.1.0-beta-110
from giraffe.
Related Issues (20)
- Migrate to System.Text.Json HOT 1
- Participate on hacktoberfest 2023? HOT 1
- Never decalre reader with `use` on `ctx.Request.Body` HOT 4
- Upgrade to .NET 8 HOT 6
- LinkGenerator doesn't work with routef HOT 1
- Giraffe 6.2 is breaks against Microsoft.IO.RecyclableMemoryStream 3.0.0 HOT 11
- Returning streams, either with WriteStreamAsync or WriteFileStreamAsync or their handler equivalents, is extremely slow HOT 4
- Question: How to approach outside in testing of a micro service? HOT 2
- Guid pattern in endpoint router matches invalid values, throws System.FormatException HOT 6
- Follow-up from "Minor code optimisation #567"
- Update SECURITY.md
- Start using fantomas to validate code submissions with CI HOT 6
- [README] Suggestion for "Getting Started"'s "Doing it manually" HOT 2
- [question] Would it be possible to make `Giraffe.EndpointRouting` case-sensitive? HOT 3
- Remove NuGet API key from the repository HOT 3
- 6.4.0 release references PR for updating to .NET 7 instead of .NET 8 HOT 1
- EndpointRouting - Create endpoint for multiple http verbs
- Request/discussion: WriteStreamAsync buffer size autotuning and/or increase default buffer size HOT 1
- Update `.vscode` debug configuration to point to existent projects
- Returning 406 when mustAccept fails HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from giraffe.