[Cs254f11] was: subst now: multithreading

Wm. Josiah Erikson wjerikson at hampshire.edu
Mon Nov 21 11:47:59 EST 2011


On second thought, after some more benchmarking, I don't think putting a 
pmap there does anything for me at all. You can't have a lazy sort call 
- that makes no sense, and my benchmarking bears that out. I think that 
all I was seeing with all four CPU's working, though not much, was just 
clojure letting the other lazy calls happen concurrently when possible 
elsewhere.
Benchmarking with "time" says I spend 95% of my time in sort-by-error, 
which makes sense to me - that's where everything happens, obviously. I 
do need to make the calls to error concurrent, unless it's actually just 
the sorting itself that takes all the time. Time to figure that out, I 
guess!
     -Josiah



On 11/21/11 11:16 AM, Wm. Josiah Erikson wrote:
> Interestingly, if I put the pmap here in sort-by-error:
>
> (defn sort-by-error
>   [population]
>   (vec (pmap second
>             (sort (fn [[err1 ind1] [err2 ind2]] (< err1 err2))
>                   (map #(vector (error %) %) population)))))
>
> It works, and I see all four CPU's working, though not very hard, I 
> guess because the second "map" call is lazy, so clojure is helping me 
> out here. Putting pmapall there works too... so I guess that solves 
> the problem and actually is fine, but I still don't know why it didn't 
> work in the other place. Maybe because lazy calls to pmap don't work? 
> That might make some sense, actually...
>
> However, I'm not seeing a lot of CPU utilization on each core, though 
> all of them are working. I've only got like ~132% maximum. I guess 
> that means that it's not CPU that's slowing me down, it's memory 
> bandwidth? Interesting. Would you agree with my assessment, Lee?
>
>     -Josiah
>
>
>
> On 11/21/11 10:28 AM, Wm. Josiah Erikson wrote:
>> Wow yeah, a load of 48 is pretty much perfect CPU utilization on that 
>> box (yes, folks, it has 48 physical processor cores!)
>>
>> Unfortunately, I haven't been able to test this yet, due to probably 
>> bugs in my program or something about function definition scope or 
>> something. So I'm just changing this in your definition:
>>
>> (defn sort-by-error
>>   [population]
>>   (vec (map second
>>             (sort (fn [[err1 ind1] [err2 ind2]] (< err1 err2))
>>                   (map #(vector (error %) %) population)))))
>>
>> to:
>>
>> (defn sort-by-error
>>   [population]
>>   (vec (map second
>>             (sort (fn [[err1 ind1] [err2 ind2]] (< err1 err2))
>>                   (pmap #(vector (error %) %) population)))))
>>
>> ...and then it complains that it doesn't know what pmod, or pd, or 
>> pquot, or prem (whichever it encounters first) are:
>>
>> #'critic_evolution.core/sort-by-error
>> critic_evolution.core=>
>> (evolve 1000)
>> Starting evolution...
>> #<CompilerException java.lang.RuntimeException: 
>> java.util.concurrent.ExecutionException: java.lang.RuntimeException: 
>> java.lang.Exception: Unable to resolve symbol: pmod in this context 
>> (NO_SOURCE_FILE:0) (NO_SOURCE_FILE:0)>
>>
>> critic_evolution.core=>
>>
>> Weird. pmod is just defined like this:
>>
>> (defn pmod
>>   "Protected modulus; returns 0 if the denominator is zero."
>>   [num denom]
>>   (if (zero? denom)
>>     0
>>     (mod num denom)))
>>
>> and the rest of them are similar. I tried using your pmap-all and got 
>> a different error:
>>
>> critic_evolution.core=>
>> (evolve 1000)
>> Starting evolution...
>> #<CompilerException java.lang.RuntimeException: 
>> java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to 
>> java.lang.Number (NO_SOURCE_FILE:0)>
>>
>> Well, it'll be fun to figure that out. The problem with pmap I don't 
>> get, but Lee, you might have an answer. The problem with pmapall I'm 
>> sure is easily solvable - I'm gonna try to figure it out now, but 
>> perhaps somebody else can see it right away.
>>
>> pmapall is defined below in the quoted part of this email. The 
>> relevant call to pmapall looks like this:
>>
>> (pmapall #(vector (error %) %) population)))
>>
>> The error function looks like this:
>>
>> ;Using the terminal map in a new, better way! Just replace those 
>> terminals with numbers and then eval. Nice.
>> (defn error
>>   "Takes an individual, replaces its terminals with numbers looked up 
>> in terminal-map, then evaluates it,
>>    casts that to an int, compares its values to scores, adds the 
>> differences up, and returns the total error"
>>   [individual]
>>    (reduce + (map #(Math/abs (- (int (eval (postwalk-replace % 
>> individual))) %2)) terminal-map scores)))
>>
>> It works, and returns a number (an int, I think, unless it's been 
>> automatically promoted). I'm not sure where we are accidentally 
>> passing a symbol to something that wants a number. Perhaps somebody 
>> else can spot it.
>>
>> -Josiah
>>
>> On 11/18/11 7:23 PM, Lee Spector wrote:
>>> (defn pmapall
>>>    "Like pmap but: 1) coll should be finite, 2) the returned sequence
>>>     will not be lazy, 3) calls to f may occur in any order, to maximize
>>>     multicore processor utilization, and 4) takes only one coll so 
>>> far."
>>>    [f coll]
>>>    (let [agents (map #(agent % :error-handler (fn [agnt except] 
>>> (println except))) coll)]
>>>      (dorun (map #(send % f) agents))
>>>      (apply await agents)
>>>      (doall (map deref agents))))
>>
>

-- 
Wm. Josiah Erikson
Network Engineer
Hampshire College
Amherst, MA 01002
(413) 559-6091



More information about the Cs254f11 mailing list