JVM: is it possible to manipulate frame stack?
Asked Answered
J

3

2

Suppose I need to execute N tasks in the same thread. The tasks may sometimes need some values from an external storage. I have no idea in advance which task may need such a value and when. It is much faster to fetch M values in one go rather than the same M values in M queries to the external storage.

Note that I cannot expect cooperation from tasks themselves, they can be concidered as nothing more than java.lang.Runnable objects.

Now, the ideal procedure, as I see it, would look like

  1. Execute all tasks in a loop. If a task requests an external value, remember this, suspend the task and switch to the next one.
  2. Fetch the values requested at the previous step, all at once.
  3. Remove all completed task (suspended ones don't count as completed).
  4. If there are still tasks left, go to step 1, but instead of executing a task, continue its execution from the suspended state.

As far as I see, the only way to "suspend" and "resume" something would be to remove its related frames from JVM stack, store them somewhere, and later push them back onto the stack and let JVM continue.

Is there any standard (not involving hacking at lower level than JVM bytecode) way to do this?

Or can you maybe suggest another possible way to achieve this (other than starting N threads or making tasks cooperate in some way)?

Jonejonell answered 1/12, 2014 at 14:51 Comment(0)
R
2

It's possible using something like quasar that does stack-slicing via an agent. Some degree of cooperation from the tasks is helpful, but it is possible to use AOP to insert suspension points from outside.

(IMO it's better to be explicit about what's going on (using e.g. Future and ForkJoinPool). If some plain code runs on one thread for a while and is then "magically" suspended and jumps to another thread, this can be very confusing to debug or reason about. With modern languages and libraries the overhead of being explicit about the asynchronicity boundaries should not be overwhelming. If your tasks are written in terms of generic types then it's fairly easy to pass-through something like scalaz Future. But that wouldn't meet your requirements as given).

Racemose answered 1/12, 2014 at 14:57 Comment(5)
Thank you, will sure look at this.Jonejonell
Looks like it needs Java 7. Our project currently uses 6, so I'll put this on hold until later.Jonejonell
Unfortunately, this doesn't seem to satisfy my constraints, because I basically need to mark every method and its callers that could be suspendable as either throwing an exception or with an annotation.Jonejonell
Did you see the "Automatic Instrumentation" section? It sounds like that works around that by using AOP (though it's marked as experimental).Racemose
Yeah, but that kinda means half of the program might get instrumented, assuming the experimental feature doesn't even err. In my case I'd use the fibers not for parallelism, but exclusively for ability to suspend and later resume. And tasks really can be anything here, including something large that spans hundreds of methods over multiple classes.Jonejonell
T
1

As mentioned, Quasar does exactly that (it usually schedules N fibers on M threads, but you can set M to 1), using bytecode transformations. It even gives each task (AKA "fiber") its own stack trace, so you can dump it and get a complete stack trace without any interference from any other task sharing the thread.

Temple answered 17/2, 2015 at 15:19 Comment(0)
H
0

Well you could try this

you need

  1. A mechanism to save the current state of the task because when the task returns its frame would be popped from the call stack. Based on the return value or something like that you can determine weather it completed or not since you would need to re-execute it from the point where it left thus u need to preserve the state information.

  2. Create a Request Data structure for each task. When ever a task wants to request something it logs it there , The data structure should support all the possible request a task can make.

  3. Store these DS in a Map. At the end of the loop you can query this DS to determine the kind of resource required by each task.

  4. get the resource put it in the DS . Start the task from the state when it returned.

  5. The task queries the DS gets the resource.

  6. The task should use this DS when ever it wants to use an external resource.

you would need to design the method in which resource is requested with special consideration since when you will re-execute the task again you would need to call this method yourself so that the task can execute from where it left.

*DS -> Data Structure

hope it helps.

Horvath answered 1/12, 2014 at 15:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.