UnsafeMutablePointer on the stack?


(Jean-Denis Muys) #1

Hi,

I have some issues using the new raw memory API. For instance, let's
suppose I want to call the `SecRandomCopyBytes` API to generate a
cryptographically secure random 32-bit number. The difficulty is its 3rd
argument, which is declared as UnsafeMutablePointer<UInt8>. Here is a
function that does that:

func entropicRandom() -> UInt32 {

    let randomWordPT = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)

    let _ = randomWordPT.withMemoryRebound(to: UInt8.self, capacity: 4) {
(p: UnsafeMutablePointer<UInt8>) -> Int32 in

        let result = SecRandomCopyBytes(kSecRandomDefault, MemoryLayout<
UInt32>.size, p)

        return result

    }

    let randomInt32 = randomWordPT[0]

    randomWordPT.deallocate(capacity: 1)

    return randomInt32

}

apparently, the calls to allocate and then deallocate suggest that there is
some heap allocation happening behind the scene here, possibly malloc/free.
Is that correct?

If so, this is quite wasteful. Is there a way to use a local variable on
the stack to achieve the same result?

Thanks,

Jean-Denis


(Dave Abrahams) #2

Hi,

I have some issues using the new raw memory API. For instance, let's
suppose I want to call the `SecRandomCopyBytes` API to generate a
cryptographically secure random 32-bit number. The difficulty is its 3rd
argument, which is declared as UnsafeMutablePointer<UInt8>. Here is a
function that does that:

func entropicRandom() -> UInt32 {

    let randomWordPT = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)

    let _ = randomWordPT.withMemoryRebound(to: UInt8.self, capacity: 4) {
(p: UnsafeMutablePointer<UInt8>) -> Int32 in

        let result = SecRandomCopyBytes(kSecRandomDefault, MemoryLayout<
UInt32>.size, p)

        return result

    }

    let randomInt32 = randomWordPT[0]

    randomWordPT.deallocate(capacity: 1)

    return randomInt32

}

apparently, the calls to allocate and then deallocate suggest that there is
some heap allocation happening behind the scene here, possibly malloc/free.
Is that correct?

Quite so.

But what did you suppose allocate and deallocate did, if not dynamic
memory allocation?

If so, this is quite wasteful. Is there a way to use a local variable on
the stack to achieve the same result?

func entropicRandom() -> UInt32 {
  var randomInt32: UInt32 = 0
  let byteCount = MemoryLayout.size(ofValue: randomInt32)

  withUnsafeMutablePointer(to: &randomInt32) {
    $0.withMemoryRebound(to: UInt8.self, capacity: byteCount) {
      SecRandomCopyBytes(kSecRandomDefault, byteCount, $0)
    }
  }
  return randomInt32
}

HTH,

···

on Sun Oct 02 2016, Jean-Denis Muys <swift-users-AT-swift.org> wrote:

--
-Dave


(Dave Abrahams) #3

You can use a local like this:
    var x: UInt32 = 0
    withUnsafePointer(to: x) { randomWordPT in
        //your existing code here
    }

Or I'm not sure if small arrays go on the heap, but

They do.

···

on Sun Oct 02 2016, Mike Ferenduros <swift-users-AT-swift.org> wrote:

    var bytes: [UInt8] = [0,0,0,0]
    _ = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
    return bytes.reduce(0) { ($0 << 8) | UInt32($1) }

reads a little nicer.

Personally I would be surprised if the malloc caused an actual measurable
performance hit tbh.

On Mon, 3 Oct 2016 at 02:15 Jean-Denis Muys via swift-users < > swift-users@swift.org> wrote:

Hi,

I have some issues using the new raw memory API. For instance, let's
suppose I want to call the `SecRandomCopyBytes` API to generate a
cryptographically secure random 32-bit number. The difficulty is its 3rd
argument, which is declared as UnsafeMutablePointer<UInt8>. Here is a
function that does that:

func entropicRandom() -> UInt32 {

    let randomWordPT = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)

    let _ = randomWordPT.withMemoryRebound(to: UInt8.self, capacity: 4) {
(p: UnsafeMutablePointer<UInt8>) -> Int32 in

        let result = SecRandomCopyBytes(kSecRandomDefault, MemoryLayout<
UInt32>.size, p)

        return result

    }

    let randomInt32 = randomWordPT[0]

    randomWordPT.deallocate(capacity: 1)

    return randomInt32

}

apparently, the calls to allocate and then deallocate suggest that there
is some heap allocation happening behind the scene here, possibly
malloc/free. Is that correct?

If so, this is quite wasteful. Is there a way to use a local variable on
the stack to achieve the same result?

Thanks,

Jean-Denis

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
-Dave


(Michael Ferenduros) #4

You can use a local like this:
    var x: UInt32 = 0
    withUnsafePointer(to: x) { randomWordPT in
        //your existing code here
    }

Or I'm not sure if small arrays go on the heap, but

    var bytes: [UInt8] = [0,0,0,0]
    _ = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
    return bytes.reduce(0) { ($0 << 8) | UInt32($1) }

reads a little nicer.

Personally I would be surprised if the malloc caused an actual measurable
performance hit tbh.

···

On Mon, 3 Oct 2016 at 02:15 Jean-Denis Muys via swift-users < swift-users@swift.org> wrote:

Hi,

I have some issues using the new raw memory API. For instance, let's
suppose I want to call the `SecRandomCopyBytes` API to generate a
cryptographically secure random 32-bit number. The difficulty is its 3rd
argument, which is declared as UnsafeMutablePointer<UInt8>. Here is a
function that does that:

func entropicRandom() -> UInt32 {

    let randomWordPT = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)

    let _ = randomWordPT.withMemoryRebound(to: UInt8.self, capacity: 4) {
(p: UnsafeMutablePointer<UInt8>) -> Int32 in

        let result = SecRandomCopyBytes(kSecRandomDefault, MemoryLayout<
UInt32>.size, p)

        return result

    }

    let randomInt32 = randomWordPT[0]

    randomWordPT.deallocate(capacity: 1)

    return randomInt32

}

apparently, the calls to allocate and then deallocate suggest that there
is some heap allocation happening behind the scene here, possibly
malloc/free. Is that correct?

If so, this is quite wasteful. Is there a way to use a local variable on
the stack to achieve the same result?

Thanks,

Jean-Denis

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Quinn “The Eskimo!”) #5

Quite. SecRandom generates cryptographically sound random numbers and thus is not optimised for speed.

Share and Enjoy

···

On 3 Oct 2016, at 01:14, Mike Ferenduros via swift-users <swift-users@swift.org> wrote:

Personally I would be surprised if the malloc caused an actual measurable performance hit tbh.

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Jens Alfke) #6

It won’t be noticeable against a call to SecRandom, as noted, but there are other circumstances where it’s a big performance hit to put a temporary buffer on the heap. (Right now I’m working on some rather performance-sensitive database code in C++ where avoiding a few heap allocations per iteration has proven to be a big win.)

Does Swift have any solution for allocating stack-based array buffers?

—Jens

···

On Oct 2, 2016, at 5:14 PM, Mike Ferenduros via swift-users <swift-users@swift.org> wrote:

Personally I would be surprised if the malloc caused an actual measurable performance hit tbh.


(Joe Groff) #7

There has been some work in the optimizer toward optimizing arrays onto the stack when they don't escape. In general, I would recommend sticking with the pointer allocate/deallocate methods if you need to directly control the destiny of the memory. If the allocate and deallocate occur unconditionally in the same function, it is possible to optimize the pair into a stack allocation. Using a local variable isn't a guarantee that you'll get stack memory, since closures may force the variable onto the heap, and furthermore subjects you to more aggressive semantic constraints on the underlying memory than you may want.

-Joe

···

On Oct 3, 2016, at 10:20 AM, Jens Alfke via swift-users <swift-users@swift.org> wrote:

On Oct 2, 2016, at 5:14 PM, Mike Ferenduros via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Personally I would be surprised if the malloc caused an actual measurable performance hit tbh.

It won’t be noticeable against a call to SecRandom, as noted, but there are other circumstances where it’s a big performance hit to put a temporary buffer on the heap. (Right now I’m working on some rather performance-sensitive database code in C++ where avoiding a few heap allocations per iteration has proven to be a big win.)

Does Swift have any solution for allocating stack-based array buffers?


(Jean-Denis Muys) #8

Indeed,

But that function was just an example. I wanted to learn about how to use the stack to call C functions that will fill some memory area passed as a pointer.

Jean-Denis

···

On 3 Oct 2016, at 09:46, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

On 3 Oct 2016, at 01:14, Mike Ferenduros via swift-users <swift-users@swift.org> wrote:

Personally I would be surprised if the malloc caused an actual measurable performance hit tbh.

Quite. SecRandom generates cryptographically sound random numbers and thus is not optimised for speed.

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users