Hello,
rif <[EMAIL PROTECTED]> writes:
> In a program I'm writing, the closure returned by the following
> function is taking essentially all the runtime:
>
> (defun make-cg-multiplier (dataset pointset sigma)
> (declare (type dataset dataset)
> (type pointset pointset)
> (type double-float sigma))
> (let ((s^2 (the double-float (* sigma sigma)))
> (n (the fixnum (veclen pointset))))
> #'(lambda (x)
> (declare (type df-vec x))
> (unless (= (veclen x) n)
> (error "The x vector and the dataset are not the same size."))
> (let ((result-vec (df-array n))
> (result-entry 0.0d0))
> (declare (type double-float result-entry))
> (fixtimes (i1 n)
> (fixfor (i2 i1 n)
> (setf result-entry
CMUCL prefers bindings to assignments. Replace this SETF with LET.
> (the double-float
> (exp (- (/ (distance (datapoint dataset (aref pointset i1))
> (datapoint dataset (aref pointset i2)))
> s^2)))))
> (if (= i1 i2)
> (incf (aref result-vec i1) (* (aref x i1) result-entry))
> (progn
> (incf (aref result-vec i2) (* (aref x i1) result-entry))
> (incf (aref result-vec i1) (* (aref x i2) result-entry))))))
> result-vec))))
>
>
> When I compile this function (speed 3, safety and debug 0), one of the
> compile-time notes is:
>
> ; #'(LAMBDA (X)
> ; (DECLARE #)
> ; (UNLESS # #)
> ; (LET #
> ; # ..))
> ; Note: Doing float to pointer coercion (cost 13), for:
> ; The second argument of CLOSURE-INIT.
>
> I don't know what this means.
The value of S^2 is boxed before putting into the closure.
> I'm vaguely guessing from the
> description that it's something that only happens once per call of the
> closure,
yes
> in which case it's fine. But I'd like to know what it is,
> and also make 100% sure that it's not in the inner loop.
(compile-file "foo.lisp" :trace-file t) and look in foo.trace. The
first closure blocks looks similar to:
IR2 block start c183
0: XEP-ALLOCATE-FRAME {# NIL}
1: SETUP-CLOSURE-ENVIRONMENT {#} => t36[EAX]
2: CLOSURE-REF t36[EAX] {0} => t37[ECX]
3: CLOSURE-REF t36[EAX] {1} => t38[EBX]
4: CLOSURE-REF t36[EAX] {2} => t39[ESI]
5: CLOSURE-REF t36[EAX] {3} => t40[EAX]
6: MOVE t41[EDX] => #:G19!42[EDX]
7: MOVE t43[S0]>t44[EDI] => t45[S0]<t46[EDI]
8: SAP-MOVE t47[S1]>t48[EDI] => t49[S1]<t50[EDI]
9: NOTE-ENVIRONMENT-START {#}
10: MOVE #:G19!42[EDX] => X!51[S2]<t52[EDX]
11: MOVE t37[ECX] => t53[S3]<t54[ECX]
12: MOVE-TO-DOUBLE t38[EBX] => t55[S4]<t56[FR0]
13: MOVE t39[ESI] => t57[S6]<t58[ESI]
14: MOVE t40[EAX] => t59[S7]<t60[EAX]
15: MOVE t45[S0]>t61[EAX] => t62[S0]<t63[EAX]
16: SAP-MOVE t49[S1]>t64[EAX] => t65[S1]<t66[EAX]
VOPs 3 and 12 unbox the value. This is done before the loop. [S4]<
means that the values is put into stack; on your machine it will
probably be in a register ([FRn]).
BTW, why are you writing so many type declarations? In CMUCL they are
needed in 3 cases:
- in communications with outer world (arguments and results of global
functions without a proclamation);
- when taking values out of an untyped storage (the double-float (car
list));
- for iteration variables.
Declaring result types of built-in functions is almost certainly
unnecessary.
--
Regards,
Alexey Dejneka
"Alas, the spheres of truth are less transparent than those of
illusion." -- L.E.J. Brouwer