Re: [racket-users] Suspending/resuming threads with custodians/benefactors

2020-11-07 Thread Matthew Flatt
for the first problem, you've found a bug in the Racket CS thread
scheduler (i.e., Racket BC behaves correctly in this case). Suspending
a thread that is sleeping didn't prevent the thread from being woken up
on its previous schedule. I've pushed a repair as commit 7a12b4ac93.

After fixing that bug and using `thread/suspend-to-kill`, the second
part works as expected. But if `t1` is created with `thread`, the
behavior you describe sounds right: `t2` cannot resume a thread that
was created with `thread` and then terminated by a custodian.

Thanks for the report!
Matthew

At Sat, 7 Nov 2020 15:26:17 -0800 (PST), Greg Rosenblatt wrote:
> I'm experimenting with using custodians to manage threads (on Racket 7.8 
> [cs]) and encountering behavior I don't understand.
> 
> I start a looping thread `t1` under a new custodian `c1`.
> 
> I then shutdown `c1` and expect `t1` to stop looping.  If I started `t1` 
> with `thread` then this expectation is met.  However, if I start it with 
> `thread/suspend-to-kill`, it continues looping even after `c1` is shut 
> down.  Is this the correct behavior?
> 
> Additionally, I later start a new thread `t2` under a new custodian `c2`, 
> which attempts to resume `t1` after the shutdown, using itself as a 
> benefactor.  However, `t1` does not seem to resume.  Is this the correct 
> behavior?
> 
> Here is the code I'm working with:
> 
> ```
> #lang racket
> 
> (define c1 (make-custodian))
> (define c2 (make-custodian))
> (define t1 #f)
> (define t2 #f)
> 
> (parameterize ((current-custodian c1))
>   ;(set! t1 (thread/suspend-to-kill  ;; (custodian-shutdown-all c1) fails 
> to suspend this thread
>   (set! t1 (thread
>  (lambda ()
>(let loop ()
>  (displayln "thread 1")
>  (sleep 2)
>  (loop))
> 
> (displayln "ENTER to continue")
> (read-line)
> 
> (custodian-shutdown-all c1)
> 
> (displayln "ENTER to continue")
> (read-line)
> 
> (parameterize ((current-custodian c2))
>   (set! t2 (thread
>  (lambda ()
>(thread-resume t1 (current-thread))
>(let loop ()
>  (displayln "thread 2")
>  (sleep 2)
>  (loop))
> 
> (displayln "ENTER to continue")
> (read-line)
> 
> (custodian-shutdown-all c2)
> 
> (displayln "ENTER to continue")
> (read-line)
> ```
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/f844779f-9abd-46bd-987f-b2b3ca3d
> 0925n%40googlegroups.com.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/20201107174703.320%40sirmail.smtps.cs.utah.edu.


[racket-users] Suspending/resuming threads with custodians/benefactors

2020-11-07 Thread Greg Rosenblatt
I'm experimenting with using custodians to manage threads (on Racket 7.8 
[cs]) and encountering behavior I don't understand.

I start a looping thread `t1` under a new custodian `c1`.

I then shutdown `c1` and expect `t1` to stop looping.  If I started `t1` 
with `thread` then this expectation is met.  However, if I start it with 
`thread/suspend-to-kill`, it continues looping even after `c1` is shut 
down.  Is this the correct behavior?

Additionally, I later start a new thread `t2` under a new custodian `c2`, 
which attempts to resume `t1` after the shutdown, using itself as a 
benefactor.  However, `t1` does not seem to resume.  Is this the correct 
behavior?

Here is the code I'm working with:

```
#lang racket

(define c1 (make-custodian))
(define c2 (make-custodian))
(define t1 #f)
(define t2 #f)

(parameterize ((current-custodian c1))
  ;(set! t1 (thread/suspend-to-kill  ;; (custodian-shutdown-all c1) fails 
to suspend this thread
  (set! t1 (thread
 (lambda ()
   (let loop ()
 (displayln "thread 1")
 (sleep 2)
 (loop))

(displayln "ENTER to continue")
(read-line)

(custodian-shutdown-all c1)

(displayln "ENTER to continue")
(read-line)

(parameterize ((current-custodian c2))
  (set! t2 (thread
 (lambda ()
   (thread-resume t1 (current-thread))
   (let loop ()
 (displayln "thread 2")
 (sleep 2)
 (loop))

(displayln "ENTER to continue")
(read-line)

(custodian-shutdown-all c2)

(displayln "ENTER to continue")
(read-line)
```

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/f844779f-9abd-46bd-987f-b2b3ca3d0925n%40googlegroups.com.


Re: [racket-users] Racket BC versus CS unsafe flonums

2020-11-07 Thread Matthew Flatt
At Sat, 7 Nov 2020 16:42:43 +0100, Dominik Pantůček wrote:
> My current understanding is that the best performance you get from
> unsafe operations while using safe operations as hints for the flonum
> unboxing algorithm, right?

I'm not sure I understand what you mean, but I don't think unsafe
operations are particularly helpful for unboxing hints.

Let's separate out safety checks from unboxing. For safety checks, I'd
put the unsafe flonum operations into two categories:

 * `fl+`, `fl-`, etc., where the only relevant check is whether an
   argument is a flonum --- In this case, the benefits of unsafe
   variants are small to nothing. Depending on context, the compiler
   can often infer that the arguments are definitely flonums, so the
   generated code is the same. It's only when the compiler cannot infer
   flonumness that an unsafe variant has any performance advantage, and
   then it's just skipping a type-tag check.

 * `flvector-ref` and `flvector-set!` --- In these cases, there's an
   array-bounds requirement that is well beyond the reach of the
   compiler to infer. So, there will be a check on every use of the
   safe variants in a loop, for example. The check also requires more
   instructions than checking flonumness, so it's easier to see some
   speedup with unsafe variants of these operations.

Unboxing is a bigger deal for performance than safety checks, though,
and unboxing is completely driven by what the compiler can infer. Using
unsafe operations provides no more or less information to the
compiler's unboxing inference than safe operations do.


Matthew

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/20201107145933.fe%40sirmail.smtps.cs.utah.edu.


Re: [racket-users] Racket BC versus CS unsafe flonums

2020-11-07 Thread Dominik Pantůček
Wow, you are faster than I :)

On 07. 11. 20 15:36, Matthew Flatt wrote:
> At Fri, 6 Nov 2020 12:45:46 -0700, Matthew Flatt wrote:
>> I will investigate faster option. A primitive without conversion could
>> make the safe `flvector-set!` slightly faster, too, by avoiding a
>> redundant check.
> 
> Long story short, I added flvectors to the Chez Scheme level as of
> v7.9.0.4. With that change, `flvector-set!` is faster, and
> `flvector-ref` and `flvector-set!` cooperate better with flonum
> unboxing.

Ok, I originally wanted to reply to your original remark about
unsafe/safe flonum operations, but this actually extends my questions.

My current understanding is that the best performance you get from
unsafe operations while using safe operations as hints for the flonum
unboxing algorithm, right?

So with flvectors it is now the same? When I convey some safe hint to
the unboxing code, is it the best (in terms of performance) to use
unsafe flvector procedures then? To be honest, when I try to write down
"definitive" rules how to structure the code (mainly tight loops) and
use safe/unsafe operations properly, I get quickly lost.

I'll do some empirical benchmarks and see whether I can get some
generally valid answer.

> 
> For example, this microbenchmark now avoids allocation and runs about 8
> times as fast:
> 
>  (let ([v (make-flvector 100)])
>(time
> (for ([j (in-range 10)])
>   (for ([i (in-range (flvector-length v))])
> (flvector-set! v i (fl+ 1.0 (flvector-ref v i)))

I was just about to ask. This is how most of my code looks right now
(albeit more complex and with very short flvectors - 3 or 9 elements
mostly). I'll test the new implementation and see if there is a difference.

> 
> Also, your program now crashes as you intended.
> 

Aweseome! (May sound weird, but I really like consistent behavior).

> 
> (To make room in Chez Scheme's type encoding for flvectors, I removed
> immutable fxvectors. Immutable fxvectors do not seem useful, and
> there's no such thing at the Racket level.)

There definitely are scenarios, where immutable fxvectors may be a good
idea. However in those scenarios, allocations ruin the performance most
of the time. And although CS performs way better with extensive box
allocations than BC, it can still quickly become a noticeable bottleneck.


Dominik

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/e6f12dab-7996-9479-2cc1-85422d9b6587%40trustica.cz.


Re: [racket-users] Racket BC versus CS unsafe flonums

2020-11-07 Thread Matthew Flatt
At Fri, 6 Nov 2020 12:45:46 -0700, Matthew Flatt wrote:
> I will investigate faster option. A primitive without conversion could
> make the safe `flvector-set!` slightly faster, too, by avoiding a
> redundant check.

Long story short, I added flvectors to the Chez Scheme level as of
v7.9.0.4. With that change, `flvector-set!` is faster, and
`flvector-ref` and `flvector-set!` cooperate better with flonum
unboxing.

For example, this microbenchmark now avoids allocation and runs about 8
times as fast:

 (let ([v (make-flvector 100)])
   (time
(for ([j (in-range 10)])
  (for ([i (in-range (flvector-length v))])
(flvector-set! v i (fl+ 1.0 (flvector-ref v i)))

Also, your program now crashes as you intended.


(To make room in Chez Scheme's type encoding for flvectors, I removed
immutable fxvectors. Immutable fxvectors do not seem useful, and
there's no such thing at the Racket level.)


Matthew

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/20201107073608.45%40sirmail.smtps.cs.utah.edu.