just-js / just

the only javascript runtime to hit no.1 on techempower :fire:
https://just.billywhizz.io/
MIT License
3.61k stars 123 forks source link

For Linux only? #1

Closed ChrisGitIt closed 3 years ago

ChrisGitIt commented 3 years ago

Hi and applause for your current up & running project!

I'm also very performance minded and would like to see it running on BSD Systems (especially FreeBSD).

Unfortunately I'm not much into C/C++ and the whole "build process" in general. But for what I have seen in the makefiles, it should not be hard to make it work under BSD Systems.

So are you currently aware of any "Linux specific" stuff that would make it hard to port to a BSD System (like kevent on BSD vs epoll on Linux (not sure if a comparison is correct here ... just read that event handling is different on the systems))? Or is your licensing forbidding porting to BSD?

billywhizz commented 3 years ago

Hi Chris. Thanks for stopping by. I am not against porting to another platform at all. BSD should be possible. Personally I don't have any experience with BSD but happy for someone to take a look at what would be needed for a port if anyone out there who is willing to help.

One of the main goals for this project is that it should be easy to learn/understand for someone with some JS and a little c/c++ experience. One of the obstacles I find with a lot of cross platform projects is you end with with a really complex and messy codebase that is diificult for new folks to comprehend. And you also end up with leaky, awkward abstractions that try to smooth out the differences between the different platforms. I am all ears for any suggestions on how we could start porting to other platform and keep the codebase clean and simple.

One obstacle to BSD as it stands is that I am currently exposing all the epoll primitives: https://github.com/just-js/just/blob/main/just.cc#L1768. There is an abstraction around this in JS-land but it is still using epoll specific constants etc. I really want to keep the c/c++ codebase as small and clean as possible so will have to think on how to reconcile these two things.

billywhizz commented 3 years ago

One thing I like about it as it currently stands is all you really need to look at to understand the whole platform is one file: https://github.com/just-js/just/blob/main/just.cc. 3000 lines of pretty simple c/c++. A lot of it is boilerplate (but I don't like macros much so happy to leave it in place). I would hope anyone with a basic understanding of c/c++ and a little linux systems knowledge would be able to understand everything going on there in a few days. and, yes, i need to add comments/docs! =)

I have spent too many hours with node.js codebase trying to hunt down weird issues and there are so many layers of abstraction that it becomes a thing only experts can do. Not meaning to be critical of node.js. It has to support a huge array of platforms and use cases. I don't see Just(js) trying to do the same thing.

ChrisGitIt commented 3 years ago

Hi and thanks for your feedback!

Your current source is in fact very readable and understandable! Having a closer look at your Postgress sources, I'm also thinking about writing a MariaDB module (might be a general MySQL module, not sure which details differ). This might then become my first C Project ... this can't be to difficult (I have no clue what I'm running into here ;-))

I also agree with your approach to keep abstractions layers out. BUT it might be a good idea to abstract the OS specific event system. I just read that libuv (is this needed by V8 anyways?) is/has a general OS specific abstraction.

"Part of Node's runtime is based on libuv, which is a cross platform asynchronous I/O library." source: https://cfsamson.github.io/book-exploring-async-basics/6_epoll_kqueue_iocp.html

This might even reduce your source code because you might not write your own epoll primitives exposings (don't know what exactly is possible within the C/C++ realm).

So what do you think about the Libuv integration? Does it make sense?

APPENDED FreeBSD itself has a Linux Compatibility Layer ... which seem to have a epoll abstraction layer included (https://reviews.freebsd.org/D1092) ... might be right now the quickest way ... nevertheless, please have a look about abstraction via libuv (might open portability to other platforms as well).

billywhizz commented 3 years ago

@ChrisGitIt great. would be happy to help and document around your efforts if you do try to put a module together. You can see from various ones i have started here that's it's fairly simple to do if you stick to a simple c-style api and don't need to create classes and templates to wrap things in. If you can't figure out how to build in your environment let me know. I need to update the README and do some documentation.

Re. Libuv. Yes, node.js is based on top of this but there is no dependency on it in v8. I have spent a lot of time with the libuv codebase in the past and it is is a big and complex codebase handling a huge amount of edge cases related to how different platforms deal with things. This is the exact thing I am hoping to avoid here. I want something small, focused and easy for newcomers/bug-hunters to hack on/understand.

I don't have a BSD environment to test on currently but will do some research and see what would be involved. Linux/BSD on x86_64 would be enough for me in terms of support (WSL2 allows near native linux performance now on Windows and I imagine this story will improve with time) and then maybe looking at supporting different architectures like arm and anywhere else v8 will currently run.

I've also started looking into compiling on alpine linux which uses a different libc. I have the basics working but a number of things I need to think about with that right now. Alpine would be a nice option for running in docker as the images are much smaller. It is also possible to statically compile the whole runtime and run it on google distroless docker. One of the spaces i think this platform could be useful is containerized linux as it should be much less resource intensive than node.js.

Thanks for the feedback. Keep it coming. Happy to answer any questions folks have for now and take a little break from coding to think about next steps.

ChrisGitIt commented 3 years ago

Hi again,

just one more try ... the wrapper from here: (https://reviews.freebsd.org/rS283441) => head/sys/compat/linux/linux_event.c Seems to be reasonable small ... you know, I would like to leave the Linux Compatibility Layer out of my BSD Installs (-:

But I will try to install Just-Js on BSD including the LinuxCompat Layer. Other issues might arise.

billywhizz commented 3 years ago

ok chris. i will have a look myself. let me know how you get on. we can also set something up to build/run using docker. i have published a package here but need to update it.

i think there will be quite a lot that won't work.

billywhizz commented 3 years ago

actually it's not going to work for you i think. the v8 lib that is being used is built using docker on debian so would have to figure out a way to build a bsd version of v8 lib also.

billywhizz commented 3 years ago

@ChrisGitIt i was doing a little experimenting tonight and i discovered VSCode Remote Containers. If you are on a Mac and have VSCode and docker you can install this extension and run everything inside docker. I think this might be best approach for now if you want to get building things.

I put some instructions on the wiki here. If you try it, let me know if it works for you.

ChrisGitIt commented 3 years ago

Hi again,

just a quick question: Have you thought about any kind of uptime monitoring software? Do you think this should be a "base" thing for production (so included in Just-Js and maybe integrated into systemD (or something alike)) or do you think that minor changes to, for example pm2, would be sufficient to fullflill the basic need for uptime handling?

rw3iss commented 3 years ago

@billywhizz Hey! Thanks for putting the docker instructions together. It all seemed to work fine up until building the modules. Following exact instructions, the last build.sh step is giving some errors. I've published the output from vscode container build.sh here: https://gist.github.com/rw3iss/fabd91a8cf9834a2dce3838867fe038a

For example: ffi.cc:3:8: error: ‘ffi_type’ does not name a type; did you mean ‘isfdtype’? pg.h:5:10: fatal error: libpq-fe.h: No such file or directory rocksdb.h:5:10: fatal error: rocksdb/c.h: No such file or directory

Tried it all twice. Not sure how to fix these. Am mostly building out of curiosity about the basics of the codebase, with not too much familiarity with lower level c libraries and the underlying JS engine internals.

billywhizz commented 3 years ago

hi @ChrisGitIt. the idea at the moment is to keep everything in the core runtime (i.e. this repo: https://github.com/just-js/just) small and simple. i.e. just wrappers around system calls and some namespacing and helpers. core will expose as much of the low level primitives as possible and more elegant and complex structures can be built around this in userland.

i also see the modules repository as a home for "blessed" modules which would form a broader "standard library" of modules for commonly needed pieces of functionality. these would be vetted and would have to be verified (i.e. have tests, be well maintained, be generally useful etc.) in order to be accepted into the official modules repo.

beyond that, i would see most of the modules being contributed by the community at large (assuming there ever is one - ha!) and would like to keep the set of official modules and functionality small.

i was involved in node.js in a very small way in the very early days and followed all the discussions in google groups etc. and i was of the opinion at the time that they were putting too much in the core. in many ways i was wrong as having a lot of functionality out of the box has been one of the keys to node.js' broad adoption and amazing success. i don't see this project as being a competitor for node.js in that sense. for me, it would be more of an option for folks who see the benefits of javascript on the server side but want low level access and capability of doing high performace, system level software in JS. also, i favour a small codebase with minimal abstraction and a focus on performance, robustness and security (mostly from being simple and easy to understand for contributors).

does that make sense? i'll see if i can write a bit more coherently about it over next few weeks.

re. process monitoring. it should be reasonably easy to put together a simple example of spawning a child process (or thread) and monitoring it in various ways, recycling it when it dies etc. i'll see if i can put something up in the examples repo over the weekend.

billywhizz commented 3 years ago

@billywhizz Hey! Thanks for putting the docker instructions together. It all seemed to work fine up until building the modules. Following exact instructions, the last build.sh step is giving some errors. I've published the output from vscode container build.sh here: https://gist.github.com/rw3iss/fabd91a8cf9834a2dce3838867fe038a

For example: ffi.cc:3:8: error: ‘ffi_type’ does not name a type; did you mean ‘isfdtype’? pg.h:5:10: fatal error: libpq-fe.h: No such file or directory rocksdb.h:5:10: fatal error: rocksdb/c.h: No such file or directory

Tried it all twice. Not sure how to fix these. Am mostly building out of curiosity about the basics of the codebase, with not too much familiarity with lower level c libraries and the underlying JS engine internals.

hi @rw3iss. yes, sorry about that. the interest in the project from you guys has taken me a little by surprise. a number of those modules were broken. i have now fixed most of them. the pg one is still not building correctly but the others should work now. if you have a chance to try again let me know. you will need to do a "make cleanall" in the just repo you checked out do and pull from master again. i have updated the vscode container configs to add some dependencies that were missing for building the modules.

if you have a chance to try again let me know how you get on.

billywhizz commented 3 years ago

@rw3iss that change has just been pushed now. sorry. am doing 20 different things at once here.

rw3iss commented 3 years ago

@billywhizz No worries! Thanks... that update seems to have worked. build.sh took almost an hour on my machine (2015 Macbook Pro 3.1Ghz). Anyway, now I just need to figure out how to run it. ./just works, but can't reach http://localhost:3000. Maybe you haven't set that up, or I need to make the endpoints myself, or maybe it's not in any state to do that yet, but a 'Run' section in the readme might be nice, if you have time. I will read through the code and see what I can figure out :-)

billywhizz commented 3 years ago

i'll add some docks. the reason the build took so long is mostly rocksdb library. it takes an age to build. also openssl. these are all optional modules that are not required. if you have the thing running in VSCode container than you just need to run

make runtime install

to build the runtime (a binary called "just") and install it to /usr/local/bin inside the docker container. you should be able to run a bunch of the examples then. i'll see if i can put some docs/walkthroughs together over the weekend.

rw3iss commented 3 years ago

Cool, thank you. It was definitely the rocksdb and openssl that took longest. I thought it was hanging ;-p I didn't realize there was an examples repo, just found it, thanks, I will play around :-) Looking forward to hearing more. Have a great weekend!

re-thc commented 3 years ago

Re. Libuv. Yes, node.js is based on top of this but there is no dependency on it in v8. I have spent a lot of time with the libuv codebase in the past and it is is a big and complex codebase handling a huge amount of edge cases related to how different platforms deal with things. This is the exact thing I am hoping to avoid here. I want something small, focused and easy for newcomers/bug-hunters to hack on/understand.

libuv is 1 of the main reasons nodejs is slow. Wouldn't use it. Even just replacing it with a different library and optimizing it properly shows enormous gains for nodejs.

billywhizz commented 3 years ago

Re. Libuv. Yes, node.js is based on top of this but there is no dependency on it in v8. I have spent a lot of time with the libuv codebase in the past and it is is a big and complex codebase handling a huge amount of edge cases related to how different platforms deal with things. This is the exact thing I am hoping to avoid here. I want something small, focused and easy for newcomers/bug-hunters to hack on/understand.

libuv is 1 of the main reasons nodejs is slow. Wouldn't use it. Even just replacing it with a different library and optimizing it properly shows enormous gains for nodejs.

Hi Harry (i think?). I think you being a little harsh there but It is big and complex and whenever i had to investigate issues trying to wade through the codebase in combination with the layers of abstraction in both JS and C++ in the node.js codebase was very painful.

i have been following alex hultman for a while. he has done some very interesting work and has been highly critical of node.js internals for a long time. again, i think he is a little harsh but he makes a lot of valid criticisms.

again, this project is only in early stages of development and is not seen as a rival for node.js. node.js has become a general purpose platform, similar to PHP in many ways. it does many things well, but if you want to get close to the metal, it makes it difficult imho.

billywhizz commented 3 years ago

and yes, i have no reason to use any higher level async or networking libraries. the goal for this project is to be a very small interface to linux syscalls/v8 internals right now. abstractions can be built on top of that in userland if there is enough interest in it. the core won't ever be much bigger than it currently is the way i see it at the moment.

billywhizz commented 3 years ago

having said that. uSocket might be something we could use but would prefer to keep dependencies as small as possible for now. one of the goals is that it can help a less experienced dev learn linux/posix systems programming. it should be easy for someone with a little c/c++, js and systems experience to pick the codebase up quickly and be able to hack on it or create modules/libraries for it.

billywhizz commented 3 years ago

If any of you folks are interested, i put a brief walkthrough of how to get up and running in VSCode using VSCode Remote Containers here. This should in theory work on Mac/Windows as well as Linux. I have tried it locally and works fine on Ubuntu 18.04.

re-thc commented 3 years ago

having said that. uSocket might be something we could use but would prefer to keep dependencies as small as possible for now. one of the goals is that it can help a less experienced dev learn linux/posix systems programming. it should be easy for someone with a little c/c++, js and systems experience to pick the codebase up quickly and be able to hack on it or create modules/libraries for it.

There's no http2 support, if that's a thing (in uSocket).

rw3iss commented 3 years ago

Hey @billywhizz, I've been wanting to try to write a simple user application on top of Just, to benchmark it on my local machine (in comparison with other benchmarks I've done here), but I'd like to run it outside of Docker for a fair comparison. This would also be nice for general development (though Docker is great for this, it eats up ~4GB memory). I know this isn't such a concern for you, but do you know if it is possible to compile Just on the Mac OS, with trivial modifications which I could try myself? If not I will continue to use the Docker setup as is, but I also don't mind helping to get it running on Mac standalone, if you think it might not be that difficult, and as a general test case.

As a first attempt, Mac doesn't see the 'binary' command (used in the makefile: builtins command):

   ~/Sites/just-mac │  main ▶ make runtime                                                                                                                                                                    ✔ ▶
ld -r -b binary just.js lib/websocket.js lib/inspector.js lib/loop.js lib/require.js lib/path.js lib/repl.js lib/fs.js -o builtins.o
ld: warning: option -b is obsolete and being ignored
ld: file not found: binary

Trying to Google but am not entirely sure of a workaround, if you might have any advice. I will be back in a few hours to research solutions more...

Update: I suppose the -b flag tries to tell the linker to process the files as binary, but this -b flag means something else in the OSX linker, I think: -b Used with -A option to strip base file's symbols. This option is obsolete. Obsolete option to produce a load map. Use -map option instead. It doesn't seem like the OSX ld command includes an option to specify the input format. Here is the manpage: https://www.unix.com/man-page/osx/1/ld/ Still looking though...

billywhizz commented 3 years ago

hi @rw3iss. that command is just bundling up the source files into an object file so they can be compiled into the binary and loaded from memory at runtime

see here and here. we just use the symbol offsets to read the contents of the files out of memory. there are various ways we could do the same thing, likely more portable than this.

i think it is going to be quite a bit of work to port to mac and will involve a lot of difficult decisions/discussions. i would prefer to put that off for now and focus on a robust implementation in linux first but happy to help in any way i can if you are keen to look at it. maybe we can do it on a branch and keep them it up to date with main.

i will have to see if i can get a cross compile setup here so i can do some testing myself. you can have a look at the uSocket source for some pointers. it runs on mac/BSD and linux. https://github.com/uNetworking/uSockets/tree/master/src

billywhizz commented 3 years ago

you can also see in the builder script i am bundling in all the sources so they can be extracted at runtime for building/bundling static binaries. still a work in progress. i set up a gitter here also. i'll keep an eye on it too. https://gitter.im/just-js/community

billywhizz commented 3 years ago

@rw3iss you can see i used to do this a different way previously. this is pretty much how node.js does the embedding of the runtime js files too. https://github.com/just-js/just/commit/14c093bdc0672a7a9c0662a3d2ff7fd3bf389429#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52R8.

here is code to initialise builtin the old way: https://github.com/just-js/just/commit/14c093bdc0672a7a9c0662a3d2ff7fd3bf389429#diff-62e04dcd135feacfb1c8fed6a11722c7e6d098241e01e455979681646d0c6ef0R6

it should be pretty easy to get something similar on mac.

rw3iss commented 3 years ago

Thanks @billywhizz, I will take a look around and let you know if I have any questions, but no worries on shifting focus at all, for sure keep it lean on linux 👍

rw3iss commented 3 years ago

Well I setup the Just server on my remote server, and was able to benchmark it there. These are the numbers in comparison to Rust (release mode) and Go, looking very nice (no, it isn't the fastest server in the world :p):

RUST remote/live server:
ab -k -l -c 50 -n 10000 http://144.202.51.193:8081/ Requests per second: 351.73 [#/sec] (mean) w/ c=250: Requests per second: 1582.45 [#/sec] (mean)

GO remote/live server:
ab -k -l -c 50 -n 10000 http://144.202.51.193:8081/ Requests per second: 349.72 [#/sec] (mean) w/ c=250: Requests per second: 1567.35 [#/sec] (mean)

JustJS remote/live server: ab -k -l -c 50 -n 10000 http://144.202.51.193:8888/ Requests per second: 346.26 [#/sec] (mean) w/ c=250: Requests per second: 1588.87 [#/sec] (mean)

Nice!

billywhizz commented 3 years ago

closing this for now