guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Efficiency of `map`


From: Nala Ginrut
Subject: Re: Efficiency of `map`
Date: Sat, 10 Jun 2017 12:38:34 +0800

Hi Mark!
Do you have any advice to optimize it without disable GC temperaly? Or the only way is to change a better GC?

2017年6月10日 12:28,"Mark H Weaver" <address@hidden>写道:
Stefan Monnier <address@hidden> writes:

>>   (define (map f l)
>>     (if (pair? l)
>>         (cons (f (car l))
>>               (map f (cdr l)))
>>         '()))
>>
>> whereas we used to have to write code like this in order to support long
>> lists without overflowing the stack:
>>
>>   (define (map f l)
>>     (let loop ((l l) (out '()))
>>       (if (pair? l)
>>           (loop (cdr l) (cons (f (car l)) out))
>>           (reverse out))))
>
> Ignoring stack usage, is the first version faster or slower than the second?
> [ Or is the speed difference negligible?  ]

I don't have time to perform proper benchmarks, but some admittedly
inadequate measurements on my Thinkpad X200 suggest that the first
version is about 1.5% faster, mainly because it makes a lot less work
for the GC.  See below for details of what I did.

> How 'bout using a side-effecting `reverse!` (like Lisp's nreverse)?

We can't do that, because in the presence of first-class continuations
where the 'f' passed to map may return more than once, using mutation to
build the result list will change the result for some programs.  Both
modern scheme standards (R6RS and R7RS) explicitly specify that "If
multiple returns occur from map, the values returned by earlier returns
are not mutated".

      Mark


address@hidden ~$ guile
GNU Guile 2.2.2
Copyright (C) 1995-2017 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (define (map1 f l) (if (pair? l) (cons (f (car l)) (map f (cdr l))) '()))
scheme@(guile-user)> (define (map2 f l) (let loop ((l l) (out '())) (if (pair? l) (loop (cdr l) (cons (f (car l)) out)) (reverse out))))
scheme@(guile-user)> (define var #f)
scheme@(guile-user)> (define test-list (iota 100000))
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 13.121194s real time, 14.072380s run time.  2.346036s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 13.006867s real time, 13.940452s run time.  2.263353s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 13.079656s real time, 13.946879s run time.  2.197271s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 13.029591s real time, 15.312230s run time.  5.601020s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 13.041985s real time, 15.306287s run time.  5.581253s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 12.003391s real time, 13.421369s run time.  3.662504s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 11.993404s real time, 13.367805s run time.  3.496328s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 11.964659s real time, 13.362942s run time.  3.544227s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 12.619559s real time, 13.153612s run time.  1.471917s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 12.600161s real time, 13.136094s run time.  1.476574s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 12.584059s real time, 13.142257s run time.  1.478289s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map1 1+ test-list)) (loop (- i 1))))
;; 12.626346s real time, 13.146946s run time.  1.466499s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 12.009064s real time, 13.361389s run time.  3.690290s spent in GC.
scheme@(guile-user)> ,time (let loop ((i 1000)) (when (positive? i) (set! var (map2 1+ test-list)) (loop (- i 1))))
;; 11.970217s real time, 13.317716s run time.  3.352065s spent in GC.
scheme@(guile-user)>

Here are the 4 best times for each procedure:

map1:
;; 12.619559s real time, 13.153612s run time.  1.471917s spent in GC.
;; 12.600161s real time, 13.136094s run time.  1.476574s spent in GC.
;; 12.584059s real time, 13.142257s run time.  1.478289s spent in GC.
;; 12.626346s real time, 13.146946s run time.  1.466499s spent in GC.

averages of 4 best times:
;; 12.607531s real time, 13.144727s run time.  1.473320s spent in GC.


map2:
;; 12.009064s real time, 13.361389s run time.  3.690290s spent in GC.
;; 11.993404s real time, 13.367805s run time.  3.496328s spent in GC.
;; 11.964659s real time, 13.362942s run time.  3.544227s spent in GC.
;; 11.970217s real time, 13.317716s run time.  3.352065s spent in GC.

averages of 4 best times:
;; 11.984336s real time, 13.352463s run time.  3.520728s spent in GC.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]