Interesting. I'll try some of your suggested tests to see if my pmapall all is 
behaving better than I thought.

Does your pmap-pool permit nesting? (That is, does it permit passing pmap-pool 
a function which itself calls pmap-pool?). If so then that would be a reason to 
prefer it over my pmapall.

Thanks,

 -Lee


On Oct 10, 2011, at 9:43 PM, j-g-faustus wrote:

> I made an alternative implementation using a thread pool and a queue, based 
> on the example at
> http://clojure.org/concurrent_programming 
> 
> In short, your pmapall and the pool-based implementation (below) both give 
> approximately
> perfect scaling on my 4/8-core system (Intel i7 920 and HT). 
> Both give close to full load on all cores and a factor 4.4 speedup compared 
> to single threaded. 
> This seems about right, the CPU has four physical cores and get a few percent 
> extra performance 
> from the virtual cores, so the speedup is approximately linear with the 
> number of cores.
> 
> pmap-pool may be a tiny bit faster than the pmapall, but they are so close 
> that I can't 
> really tell.
> 
> It is possible that there is some sort of synchronization overhead on your 
> 48-core machine.
> 95% of the tasks are practically noops, after all - just the cost of a single 
> function call. 
> There are only 48 tasks in your test that actually require computation, so 
> each 
> core will do a bunch of noops and perhaps one "real" task. 
> 
> In real time, a single i7 920 runs the test just as fast as your 48 cores. I 
> don't expect that's
> representative for what your 48 cores can do.
> 
> I suggest
> * Increase the test size and/or the density of "heavy" tasks.
> * Let the "light" tasks do a bit more computation, at least enough to pay for 
> the 
> overhead of calling them.
> * Start with a smaller number of threads, and see where it stops scaling 
> linearly.
> 
> 
> Threadpool/queue-based implementation:
> 
> (import '(java.util.concurrent Executors))
> (defn pmap-pool [f coll]
>   (let [queue (ref coll)  ;; shared queue of work units
>         nthreads  (.availableProcessors (Runtime/getRuntime))
>         pool  (Executors/newFixedThreadPool nthreads)
>         tasks (map (fn [_] 
>                      (fn [] ; one task per thread
>                        (let [local-res (atom [])] ;; collect results per 
> thread to minimize synchronization
>                          (while (seq @queue)
>                            ;; queue may be emptied between 'while'
>                            ;; and 'dosync'.
>                            (when-let [wu (dosync
>                                                 ;; grab work unit, update 
> queue
>                                                 (when-let [w (first @queue)]
>                                                   (alter queue next)
>                                                   w))]
>                              (swap! local-res conj (f wu))))
>                          local-res)))
>                    (range nthreads))
>         results (doall (map #(deref (.get %)) ;; blocks until completion
>                             (.invokeAll pool tasks))) ;; start all tasks
>         results (reduce concat results)]
>     (.shutdown pool)
>     ;; sanity check
>     (when-not (and (empty? @queue)     
>                    (= (count results) (count coll))
>                    (every? #(= % :done) results))
>       (println "ERROR: queue " (count @queue) " #results" (count results)))
>     results))
> 
> Results on an i7 920, 4 cores/8 threads (hyperthreading), Ubuntu 10.10:
> 
> user=> (time (last (map fast-or-slow inputs))))
> "Elapsed time: 161891.732036 msecs", 100% CPU (out of 800% possible)
> 
> user=> (time (last (pmap fast-or-slow inputs))))
> "Elapsed time: 163139.249677 msecs", 100% CPU
> pmap has zero effect on my system, it won't use more than one core.
> 
> user=> (time (last (pmapall fast-or-slow inputs))))    
> "Elapsed time: 37710.349712 msecs", ~793% CPU 
> 
> user=> (time (last (pmap-pool fast-or-slow inputs))))
> "Elapsed time: 36393.132824 msecs", ~795% CPU
> 
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

--
Lee Spector, Professor of Computer Science
Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspec...@hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to