Resource limits for Haskell

Ever wanted to write this? -- | Forks a thread, but kills it if it has more than 'limit' -- bytes resident on the heap. forkIOWithSpaceLimit :: IO () -> {- limit -} Int -> IO ThreadId I have a proposal (and some unpublished experimental patches) which do just that. Check it out at: http://hackage.haskell.org/trac/ghc/wiki/Commentary/ResourceLimits Comments, bikeshedding and critique appreciated. Cheers, Edward

Nice!
The API has ccsDynamic, while the example uses newCostCentreStack.
Would it be possible to attach a listener to GC-events and dynamically
adjust the listenCostCentreStack to trigger before major GCs?
Is this secure in the Safe Haskell sense? Can this be used to create a
secure computation wrt resources? Could we listen to MUT seconds?
Alexander
On Fri, Mar 8, 2013 at 9:52 AM, Edward Z. Yang
Ever wanted to write this?
-- | Forks a thread, but kills it if it has more than 'limit' -- bytes resident on the heap. forkIOWithSpaceLimit :: IO () -> {- limit -} Int -> IO ThreadId
I have a proposal (and some unpublished experimental patches) which do just that. Check it out at: http://hackage.haskell.org/trac/ghc/wiki/Commentary/ResourceLimits
Comments, bikeshedding and critique appreciated.
Cheers, Edward
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://www.haskell.org/mailman/listinfo/ghc-devs

Excerpts from Alexander Kjeldaas's message of Fri Mar 08 01:09:27 -0800 2013:
The API has ccsDynamic, while the example uses newCostCentreStack.
Oops, fixed. (Added the newCostCentreStack helper function).
Would it be possible to attach a listener to GC-events and dynamically adjust the listenCostCentreStack to trigger before major GCs?
Yes, but these listeners would only trigger after the GC, and have no guarantee of triggering in a timely fashion (e.g. before the next GC). Generally it's only safe to trigger "one-time" events.
Is this secure in the Safe Haskell sense? Can this be used to create a secure computation wrt resources? Could we listen to MUT seconds?
That's the idea! But we'll need semantics before we can say for sure. Actually, as far as time resources are concerned, the hope is to use this in conjunction with http://hackage.haskell.org/trac/ghc/ticket/7606 Edward

On Fri, Mar 8, 2013 at 10:14 AM, Edward Z. Yang
Excerpts from Alexander Kjeldaas's message of Fri Mar 08 01:09:27 -0800 2013:
The API has ccsDynamic, while the example uses newCostCentreStack.
Oops, fixed. (Added the newCostCentreStack helper function).
Would it be possible to attach a listener to GC-events and dynamically adjust the listenCostCentreStack to trigger before major GCs?
Yes, but these listeners would only trigger after the GC, and have no guarantee of triggering in a timely fashion (e.g. before the next GC). Generally it's only safe to trigger "one-time" events.
Regarding "timely", can this be exploited by a Safe Haskell "tenant" to obstruct invocation of the listener to exceed resource limits? Are there any guarantees that can be given? Here are some random thoughts: During a GC, maybe the thunk attached to the cost centre stack could be put behind the listener on the same capability. Or with the tickets system, maybe the listener could steal tickets from the thunk at every GC until it has executed, or something like that. Or a thunk could be associated with an allocation budget, independent of the resident size, and when the allocation budget is exceeded, it will block on an MVar. The listener/monitor has to run to increase the allocation budget. Alexander
Is this secure in the Safe Haskell sense? Can this be used to create a secure computation wrt resources? Could we listen to MUT seconds?
That's the idea! But we'll need semantics before we can say for sure. Actually, as far as time resources are concerned, the hope is to use this in conjunction with http://hackage.haskell.org/trac/ghc/ticket/7606
Edward

Excerpts from Alexander Kjeldaas's message of Fri Mar 08 01:32:50 -0800 2013:
Regarding "timely", can this be exploited by a Safe Haskell "tenant" to obstruct invocation of the listener to exceed resource limits? Are there any guarantees that can be given?
With the current scheduler implementation, the tenant will get at most one more scheduled quantum to use lots of resources before the listener actually manages to kill it. If you are working with soft limits, this might be good enough.
Here are some random thoughts: During a GC, maybe the thunk attached to the cost centre stack could be put behind the listener on the same capability.
Yes. Actually, it's simpler than that; just put the listener in the front of the queue. You will be sad if the listener takes too long to figure out what to do though!
Or with the tickets system, maybe the listener could steal tickets from the thunk at every GC until it has executed, or something like that.
Yes, this is a good synergy with stride scheduling. An even simpler measure is to give the listener max number of tickets, so it will get scheduled before the tenant.
Or a thunk could be associated with an allocation budget, independent of the resident size, and when the allocation budget is exceeded, it will block on an MVar. The listener/monitor has to run to increase the allocation budget.
This would correspond to the ability to "freeze" Haskell threads in mid-execution; no MVar blocking necessary. This is not possible with the current RTS. I don't know how hard it would be to do. Edward

On Fri, Mar 8, 2013 at 10:40 AM, Edward Z. Yang
Excerpts from Alexander Kjeldaas's message of Fri Mar 08 01:32:50 -0800 2013:
Regarding "timely", can this be exploited by a Safe Haskell "tenant" to obstruct invocation of the listener to exceed resource limits? Are there any guarantees that can be given?
With the current scheduler implementation, the tenant will get at most one more scheduled quantum to use lots of resources before the listener actually manages to kill it. If you are working with soft limits, this might be good enough.
Here are some random thoughts: During a GC, maybe the thunk attached to the cost centre stack could be put behind the listener on the same capability.
Yes. Actually, it's simpler than that; just put the listener in the front of the queue. You will be sad if the listener takes too long to figure out what to do though!
Or with the tickets system, maybe the listener could steal tickets from
With this scheduling trick, it seems that it should be possible to guarantee that at most one scheduled quantum + one nursery of memory is used. (The non-allocating process is still a problem if I understand correctly). Another API semantics that comes to mind is limit the resident size in a tree-like fashion so that whoever does forkIO will get the child resident size attached to his own process. This requires a listener to be able to kill off whole process-trees (think cgroups in linux). the
thunk at every GC until it has executed, or something like that.
Yes, this is a good synergy with stride scheduling. An even simpler measure is to give the listener max number of tickets, so it will get scheduled before the tenant.
Or a thunk could be associated with an allocation budget, independent of the resident size, and when the allocation budget is exceeded, it will block on an MVar. The listener/monitor has to run to increase the allocation budget.
This would correspond to the ability to "freeze" Haskell threads in mid-execution; no MVar blocking necessary. This is not possible with the current RTS. I don't know how hard it would be to do.
Random idea: Maybe there could be a never-executed capability in the RTS. Schedule the frozen process on that capability. This seems to be doable from the RTS side of things. When some condition arises, schedule it on the frozen capability. Then notify something in Haskell land. I don't know how to do the notification - when I looked at notifying through MVars for the event log it wasn't as easy as pie. Alexander
Edward

Excerpts from Alexander Kjeldaas's message of Fri Mar 08 02:06:07 -0800 2013:
Yes. Actually, it's simpler than that; just put the listener in the front of the queue. You will be sad if the listener takes too long to figure out what to do though!
With this scheduling trick, it seems that it should be possible to guarantee that at most one scheduled quantum + one nursery of memory is used. (The non-allocating process is still a problem if I understand correctly).
Well, that's why you compile with -falways-yields http://hackage.haskell.org/trac/ghc/ticket/367
Another API semantics that comes to mind is limit the resident size in a tree-like fashion so that whoever does forkIO will get the child resident size attached to his own process. This requires a listener to be able to kill off whole process-trees (think cgroups in linux).
This is a little more difficult, because I do not know how to do inherited resource counts efficiently. (The profiler does do them, but only at the *end* of the process, and it involves walking all of the stacks.) It may still be worth implementing.
This would correspond to the ability to "freeze" Haskell threads in mid-execution; no MVar blocking necessary. This is not possible with the current RTS. I don't know how hard it would be to do.
Random idea: Maybe there could be a never-executed capability in the RTS. Schedule the frozen process on that capability. This seems to be doable from the RTS side of things. When some condition arises, schedule it on the frozen capability. Then notify something in Haskell land. I don't know how to do the notification - when I looked at notifying through MVars for the event log it wasn't as easy as pie.
That would be pretty cute implementation strategy; freezing and unfreezing corresponds to moving process on and off the cap. Of course, why not just dispense with the entire capability and just have a list of frozen TSOs? Edward

"Edward Z. Yang"
Ever wanted to write this?
-- | Forks a thread, but kills it if it has more than 'limit' -- bytes resident on the heap. forkIOWithSpaceLimit :: IO () -> {- limit -} Int -> IO ThreadId
I have a proposal (and some unpublished experimental patches) which do just that. Check it out at: http://hackage.haskell.org/trac/ghc/wiki/Commentary/ResourceLimits
Comments, bikeshedding and critique appreciated.
...here's just a link to a previous related short discussion for completeness: http://www.haskell.org/pipermail/glasgow-haskell-users/2012-April/022258.htm... cheers, hvr

OK, I've posted a draft patch: http://hackage.haskell.org/trac/ghc/ticket/7763 Edward Excerpts from Edward Z. Yang's message of Fri Mar 08 00:52:37 -0800 2013:
Ever wanted to write this?
-- | Forks a thread, but kills it if it has more than 'limit' -- bytes resident on the heap. forkIOWithSpaceLimit :: IO () -> {- limit -} Int -> IO ThreadId
I have a proposal (and some unpublished experimental patches) which do just that. Check it out at: http://hackage.haskell.org/trac/ghc/wiki/Commentary/ResourceLimits
Comments, bikeshedding and critique appreciated.
Cheers, Edward
participants (3)
-
Alexander Kjeldaas
-
Edward Z. Yang
-
Herbert Valerio Riedel