Weber-0.0.4 and some notes about optimization

I released Weber-0.0.4 at this week. And here are some words about it. Current release mainly is a bug fixing and optimization and you don't find any new major features in it. First of all about performance, it became much better than previous Weber-0.0.3. I tested Weber at my workstation, with approximately the same web applications with the different web frameworks, maybe these results are not very objective, but i can see that weber now comparable with other web frameworks in speed. I tested Weber with:
wrk -c2000 -t8 http://localhost:8080/
all web application were sesion disabled. And here are the results:

If we'll compare current results with the Weber-0.0.3, it showed really worse results, something about 1000Req/s, like ChicagoBoss. As i said, there were much work for optimization it. And here some words about optimization.

How i raised Weber performance


First of all macroses. Macro! Macro! Macro!, Yes, you can read in book by Dave's Thomas:
Macros can easily make your code harder to understand. So never use a macro when you could use a function.
And it's true. But... i was guided by the following principle:
If you can do something in compile time, do it.
Let's see in some examples. What is the standard Weber's workflow? User sends request to the some URL, for example to the /main. Weber need to parse this url, understand which resource to return to the user. So... Weber must to find view, read it's content, compile it with EEx if need and return to the user. But it's very labor-intensive occupation to find/read/compile view for the every user's request. Weber makes it simple. It reads and compile all views it in compile time and generates modules with function which will return alredy compiled view's content. Here is it:


That's all. Now if we have view which path is project/lib/views/layout/index.html, we'll get module: Elixir.Views.Layout.Index and if we'll call: Elixir.Views.Layout.Index.__view__, we will get compiled content of this view. And that's all! We read and compile all views only one time, in compile time, instead reading/compiling it for every request. Second little example. When the request comes, Weber must understand, which module to call for getting compiled view content. Previously i had a simple function which returned all views from the current project:


It's pretty simple and works perfectly. But fprof showed that it was the slowest part in Weber. I created macros which returns the same result:


It generates Elixir.Weber.Path module and number of functions. And weber does it in compile time too. Now we can call Elixir.Weber.Path.__root__ for getting root directory, or Elixir.Weber.Path.__views__ for getting all views of current project. That's All. There are many another little optimizations in weber, but here I described the main approaches. If you will have any questions/suggestions/problems with Weber, please write us to the issues. Any contributions are welcome!

Links




No comments: