# Changelog Notable changes to Mac Performance Monitor. This project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/). ## [Unreleased] ## [2.4.0] - 2026-10-17 ### Changed - **The GPU tab is easier to scan.** The process list is now near the top, beside the category split and AI workloads. In the default window you can see it without scrolling. The six charts now share one panel with a picker (Utilization, Power, Bandwidth, Neural Engine, Temperature), and the headline cards fit on one row. Explanations moved behind info buttons. The page is about half as tall as before. - **Less RAM for the recorder and menu bar** ([#145](https://github.com/Zesty0wl/mac-performance-monitor/issues/145)). Small charts now draw into reusable images. Process rows use small cached icons. In menu-only tests, warm idle memory fell from 152-166 MiB to 68-76 MiB. The app still uses more RAM after you open the main window. See the [performance report](docs/performance-budget.md) for test conditions and limits. - The app frees unused lists, charts, icons and cached history when you close the last menu or window. It skips this cleanup if you reopen one. Recording, alerts and sample history stay intact. - Menu panels no longer rebuild the full process table. Leak scans read one process's history at a time and skip extra raw reads when minute history is enough. Slow scans no longer queue behind each other. - Caches for process paths and code-signing details now have fixed limits. They no longer keep growing as you start more processes. - The five process-detail charts now use the bitmap renderer too. Their isolated benchmark fell from 206 MiB to about 35 MiB while open. This trades some CPU time for lower RAM use. Whole-app memory still stays above its fresh-launch level after closing the window. - History reads now handle one row at a time, without keeping a second copy of the database rows. Explorer reuses each raw point's values for its low and high readings. Gaps, stored detail and read limits stay the same. - The menu bar reuses text layouts for cells that have not changed. It updates the alert badge only when the count changes. It keeps only the latest layout for each of the seven metrics. The look and click targets stay the same. ### Fixed - **The Processes panel no longer expands and shrinks when you select a different process.** It keeps a fixed width inside the window. The table and details no longer overlap. A new selection changes only the contents and scrolls back to the top. - Idle cleanup logs now report how many bytes the allocator released, including zero. ### Added - The chart benchmark has a `--teardown` option to measure memory after its window closes. It also checks how much more RAM the app can free. New tests cover cleanup, cache limits, charts and the details panel at different window sizes. ## [2.3.1] - 2026-10-11 ### Fixed - **Memory use climbed every time the menu bar dropdown opened** ([#145](https://github.com/Zesty0wl/mac-performance-monitor/issues/145)). Each closed dropdown stayed in memory, still updating in the background, at about 25 MB apiece, so after a few days of normal use the app could reach 600 MB or more and use more CPU than it should. Closed dropdowns are now released: 48 open and close cycles that would have added over 1 GB now leave the app at about 64 MB once idle. The leak dates from 1.7.0, when the language picker arrived. ## [2.3.0] - 2026-10-04 ### Added - **Temperatures follow your Mac's unit** ([#134](https://github.com/Zesty0wl/mac-performance-monitor/issues/134)). Every temperature in the app, from the menu bar and Dashboard to Hardware sensors, Explorer, Energy and Ask, now shows in the unit chosen in System Settings > General > Language & Region > Temperature, so Macs set to Fahrenheit see °F. Settings > General > Temperature can override it. History is still recorded in Celsius, so switching is instant, loses nothing, and leaves exports and the AI agents' data unchanged. - Insights can flag screen capture that is slowing the desktop: WindowServer busy with most of a core for 2 minutes while macOS's screen capture service (replayd) is busy too, even when total CPU and memory pressure look normal. It covers any capture source, such as screen sharing, screen recording or an AI agent watching the screen. The card names the app when it recognizes the capture helper (OpenAI's Computer Use service for now) and otherwise points to the purple screen recording icon in the menu bar. It uses existing readings and does not record the screen or stop processes. ### Changed - **Ask About This Mac is rebuilt for people new to Macs** (macOS 27). It opens with a one-line verdict and a tile for each part of the Mac (Processor, Memory, Graphics, Neural Engine, Network, Storage, Battery, Heat), each with a plain status such as Calm, Busy or Worth a look. Tap a tile or a starter question, or type your own. The app reads its own history, compares it with what is normal for your Mac, and works out which apps are responsible; Apple's on-device model then explains it in everyday words and suggests one safe next step. Each answer links to the matching charts, opened in Explorer at the right time with the right apps selected, and shows the facts behind it. Nothing leaves your Mac, and the conversation is cleared when Ask closes. - **Hand off to an AI agent.** For deeper digging, Ask can copy a ready-made prompt (with your current question and its facts) for Claude Code, Codex or another AI agent, or the one-line command that connects one. The app now ships `mpm`, a read-only command-line tool and MCP server inside the app (`Contents/MacOS/mpm`), with documented `agent_*` SQL views of the history, the same judged summaries Ask uses, and `macperfmonitor://` links that open the matching charts in Explorer. The agent sends what it reads to its own provider, so Ask explains that before the first copy. The new [AI agents guide](docs/ai-agents.md) covers setup for Claude Code, Codex, Claude Desktop, Cursor and VS Code, the tools and data agents get, and what leaves your Mac. - **A program busy for hours is now flagged.** A part of macOS stuck in a loop (such as contactsd syncing Contacts all night) used to go unnoticed: the Mac looked only a little busier than usual. Alerts now watch each program across its restarts and warn when one keeps about a core busy for an hour, and Ask's Processor tile names it and says what to do. Apps you are using, and jobs that finish on their own such as Spotlight indexing, stay observations first. It has its own switch in Settings > Alerts. - Ask names the app behind its busiest processes: a build's compiler runs count as Xcode, and Chrome's helpers as Chrome. System processes that keep growing get advice that fits them instead of "quit and reopen". - The Ask preview's optional Qwen and DeepAnalyze downloads, its local AI worker and its report Shortcuts are gone. Models downloaded by earlier versions are deleted to free the space. Siri and Shortcuts can still open Ask. - The Dashboard's right-hand rail shows a CPU usage history chart directly under the live CPU cores grid, with its average, peak and minimum band. It replaces the rail's Swap chart, which repeated the Swap card already in the row of memory cards. - With one or two charts showing, the Explorer stacks them full width and shares the window height between them instead of leaving most of the workspace empty. - An Explorer chart no longer lets a single spike set its whole axis. When a few isolated samples tower over the rest, the axis fits the rest and the chart header shows the spike's value; click it to see the full scale. - Tabs you have left stop working in the background. On macOS 26 and later every tab visited since the window opened kept updating while hidden, so a long session grew slower and used more memory with each tab opened. The app also launches about a second faster, and the Processes, Hardware and Explorer tabs open more quickly. - The app does less work in the background. The history database is flushed once a minute instead of every 15 seconds, which cuts what it writes to disk by about a tenth. The leak scan runs in under half the time with about half the memory, alert checks no longer re-sort a week of past alerts each time, and chart history the app no longer needs is released sooner. ### Fixed - The main window can enter full screen even when it opens while the app is running in the background without a Dock icon. - The menu bar item keeps its place after an update ([#120](https://github.com/Zesty0wl/mac-performance-monitor/issues/120)). macOS forgot the position of the unnamed item whenever the app was replaced, so each update put it back beside the notch, where a crowded menu bar hides it. The item now has a stable name, so a spot you Command-drag it to survives updates. The first launch of this version still uses the default spot. - The app no longer crashes when a process inspector's Disk I/O charts show a process that has just restarted. The restart gap marker reached the rate label as NaN, which crashed the app when converted to a whole number. Rate labels now treat missing values as zero, and chart summaries skip gap markers. - **The menu bar item appears again when a specific language is chosen** ([#124](https://github.com/Zesty0wl/mac-performance-monitor/issues/124)). With the language set to anything but Follow System, the app restarted itself in place at launch to apply it. On macOS 27 the menu bar could not recognise the restarted process, so the item never showed. The language is now applied without a restart. - Turning Hide Notch off outside the menu now brings the notch back. The display switch is permanent, and only the menu's Show Notch used to undo it, so writing `hideNotch` false while the menu bar item was invisible left the Mac on the notch-free resolution. At launch the app now restores the notched resolution when it made the switch itself. A resolution picked in System Settings is left alone. - Leak and memory budget alerts no longer flicker in the menu bar. Every process scan briefly marked them unknown because its samples were stamped a few milliseconds after the moment they were checked against, so an alert appeared and vanished before it could be read. - The main window can be dragged again on macOS 26 and 27. It opened too narrow to leave any empty toolbar beside the tab strip, which is the only place to grab it. The minimum and default widths now fit the tab titles of the chosen language with room to spare. ## [2.2.1] - 2026-09-23 ### Fixed - **Liquid Glass is back on macOS 26 and 27** ([#117](https://github.com/Zesty0wl/mac-performance-monitor/issues/117)). Version 2.2.0 was the first release built with Xcode 27. Its default Swift build engine recorded the macOS 15 deployment target as the app's SDK version, so macOS showed the older, pre-Liquid Glass appearance. The build script now passes the real SDK version to the linker. Bundling fails if the app binary records an SDK older than 26. The minimum macOS stays 15. - The main window no longer restores itself at startup. The saved startup setting controls whether it opens. The app no longer relies on macOS launch data. A pinned Dock icon no longer takes focus when no window is open. ### Added - **Start minimised** in Settings > General > Startup, on by default. With the menu bar on, the app starts without opening its main window, including at login. Turn it off to show the window at startup. The window always opens at startup if the menu bar is off. First-run setup still appears. - A one-time request to star the app on GitHub. It waits at least seven days from the first launch this version records. You must also have used a menu bar panel and the main window. The request waits until the main window is in front with no other prompt. Either response stops future requests. These usage flags stay on your Mac. ## [2.2.0] - 2026-09-20 ### Added - **Ask About This Mac (Preview)** provides current reports and opt-in local AI checks. Open Ask from the toolbar, app menu, or menu bar. Turn on explanations separately to share readings with the model. It can request up to four read-only data checks over the past seven days, then cite the readings behind its answer. It cannot run commands, delete files, or change settings. - **Local model choices:** Apple on-device is the default on supported Macs with macOS 26.4 or later and Apple Intelligence enabled. Optional Qwen3 4B, Qwen3.5 4B, and DeepAnalyze 8B downloads are about 2.3 GB, 3.1 GB, and 5.0 GB. These downloaded models need Apple silicon, at least 16 GiB RAM, and normal memory pressure. Each has its own download and removal controls. Qwen3.5 and DeepAnalyze are experimental and need an explicit download. Existing preview selections remain unchanged; Ask never silently switches models. - Ask shows model readiness, progress through data checks, cited facts, uncertainty, and a follow-up question. A pause notice explains resource limits. Rejected answers give a specific reason while measured reports remain usable. Closing Ask clears the conversation; no cloud inference or saved chat is used. - Six preview App Shortcuts open Ask or return current reports. Siri and Shortcuts sharing needs its own consent and follows Apple's processing rules. See the [Ask preview scope](docs/ai-integration-prd.md#generative-preview). - **GPU bandwidth history (Preview)** charts Total, Reads, and Writes together in GB/s, with the same time range as utilization and hover details. Rates are approximations from macOS bandwidth buckets, not exact byte counters. One quiet caption explains the limits. New samples persist across restarts; missing readings and older logs remain gaps. - **ANE Time** on macOS 27 uses kernel-accounted Neural Engine time, in ms/s. It is not a percent of compute capacity or per-app attribution. GPU, Explorer, and Ask distinguish partial coverage from missing readings. - **ANE Power** uses Apple's powermetrics through the approved Full Coverage helper. It has a separate watts card, chart, and Explorer/Ask readings. The GPU menu shows separate ANE time and power charts for the last 60 seconds. Power is an estimate, not utilization; ANE Time does not need the helper. - **Usage Timeline** shows when the recorder observed a process running. Right-click a process to open it. Optional Apple app and media activity is separate and needs Full Disk Access plus a per-window opt-in. Its device and foreground status are unverified; those optional records stay in memory only. ### Changed - History views start at 30 minutes when no choice is saved. Each view keeps its own range across tab changes, window closure, and app restarts. Explorer keeps your chosen zoom span; opening alert evidence does not overwrite it. - The GPU tab's **Active** card is now **GPU awake**. It measures powered and clocked time, including waits, not GPU workload. Clock-state help explains that distinction. ANE Time and ANE Power cards sit next to each other. ### Fixed - GPU Memory and GPU awake now have recorded card and detail charts. New recordings retain averages, bounds, and valid-reading counts. Old records remain unknown instead of showing invented values. - Missing or invalid GPU OFF-state readings no longer appear as 100% awake. - Main-window toolbar controls stay mounted while tab content loads or a window reopens, avoiding the earlier first-open layout problem. ### Build And Preview Limits - Source app bundles now need Xcode 27 for App Intents metadata and the Metal Toolchain for local inference. Build scripts detect changed Metal toolchain paths. Bundling includes inference resources and licences, preserves Sparkle, and keeps model weights out of the app. The app's macOS 15 baseline is unchanged. - Generated answers can be wrong even when citations pass checks. Qwen3.5 and DeepAnalyze still need real-model tests. Memory pressure can stop inference on an otherwise eligible Mac. Current measured reports remain available. - New GPU history starts with new recordings. ANE counters depend on hardware and macOS support. Native translation review, signed Siri/Shortcuts checks, and wider workload testing remain release checks, not claims from unit tests. ## [2.1.0] - 2026-09-11 ### Added - The Dashboard now shows uptime beneath the machine details, with the boot date on hover. It measures time since the Mac restarted, including sleep, and refreshes once a minute. - Energy now has an Accessories panel for battery levels from mice, keyboards, AirPods, and other devices. It shows the left earbud, right earbud, and case when macOS reports them. A charging icon appears only when that state is known. The app checks at most once a minute. With battery alerts off, checks stop when Energy is hidden. Missing values stay unknown. If a read fails, the card marks older values as last reported. The command has time and size limits. An unreadable report shows as unavailable. - Low accessory battery alerts are now an opt-in under Settings > Alerts. Choose a level from 5% to 50%; the default is 20%. Two low reports confirm the warning. AirPods parts share one quiet notice, which opens Energy. The app remembers notices across restarts and waits for charge to recover before sending another. Enabled alerts keep the same minute-limited reader active while the app is running, even with Energy hidden. ### Changed - All six Energy cards now open a snapshot with a larger chart and an explanation. Charge, runtime, Mac power draw, and battery temperature use the page's time range. Choose a different range in a pop-out without changing the page. Charge and runtime also offer "Since unplugging" when the app saw the switch to battery power. - Health and Cycles now have their own month and year ranges, with daily records for each battery pack. These records survive the usual 90-day limit, but still count toward the database size cap. Trends grow from real readings with history logging enabled; missing older data stays missing. - Runtime uses the macOS estimate first, or recent use after at least three minutes of steady discharge. Past estimates stay as recorded. A separate dashed line forecasts charge at the same rate of use; it is not saved as a real reading. - Mac power draw and signed battery flow are distinct. Card headings wrap and secondary values sit below the main figure so they fit narrow windows. See the [Energy guide](docs/energy-design.md) for ranges and storage limits. - Process detail and Explorer charts can include earlier, non-overlapping instances of the same program. Restart boundaries break the chart lines and disk-rate calculations; concurrent instances are not added together. - Accessory percentages match the Dashboard card fonts. Long battery manufacturer names truncate at the end instead of in the middle. ## [2.0.0] - 2026-09-10 See the [2.0.0 release notes](https://github.com/Zesty0wl/mac-performance-monitor/releases/tag/v2.0.0.231) for the short overview. ### Changed - **Alerts now track growth and worsening conditions.** Stable swap usage no longer triggers a warning just for crossing a fixed number. Growth and paging rules use fresh evidence, confirmation, and recovery windows. Further growth can trigger an escalation without first dropping below the old threshold. Modest process growth stays quiet; plateaus and stale samples no longer count as ongoing growth. Related memory alerts share a notice, and only critical notices request sound. The menu separates observations from active alerts, offers a one-hour snooze, and opens alert evidence in Explorer. Local incident state survives restarts. See [Adaptive alerts](docs/adaptive-alerts.md) for the rules, settings changes, and verification limits. - **Analytics becomes Explorer.** The new start screen brings machine, process, and sensor charts into one workspace with a shared cursor and time window. Pin an instant, jump to an exact time, compare up to eight running or exited processes, and inspect recorded values, source intervals, and the full machine row. Choose charts from searchable groups, switch between a grid and a list, or focus one chart. Command-scroll zooms around the pointer across all charts; ordinary scrolling still moves the page. CSV exports the visible data; process trace import/export and the previous process monitor remain available. Current hardware inventory is separate from historical evidence. See the [Explorer guide](docs/explorer-design.md). - **The app comes first now, and the menu bar item is optional.** Requested in #21 and #67. Until now the menu bar read-out was the app: it could not be turned off, it was the only thing that could open a window, and it held the only Quit command. Three things change together. - **Show in the menu bar** is a switch in Settings. Turn it off and monitoring, recording and alerts carry on exactly as before. Open the window again from the Dock, Spotlight or Launchpad. - **Record history** is now its own switch rather than half of a Mode picker, so recording and the menu bar item are independent. The old Mode setting carries over: menu-bar-only becomes recording off, and everything else becomes recording on, with the item left on either way. - **The Dock icon follows the window.** Mac Performance Monitor appears in the Dock whenever one of its windows is open, which is also what gives it the standard menus and Command-Q, and drops out of the Dock when the last window closes. A preference keeps it there permanently, replacing the old "show icon in the Dock" toggle, which it inherits. - Launching the app now opens its window, rather than appearing to do nothing. Opening at login stays quiet, with no window and no Dock icon. - Closing the last window quits the app when neither the menu bar item nor recording is switched on. With either on, it keeps running as before. - **Dashboard charts separate averages from bursts.** Each range uses fixed time intervals for the clear average line, with the unsmoothed recorded range in a translucent layer behind it. Range bars and separate outline traces are gone. Short bursts keep their detail rather than being reduced to the average's intervals. Pressure, processor, network, disk, swap, thermals, and the six headline strips use the same statistics. Resizing keeps the averages fixed and can reveal finer detail in the recorded range. New stored history retains minima and sensor-specific counts as well as peaks. Older missing bounds remain unknown, and thermal averages with unknown counts are marked approximate. The standard and app-wide rollout guide are in [Dashboard chart standard](docs/dashboard-chart-standard.md). - Tabs other than Dashboard and Explorer share the existing line-and-band renderer and load every stored row instead of thinning history before drawing. Stored ranges include recent finer-resolution rows up to the present. The Processes load card shows the recorded 1, 5, and 15 minute load averages together, including in its enlarged detail chart. - Per-core bars show current measured usage, hardware overview panels use the available width, and the process table appears promptly when a window opens. - The compiler-driven string-coverage check now fails when the interface uses a key that the catalog does not carry. CI runs it alongside the source-text check and Apple's catalog compiler. A documented allowlist covers strings that are the same in every language, such as units and identifiers. ### Security - Sparkle, the updater framework, moved from 2.9.3 to 2.9.6. That picks up two high-severity advisories published on 17 August 2026, GHSA-3x7w-j75x-ppq5 (a symlink race between validating and moving an update, local privilege escalation when the installer runs in the system domain) and GHSA-4v99-qgq9-6pxp (root-privileged cache cleanup following a symlink under the user's home), plus the intervening delta-patching hardening. Reported in #70 by @ForksApps. The bundled framework and the appcast tools were replaced together from Sparkle's Swift Package Manager release, verified against the checksum Sparkle pins for it. ### Added - The new Alerts menu shows all active alerts. Click the red badge to open it. Each process has its own list, with the time each alert began. Click a process name to open its details. Alerts for the whole Mac form a separate group. The badge counts alerts, not alert types. - Hover details on the Energy charge, die-temperature, and fan timelines, plus the charge, power, and battery-temperature card charts. Readouts show the date, time, and value in the correct units. Thermal hover identifies CPU and GPU separately and marks a missing sensor reading as unavailable. - Hover details on every Dashboard chart, including headline sparklines. Readouts show each series' interval average, known bounds, sample count, source resolution, and missing readings. Every Dashboard card has a detail view with a larger chart or breakdown, captured values, and explanations. Detail views are frozen snapshots so they stay still during investigation. - German and French localizations, generated by Claude Fable 5.1, Anthropic's AI model, from the English source strings. They have not yet been reviewed by native speakers: Settings says so whenever either language is active, every string is unapproved on Crowdin until a native speaker approves it, and corrections are welcome at https://crowdin.com/project/mac-performance-monitor. A language leaves the notice once a native speaker has been through it. ### Fixed - The network menu now uses fixed columns for interface details, session totals, latency, jitter, and packet loss. Missing readings retain their space, and the app list reserves six rows so traffic changes do not resize the menu. - The disk menu no longer jumps as device activity changes. Each physical disk has fixed read/write columns, with throughput and service time on separate rows. Idle readings keep their space, and warning icons show error and retry counts on hover without changing the layout. - A cyclic-growth test fixture now uses smaller typed expressions to reduce compiler work after a hosted CI type-checking timeout. - The French Explorer capacity warning now describes reaching the comparison limit, not a completed Explorer. - Fixed a crash during background history maintenance. Process-cache pruning, clearing, and lookups now share the database writer queue with sample inserts. Cleanup after a failed transaction also finishes on that queue before another write can start. - Metric card details no longer open as a small, empty grey sheet on the first click. The captured data now controls sheet presentation directly. Closing and reopening the detail view captures a fresh snapshot. - GPU thermal sensor discovery no longer drops a valid die sensor for the whole session when its first value is zero or unavailable. Failed reads remain missing; they are not replaced with zero or CPU temperature. Dashboard thermal charts keep these gaps visible and distinguish missing readings from older records whose full range was never stored. - Alerts no longer depend on a visible window or full history recording. System alerts use fresh system samples independently of the display refresh setting. Process alerts request a scan at least once a minute when nothing else needs one, and enabled GPU alerts keep GPU sampling active. - With no menu bar item, no window and no panel open, the sampler no longer publishes to the main thread every second for nobody to read. - A chart resuming after a gap no longer climbs vertically from zero. The sampler's first tick after launch has nothing to difference against, so its CPU, network and disk figures were zero by construction, and that tick was both recorded and drawn: every restart left a zero at the start of the run. The first tick still seeds the sampler and drives the first process scan, but it is neither recorded nor charted. - Long-range charts no longer mistake each stored aggregate for an isolated point. Source intervals describe the time those rows cover; finer live data still uses its own cadence when detecting gaps. - Gaps in the recently drawn line, and straight lines across periods when the app was not running: samples kept arriving while the window was covered but were dropped, and the gap threshold grew with the range (two and a half minutes at an hour) so real holes were bridged. Samples are now kept while the window is covered, and a gap is anything beyond three times the cadence. - The thermals chart changed shape as it scrolled: its buckets were sized from the data's extent rather than the axis, so every new sample moved every boundary. Buckets are anchored to absolute time now. - 99 interface strings were never in the catalog, so they stayed English in every language whatever you chose. They are SwiftUI literals that the source-scanning check cannot see, from the battery detail panels, the network adapter and scan views, the hardware overview, the memory inspector, the menu bar panels, the chart accessibility labels, and a set of messages and hints. All are now translated into Simplified Chinese, German and French. Reported in #60. - Six more strings had translations that could never be found, because the catalog stored the key in a form the app never looks up: five carried a literal escape sequence such as `\u{2026}`, which Swift resolves to a character before any lookup happens, and one used three full stops where the app writes an ellipsis. They include the Login Items notice, the Settings explanation of per-app network attribution, two onboarding cards about memory, and the Check for Updates menu item, all of which showed English on an otherwise translated screen. Fourteen further escaped keys duplicated entries that were already correct and have been removed. ### Upgrade Notes - Existing alert on/off choices and explicit process-memory budgets remain intact. The old fixed swap ceiling no longer controls alerts; swap now uses growth and paging evidence. Quiet Evaluation can observe growth without sending growth notifications. - Existing history stays available. New database fields preserve chart bounds, sample counts, and paging evidence from new readings; they cannot restore detail that older versions did not record. Back up the app's data before testing a downgrade. - A small local incident checkpoint and delivery log are separate from full performance-history recording. They let alerts retain notification state across restarts, even when full history is off. - The menu bar, history recorder, and Dock icon now have separate controls. Existing mode settings carry forward to the new switches. - Existing process trace files remain supported. Current hardware inventory is still an on-demand snapshot, not a historical inventory. ## [1.7.1] - 2026-09-03 ### Fixed - In Simplified Chinese, the Hardware tab listed every CPU instruction-set feature as unsupported. The check compared the translated value against the English word "Supported", so nothing ever matched. The compiler-driven coverage check that found this now lives in `Scripts/check-string-coverage.py`. - Two labels, the core count in the system header and the "N supported" count in Hardware, stayed English in Chinese. SwiftUI looks up an integer interpolation as `%lld`, and the catalog only carried the `%@` form those labels never used. - Sizes and plural forms now follow the display language rather than English conventions. A German or French reader sees "1,4 GB", and languages with more than two plural forms (Russian, Arabic, Polish) get the right form for each count, which the previous lookup path could not do. ### Changed - Localization moved to an Apple String Catalog: one file, `Localizations/Localizable.xcstrings`, holding every language, compiled into the app at build time. Translators can edit the file directly or work in the browser at https://crowdin.com/project/mac-performance-monitor with no git or Xcode; see TRANSLATING.md. CI now rejects a missing translation in a complete language, a mismatched format specifier and a malformed plural, so a translation pull request cannot break the build for the languages it does not touch. Existing translations carried across unchanged. - Homebrew: the app is in the main homebrew-cask repository, so `brew install --cask mac-performance-monitor` works without a tap, and Homebrew's bot picks up each release on its own. ## [1.7.0] - 2026-09-01 ### Added - Simplified Chinese localization, and a language picker in Settings (Follow System, English, or 简体中文). Contributed by @zbsdsb, who wrote the original translation, and extended by @Maybe404 to cover the interface text that reaches the screen as String values rather than as literals SwiftUI can resolve on its own. The Disk Map, its Full Disk Access flow and the advisor's guidance are all translated. - A translations guide in CONTRIBUTING.md. New languages are on hold for a short while during a move to String Catalogs; existing translations carry across unchanged. ### Fixed - The setup wizard had no visible way to finish. The final step had outgrown its window, so the step icon was clipped and the footer, including the primary button, sat below the bottom edge. Step content now scrolls with the footer pinned, and the flow ends on a closing card offering Close and Open Dashboard. - Installing or updating through Homebrew failed with a checksum mismatch. The cask recorded the checksum of a build made before notarization, and stapling changes the file. deploy.sh now derives the checksum from the installer it actually published. - Building without an Apple Developer certificate produced an app that was killed at launch, because ad-hoc signing with Hardened Runtime cannot load the bundled Sparkle framework. Contributed by @Maybe404. This affected contributors, not released builds. ## [1.6.0] - 2026-08-31 ### Added - **Disk Map.** The Disk tab has a second page for the question the rest of the tab could not answer: what is using the space. Scan the startup disk, any mounted volume or any folder and see it as a squarified treemap you can zoom into (double-click, Escape, breadcrumbs), coloured by kind, age, safety or depth, with a hover read-out and a detail rail that follows the selection. The numbers are the professional kind: allocated bytes rather than lengths, hard links counted once, clones flagged and, on selection, "would free now" read from the filesystem so a 21 GB clone shows as freeing nothing. A bar reconciles the scan against the volume's used figure (macOS system volumes, purgeable space, shared blocks, folders macOS would not let it read, data vaults) so the total agrees with Finder and every caveat is a chip. Largest and Oldest tables, a Kinds view with app bundles rolled up, a Reclaim view that groups known locations (caches, Xcode DerivedData, simulator runtimes, iOS backups, Docker images, cloud folders, Photos and Mail libraries and more) by how safe they are to remove with the proper way to reclaim each, and a Changes view comparing the scan with the previous one. Reveal in Finder, Quick Look and Move to Trash on every item, the last behind a confirmation and an inode check so a scan that is days old never removes something that replaced what you saw; the space moves to an In Trash figure until Finder empties the Trash. Full Disk Access is requested in context (with the relaunch it needs) and never as a modal; without it the page says exactly which folders were skipped. Scans use `getattrlistbulk` on a handful of utility-priority threads that never download iCloud files: a 3 M-file startup disk takes about twenty seconds and its total matches `du` to the byte, and the last scan comes back instantly on the next open from a compact snapshot file. Shift-Command-D opens it from anywhere. ### Changed - **The Analytics grid is drawn with the app's Canvas charts.** It was the last Swift Charts surface: every chart was built from one mark per data point, so a full grid re-laid-out around 14,000 marks every time the live window slid a tick, and each added process made it visibly worse (the tab, and with it the app, crawled with several processes overlaid). The grid and the focused chart now ride the same Canvas machinery as the rest of the app, with everything kept: overlaid processes with their colours, legend-hover dimming, gap handling, the combined scrub read-out, wall-clock axes (now with seconds on the short spans), and the full zoom/pan/rubber-band interaction set. Measured at eight overlaid processes, the per-tick cost of the charts fell by more than 3x and no longer grows with the process count; scrubbing no longer re-lays-out the series at all. The trace viewer shares the component and gets the same. - **Long Analytics spans no longer re-transform the whole window every tick.** Appending one live sample re-projected and re-downsampled every metric for every process over the full raw window (millions of point operations on the six-hour span). The rebuild is now paced to the chart's own downsample bucket, like the strip charts whose completed columns are final: every tick on the live span, about once a minute on six hours, with nothing visible changing in between. ### Fixed - **Menu-bar popovers can no longer crash the app in a layout loop.** On macOS 26 a popover resize could enter an AppKit/SwiftUI feedback cycle (the hosting view answers "window laid out" by setting the window frame, which lays out again) that recursed until the main thread overran its stack, killing the app while a dropdown was open. The driver is a fractional content height (glass-material metrics) that a pixel-aligned window frame can never match, so the resize chases it forever. All six status-item popovers now wrap their content in a root layout that reports sizes rounded up to whole points, with sub-point hysteresis so ideal-size jitter cannot flip the rounded height back and forth across an integer boundary. Every consumer of the size, the animated window-resize target included, now chases a frame the window can actually reach, and the resize converges. - **The installer pkg can no longer relocate onto a stray copy of the app.** pkgbuild's default marks the bundle relocatable, so macOS could follow LaunchServices to any copy of the app on disk (a build tree, an old copy in Downloads) and write the payload there, as root, instead of /Applications. The pkg is now built from a staged root with BundleIsRelocatable off; the receipt identifier and version are unchanged. - **Sensor chart lines no longer cross the vertical axis.** The Hardware overview's sensor charts keep samples slightly older than their five-minute window so the line enters from the left edge, but those points were stroked straight through the axis labels. Chart series are now clipped to the plot area. - **Sensor temperature figures are readable in light mode.** The heat-colored values on the sensor cards (and in the per-sensor sheet) used a bright ramp that only reads against a dark backdrop; light mode now uses a darker, more saturated variant of the same cool-to-hot ramp. ## [1.5.0] - 2026-08-27 ### Added - **Temperature monitoring.** The SMC reader now classifies every readable sensor by domain with no key cap: CPU die (P and E cores, reported as the hottest core plus the average, since "CPU temperature" means the hottest core), the GPU's own cluster sensors, SSD, battery, airflow, skin and board, wireless, voltage rails, and every fan the controller reports. This also fixes a discovery bug on chips with many voltage-rail keys, where the old 12-key cap filled with rails before any die sensor was found and the reported die temperature could read about 33 C at idle against an actual 38 to 53 C. Research notes and the probed sensor inventory are in `docs/temperature-design.md`. - **Thermal history (schema v14):** system rows record per-domain temperatures (hottest sensor), the fastest fan, and macOS's thermal pressure verdict, with average and max rollups through the minute and hour tiers. Max is the invariant everywhere, since thermal history answers "how hot did it get". The Energy tab gains a Thermals panel: CPU and GPU die history, a live status line, and a fan chart hidden on fanless Macs. - **Sensor-domain history (schema v15):** the remaining sensor groups (P and E core die separately, airflow, skin and board, wireless, voltage rails) are recorded like the headline domains, and the Hardware overview's sensor charts read their history back on launch, so a restart no longer starts the trend lines from blank. - **A Temperature metric in the combined menu bar item:** opt-in like the other metrics, showing the hottest CPU die sensor as a bare degree figure. Its panel leads with that figure tinted by macOS's thermal pressure verdict, never by a degree threshold (a hot number in green is a Mac working as designed), above a live die sparkline and per-domain rows for GPU, SSD, battery, fans and the verdict. - **Thermal throttling events and a sustained-throttling alert:** each step up into serious or critical pressure is recorded and attributed to the top CPU process at that tick, listed under the Energy tab's Thermals panel. The alert is off by default (fanless Macs throttle routinely under real work): it fires once after 30 sustained seconds, names the process working the CPU hardest, and re-arms on recovery. - **The fan-drift insight, a dust signal:** compares this fortnight's fan speeds against six weeks ago at the same die temperature (matched in 2.5 C bands, so a busier, hotter month never reads as drift). A finding needs both 20% and 300 rpm of drift, and suggests cleaning the vents. Young databases, fanless Macs and seasonal shifts stay silent. - **Temperature charts across the app:** a CPU and GPU die cell in the Analytics grid, a Temperature panel on the GPU tab, a live CPU die card on the Processes header (it appears only once a temperature has been seen, so SMC-less Macs keep the three-card header), and a Thermals panel plus Top CPU processes in the Dashboard rail. - **Sensors in the Hardware explorer:** every readable SMC temperature key, grouped by domain with counts and hottest readings, copyable and exportable like the rest of the inventory. The Hardware overview gains a live sensor card per domain in the detail-rail chart style; clicking one opens a deep-dive sheet listing every individual sensor behind the figure, re-read live while open. ### Changed - **The Refresh interval dial now governs everything visible.** Above 1 s the dial previously slowed only the hidden full scan, while the menu bar image, every live chart and the on-screen process rows kept updating once a second. A UI gate derived from the dial now paces all of it; an open menu bar popover pins to every tick (its live strips are the point of opening one), and an opening tab paints immediately rather than waiting out a slow dial. The 1 Hz sampling underneath is unchanged, so charts redraw with full-resolution data and logging density is untouched. - **Kernel memory-pressure events no longer bypass the dial.** Under sustained pressure the kernel signals repeatedly, and each event used to re-sort the Processes table and republish every live surface, piling on main-thread work exactly when the Mac was struggling. A pressure event now forces only the process scan and an immediate alert evaluation. ### Fixed - **The first-run wizard and reopen reliably produce a window.** The wizard's auto-open was a fire-once notification racing a listener that could mount later, so a lost race dropped the wizard (and second launches could open nothing). Open requests now queue until the window router is ready, the onboarding scene presents itself on first run, and "Get started" opens the main window. - **Two GPU history read-path drops:** system rows never read the v13 GPU columns back, and the chart downsampler dropped the GPU series on any range over the point cap, so the 24 hr GPU history chart drew blank. - **The macOS 15 SDK compiles again:** macOS 26 SDK-only symbols (Metal 4, Wi-Fi 7 PHY mode) are guarded by compiler version, not a runtime check. ## [1.4.0] - 2026-08-23 ### Added - **A GPU tab:** what the GPU is doing, at what clock and power, who is using it, and how much of that is AI work. Live utilization (device, renderer, tiler, active share) and power (GPU, Neural Engine, CPU) timelines with history, the chip's clock-state residency, thermal limit and power cap from IOReport, and a "who is using the GPU" table built from the AGX driver's per-context accounting, which needs no helper and no root: GPU share, milliseconds of GPU time per second, and last activity for every process holding a Metal context. Processes are classified into AI and ML, display and UI, media, and other; known runtimes (Ollama, llama.cpp, MLX, LM Studio, Core ML hosts, Apple Intelligence, the media analysis daemons) are named, and a bare Python or Node serving a model is recognised from its command line, with the model file where the arguments say. An AI workloads card shows those processes with their GPU share and whether the Neural Engine is busy. Research and data sources are in `docs/gpu-tab-design.md`. - **GPU history (schema v13):** system samples record GPU utilization and GPU and Neural Engine power, process samples record GPU time and share, all with minute and hour rollups, so the GPU timelines have a past to show. - **Sustained high GPU alert:** off by default, with a threshold in Settings, alongside the existing pressure, swap and per-process alerts. - **Top GPU processes in the menu bar:** the GPU dropdown (and the GPU panel of the combined item) lists the processes drawing on the GPU with their share, naming the AI runtime where there is one. An empty list after a scan reads "Nothing is using the GPU" rather than "Sampling". - **A Hardware tab:** this Mac's inventory as a searchable, browsable tree with a visual overview: a block diagram of the system on a chip (CPU clusters with one square per core, the GPU's cores, the Neural Engine, the unified memory they share, scaled to fit anything up to an Ultra), capacity bars for memory and volumes, the displays drawn to their aspect ratio, the battery's health ring, the radios and buses, and the running software. Nineteen sections cover everything `system_profiler` and the kernel report: Mac identity, processor (performance levels with their caches, every instruction-set feature the kernel publishes), Metal device limits, memory, displays, storage, power and battery (the raw gauge: cells, adapter, manufacture date), network, Wi-Fi via CoreWLAN, Bluetooth, USB, Thunderbolt and USB4, audio, cameras, PCI, peripherals, printers, security (secure boot, SIP, signed system volume, the Secure Element) and software. Search matches any title or property; every value copies with a click; any item or the whole inventory exports as text or JSON. The page reads once when opened and again only on Refresh (Command-R), never on the sampling tick. - **250 ms and 500 ms refresh intervals:** the live charts, read-outs and the process rows on screen now move at the dial rate, including 4 Hz. The full per-process scan, the table order, rankings and alerts keep a 5 s floor. - **A chart benchmark harness** (`--benchmark-charts`): measures the live pipeline per tick offscreen, renders any page to a PNG with `--snapshot`, and checks the Hardware page against an Ultra-sized chip. ### Changed - **Every live chart is now a scrolling strip:** a fixed trailing window that moves right to left as samples arrive, drawn by AppKit layers that scroll by moving pixels rather than repainting. Completed columns are final (bucket extremes are anchored to absolute time), so a tick costs the same whether the window holds a minute or seven days of samples. With the window open on the Dashboard at 250 ms the app's CPU fell from about 53% to about 11%; the per-tick cost of the Dashboard page dropped from 45 ms to under 8 ms. Details and every measurement are in `docs/efficiency-analysis-2026-08-22.md`. - **Everything that moves is an AppKit surface:** sparklines, metric cards, timelines, the core grid, the taxonomy bar and the header read-outs repaint their own layers from feeds; SwiftUI builds the static chrome once. The process table is an AppKit outline view whose rows on screen are re-read at the dial rate (task info, rusage and GPU time for just those pids, about a millisecond for thirty rows) and patched in place; re-sorting happens on the 5 s calc. - **Menu bar items follow the dial** and skip unchanged renders, so the status item figures move with the charts instead of lagging them. - **The per-process scan runs on its own queue:** the system tick publishes at once and never waits behind a scan; scans never pile up, and a forced scan (a pressure event) is remembered rather than dropped. - **Cheaper Network and Disk pages at fast dials:** SystemConfiguration, CoreWLAN and host-name lookups are cached between polls, and the block storage enumeration is reused across reads. - **Process detail and system header** re-render only when the model publishes; their live parts ride the feeds. ### Fixed - **The GPU tab and GPU dropdown updated once a second regardless of the dial:** the device read (IORegistry, IOReport, SMC) was decimated to 1 Hz. It now runs every tick while a GPU surface is open (the driver's utilization figure does change between sub-second reads) and once a second when only the menu bar icon or history logging wants it. - **A reopened popover could offer kill or inspect on stale rows:** a top process list older than the dial interval is cleared when its popover opens, until the immediate scan lands. ## [1.3.8] - 2026-08-14 ### Added - **A dedicated Disk tab:** every disk fact the system exposes, on one page. Live read/write throughput and IOPS with history, per-operation service latency and a busy-time utilization figure derived from the driver's counters, a card per physical device with its full hardware identity (model, vendor, firmware, serial, interconnect, NAND status, NVMe revision, block size), per-volume capacity bars grouped by APFS container with purgeable space and role badges, SMART health for the internal SSD (temperature, life used, spare, power-on hours, unsafe shutdowns, lifetime reads and writes), a boot-volume free-space trend with a low-space rule, and the top processes by attributed disk I/O over the selected range. The menu bar disk panel's Open button now lands on the new tab. - **Disk detail history (schema v12):** system samples now record read/write service latency, disk utilization, and boot volume free space (sampled once a minute), with minute and hour rollups. The new columns are nullable on purpose: an interval with no IO charts as a gap, never as a fake 0 ms, and free space keeps its low water mark through every aggregation tier. ### Fixed - **Hot battery temperatures are no longer misread as sub-zero:** the AppleSmartBattery `Temperature` key is centi-degrees, and most controllers report centi-Celsius while a few report centi-Kelvin. The decoder told the two apart with a greater-than-100 threshold, but 100 degrees is plausible for an actively failing cell, so a genuine (if extreme) Celsius reading above that was treated as Kelvin and converted to a value below absolute zero. The detector now uses a 200 threshold: no real Celsius reading reaches it (thermal runaway destroys the cell first), and no real Kelvin reading falls below it (that would be a battery colder than minus 73 degrees), so the two units separate cleanly. The decode is also extracted into a pure helper so it is unit-tested alongside the other battery decoders. - **The network scanner recognises the whole IPv6 link-local range:** the NDP table parser and the per-interface address collector matched only an `fe80` prefix, but RFC 4291 defines link-local unicast as `fe80::/10`, which spans `fe80::` through `febf::`. Addresses in `fe90::` to `febf::` were sorted into the global bucket of the NDP view and, on the Network page, were kept in the global IPv6 list instead of being filtered out as link-local noise. A shared `isIPv6LinkLocal` predicate now matches the full `fe80::/10` range, so every link-local address lands in the right place. - **The deep memory inspector no longer traps on a malformed size token:** `MemoryInspection.parseBytes` built its result with `UInt64((value * multiplier).rounded())`, and `value` is parsed straight from a `footprint` / `heap` / `vmmap` token. Any non-representable result (a negative number, an `inf` / `NaN` token, or a value past `UInt64.max`) made that initializer trap with a fatal error, aborting the inspector mid-parse even though the function advertises "returns nil if it cannot be parsed". The conversion now uses `UInt64(exactly:)`, which returns nil for those inputs, so a stray token is treated as unparseable instead of crashing the report. ## [1.3.7] - 2026-08-09 ### Fixed - **A timed-out memory inspection no longer masquerades as success:** the deep memory inspector shells out to Apple's tools (`footprint`, `heap`, `leaks`, `sample`) under a hard timeout, and a wedged target that printed a few lines before hanging was killed on time, but its partial text was then returned as a complete `.success` instead of `.failure(.timedOut)`. The decision checked the captured text before the timeout flag, so any output at all, however truncated, hid that the run had been cut short. The timeout now wins regardless of output: a run killed for exceeding the limit reports `.timedOut` even when it managed to write partial stdout first, so an incomplete report is shown as a failure rather than presented as the tool's full answer. - **Quiet the notification spam during a sustained memory crisis:** real memory pressure can bounce between critical and normal while the kernel compresses, swaps, and throttles, and every bounce re-armed the alert so the next critical tick fired a fresh notification. The engine now delivers at most one notification for each alert during a cooldown window (five minutes by default), so a condition that keeps flapping notifies once instead of re-firing on every flap. The condition is still tracked and shown as active until it genuinely recovers; only the repeat notifications are held back. - **Vendor grouping works for processes whose team id resolves late:** the recording cache short-circuited the per-process upsert on (name, path, bundle id) without checking the team id, so a process first seen with team_id nil (the common case, since codesign lookups are expensive and the sampler resolves a team id for only ~30 of ~800 processes per tick) and later resolved to a real team id never had that id written, leaving the row NULL forever. Grouping by vendor, which keys on team_id, therefore broke for the bulk of processes after every app launch. The cache now carries the team id and compares it, so a late-resolved id defeats the short-circuit and the row's existing COALESCE upsert heals it in place. - **Disk tab trend no longer flattens to zero on long ranges:** the Disk tab's read/write trend lines collapsed to a flat zero on any dashboard range whose point count exceeded the chart cap (the six-hour, day, and longer windows), even though the underlying raw and minute-tier rows carried the values. The chart downsampler builds one averaged point per time bucket, and it carried the pressure, memory, CPU, battery, and network scalars through but omitted the four disk-throughput fields, so they defaulted to 0. The four disk scalars (read and write bytes per second, and read and write operations per second) are now averaged per bucket like the network scalars, the same fix the battery and network fields already got. The downsampler also moved from the app target into `MacPerfMonitorCore/Persistence` (alongside the history type it operates on), bringing this chart-path function under the headless test suite for the first time. ## [1.3.6] - 2026-08-04 ### Fixed - **Exited processes keep their real name:** an app could be recorded in the history under the name "xpcproxy" instead of its own, so killing (say) Microsoft Word left the Analytics picker offering an "xpcproxy" entry with Word's data. macOS launches apps through an xpcproxy trampoline that becomes the app in place, and a sample straddling that moment captured the trampoline's name with the app's path; the recording cache then froze that first glimpse for the whole session. The store now refreshes a process's recorded name, path, and bundle when they change, and rows already recorded with the trampoline's name resolve their display name from the executable path, so existing history heals without a migration. - **Real icons for exited processes:** the Analytics legend and picker showed this app's own icon for any process that was no longer running. The executable path is now captured when a process is added to the chart, so an exited process keeps its actual app icon. Processes with no usable path, or whose binary has since been deleted, show the system's generic executable icon rather than masquerading as this app. ## [1.3.5] - 2026-08-02 ### Added - **Hide Notch:** a toggle in the menu bar panel's overflow menu switches the built-in display to its notch-free mode, so the menu bar drops below the camera housing and runs edge to edge. On a 14-inch that returns 185pt the notch was taking, which is what makes room for status items on a crowded bar. The choice is remembered and re-applied at launch and whenever the display configuration changes, so a reboot does not undo it; changing scaled size in System Settings keeps the notch hidden at the size you picked. Only appears on Macs with a notch. - **Chart processes that have exited:** the Analytics picker now lists processes the history recorded but that are no longer running, alongside the running ones, with the time each was last seen. Their data was always in the database and the charts always drew them; only the live-process list stood in the way. Searching runs against the whole window rather than the visible page, so a process that exited hours ago is still reachable. ### Changed - **Group members are merged per program:** a process that was quit and relaunched, and an app's many identical helper instances, now share one row instead of appearing once per PID. A row shows what its instances weighed together while running, carries an instance count, and notes how much of the window the program was actually up for. Group cards count programs and name the biggest contributors. ### Fixed - **Group totals no longer inflated by exited members:** on the raw tier a member's last footprint was carried forward for the rest of the window, so every instance that had died kept contributing to the group's timeline. Members are now dropped one heartbeat after their last sample, which is what tells a live process from a dead one. Groups whose members restart often read far heavier than they were. ## [1.3.4] - 2026-08-01 ### Changed - **New app icon:** the Dock, Finder, and Launchpad icon is now a blue activity chart with an alert marker, replacing the previous line-and-nodes mark. It reads more clearly at small sizes and matches the app's charting and alerting focus. ## [1.3.3] - 2026-07-29 ### Fixed - **Combined menu bar dual-rate layout:** Disk and Network Focus/Strip readouts no longer overlap their down/up figures. Stacked rates use matched compact fonts and a shared half-height layout, and sit on the same 22pt band as other strip cells. - **Strip caption cells:** RAM, CPU, and GPU titles sit higher with larger medium-weight values, so the strip stays even without the over-bold look that clashed with Disk/Network rates. ### Changed - **Sampling hot path:** `RingBuffer.elements()` returns a chronological collection view instead of copying a full array each read. Bundle IDs are cached by `.app` path so helpers sharing one bundle do not each re-read `Info.plist` on first sight. ## [1.3.2] - 2026-07-10 ### Added - **Network Scan:** discover devices on a selected local interface and IPv4 subnet in a sortable, horizontally scrollable table. Results include reachability, MAC address, host and service names, vendor, SMB identity, optional IPv6 columns, editable device labels and comments, plus on-demand TCP port scans. Vendor cells show queued and lookup states before reporting a result, and resolved or unknown MAC prefixes are cached for faster repeat scans. Private or randomized MAC addresses are identified separately because they contain no IEEE vendor ID, rather than being reported as vendor not found. ## [1.3.1] - 2026-07-10 ### Added - **Physical disk activity:** optional Disk readout in the combined menu bar, with read and write throughput, IOPS, device identity, service time, errors, retries, and a live process-attributed leaderboard. - **Disk history:** physical read and write trends on Dashboard, range-aware top disk processes, Disk ranking in Insights, and separate read and write charts in each process detail. ### Changed - **Clear directional readouts:** Network and Disk use distinct system icons with fixed-width download/upload or read/write rows, so changing values do not move their arrows. ### Fixed - **Stable Disk panel:** the process leaderboard always reserves eight ranked rows, so scans can reorder activity without moving the Open and Settings controls. - **Correct multi-display contrast:** each copy of the combined status item now follows its own display's menu bar appearance. Light and dark menu bars remain legible at the same time instead of both following whichever display was active. ## [1.3.0] - 2026-07-10 ### Added - **One combined menu bar item:** memory pressure, CPU, GPU, energy, and network now share one compact status item instead of occupying five separate spaces. - **Configurable readouts:** choose any combination of metrics, put them in the order you prefer, and switch between Focus mode for one value and Strip mode for every selected value. At least one readout always remains available. - **Context-aware panels:** clicking a metric in the status strip opens its panel. Clicking another metric while the panel is open switches the content in place. - **Persistent alarm state:** active alert conditions stay visible until they recover using the same hysteresis as notifications. ### Changed - **Clearer compact typography:** short RAM, CPU, GPU, and BAT labels identify the percentage readouts. Network shows fixed-width download and upload rates, with stable trailing arrows that do not move as the values change length. - **Calmer status colors:** normal readouts follow the menu bar's light or dark appearance. Active alarms add a red warning marker while values remain in the highest-contrast system color. - **Unified panel navigation:** the combined panel uses text labels for each metric, shows both network directions, and provides full-cell click targets. - **Relevant Open actions:** RAM and GPU open Dashboard, CPU opens Processes, energy opens Energy, and network opens Network. The action label names its destination. ### Fixed - **Reliable menu bar targeting:** changing digit counts no longer shifts the network arrows, and clicking a different metric no longer closes the open panel. - **Accessible alarm presentation:** alarm state no longer turns whole readouts red, which was difficult to read against some menu bar backgrounds. ## [1.2.1] - 2026-07-10 ### Added - **Share process data (Analytics):** export recorded process history to a compressed `.mpmtrace` file. Choose the current view or the last 1, 6, or 24 hours or 7 days, at full, standard, or coarse resolution. Open a trace from Analytics or double-click it in Finder. Imported traces remain interactive even when their processes are not running on your Mac. - **Broader process descriptions:** glossary version 4 adds 137 descriptions, including 72 Microsoft entries and 22 for Office. It covers Word, Excel, PowerPoint, Outlook, OneNote, Teams, OneDrive, Edge, Defender, Intune, Company Portal, Entra sign-in, AutoUpdate, Global Secure Access, Microsoft 365 Copilot, Scout, and their helpers. ### Changed - **Faster Analytics interaction:** trace import, export, chart preparation, projection, and statistics now run away from the main thread. The app limits zoom and pan updates to the display rate and uses binary search for visible ranges. Imported traces retain every process and plot up to eight selected overlays. - **More efficient history access:** multi-process history loads now use bounded, batched SQL reads. New covering indexes speed up network leaderboards and process pruning on large databases. - **Bounded maintenance work:** retention now deletes data in short transactions. Sample writes stay responsive after large policy changes. Disabling logging also releases history caches and stale analysis data. - **Lower sampling overhead:** one interface-list pass now collects system network counters and addresses. The app also caches the fixed page-size and physical-memory values. - **Safer glossary matching:** signed glossary updates can match exact executable paths, stable suffixes, and path patterns. This avoids false labels for generic names such as `log`, `node`, `profiles`, and `tracer`. ### Fixed - **Bounded trace files:** imports and exports now share size, process, and point limits. Streaming decompression and validation reject damaged, unsupported, or inconsistent traces before they exhaust memory or create invalid charts. - **Reliable trace export:** users can cancel database reads and output preparation. File writes use a temporary file and an atomic final commit. The app cannot create a trace that its own reader refuses to open. - **Database write recovery:** a failed transaction no longer leaves stale process IDs or change-gating state in memory. Retrying the same write now succeeds. - **Memory-inspection cleanup:** capped tool output now stops and drains the child promptly. Launch failures no longer retain pipe descriptors or blocked readers. - **Extreme counter handling:** disk throughput differences no longer overflow when read and write counters approach their integer limits. ## [1.2.0] - 2026-07-07 ### Added - **Analytics timeline:** a draggable timeline under the charts. In the multi-chart grid, panning, zooming, or scrolling the timeline moves every chart together. Drag the bar to pan, drag its edges to zoom, or scroll and pinch to zoom about the pointer. - **Chart zoom on the charts:** scroll-wheel and pinch now zoom the analytics charts directly, in both the grid and the focused single-chart view. - **Statistics overlay:** in single-chart mode, an optional panel showing each process's average, peak, current value, and trend across the visible window. ## [1.1.5] - 2026-07-05 The first public, open-source (MIT) release. Mac Performance Monitor is a macOS performance analyzer and logger that lives in your menu bar. It records CPU, memory pressure, GPU, network, battery, and per-process usage to a local database, then helps you find trends, leaks, and the processes behind them. ### Features - **Dashboard:** memory pressure as a 0 to 100 index, a processor timeline, CPU cores, a memory composition breakdown, swap, and live network throughput, with a plain-language verdict. - **Process explorer:** a live, sortable, filterable table of every process, plus a detail inspector charting memory footprint, CPU, file descriptors, and disk I/O over time, with Rosetta status and code-signing details. - **Energy:** battery health and wear, an energy-flow view of what is drawing power, charge history, and the top energy users. - **Network:** download and upload throughput, per-adapter detail, and connection configuration, with optional per-app tracking. - **Analytics:** build your own per-process charts (memory, CPU, network, file descriptors, disk I/O) over any window, from a configurable-resolution local log. - **Insights:** plain-language callouts for what changed, a pressure-event history, and the heaviest consumers by memory, CPU, energy, or network. - **Process groups:** group related apps and helpers into a stack and see its blended footprint as a share of the device. - **Leak detection:** flags processes whose footprint climbs steadily. - **Deep-dive diagnostics:** explains what a process is and whether its behavior is normal, using signed, updatable check packs and a process glossary. - **Menu bar:** pressure, CPU, GPU, network, and battery readouts, each with a quick popover. - **Alerts:** quiet-by-default notifications for critical pressure, sustained swap, per-process ceilings, and suspected leaks, with hysteresis so they do not spam. ### Under the hood - Apple silicon only. Distributed as a Developer ID signed, notarized, stapled installer (`.pkg`), with in-app auto-updates via Sparkle from GitHub Releases. - No telemetry. Every sample is stored locally in SQLite (via GRDB) and never leaves your Mac. - A clean split between a headless, unit-tested data layer and the SwiftUI app. CI builds, tests, and lints on every push and pull request. [Unreleased]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.4.0.289...HEAD [2.4.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.3.1.280...v2.4.0.289 [2.3.1]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.3.0.279...v2.3.1.280 [2.3.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.2.1.261...v2.3.0.279 [2.2.1]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.2.0.260...v2.2.1.261 [2.2.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.1.0.236...v2.2.0.260 [2.1.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v2.0.0.231...v2.1.0.236 [2.0.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.7.1.206...v2.0.0.231 [1.7.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.6.0.204...v1.7.0.205 [1.6.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.5.0.198...v1.6.0.204 [1.5.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.4.0.197...v1.5.0.198 [1.4.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.8.189...v1.4.0.197 [1.3.8]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.7.186...v1.3.8.189 [1.3.7]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.6.181...v1.3.7.186 [1.3.6]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.5.178...v1.3.6.181 [1.3.5]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.4.177...v1.3.5.178 [1.3.4]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.3.176...v1.3.4.177 [1.3.3]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.2.174...v1.3.3.176 [1.3.2]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.1.158...v1.3.2.174 [1.3.1]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.3.0.148...v1.3.1.158 [1.3.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.2.1.131...v1.3.0.148 [1.2.1]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.2.0.127...v1.2.1.131 [1.2.0]: https://github.com/Zesty0wl/mac-performance-monitor/compare/v1.1.5.118...v1.2.0.127 [1.1.5]: https://github.com/Zesty0wl/mac-performance-monitor/releases/tag/v1.1.5.118