6 ms·
As usual, happy to answer any questions.
by sadiq 5y ago
As usual, happy to answer any questions.
- pdimitar 5y agoIs the previous plan for adding effects in OCaml 5.1 still in place? I am very excited not only for the native parallelism that's coming in 5.0 but also about the effect handlers! I am sure many others are looking to start creating very interesting things with them, e.g. Rust-alike async capabilities or Erlang's preemptive green threads / actors runtime.
- sadiq 5y ago5.00 (the first release with multicore) will include effects! More info: https://discuss.ocaml.org/t/multicore-ocaml-september-2021-effect-handlers-will-be-in-ocaml-5-0/8554 https://discuss.ocaml.org/t/multicore-ocaml-september-2021-e...
- pdimitar 5y agoOh. I haven't followed lately. Thanks a lot for the updated info! Really looking forward to what the community will build with OCaml 5.00! IMO it will shoot the language straight into the mainstream and I can't wait. OCaml is applicable for like 90% what's out there, including as a Python replacement. And its syntax is often much terser than Rust (although the higher-level typing constructs can be confusing to read). After that, all that's left is a tool like Elixir's mix or Rust's cargo and the language is basically not only in the 21st century but much farther than many others! Looking forward to it.
- square_usual 5y ago> all that's left is a tool like Elixir's mix This so much. Mix is so pleasant to work with, but getting an OCaml project off the ground requires messing with dune + esy if you want consistent and isolated package management. It's a massive pain.
- jasone 5y agoYes, but note the absence of syntactic support. Effects will be usable for writing libraries and experimentation, but routine use won't be very ergonomic until a later release.
- simplify 5y agoConsidering the hard part of effects is implementing them at the language level, deferring on syntax is a good problem to have.
- Zababa 5y agoI've searched a bit for this and haven't been able to find a good answer. Let's say that I have m tasks that I want to run concurrently on n cores, for example handling HTTP requests or searching for something in files. I'd also like to not have to manage manually how the tasks are going to be distributed. Basically, have the same experience as when writing Go code. Is there a way to do this in multicore OCaml? I've found the task pool in domainslib [1] but I'm not sure if it's what I'm looking for. [1]: https://github.com/ocaml-multicore/domainslib/blob/master/lib/task.mli https://github.com/ocaml-multicore/domainslib/blob/master/li...
- vphantom 5y agoI think libraries like Lwt will be the ones to offer the level of abstraction which you're describing. I too would like to see the simplicity of goroutines make it into OCaml 5 ASAP.
- sadiq 5y agoYou could use eio with an event loop per domain and the domain manager to distribute work to other domains. The restriction at the moment is that the tasks you spin off to other domains can't do asynchronous io. There is work on-going at the moment to bridge or even unify eio (concurrency via effects) and domainslib (nested parallelism via domains and effects) but it's a few months out.
- Zababa 5y agoThank you for the clear explanation!
- talex5 5y agoTo clarify that, there are two systems here: - domainslib schedules all tasks across all cores (like Go). - eio keeps tasks on the same core (and you can use a shared job queue to distribute work between cores if you want). Eio can certainly do async IO on multiple cores. Moving tasks freely between cores has some major downsides - for example every time a Go program wants to access a shared value, it needs to take a mutex (and be careful to avoid deadlocks). Such races can be very hard to debug. I suspect that the extra reliability is often worth the cost of sometimes having unbalanced workloads between cores. We're still investigating how big this effect is. When I worked at Docker, we spent a lot of time dealing with races in the Go code, even though almost nothing in Docker is CPU intensive! For a group of tasks on a single core, you can be sure that e.g. incrementing a counter or scanning an array is an atomic operation. Only blocking operations (such as reading from a file or socket) can allow something else to run. And eio schedules tasks deterministically, so if you test with (deterministic) mocks then the trace of your tests is deterministic too. Eio's own unit-tests are mostly expect-based tests where the test just checks that the trace output matches the recorded trace, for example. The Eio README has more information, plus a getting-started guide: https://github.com/ocaml-multicore/eio/blob/main/README.md https://github.com/ocaml-multicore/eio/blob/main/README.md
- rwmj 5y agoI'm slightly concerned if this means changing C extensions (of which we have rather a lot). We only have a few places that use "naked" pointers, which are in any case deprecated, and we should be able to fix those easily enough. Mostly the rest are fairly ordinary extensions that just call C functions and use the usual CAMLparam stuff. We do have a few places that register global roots. And several packages that do callbacks from C back to OCaml. We also use @@noalloc a lot. Is there anything else? Since there's so much code, what should I be grepping for to find code that might be of concern? Edit: Some examples of simple stuff: https://github.com/libguestfs/libguestfs-common/blob/master/mltools/tools_utils-c.c https://github.com/libguestfs/libguestfs-common/blob/master/... https://github.com/libguestfs/libguestfs-common/blob/master/mlpcre/pcre-c.c https://github.com/libguestfs/libguestfs-common/blob/master/... https://github.com/libguestfs/libguestfs-common/blob/master/mlutils/unix_utils-c.c https://github.com/libguestfs/libguestfs-common/blob/master/... More complex stuff: https://gitlab.com/nbdkit/nbdkit/-/tree/master/plugins/ocaml https://gitlab.com/nbdkit/nbdkit/-/tree/master/plugins/ocaml http://oirase.annexia.org/tmp/ocaml/ http://oirase.annexia.org/tmp/ocaml/
- avsm 5y agoYou may find the “nnpchecker” configure option in 4.13.0 useful. This will print a detected use of naked pointers to stderr, which can hopefully be triggered by test suites. Noalloc and registering roots should all be the same, as are callbacks (for sequential code, which all existing code will be)
- sadiq 5y agoTo echo what avsm said, our intention is to preserve the C API. With the exception of naked pointers, if you follow the rules around the existing C API then your extensions should continue to work in sequential code running on 5.0. We have a scheduled build and test of every package in opam with multicore: http://check.ocamllabs.io:8082/ http://check.ocamllabs.io:8082/ to try to shake out C API incompatibilities and that's proved fruitful. If you do find things that don't work on 5.0, please let us know (and if you can, get it in to opam so we test it automatically!).
- 5y ago
- jpf0 5y agoA bunch of questions: Is multi-threading happening at the level of user-defined functions? How are threads scheduled? What's the underlying method or library for enabling multi-threading (Cilk, openMP, some LWT library...)? To what extent has this level of granularity been tested against other levels of nested parallelism (e.g. SIMD or otherwise parallel operators)? Have you tested performance by OS, and if so, have you noted any necessary OS-level modifications related to thread management? Is this part of a broader roadmap for accelerator integration?
- sadiq 5y ago1. Domains are the unit of parallelism. A domain is essentially an OS thread with a bunch of extra runtime book-keeping data. You can use Domain.spawn (https://github.com/ocaml-multicore/ocaml-multicore/blob/5.00/stdlib/domain.mli#L23 https://github.com/ocaml-multicore/ocaml-multicore/blob/5.00...) to spawn off a new domain which will run the supplied function and terminate when it finishes. This is heavyweight though, domains are expected to be long-running. 2. Domainslib is the library developed alongside multicore to aid users in exploiting parallelism. It supports nested parallelism and is pretty highly optimised (https://github.com/ocaml-multicore/domainslib/pull/29 https://github.com/ocaml-multicore/domainslib/pull/29 for some graphs/numbers). The domainslib repo has some good examples: https://github.com/ocaml-multicore/domainslib/tree/master/test https://github.com/ocaml-multicore/domainslib/tree/master/te... 3. We've not tested against other forms of parallelism. There isn't anything stopping you exploiting SIMD in addition to parallelism from domains. 4. No, we've not compared performance by OS. 5. No plans for the multicore team to look at accelerator integration at the moment.
- jez 5y agoThis is only glancingly related to the topic of multicore but I figure I’ll venture the question anyways: There were three big reasons pushing me towards other languages (C++, Rust) for a certain class of throughput-focused workflows: 1. Lack of multicore execution 2. Lack of control over how many bytes a datatype is (useful for many things, like ensuring something fits in a machine word or can avoid chasing a pointer in a loop) 3. Difficulty controlling where memory is allocated/copied vs moved (though some of this is less relevant when everything uses reference semantics and mutability is tracked with ref/mutable) I’ll be glad to see (1) fading into history! Do you have any personal tips/anecdotes for memory optimizations in practice, or any suggestions for something to read/follow/search?
- sadiq 5y agoFor both 2 and 3 you may find https://github.com/ocaml/RFCs/blob/unboxed-types/rfcs/unboxed-types.md https://github.com/ocaml/RFCs/blob/unboxed-types/rfcs/unboxe... very interesting. I'm hoping that progresses beyond the RFC stage.