anchor.diff:          Log.warn "took %A" (sw.MicroTime / 10)
   
   
  +
  +        let mutable hist : MapExt<int, int * float> = MapExt.empty
  +
           // download the result and check it against the CPU version
           let result = Array.zeroCreate cnt
           output.Download(result)
  -        let mutable ok = true
           for i in 0 .. cnt - 1 do
  -            let t = result.[i] * check.[i].Inverse
  -            if not (t.IsIdentity(1.0E-3f)) then
  -                if ok then
  -                    printfn "ERROR"
  -                    ok <- false
  -                printfn "  %d: %A" i t.NormMax
  -
  -        if ok then printfn "OK"
  +            let d = M44d.Distance2(M44d.op_Explicit result.[i], M44d.op_Explicit check.[i]) |> float
  +            let e = if d <= 0.0 then -1000 else Fun.Log10 d |> int
  +            hist <-
  +                hist |> MapExt.alter e (fun o ->
  +                    match o with
  +                        | Some (cnt, v) -> Some (cnt + 1, v + d)
  +                        | None -> Some (1, d)
  +                )
  +
  +        printfn "results"
  +        for (e,(cnt,v)) in MapExt.toSeq hist do
  +            if e <= -1000 then
  +                printfn "   0:          (%d)" cnt
  +            else
  +                let v = (v / float cnt)
  +                let v = v / (10.0 ** float e)
  +                printfn "   1E%d: %.3f (%d)" e v cnt
  +
   
           // relase all the resources
           cmd.Dispose()
  
positive.code:                 member x.Dispose() = x.Dispose()
  
  
      [<AbstractClass; Sealed; Extension>]
      type DeviceScanExtensions private() =
          [<Extension>]
  
negative.code: 
              do device.OnDispose.Add (fun _ -> release())
  
              member x.Invoke(input : IBufferVector<'a>, output : IBufferVector<'a>) =
                  let rec build (input : IBufferVector<'a>) (output : IBufferVector<'a>) =
                      command {
                          let cnt = int input.Size
                          let args0 = ComputeShader.newInputBinding scan pool
  
                          try
                              args0.["inputOffset"] <- input.Offset |> int
                              args0.["inputDelta"] <- input.Delta |> int
                              args0.["inputSize"] <- input.Size |> int
                              args0.["inputData"] <- input.Buffer
                              args0.["outputOffset"] <- output.Offset |> int
                              args0.["outputDelta"] <- output.Delta |> int
                              args0.["outputData"] <- output.Buffer
                              args0.Flush()
  
                              do! Command.Bind scan
                              do! Command.SetInputs args0
                              do! Command.Dispatch(ceilDiv (int input.Size) scanSize)
                              do! Command.SyncWrite(output.Buffer)
  
                              let oSums = output.[int64 scanSize - 1L .. ].Strided(scanSize)
                              if oSums.Size > 1L then
                              
                                  do! build oSums oSums
  
                                  let args1 = ComputeShader.newInputBinding fixup pool
                                  try
                                      args1.["inputData"] <- oSums.Buffer
                                      args1.["inputOffset"] <- oSums.Offset |> int
                                      args1.["inputDelta"] <- oSums.Delta |> int
                                      args1.["outputData"] <- output.Buffer
                                      args1.["outputOffset"] <- output.Offset |> int
                                      args1.["outputDelta"] <- output.Delta |> int
                                      args1.["count"] <- output.Size |> int
                                      args1.["groupSize"] <- scanSize
                                      args1.Flush()
  
                                      do! Command.Bind fixup
                                      do! Command.SetInputs args1
                                      do! Command.Dispatch(ceilDiv (int output.Size - scanSize) halfScanSize)
                                      do! Command.SyncWrite(output.Buffer)
                                  finally
                                      args1.Dispose()
  
  
                          finally
                              args0.Dispose()
                      }
  
                  if input.Size > 1L then
                      build input output
                  else
                      Command.Nop
  
              member x.Compile(input : Buffer<'a>, output : Buffer<'a>) =
                  let cmd = device.GraphicsFamily.DefaultCommandPool.CreateCommandBuffer(CommandBufferLevel.Primary)
  