Skip to content

Commit

Permalink
Show both size and actual size of files (#742)
Browse files Browse the repository at this point in the history
Right now we show only actual size of files on disk which excludes empty blocks of the recently introduced sparced format in #671. This makes impossible to get info about disk size that we just set via `tart set`.

Here is an example of `tart list` output before the change:

```
Source Name                                                                                                            Size State
local  sonoma-base                                                                                                     22   stopped
local  sonoma-vanilla                                                                                                  18   stopped
local  sonoma-xcode                                                                                                    67   stopped
local  ubuntu                                                                                                          1    stopped
oci    ghcr.io/cirruslabs/macos-sonoma-base:latest                                                                     22   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-base@sha256:16c1593bbaf787b20b3c0bc094c5b6baf71c937d22c2e4596da85ac55c92e6cc    22   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-vanilla:14.3                                                                    17   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-vanilla@sha256:23c4e853d48d00a4333346d66a32b2b5aad900cc0dc10e7ecb9dbe67b6f587f4 17   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-xcode:latest                                                                    67   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-xcode@sha256:d0cb8d01424a68b89e0f16f5371bf2152b2c115bd886341a6ba8da42121d1f41   67   stopped
oci    ghcr.io/cirruslabs/ubuntu:22.04                                                                                 1    stopped
oci    ghcr.io/cirruslabs/ubuntu@sha256:037763feb7a15d6077edeb7a097738c34313637d16036764b4c196d28d8b429c               1    stopped
```

And here is the output after the change:

```
Source Name                                                                                                            Disk Size State
local  sonoma-base                                                                                                     50   22   stopped
local  sonoma-vanilla                                                                                                  50   18   stopped
local  sonoma-xcode                                                                                                    90   67   stopped
local  ubuntu                                                                                                          20   1    stopped
oci    ghcr.io/cirruslabs/macos-sonoma-base:latest                                                                     50   22   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-base@sha256:16c1593bbaf787b20b3c0bc094c5b6baf71c937d22c2e4596da85ac55c92e6cc    50   22   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-vanilla:14.3                                                                    50   17   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-vanilla@sha256:23c4e853d48d00a4333346d66a32b2b5aad900cc0dc10e7ecb9dbe67b6f587f4 50   17   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-xcode:latest                                                                    90   67   stopped
oci    ghcr.io/cirruslabs/macos-sonoma-xcode@sha256:d0cb8d01424a68b89e0f16f5371bf2152b2c115bd886341a6ba8da42121d1f41   90   67   stopped
oci    ghcr.io/cirruslabs/ubuntu:22.04                                                                                 20   1    stopped
oci    ghcr.io/cirruslabs/ubuntu@sha256:037763feb7a15d6077edeb7a097738c34313637d16036764b4c196d28d8b429c               20   1    stopped
```

Additionally, `tart get` will print actual size with a 3 decimal point precision which will help to track growth in disk images for our templates.

`tart get` before:

```
CPU Memory Disk Display  State
4   8192   67   1024x768 stopped
```

`tart get` after:

```
CPU Memory Disk Size   Display  State
4   8192   90   67.333 1024x768 stopped
```
  • Loading branch information
fkorotkov authored Feb 27, 2024
1 parent a40e104 commit 5c7743b
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Sources/tart/Commands/Clone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ struct Clone: AsyncParsableCommand {
// APFS is doing copy-on-write so the above cloning operation (just copying files on disk)
// is not actually claiming new space until the VM is started and it writes something to disk.
// So once we clone the VM let's try to claim a little bit of space for the VM to run.
try Prune.reclaimIfNeeded(UInt64(sourceVM.sizeBytes()), sourceVM)
try Prune.reclaimIfNeeded(UInt64(sourceVM.allocatedSizeBytes()), sourceVM)
}, onCancel: {
try? FileManager.default.removeItem(at: tmpVMDir.baseURL)
})
Expand Down
4 changes: 2 additions & 2 deletions Sources/tart/Commands/Get.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fileprivate struct VMInfo: Encodable {
let CPU: Int
let Memory: UInt64
let Disk: Int
let Size: String
let Display: String
let Running: Bool
let State: String
Expand All @@ -22,10 +23,9 @@ struct Get: AsyncParsableCommand {
func run() async throws {
let vmDir = try VMStorageLocal().open(name)
let vmConfig = try VMConfig(fromURL: vmDir.configURL)
let diskSizeInGb = try vmDir.sizeGB()
let memorySizeInMb = vmConfig.memorySize / 1024 / 1024

let info = VMInfo(CPU: vmConfig.cpuCount, Memory: memorySizeInMb, Disk: diskSizeInGb,
let info = VMInfo(CPU: vmConfig.cpuCount, Memory: memorySizeInMb, Disk: try vmDir.sizeGB(), Size: String(format: "%.3f", Float(try vmDir.allocatedSizeBytes()) / 1000 / 1000 / 1000),
Display: vmConfig.display.description, Running: try vmDir.running(), State: try vmDir.state())
print(format.renderSingle(info))
}
Expand Down
5 changes: 3 additions & 2 deletions Sources/tart/Commands/List.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SwiftUI
fileprivate struct VMInfo: Encodable {
let Source: String
let Name: String
let Disk: Int
let Size: Int
let Running: Bool
let State: String
Expand Down Expand Up @@ -37,13 +38,13 @@ struct List: AsyncParsableCommand {

if source == nil || source == "local" {
infos += sortedInfos(try VMStorageLocal().list().map { (name, vmDir) in
try VMInfo(Source: "local", Name: name, Size: vmDir.sizeGB(), Running: vmDir.running(), State: vmDir.state())
try VMInfo(Source: "local", Name: name, Disk: vmDir.sizeGB(), Size: vmDir.allocatedSizeGB(), Running: vmDir.running(), State: vmDir.state())
})
}

if source == nil || source == "oci" {
infos += sortedInfos(try VMStorageOCI().list().map { (name, vmDir, _) in
try VMInfo(Source: "oci", Name: name, Size: vmDir.sizeGB(), Running: vmDir.running(), State: vmDir.state())
try VMInfo(Source: "oci", Name: name, Disk: vmDir.sizeGB(), Size: vmDir.allocatedSizeGB(), Running: vmDir.running(), State: vmDir.state())
})
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/tart/Commands/Prune.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ struct Prune: AsyncParsableCommand {
var prunablesToDelete: [Prunable] = []

for prunable in prunables {
let prunableSizeBytes = UInt64(try prunable.sizeBytes())
let prunableSizeBytes = UInt64(try prunable.allocatedSizeBytes())

if prunableSizeBytes <= spaceBudgetBytes {
// Don't mark for deletion as
Expand Down Expand Up @@ -158,7 +158,7 @@ struct Prune: AsyncParsableCommand {
.sorted { try $0.accessDate() < $1.accessDate() }

// Does it even make sense to start?
let cacheUsedBytes = try prunables.map { try $0.sizeBytes() }.reduce(0, +)
let cacheUsedBytes = try prunables.map { try $0.allocatedSizeBytes() }.reduce(0, +)
if cacheUsedBytes < reclaimBytes {
return
}
Expand All @@ -177,9 +177,9 @@ struct Prune: AsyncParsableCommand {
continue
}

try SentrySDK.span?.setData(value: prunable.sizeBytes(), key: prunable.url.path)
try SentrySDK.span?.setData(value: prunable.allocatedSizeBytes(), key: prunable.url.path)

cacheReclaimedBytes += try prunable.sizeBytes()
cacheReclaimedBytes += try prunable.allocatedSizeBytes()

try prunable.delete()
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/tart/Prunable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ protocol Prunable {
var url: URL { get }
func delete() throws
func accessDate() throws -> Date
// size on disk as seen in Finder including empty blocks
func sizeBytes() throws -> Int
// actual size on disk without empty blocks
func allocatedSizeBytes() throws -> Int
}
6 changes: 5 additions & 1 deletion Sources/tart/URL+Prunable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ extension URL: Prunable {
try FileManager.default.removeItem(at: self)
}

func sizeBytes() throws -> Int {
func allocatedSizeBytes() throws -> Int {
try resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize!
}

func sizeBytes() throws -> Int {
try resourceValues(forKeys: [.totalFileSizeKey]).totalFileSize!
}
}
8 changes: 8 additions & 0 deletions Sources/tart/VMDirectory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ struct VMDirectory: Prunable {
try baseURL.accessDate()
}

func allocatedSizeBytes() throws -> Int {
try configURL.allocatedSizeBytes() + diskURL.allocatedSizeBytes() + nvramURL.allocatedSizeBytes()
}

func allocatedSizeGB() throws -> Int {
try allocatedSizeBytes() / 1000 / 1000 / 1000
}

func sizeBytes() throws -> Int {
try configURL.sizeBytes() + diskURL.sizeBytes() + nvramURL.sizeBytes()
}
Expand Down

0 comments on commit 5c7743b

Please sign in to comment.