On 26/05/2013, at 12:43 PM, srean wrote: > Now that you bring up parallelism, any plans of enabling OpenMP for Felix.
I have looked at it with intent. A flag to say if OpenMP is available is generated. However there's a problem. OpenMP primarily works by #pragma-ing subsequent loops, which are written as ordinary C, something like this from memory: #pragma openmp someopt for(i=0; i<n; ++i) { ... } The problem is .. felix never generates for loops. It always generates gotos. Because loops have scope. In other words, they can have local variables. In other words use stack frames on the machine stack. So it isn't safe to generate them in general. It would be tricky to detect exactly when it was safe to do so (though not impossible) but the openmp pragmas would be meaningless in the cases it wasn't safe and the programmer would be hard pressed to know exactly when that was. On the other hand, we can get *felix* to do the same job. Indeed one algorithm for matrices is: (a) calculate a reasonable job size such as 100 x 100 matrix multiplied by another. (b) if the job exceeds that size break it up with a fixed formula. (c) submit the jobs to a job queue. (d) a thread pool executes the jobs. This is a common technique. You just pick the job size so the overheads of the parallelisation are small enough they're dominated by the real time performance improvement. Felix already has a "concurrently" statement which can execute any array of procedures in parallel. That's not the same as queuing them to a pool. [Felix also has a thread pool and queue, but its designed for encapsulated C++ jobs not Felix procedures, i.e. the GC doesn't know about the worker threads. This pool is actually used for handling async I/O I think] More work can be done on this when client demand exists .. :) > I have no idea how that would work though, because as far as I know, Felix > reduces all flow control to a graph of goto's, whereas OpenMP works best with > for loops. So unless loops are reconstituted in the C++ code generator it > might be difficult to make use of OpenMP or many of the compiler > optimizations, unrolling and vectorization (SIMD). Yes. Exactly. > > Ok so what I understood is that objects created in the frames stay accessible > (if you so desire) and procs know who called them and where. Did I get it > right ? The only way to understand properly is to look at the actual C++ code. Bad time to build Felix: I just found a file I forgot to commit and have deleted :-> I'll have to do it again. Grr. A grammar file. With messy scheme code ;( > My motivation for asking the question was whether its possible to jump back > into the frame and resume. From your description It seems that if I am in a > Felix proc that would be possible by jumping "up" to its caller. Reminds me > of TCL :) You can jump to an enclosing proc that's active safely. However you cannot jump to a "used" proc that's completed safely. Felix zeros out the caller pointer if I remember rightly, so any pointers to data in the frame don't make the whole history of the call reachable. this means that when that dead proc "returns" the associated fthread just dies. In functional languages continuations are read only and so re-enterable. But in Felix procedural continuations have mutable variables in them. So whilst you CAN re-enter them, you will get the variables in the state that was left around when the previous thread of control exited. So now you know how fibres (fthreads) work. When you write on a channel (or read), and there's no corresponding read (or write) the fibre is suspended. When there is a matching read (or write) the fibre is resumed. It's precisely a suspended procedure stack frame (on the heap). Its resumed with all its local variables having the same values they did when it last left off. However note the fibre continues where it last left off. It isn't being re-entered from the top. > That reminds me, you also have generators, right. How do I know that the > generator is done yielding all of what it had to yield ? Beats me. How do you know? Its up to you to decide. Streams iterators are a kind of generator. As you know a stream is an infinite list. To represent a finite list a stream iterator uses the protocol like: 1,2,3 --> Some 1, Some 2, Some 3, None, None, None ........ That's one way. But you can have infinite generators and they're useful. For example: gen integers () () { again:> var i = 0; yield i; ++i; goto again; } That generates an infinite sequence of integers. Very useful in a compiler for getting a "fresh integer". Another example is: var seq = integers (); for i in list (100,200, 300) do println$ (seq(), i); done So here, you don't need to know when the generator is "finished". You just call it when you need it. Something else determines how many calls are done. > You lost me here. I use C++ functors. I think you are saying that if I use > C++ functors and they throw, I can jump back in, can I ? Sure you can. Just do this, which is exactly what Felix does: struct cont { int pc; virtual cont * resume(); }; struct F : virtual cont { cont * resume() { switch (pc) { case 1: ..... case 2: .... ... pc = 3; return this; case 3: .... } }; while(p)p->resume(); I left out a bit of stuff for clarity. This is *exactly* what Felix does. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ Try New Relic Now & We'll Send You this Cool Shirt New Relic is the only SaaS-based application performance monitoring service that delivers powerful full stack analytics. Optimize and monitor your browser, app, & servers with just a few lines of code. Try New Relic and get this awesome Nerd Life shirt! http://p.sf.net/sfu/newrelic_d2d_may _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language