Get Total free memory (RAM) of iOS/iPadOS device in swift - ios

I know this has been asked multiple times, and I spent already multiple days to have the exact code for that, but seems I am still far away and I need help.
I use the below code,
/**
TOTAL DEVICE RAM MEMORY
**/
let total_bytes = Float(ProcessInfo.processInfo.physicalMemory)
let total_megabytes = total_bytes / 1024.0 / 1024.0
/**
FREE DEVICE RAM MEMORY
**/
var usedMemory: Int64 = 0
var totalUsedMemoryInMB: Float = 0
var freeMemoryInMB: Float = 0
let hostPort: mach_port_t = mach_host_self()
var host_size: mach_msg_type_number_t = mach_msg_type_number_t(MemoryLayout<vm_statistics_data_t>.stride / MemoryLayout<integer_t>.stride)
var pagesize:vm_size_t = 0
host_page_size(hostPort, &pagesize)
var vmStat: vm_statistics = vm_statistics_data_t()
let capacity = MemoryLayout.size(ofValue: vmStat) / MemoryLayout<Int32>.stride
let status: kern_return_t = withUnsafeMutableBytes(of: &vmStat) {
let boundPtr = $0.baseAddress?.bindMemory( to: Int32.self, capacity: capacity )
return host_statistics(hostPort, HOST_VM_INFO, boundPtr, &host_size)
}
if status == KERN_SUCCESS {
usedMemory = (Int64)((vm_size_t)(vmStat.active_count + vmStat.inactive_count + vmStat.wire_count) * pagesize)
totalUsedMemoryInMB = (Float)( usedMemory / 1024 / 1024 )
freeMemoryInMB = total_megabytes - totalUsedMemoryInMB
print("free memory: \(freeMemoryInMB)")
}
And I got the below results (real devices)
iPhone XR
free memory: 817.9844
Difference of about 150MB
iPhone13 Pro Max
free memory: 1384.2031
Difference of about 700MB
iPad 2021
free memory: 830.9375
Difference of about 170MB
I also used the below variants, with even worst results
//usedMemory = (Int64)((vm_size_t)(vmStat.active_count + vmStat.inactive_count + vmStat.wire_count + vmStat.free_count) * pagesize)
//usedMemory = (Int64)((vm_size_t)(vmStat.active_count + vmStat.wire_count) * pagesize)
//usedMemory = (Int64)((vm_size_t)(vmStat.inactive_count + vmStat.wire_count) * pagesize)
//usedMemory = (Int64)((vm_size_t)(vmStat.active_count + vmStat.inactive_count ) * pagesize)
A difference of about 100 MB is ok, but really do not understand why it is function of the device and I am not sure how can I can have a reliable value.
If that is not possible the difference between the real and the one got by the code for each device will be consistant so that I can pad it to get the real value?
My app is using scenekit and is hangry of resources, need to remove details once I am exsausting the memory.
Any help is appreciated.

I hope this method will help you -
var physicalMemory: UInt64 {
return (ProcessInfo().physicalMemory / 1024) / 1024 // in MB
}
func deviceRemainingFreeSpace() -> Int64? {
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
guard
let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: documentDirectory),
let freeSize = systemAttributes[.systemFreeSize] as? NSNumber
else {
return nil
}
return (freeSize.int64Value / 1024) / 1024 // in MB
}

Related

Adam Optimizer is apparently not converging

I am trying to write a neural network in rust + arrayfire, and while gradient descent works, ADAM does not.
fn back_propagate(
&mut self,
signals: &Vec<Array<f32>>,
labels: &Array<u8>,
learning_rate_alpha: f64,
batch_size: i32,
) {
let mut output = signals.last().unwrap();
let mut error = output - labels;
for layer_index in (0..self.num_layers - 1).rev() {
let signal = Self::add_bias(&signals[layer_index]);
let deriv = self.layer_activations[layer_index].apply_deriv(output);
let delta = &(deriv * error).T();
let matmul = matmul(&delta, &signal, MatProp::NONE, MatProp::NONE);
let gradient_t = (matmul / batch_size).T();
match self.optimizer {
Optimizer::GradientDescent => {
let weight_update = learning_rate_alpha * gradient_t;
self.weights[layer_index] -= weight_update;
}
Optimizer::Adam => {
let exponents = constant(2f32, gradient_t.dims());
self.first_moment_vectors[layer_index] = (&self.beta1[layer_index]
* &self.first_moment_vectors[layer_index])
+ (&self.one_minus_beta1[layer_index] * &gradient_t);
self.second_moment_vectors[layer_index] = (&self.beta2[layer_index]
* &self.second_moment_vectors[layer_index])
+ (&self.one_minus_beta2[layer_index]
* arrayfire::pow(&gradient_t, &exponents, true));
let corrected_first_moment_vector = &self.first_moment_vectors[layer_index]
/ &self.one_minus_beta1[layer_index];
let corrected_second_moment_vector = &self.second_moment_vectors[layer_index]
/ &self.one_minus_beta2[layer_index];
let denominator = sqrt(&corrected_second_moment_vector) + 1e-8;
let weight_update =
learning_rate_alpha * (corrected_first_moment_vector / denominator);
self.weights[layer_index] -= weight_update;
}
}
output = &signals[layer_index];
let err = matmulTT(
&delta,
&self.weights[layer_index],
MatProp::NONE,
MatProp::NONE,
);
error = index(&err, &[seq!(), seq!(1, output.dims()[1] as i32, 1)]);
}
}
I've stored beta1, beta2, 1-beta1, 1-beta2 in constant arrays for every layer just to avoid having to recompute them. It appears to have made no difference.
GradientDescent converges with a learning rate alpha=2.0, however with Adam, if i use alpha>~0.02, the network appears to get locked in. Funnily enough, if I remove all the hidden layers, it does work. Which tells me something, but I'm not sure what it is.
I figured it out, for anyone else, my alpha=0.01 is still too high, once I reduced it to 0.001, it converged very quickly

How can I convert my UInt8 array to Data? (Swift)

I am trying to communicate with a Bluetooth laser tag gun that takes data in 20 byte chunks, which are broken down into 16, 8 or 4-bit words. To do this, I made a UInt8 array and changed the values in there. The problem happens when I try to send the UInt8 array.
var bytes = [UInt8](repeating: 0, count: 20)
bytes[0] = commandID
if commandID == 240 {
commandID = 0
}
commandID += commandIDIncrement
print(commandID)
bytes[2] = 128
bytes[4] = UInt8(gunIDSlider.value)
print("Response: \(laserTagGun.writeValue(bytes, for: gunCControl, type: CBCharacteristicWriteType.withResponse))")
commandID is just a UInt8. This gives me the error, Cannot convert value of type '[UInt8]' to expected argument type 'Data', which I tried to solve by doing this:
var bytes = [UInt8](repeating: 0, count: 20)
bytes[0] = commandID
if commandID == 240 {
commandID = 0
}
commandID += commandIDIncrement
print(commandID)
bytes[2] = 128
bytes[4] = UInt8(gunIDSlider.value)
print("bytes: \(bytes)")
assert(bytes.count * MemoryLayout<UInt8>.stride >= MemoryLayout<Data>.size)
let data1 = UnsafeRawPointer(bytes).assumingMemoryBound(to: Data.self).pointee
print("data1: \(data1)")
print("Response: \(laserTagGun.writeValue(data1, for: gunCControl, type: CBCharacteristicWriteType.withResponse))")
To this, data1 just prints 0 bytes and I can see that laserTagGun.writeValue isn't actually doing anything by reading data from the other characteristics. How can I convert my UInt8 array to Data in swift? Also please let me know if there is a better way to handle 20 bytes of data than a UInt8 array. Thank you for your help!
It looks like you're really trying to avoid a copy of the bytes, if not, then just init a new Data with your bytes array:
let data2 = Data(bytes)
print("data2: \(data2)")
If you really want to avoid the copy, what about something like this?
let data1 = Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: bytes), count: bytes.count, deallocator: .none)
print("data1: \(data1)")

Approach for reading arbitrary number of bits in swift

I'm trying to do some binary file parsing in swift, and although i have things working I have a situation where i have variable fields.
I have all my parsing working in the default case
I grab
1-bit field
1-bit field
1-bit field
11-bits field
1-bit field
(optional) 4-bit field
(optional) 4-bit field
1-bit field
2-bit field
(optional) 4-bit field
5-bit field
6-bit field
(optional) 6-bit field
(optional) 24-bit field
(junk data - up until byte buffer 0 - 7 bits as needed)
Most of the data uses only a certain set of optionals so I've gone ahead and started writing classes to handle that data. My general approach is to create a pointer structure and then construct a byte array from that:
let rawData: NSMutableData = NSMutableData(data: input_nsdata)
var ptr: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8(rawData.mutableBytes)
bytes = UnsafeMutableBufferPointer<UInt8>(start: ptr, count: rawData.length - offset)
So I end up working with an array of [UInt8] and I can do my parsing in a way similar to:
let b1 = (bytes[3] & 0x01) << 5
let b2 = (bytes[4] & 0xF8) >> 3
return Int(b1 | b2)
So where I run into trouble is with the optional fields, because my data does not lie specifically on byte boundaries everything gets complicated. In the ideal world I would probably just work directly with the pointer and advance it by bytes as needed, however, there is no way that I'm aware of to advance a pointer by 3-bits - which brings me to my question
What is the best approach to handle my situation?
One idea i thought was to come up with various structures that reflect the optional fields, except I'm not sure in swift how to create bit-aligned packed structures.
What is my best approach here? For clarification - the initial 1-bit fields determine which of the optional fields are set.
If the fields do not lie on byte boundaries then you'll have to keep
track of both the current byte and the current bit position within a byte.
Here is a possible solution which allows to read an arbitrary number
of bits from a data array and does all the bookkeeping. The only
restriction is that the result of nextBits() must fit into an UInt
(32 or 64 bits, depending on the platform).
struct BitReader {
private let data : [UInt8]
private var byteOffset : Int
private var bitOffset : Int
init(data : [UInt8]) {
self.data = data
self.byteOffset = 0
self.bitOffset = 0
}
func remainingBits() -> Int {
return 8 * (data.count - byteOffset) - bitOffset
}
mutating func nextBits(numBits : Int) -> UInt {
precondition(numBits <= remainingBits(), "attempt to read more bits than available")
var bits = numBits // remaining bits to read
var result : UInt = 0 // result accumulator
// Read remaining bits from current byte:
if bitOffset > 0 {
if bitOffset + bits < 8 {
result = (UInt(data[byteOffset]) & UInt(0xFF >> bitOffset)) >> UInt(8 - bitOffset - bits)
bitOffset += bits
return result
} else {
result = UInt(data[byteOffset]) & UInt(0xFF >> bitOffset)
bits = bits - (8 - bitOffset)
bitOffset = 0
byteOffset = byteOffset + 1
}
}
// Read entire bytes:
while bits >= 8 {
result = (result << UInt(8)) + UInt(data[byteOffset])
byteOffset = byteOffset + 1
bits = bits - 8
}
// Read remaining bits:
if bits > 0 {
result = (result << UInt(bits)) + (UInt(data[byteOffset]) >> UInt(8 - bits))
bitOffset = bits
}
return result
}
}
Example usage:
let data : [UInt8] = ... your data ...
var bitReader = BitReader(data: data)
let b1 = bitReader.nextBits(1)
let b2 = bitReader.nextBits(1)
let b3 = bitReader.nextBits(1)
let b4 = bitReader.nextBits(11)
let b5 = bitReader.nextBits(1)
if b1 > 0 {
let b6 = bitReader.nextBits(4)
let b7 = bitReader.nextBits(4)
}
// ... and so on ...
And here is another possible implemention, which is a bit simpler
and perhaps more effective. It collects bytes into an UInt, and
then extracts the result in a single step.
Here the restriction is that numBits + 7 must be less or equal
to the number of bits in an UInt (32 or 64). (Of course UInt
can be replace by UInt64 to make it platform independent.)
struct BitReader {
private let data : [UInt8]
private var byteOffset = 0
private var currentValue : UInt = 0 // Bits which still have to be consumed
private var currentBits = 0 // Number of valid bits in `currentValue`
init(data : [UInt8]) {
self.data = data
}
func remainingBits() -> Int {
return 8 * (data.count - byteOffset) + currentBits
}
mutating func nextBits(numBits : Int) -> UInt {
precondition(numBits <= remainingBits(), "attempt to read more bits than available")
// Collect bytes until we have enough bits:
while currentBits < numBits {
currentValue = (currentValue << 8) + UInt(data[byteOffset])
currentBits = currentBits + 8
byteOffset = byteOffset + 1
}
// Extract result:
let remaining = currentBits - numBits
let result = currentValue >> UInt(remaining)
// Update remaining bits:
currentValue = currentValue & UInt(1 << remaining - 1)
currentBits = remaining
return result
}
}

UInt8 is not convertible to CGFloat error in iOS Swift

I am a beginner level programmer in iOS app development using Swift. Now I am facing the compile time issue "UInt8 is not convertible to CGFloat"
var numberOfAvatars:Int = 8
let count:Int = 1
let columns:Int = 3
let dimension:CGFloat = 84.0
var spacing:CGFloat = (avatarContentcroll.frame.size.width - columns * dimension)/(columns+1)
var scHeight:CGFloat = spacing + (numberOfAvatars/columns) * (dimension + spacing)
I've tried all the solutions out there and did many experiments. And I am not sure why still I am getting this error.
You have to do it explicitly as
var spacing:CGFloat = CGFloat((avatarContentcroll.frame.size.width) - CGFloat(columns) * (dimension))/(columns+1)
var scHeight:CGFloat = CGFloat(spacing + (CGFloat(numberOfAvatars)/CGFloat(columns)) * (dimension + spacing))
or you can try converting every expression in CGFloat
var spacing:CGFloat = ((avatarContentcroll.frame.size.width) - CGFloat(columns) * (dimension))/(columns+1)
var scHeight:CGFloat = spacing + (CGFloat(numberOfAvatars)/CGFloat(columns)) * (dimension + spacing)
You must explicitly cast your Ints as CGFloats (via as), or construct them -- like so:
var spacing:CGFloat = ((avatarContentcroll.frame.size.width) - CGFloat(columns) * (dimension))/(columns+1)
var scHeight:CGFloat = spacing + (CGFloat(numberOfAvatars)/CGFloat(columns)) * (dimension + spacing)

AVAudioRecorder through accelerate FFT into frequency - EXECUTION

My main goal: find the frequency of the noises being pulled in through AVAudioRecorder. I have followed this:
http://www.ehow.com/how_12224909_detect-blow-mic-xcode.html
I have read up on many questions on SO asking how to detect frequency. The majority of those answers say, "Use FFT!" and then the question ask-ers say, "Oh, great!".
My question is, how do you get from here:
- (void)levelTimerCallback {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
if (lowPassResults > sensitivitySlider.value) {
NSLog(#"Sound detected");
//What goes here so I can spit out a frequency?
}
}
Somehow magically use FFT... (I will use accelerate.h),
And wind up with "The frequency = 450.3"?
If somebody could show me the actual code that I would use to
Plug the sound from the AVAudioRecorder into Accelerate
and
How to turn the result into a frequency...
That would be greatly appreciated.
Thanks in advance.
Nothing "goes there", as the AVRecorder API does not plug into the Accelerate framework. Instead, you have to use a completely different API, the Audio Queue or RemoteIO Audio Unit API, to capture audio input, a completely different code arrangement, such as waiting for callbacks to get your data, buffer size management to get data arrays of the appropriate size to feed an FFT, then know enough DSP to post-process the FFT results for the particular kind of frequency measure for which you are looking.
Well, it turns out that something CAN "go there". Instead of using Accelerate, I bought a book on Fourier Analysis on Amazon and used it to build my own FFT. Which spits out not a single frequency but the levels of each of many frequencies, which is basically what I wanted.
Here's my FFT-computing class:
class FFTComputer: NSObject {
class func integerBitReverse(_ input:Int,binaryDigits:Int) -> Int {
return integerForReversedBooleans(booleansForInt(input, binaryDigits: binaryDigits))
}
class func integerForReversedBooleans(_ booleans:[Bool]) -> Int {
var integer = 0
var digit = booleans.count - 1
while digit >= 0 {
if booleans[digit] == true {
integer += Int(pow(Double(2), Double(digit)))
}
digit -= 1
}
return integer
}
class func Pnumber(_ k:Int,placesToMove:Int, gamma:Int) -> Int {
var booleans = booleansForInt(k, binaryDigits: gamma)
for _ in 0 ..< placesToMove {
booleans.removeLast()
booleans.insert(false, at: 0)
}
return integerForReversedBooleans(booleans)
}
class func booleansForInt(_ input:Int,binaryDigits:Int) -> [Bool] {
var booleans = [Bool]()
var remainingInput = input
var digit = binaryDigits - 1
while digit >= 0 {
let potential = Int(pow(Double(2), Double(digit)))
if potential > remainingInput {
booleans.append(false)
} else {
booleans.append(true)
remainingInput -= potential
}
digit += -1
}
return booleans
}
class func fftOfTwoRealFunctions(_ realX1:[CGFloat], realX2:[CGFloat], gamma:Int) -> (([CGFloat],[CGFloat]),([CGFloat],[CGFloat])) {
let theFFT = fft(realX1, imaginaryXin: realX2, gamma: gamma)
var R = theFFT.0
var I = theFFT.1
let N = Int(pow(2.0, Double(gamma)))
var realOut1 = [CGFloat]()
var imagOut1 = [CGFloat]()
var realOut2 = [CGFloat]()
var imagOut2 = [CGFloat]()
for n in 0..<N {
var Rback:CGFloat
var Iback:CGFloat
if n == 0 {
Rback = R[0]
Iback = I[0]
} else {
Rback = R[N-n]
Iback = I[N-n]
}
realOut1.append(CGFloat(R[n]/2 + Rback/2))
realOut2.append(CGFloat(I[n]/2 + Iback/2))
imagOut1.append(CGFloat(I[n]/2 - Iback/2))
imagOut2.append(-CGFloat(R[n]/2 - Rback/2))
}
return ((realOut1,imagOut1),(realOut2,imagOut2))
}
class func fft(_ realXin:[CGFloat], imaginaryXin:[CGFloat], gamma:Int) -> ([CGFloat],[CGFloat]) {
var realX = realXin
var imaginaryX = imaginaryXin
let N = Int(pow(2.0, Double(gamma)))
var N2 = N/2
var NU1 = gamma - 1 // Always equals (gamma - l)
var realWP:Double = 1
var imaginaryWP:Double = 0
var redoPCounter = 0
func redoP(_ k:Int, places:Int) {
let P = Pnumber(k, placesToMove:places, gamma: gamma)
let inside = (-2*Double.pi*Double(P))/Double(N)
realWP = cos(inside)
imaginaryWP = sin(inside)
}
var l = 1
while l <= gamma {
var k = 0
var I = 1
while k < N - 1 {
if redoPCounter == N2 {
redoP(k,places: NU1)
redoPCounter = 0
}
redoPCounter += 1
// Swift.print(realX.count,imaginaryX.count,k+N2)
let realT1 = (realWP*Double(realX[k + N2]))-(imaginaryWP*Double(imaginaryX[k + N2]))
let imaginaryT1 = (realWP*Double(imaginaryX[k + N2]))+(imaginaryWP*Double(realX[k + N2]))
realX[k+N2] = realX[k] - CGFloat(realT1)
imaginaryX[k+N2] = imaginaryX[k] - CGFloat(imaginaryT1)
realX[k] = realX[k] + CGFloat(realT1)
imaginaryX[k] = imaginaryX[k] + CGFloat(imaginaryT1)
k += 1
if I == N2 {
k += N2
I = 1
} else {
I += 1
}
}
N2 = N2/2
NU1 = NU1 - 1
redoPCounter = 0
realWP = 1
imaginaryWP = 0
l += 1
}
for k in 0 ..< N - 1 {
let i = integerBitReverse(k, binaryDigits:gamma)
if i > k {
let placeholderReal = realX[k]
let placeholderImaginary = imaginaryX[k]
realX[k] = realX[i]
imaginaryX[k] = imaginaryX[i]
realX[i] = placeholderReal
imaginaryX[i] = placeholderImaginary
}
}
return (realX,imaginaryX)
}
class func magnitudeAndPhasePresentations(_ realX:[CGFloat], imaginaryX:[CGFloat]) -> ([CGFloat],[CGFloat]) {
var magnitudes = [CGFloat]()
var phases = [CGFloat]()
var lastMagnitude:CGFloat = 0
var lastPhase:CGFloat = 0
for n in 0 ..< realX.count {
let real = realX[n]
let imaginary = imaginaryX[n]
if real != 0 {
lastMagnitude = sqrt(pow(real, 2)+pow(imaginary, 2))
lastPhase = atan(imaginary/real)
}
magnitudes.append(lastMagnitude)
phases.append(lastPhase)
}
return (magnitudes,phases)
}
class func magnitudePresentation(_ realX:[CGFloat], imaginaryX:[CGFloat]) -> [CGFloat] {
var magnitudes = [CGFloat]()
var lastMagnitude:CGFloat = 0
for n in 0 ..< realX.count {
let real = realX[n]
let imaginary = imaginaryX[n]
if real != 0 {
lastMagnitude = sqrt(pow(real, 2)+pow(imaginary, 2))
}
magnitudes.append(lastMagnitude)
}
return magnitudes
}
}
And to get the audio, I used Novocaine: https://github.com/alexbw/novocaine
I would recommend reading a bit about the Fourier Transform, but it really doesn't have to be that difficult to plug data from Novocaine (the mic) into an FFTComputer and get back some frequencies.
(2 to the gamma is the count of realXin. I could have just computed gamma, so if you want to change that, go ahead. Just turn the Novocaine data into an array of CGFloats, put that in realXin, put an empty array of the same size in imagXin, and enter the right gamma. Then, maybe graph the output to see the frequencies.)

Resources