Counting in Threads


(Gerriet M. Denkmann) #1

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);
dispatch_apply( nbrInterations, queue, ^void(size_t idx)
  {
    uint64_t tCount = 0;
    ... do some counting ...
    atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );
  }
)

Currently I am using:

var counter: UInt64 = 0
let dsema = DispatchSemaphore(value: 1)
DispatchQueue.concurrentPerform( iterations: nbrInterations )
{ ( idx: size_t) -> Void in
      
  var tCount: UInt64 = 0
  ... do some counting ...
  _ = dsema.wait(timeout: .distantFuture)
  counter += tCount;
  dsema.signal()
}

Is there a better way?

Gerriet.


(Daniel Dunbar) #2

I suspect one of the actual compiler people might tell me I shouldn't trust this, but in practice it works:

···

--
import Darwin.C

public class AtomicInt32 {
    public fileprivate (set) var value : Int32 = 0
    
    /// Create a new atomic integer with the specified initial value.
    public init(_ value: Int32 = 0) {
        self.value = value
    }
    
    /// Add one to the value.
    public func increment () {
        OSAtomicIncrement32(&value)
    }
}

public func +=(int: AtomicInt32, value: Int32) {
    OSAtomicAdd32(value, &int.value)
}
--

Would also love to know if compiler guarantees I *can* trust this.

Note that this has to be a class for this to be in any way safe, which means it is also rather inefficient if the use case was having a lot of them.

- Daniel

On Oct 12, 2016, at 12:47 AM, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);
dispatch_apply( nbrInterations, queue, ^void(size_t idx)
  {
    uint64_t tCount = 0;
    ... do some counting ...
    atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );
  }
)

Currently I am using:

var counter: UInt64 = 0
let dsema = DispatchSemaphore(value: 1)
DispatchQueue.concurrentPerform( iterations: nbrInterations )
{ ( idx: size_t) -> Void in
      
  var tCount: UInt64 = 0
  ... do some counting ...
  _ = dsema.wait(timeout: .distantFuture)
  counter += tCount;
  dsema.signal()
}

Is there a better way?

Gerriet.

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


(Philippe Hausler) #3

I was under the impression that taking the address was more than a single load instruction and would emit a placeholder invalid value: which would make that technically unsafe in a threaded context.

···

Sent from my iPhone

On Oct 12, 2016, at 8:18 AM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

I suspect one of the actual compiler people might tell me I shouldn't trust this, but in practice it works:
--
import Darwin.C

public class AtomicInt32 {
   public fileprivate (set) var value : Int32 = 0

   /// Create a new atomic integer with the specified initial value.
   public init(_ value: Int32 = 0) {
       self.value = value
   }

   /// Add one to the value.
   public func increment () {
       OSAtomicIncrement32(&value)
   }
}

public func +=(int: AtomicInt32, value: Int32) {
   OSAtomicAdd32(value, &int.value)
}
--

Would also love to know if compiler guarantees I *can* trust this.

Note that this has to be a class for this to be in any way safe, which means it is also rather inefficient if the use case was having a lot of them.

- Daniel

On Oct 12, 2016, at 12:47 AM, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);
dispatch_apply( nbrInterations, queue, ^void(size_t idx)
   {
       uint64_t tCount = 0;
       ... do some counting ...
       atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );
   }
)

Currently I am using:

var counter: UInt64 = 0
let dsema = DispatchSemaphore(value: 1)
DispatchQueue.concurrentPerform( iterations: nbrInterations )
{ ( idx: size_t) -> Void in
           
   var tCount: UInt64 = 0
   ... do some counting ...
   _ = dsema.wait(timeout: .distantFuture)
   counter += tCount;
   dsema.signal()
}

Is there a better way?

Gerriet.

_______________________________________________
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


(Daniel Dunbar) #4

Not in this case, today:

···

--
$ cat x.swift
import Darwin.C

public class AtomicInt32 {
   public fileprivate (set) var value : Int32 = 0

   /// Create a new atomic integer with the specified initial value.
   public init(_ value: Int32 = 0) {
       self.value = value
   }

   /// Add one to the value.
   public func increment () {
       OSAtomicIncrement32(&value)
   }
}

$ swiftc -S -o - x.swift -O | grep '.globl __TFC4main11AtomicInt329incrementfT_T_' -A16
  .globl __TFC4main11AtomicInt329incrementfT_T_
  .align 4, 0x90
__TFC4main11AtomicInt329incrementfT_T_:
  .cfi_startproc
  pushq %rbp
Ltmp4:
  .cfi_def_cfa_offset 16
Ltmp5:
  .cfi_offset %rbp, -16
  movq %rsp, %rbp
Ltmp6:
  .cfi_def_cfa_register %rbp
  leaq 16(%rdi), %rsi
  movl $1, %edi
  popq %rbp
  jmp _OSAtomicAdd32
  .cfi_endproc
--

- Daniel

On Oct 12, 2016, at 8:31 AM, Philippe Hausler <phausler@apple.com> wrote:

I was under the impression that taking the address was more than a single load instruction and would emit a placeholder invalid value: which would make that technically unsafe in a threaded context.

Sent from my iPhone

On Oct 12, 2016, at 8:18 AM, Daniel Dunbar via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I suspect one of the actual compiler people might tell me I shouldn't trust this, but in practice it works:
--
import Darwin.C

public class AtomicInt32 {
   public fileprivate (set) var value : Int32 = 0

   /// Create a new atomic integer with the specified initial value.
   public init(_ value: Int32 = 0) {
       self.value = value
   }

   /// Add one to the value.
   public func increment () {
       OSAtomicIncrement32(&value)
   }
}

public func +=(int: AtomicInt32, value: Int32) {
   OSAtomicAdd32(value, &int.value)
}
--

Would also love to know if compiler guarantees I *can* trust this.

Note that this has to be a class for this to be in any way safe, which means it is also rather inefficient if the use case was having a lot of them.

- Daniel

On Oct 12, 2016, at 12:47 AM, Gerriet M. Denkmann via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);
dispatch_apply( nbrInterations, queue, ^void(size_t idx)
   {
       uint64_t tCount = 0;
       ... do some counting ...
       atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );
   }
)

Currently I am using:

var counter: UInt64 = 0
let dsema = DispatchSemaphore(value: 1)
DispatchQueue.concurrentPerform( iterations: nbrInterations )
{ ( idx: size_t) -> Void in
           
   var tCount: UInt64 = 0
   ... do some counting ...
   _ = dsema.wait(timeout: .distantFuture)
   counter += tCount;
   dsema.signal()
}

Is there a better way?

Gerriet.

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

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


(Shawn Erickson) #5

So we would have to drop down to C code, etc. to safely leverage OSAtomic?

···

On Wed, Oct 12, 2016 at 8:32 AM Philippe Hausler via swift-users < swift-users@swift.org> wrote:

I was under the impression that taking the address was more than a single
load instruction and would emit a placeholder invalid value: which would
make that technically unsafe in a threaded context.

Sent from my iPhone

On Oct 12, 2016, at 8:18 AM, Daniel Dunbar via swift-users < > swift-users@swift.org> wrote:

I suspect one of the actual compiler people might tell me I shouldn't
trust this, but in practice it works:
--
import Darwin.C

public class AtomicInt32 {
   public fileprivate (set) var value : Int32 = 0

   /// Create a new atomic integer with the specified initial value.
   public init(_ value: Int32 = 0) {
       self.value = value
   }

   /// Add one to the value.
   public func increment () {
       OSAtomicIncrement32(&value)
   }
}

public func +=(int: AtomicInt32, value: Int32) {
   OSAtomicAdd32(value, &int.value)
}
--

Would also love to know if compiler guarantees I *can* trust this.

Note that this has to be a class for this to be in any way safe, which
means it is also rather inefficient if the use case was having a lot of
them.

- Daniel

On Oct 12, 2016, at 12:47 AM, Gerriet M. Denkmann via swift-users < > swift-users@swift.org> wrote:

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);

dispatch_apply( nbrInterations, queue, ^void(size_t idx)

   {

       uint64_t tCount = 0;

       ... do some counting ...

       atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );

   }

)

Currently I am using:

var counter: UInt64 = 0

let dsema = DispatchSemaphore(value: 1)

DispatchQueue.concurrentPerform( iterations: nbrInterations )

{ ( idx: size_t) -> Void in

   var tCount: UInt64 = 0

   ... do some counting ...

   _ = dsema.wait(timeout: .distantFuture)

   counter += tCount;

   dsema.signal()

}

Is there a better way?

Gerriet.

_______________________________________________

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

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


(Philippe Hausler) #6

Or allocate a pointer for it. The other alternative would be NSLock but that might be swatting flies with sledgehammers. We had a similar issue implementing NSLock in swift-corelibs-foundation where taking the address of a pthread mutex corrupted the structure for when another thread would attempt to grab it.

···

Sent from my iPhone

On Oct 12, 2016, at 4:45 PM, Shawn Erickson <shawnce@gmail.com> wrote:

So we would have to drop down to C code, etc. to safely leverage OSAtomic?

On Wed, Oct 12, 2016 at 8:32 AM Philippe Hausler via swift-users <swift-users@swift.org> wrote:
I was under the impression that taking the address was more than a single load instruction and would emit a placeholder invalid value: which would make that technically unsafe in a threaded context.

Sent from my iPhone

On Oct 12, 2016, at 8:18 AM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

I suspect one of the actual compiler people might tell me I shouldn't trust this, but in practice it works:
--
import Darwin.C

public class AtomicInt32 {
   public fileprivate (set) var value : Int32 = 0

   /// Create a new atomic integer with the specified initial value.
   public init(_ value: Int32 = 0) {
       self.value = value
   }

   /// Add one to the value.
   public func increment () {
       OSAtomicIncrement32(&value)
   }
}

public func +=(int: AtomicInt32, value: Int32) {
   OSAtomicAdd32(value, &int.value)
}
--

Would also love to know if compiler guarantees I *can* trust this.

Note that this has to be a class for this to be in any way safe, which means it is also rather inefficient if the use case was having a lot of them.

- Daniel

On Oct 12, 2016, at 12:47 AM, Gerriet M. Denkmann via swift-users <swift-users@swift.org> wrote:

How to translate this to Swift:

__block atomic_uint_fast64_t counter = ATOMIC_VAR_INIT(0);
dispatch_apply( nbrInterations, queue, ^void(size_t idx)
   {
       uint64_t tCount = 0;
       ... do some counting ...
       atomic_fetch_add_explicit( &counter, tCount, memory_order_relaxed );
   }
)

Currently I am using:

var counter: UInt64 = 0
let dsema = DispatchSemaphore(value: 1)
DispatchQueue.concurrentPerform( iterations: nbrInterations )
{ ( idx: size_t) -> Void in
           
   var tCount: UInt64 = 0
   ... do some counting ...
   _ = dsema.wait(timeout: .distantFuture)
   counter += tCount;
   dsema.signal()
}

Is there a better way?

Gerriet.

_______________________________________________
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

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