Skip to content

Bring development inline with main #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@

## Install via Homebrew

Help get us on the official Homebrew formulas by giving us a star and watching this repo! [mactop](https://github.com/context-labs/mactop)

```bash
brew tap context-labs/mactop https://github.com/context-labs/mactop
```
You can install [mactop](https://github.com/context-labs/mactop) via Homebrew! https://brew.sh

```bash
brew install mactop
Expand Down Expand Up @@ -108,10 +104,18 @@ Use the following keys to interact with the application while its running:
## Confirmed tested working M series chips

- M1
- M1 Pro
- M1 Max
- M1 Ultra

(If you have a confirmed working M series chip that is not listed, please open an issue!)
- M2
- M2 Pro
- M2 Max
- M2 Ultra
- M3
- M3 Pro
- M3 Max

(If you have a confirmed working M series chip that is not listed, please open an issue, so we may add it here!)

## Contributing

Expand Down
8 changes: 4 additions & 4 deletions mactop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
class Mactop < Formula
desc "Apple Silicon Monitor Top written in Go Lang"
homepage "https://github.com/context-labs/mactop"
version "0.1.3"
version "0.1.7"
depends_on :macos

if Hardware::CPU.arm?
url "https://github.com/context-labs/mactop/releases/download/v0.1.3/mactop_0.1.3_darwin_arm64.tar.gz"
sha256 "179d6fd03e41930164ca6f8843af635ccaffc3cfd1e1a2a089b5bfda68fc95e8"
on_arm do
url "https://github.com/context-labs/mactop/releases/download/v0.1.7/mactop_0.1.7_darwin_arm64.tar.gz"
sha256 "40857c92beb8e13fb6a50b1563adb7c7ced5c6dbdc56d35d3546e4a6c4ffc52a"

def install
bin.install "mactop"
Expand Down
29 changes: 18 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ var (
updateInterval = 1000
)

var (
dataRegex = regexp.MustCompile(`(?m)^\s*(\S.*?)\s+(\d+)\s+(\d+\.\d+)\s+\d+\.\d+\s+`)
outRegex = regexp.MustCompile(`out:\s*([\d.]+)\s*packets/s,\s*([\d.]+)\s*bytes/s`)
inRegex = regexp.MustCompile(`in:\s*([\d.]+)\s*packets/s,\s*([\d.]+)\s*bytes/s`)
readRegex = regexp.MustCompile(`read:\s*([\d.]+)\s*ops/s\s*([\d.]+)\s*KBytes/s`)
writeRegex = regexp.MustCompile(`write:\s*([\d.]+)\s*ops/s\s*([\d.]+)\s*KBytes/s`)
residencyRe = regexp.MustCompile(`(\w+-Cluster)\s+HW active residency:\s+(\d+\.\d+)%`)
frequencyRe = regexp.MustCompile(`(\w+-Cluster)\s+HW active frequency:\s+(\d+)\s+MHz`)
re = regexp.MustCompile(`GPU\s*(HW)?\s*active\s*(residency|frequency):\s+(\d+\.\d+)%?`)
freqRe = regexp.MustCompile(`(\d+)\s*MHz:\s*(\d+)%`)
)

func setupUI() {
appleSiliconModel := getSOCInfo()
modelText = w.NewParagraph()
Expand Down Expand Up @@ -401,10 +413,10 @@ func main() {
}

func setupLogfile() (*os.File, error) {
if err := os.MkdirAll("logs", 0755); err != nil {
if err := os.MkdirAll("/var/log", 0755); err != nil {
return nil, fmt.Errorf("failed to make the log directory: %v", err)
}
logfile, err := os.OpenFile("logs/mactop.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0660)
logfile, err := os.OpenFile("/var/log/mactop.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0660)
if err != nil {
return nil, fmt.Errorf("failed to open log file: %v", err)
}
Expand Down Expand Up @@ -525,7 +537,6 @@ func updateProcessUI(processMetrics []ProcessMetrics) {

func parseProcessMetrics(powermetricsOutput string, processMetrics []ProcessMetrics) []ProcessMetrics {
lines := strings.Split(powermetricsOutput, "\n")
dataRegex := regexp.MustCompile(`(?m)^\s*(\S.*?)\s+(\d+)\s+(\d+\.\d+)\s+\d+\.\d+\s+`)
seen := make(map[int]bool) // Map to track seen process IDs
for _, line := range lines {
matches := dataRegex.FindStringSubmatch(line)
Expand Down Expand Up @@ -554,8 +565,7 @@ func parseProcessMetrics(powermetricsOutput string, processMetrics []ProcessMetr
}

func parseActivityMetrics(powermetricsOutput string, netdiskMetrics NetDiskMetrics) NetDiskMetrics {
outRegex := regexp.MustCompile(`out:\s*([\d.]+)\s*packets/s,\s*([\d.]+)\s*bytes/s`)
inRegex := regexp.MustCompile(`in:\s*([\d.]+)\s*packets/s,\s*([\d.]+)\s*bytes/s`)

outMatches := outRegex.FindStringSubmatch(powermetricsOutput)
inMatches := inRegex.FindStringSubmatch(powermetricsOutput)
if len(outMatches) == 3 {
Expand All @@ -566,8 +576,7 @@ func parseActivityMetrics(powermetricsOutput string, netdiskMetrics NetDiskMetri
netdiskMetrics.InPacketsPerSec, _ = strconv.ParseFloat(inMatches[1], 64)
netdiskMetrics.InBytesPerSec, _ = strconv.ParseFloat(inMatches[2], 64)
}
readRegex := regexp.MustCompile(`read:\s*([\d.]+)\s*ops/s\s*([\d.]+)\s*KBytes/s`)
writeRegex := regexp.MustCompile(`write:\s*([\d.]+)\s*ops/s\s*([\d.]+)\s*KBytes/s`)

readMatches := readRegex.FindStringSubmatch(powermetricsOutput)
writeMatches := writeRegex.FindStringSubmatch(powermetricsOutput)
if len(readMatches) == 3 {
Expand All @@ -587,8 +596,7 @@ func parseCPUMetrics(powermetricsOutput string, cpuMetrics CPUMetrics, modelName
pCores := []int{}
var eClusterActiveSum, pClusterActiveSum, eClusterFreqSum, pClusterFreqSum float64
var eClusterCount, pClusterCount, eClusterActiveTotal, pClusterActiveTotal, eClusterFreqTotal, pClusterFreqTotal int
residencyRe := regexp.MustCompile(`(\w+-Cluster)\s+HW active residency:\s+(\d+\.\d+)%`)
frequencyRe := regexp.MustCompile(`(\w+-Cluster)\s+HW active frequency:\s+(\d+)\s+MHz`)

if modelName == "Apple M3 Max" || modelName == "Apple M2 Max" { // For the M3/M2 Max, we need to manually parse the CPU Usage from the powermetrics output (as current bug in Apple's powermetrics)
for _, line := range lines {

Expand Down Expand Up @@ -808,8 +816,7 @@ func max(nums ...int) int {
}

func parseGPUMetrics(powermetricsOutput string, gpuMetrics GPUMetrics) GPUMetrics {
re := regexp.MustCompile(`GPU\s*(HW)?\s*active\s*(residency|frequency):\s+(\d+\.\d+)%?`)
freqRe := regexp.MustCompile(`(\d+)\s*MHz:\s*(\d+)%`)

lines := strings.Split(powermetricsOutput, "\n")

for _, line := range lines {
Expand Down