mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-08-23 07:48:06 +00:00
chore: migrate repository to standard knowledge base layout
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
[[nodiscard]] auto btop_main(std::span<const std::string_view> args) -> int;
|
||||
@@ -0,0 +1,216 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "btop_cli.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/base.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "btop_shared.hpp"
|
||||
#include "config.h"
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
static constexpr auto BOLD = "\033[1m"sv;
|
||||
static constexpr auto BOLD_UNDERLINE = "\033[1;4m"sv;
|
||||
static constexpr auto BOLD_RED = "\033[1;31m"sv;
|
||||
static constexpr auto YELLOW = "\033[33m"sv;
|
||||
static constexpr auto RESET = "\033[0m"sv;
|
||||
|
||||
static void version() noexcept {
|
||||
if constexpr (GIT_COMMIT.empty()) {
|
||||
fmt::println("btop version: {}{}{}", BOLD, Global::Version, RESET);
|
||||
} else {
|
||||
fmt::println("btop version: {}{}+{}{}", BOLD, Global::Version, GIT_COMMIT, RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void build_info() noexcept {
|
||||
fmt::println("Compiled with: {} ({})", COMPILER, COMPILER_VERSION);
|
||||
fmt::println("Configured with: {}", CONFIGURE_COMMAND);
|
||||
}
|
||||
|
||||
static void error(std::string_view msg) noexcept {
|
||||
fmt::println("{}error:{} {}\n", BOLD_RED, RESET, msg);
|
||||
}
|
||||
|
||||
namespace Cli {
|
||||
[[nodiscard]] auto parse(const std::span<const std::string_view> args) noexcept -> Result {
|
||||
Cli cli {};
|
||||
|
||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||
auto arg = *it;
|
||||
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
usage();
|
||||
help();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
if (arg == "-v" || arg == "-V") {
|
||||
version();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
if (arg == "--version") {
|
||||
version();
|
||||
build_info();
|
||||
return std::unexpected { 0 };
|
||||
}
|
||||
|
||||
if (arg == "-d" || arg == "--debug") {
|
||||
cli.debug = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "--force-utf") {
|
||||
cli.force_utf = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-l" || arg == "--low-color") {
|
||||
cli.low_color = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-t" || arg == "--tty") {
|
||||
if (cli.force_tty.has_value()) {
|
||||
error("tty mode can't be set twice");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
cli.force_tty = std::make_optional(true);
|
||||
continue;
|
||||
}
|
||||
if (arg == "--no-tty") {
|
||||
if (cli.force_tty.has_value()) {
|
||||
error("tty mode can't be set twice");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
cli.force_tty = std::make_optional(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "-c" || arg == "--config") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Config requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
auto config_file = stdfs::path { arg };
|
||||
|
||||
if (stdfs::is_directory(config_file)) {
|
||||
error("Config file can't be a directory");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
cli.config_file = std::make_optional(config_file);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-f" || arg == "--filter") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Filter requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
cli.filter = std::make_optional(arg);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-p" || arg == "--preset") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Preset requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
try {
|
||||
auto preset_id = std::clamp(std::stoi(arg.data()), 0, 9);
|
||||
cli.preset = std::make_optional(preset_id);
|
||||
} catch (std::invalid_argument& e) {
|
||||
error("Preset must be a positive number");
|
||||
return std::unexpected { 1 };
|
||||
} catch (std::out_of_range& e) {
|
||||
error(fmt::format("Preset argument is out of range: {}", arg.data()));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg == "--themes-dir") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Themes directory requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
auto themes_dir = stdfs::path { arg };
|
||||
|
||||
if (not stdfs::is_directory(themes_dir)) {
|
||||
error("Themes directory does not exist or is not a directory");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
cli.themes_dir = std::make_optional(themes_dir);
|
||||
continue;
|
||||
}
|
||||
if (arg == "-u" || arg == "--update") {
|
||||
// This flag requires an argument.
|
||||
if (++it == args.end()) {
|
||||
error("Update requires an argument");
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
|
||||
auto arg = *it;
|
||||
try {
|
||||
auto refresh_rate = std::max(std::stoi(arg.data()), 100);
|
||||
cli.updates = refresh_rate;
|
||||
} catch (std::invalid_argument& e) {
|
||||
error("Update must be a positive number");
|
||||
return std::unexpected { 1 };
|
||||
} catch (std::out_of_range& e) {
|
||||
error(fmt::format("Update argument is out of range: {}", arg.data()));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
error(fmt::format("Unknown argument '{}{}{}'", YELLOW, arg, RESET));
|
||||
return std::unexpected { 1 };
|
||||
}
|
||||
return cli;
|
||||
}
|
||||
|
||||
void usage() noexcept {
|
||||
fmt::println("{0}Usage:{1} {2}btop{1} [OPTIONS]\n", BOLD_UNDERLINE, RESET, BOLD);
|
||||
}
|
||||
|
||||
void help() noexcept {
|
||||
fmt::print(
|
||||
"{0}Options:{1}\n"
|
||||
" {2}-c, --config{1} <file> Path to a config file\n"
|
||||
" {2}-d, --debug{1} Start in debug mode with additional logs and metrics\n"
|
||||
" {2}-f, --filter{1} <filter> Set an initial process filter\n"
|
||||
" {2} --force-utf{1} Override automatic UTF locale detection\n"
|
||||
" {2}-l, --low-color{1} Disable true color, 256 colors only\n"
|
||||
" {2}-p, --preset{1} <id> Start with a preset (0-9)\n"
|
||||
" {2}-t, --tty{1} Force tty mode with ANSI graph symbols and 16 colors only\n"
|
||||
" {2} --themes-dir{1} <dir> Path to a custom themes directory\n"
|
||||
" {2} --no-tty{1} Force disable tty mode\n"
|
||||
" {2}-u, --update{1} <ms> Set an initial update rate in milliseconds\n"
|
||||
" {2}-h, --help{1} Show this help message and exit\n"
|
||||
" {2}-V, --version{1} Show a version message and exit (more with --version)\n",
|
||||
BOLD_UNDERLINE, RESET, BOLD
|
||||
);
|
||||
}
|
||||
|
||||
void help_hint() noexcept {
|
||||
fmt::println("For more information, try '{}--help{}'", BOLD, RESET);
|
||||
}
|
||||
} // namespace Cli
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace Cli {
|
||||
namespace stdfs = std::filesystem;
|
||||
|
||||
// Configuration options set via the command line.
|
||||
struct Cli {
|
||||
// Alternate path to a configuration file
|
||||
std::optional<stdfs::path> config_file;
|
||||
// Enable debug mode with additional logs and metrics
|
||||
bool debug {};
|
||||
// Set an initial process filter.
|
||||
std::optional<std::string> filter;
|
||||
// Only use ANSI supported graph symbols and colors
|
||||
std::optional<bool> force_tty;
|
||||
// Use UTF-8 locale even if not detected
|
||||
bool force_utf {};
|
||||
// Disable true color and only use 256 color mode
|
||||
bool low_color {};
|
||||
// Start with one of the provided presets
|
||||
std::optional<std::uint32_t> preset;
|
||||
// Path to a custom themes directory
|
||||
std::optional<stdfs::path> themes_dir;
|
||||
// The initial refresh rate
|
||||
std::optional<std::uint32_t> updates;
|
||||
};
|
||||
|
||||
using Result = std::expected<Cli, std::int32_t>;
|
||||
|
||||
// Parse the command line arguments
|
||||
[[nodiscard]] auto parse(std::span<const std::string_view> args) noexcept -> Result;
|
||||
|
||||
// Print a usage header
|
||||
void usage() noexcept;
|
||||
|
||||
// Print a help message
|
||||
void help() noexcept;
|
||||
|
||||
// Print a hint on how to show more help
|
||||
void help_hint() noexcept;
|
||||
} // namespace Cli
|
||||
@@ -0,0 +1,831 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::string_view;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
|
||||
using namespace std::literals;
|
||||
using namespace Tools;
|
||||
|
||||
//* Functions and variables for reading and writing the btop config file
|
||||
namespace Config {
|
||||
|
||||
atomic<bool> locked (false);
|
||||
atomic<bool> writelock (false);
|
||||
bool write_new;
|
||||
|
||||
const vector<array<string, 2>> descriptions = {
|
||||
{"color_theme", "#* Name of a btop++/bpytop/bashtop formatted \".theme\" file, \"Default\" and \"TTY\" for builtin themes.\n"
|
||||
"#* Themes should be placed in \"../share/btop/themes\" relative to binary or \"$HOME/.config/btop/themes\""},
|
||||
|
||||
{"theme_background", "#* If the theme set background should be shown, set to False if you want terminal background transparency."},
|
||||
|
||||
{"truecolor", "#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false."},
|
||||
|
||||
{"force_tty", "#* Set to true to force tty mode regardless if a real tty has been detected or not.\n"
|
||||
"#* Will force 16-color mode and TTY theme, set all graph symbols to \"tty\" and swap out other non tty friendly symbols."},
|
||||
|
||||
{"presets", "#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets.\n"
|
||||
"#* Format: \"box_name:P:G,box_name:P:G\" P=(0 or 1) for alternate positions, G=graph symbol to use for box.\n"
|
||||
"#* Use whitespace \" \" as separator between different presets.\n"
|
||||
"#* Example: \"cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty\""},
|
||||
|
||||
{"vim_keys", "#* Set to True to enable \"h,j,k,l,g,G\" keys for directional control in lists.\n"
|
||||
"#* Conflicting keys for h:\"help\" and k:\"kill\" is accessible while holding shift."},
|
||||
|
||||
{"rounded_corners", "#* Rounded corners on boxes, is ignored if TTY mode is ON."},
|
||||
|
||||
{"terminal_sync", "#* Use terminal synchronized output sequences to reduce flickering on supported terminals."},
|
||||
|
||||
{"graph_symbol", "#* Default symbols to use for graph creation, \"braille\", \"block\" or \"tty\".\n"
|
||||
"#* \"braille\" offers the highest resolution but might not be included in all fonts.\n"
|
||||
"#* \"block\" has half the resolution of braille but uses more common characters.\n"
|
||||
"#* \"tty\" uses only 3 different symbols but will work with most fonts and should work in a real TTY.\n"
|
||||
"#* Note that \"tty\" only has half the horizontal resolution of the other two, so will show a shorter historical view."},
|
||||
|
||||
{"graph_symbol_cpu", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"graph_symbol_gpu", "# Graph symbol to use for graphs in gpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
#endif
|
||||
{"graph_symbol_mem", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"graph_symbol_net", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"graph_symbol_proc", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
|
||||
|
||||
{"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\" and \"gpu0\" through \"gpu5\", separate values with whitespace."},
|
||||
|
||||
{"update_ms", "#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs."},
|
||||
|
||||
{"proc_sorting", "#* Processes sorting, \"pid\" \"program\" \"arguments\" \"threads\" \"user\" \"memory\" \"cpu lazy\" \"cpu direct\",\n"
|
||||
"#* \"cpu lazy\" sorts top process over time (easier to follow), \"cpu direct\" updates top process directly."},
|
||||
|
||||
{"proc_reversed", "#* Reverse sorting order, True or False."},
|
||||
|
||||
{"proc_tree", "#* Show processes as a tree."},
|
||||
|
||||
{"proc_colors", "#* Use the cpu graph colors in the process list."},
|
||||
|
||||
{"proc_gradient", "#* Use a darkening gradient in the process list."},
|
||||
|
||||
{"proc_per_core", "#* If process cpu usage should be of the core it's running on or usage of the total available cpu power."},
|
||||
|
||||
{"proc_mem_bytes", "#* Show process memory as bytes instead of percent."},
|
||||
|
||||
{"proc_cpu_graphs", "#* Show cpu graph for each process."},
|
||||
|
||||
{"proc_info_smaps", "#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate)"},
|
||||
|
||||
{"proc_left", "#* Show proc box on left side of screen instead of right."},
|
||||
|
||||
{"proc_filter_kernel", "#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop)."},
|
||||
|
||||
{"proc_aggregate", "#* In tree-view, always accumulate child process resources in the parent process."},
|
||||
|
||||
{"keep_dead_proc_usage", "#* Should cpu and memory usage display be preserved for dead processes when paused."},
|
||||
|
||||
{"cpu_graph_upper", "#* Sets the CPU stat shown in upper half of the CPU graph, \"total\" is always available.\n"
|
||||
"#* Select from a list of detected attributes from the options menu."},
|
||||
|
||||
{"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n"
|
||||
"#* Select from a list of detected attributes from the options menu."},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"show_gpu_info", "#* If gpu info should be shown in the cpu box. Available values = \"Auto\", \"On\" and \"Off\"."},
|
||||
#endif
|
||||
{"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."},
|
||||
|
||||
{"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."},
|
||||
|
||||
{"cpu_bottom", "#* Show cpu box at bottom of screen instead of top."},
|
||||
|
||||
{"show_uptime", "#* Shows the system uptime in the CPU box."},
|
||||
|
||||
{"show_cpu_watts", "#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo."},
|
||||
|
||||
{"check_temp", "#* Show cpu temperature."},
|
||||
|
||||
{"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."},
|
||||
|
||||
{"show_coretemp", "#* Show temperatures for cpu cores also if check_temp is True and sensors has been found."},
|
||||
|
||||
{"cpu_core_map", "#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core.\n"
|
||||
"#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine.\n"
|
||||
"#* Format \"x:y\" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries.\n"
|
||||
"#* Example: \"4:0 5:1 6:3\""},
|
||||
|
||||
{"temp_scale", "#* Which temperature scale to use, available values: \"celsius\", \"fahrenheit\", \"kelvin\" and \"rankine\"."},
|
||||
|
||||
{"base_10_sizes", "#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024."},
|
||||
|
||||
{"show_cpu_freq", "#* Show CPU frequency."},
|
||||
#ifdef __linux__
|
||||
{"freq_mode", "#* How to calculate CPU frequency, available values: \"first\", \"range\", \"lowest\", \"highest\" and \"average\"."},
|
||||
#endif
|
||||
{"clock_format", "#* Draw a clock at top of screen, formatting according to strftime, empty string to disable.\n"
|
||||
"#* Special formatting: /host = hostname | /user = username | /uptime = system uptime"},
|
||||
|
||||
{"background_update", "#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort."},
|
||||
|
||||
{"custom_cpu_name", "#* Custom cpu model name, empty string to disable."},
|
||||
|
||||
{"disks_filter", "#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace \" \".\n"
|
||||
"#* Only disks matching the filter will be shown. Prepend exclude= to only show disks not matching the filter. Examples: disk_filter=\"/boot /home/user\", disks_filter=\"exclude=/boot /home/user\""},
|
||||
|
||||
{"mem_graphs", "#* Show graphs instead of meters for memory values."},
|
||||
|
||||
{"mem_below_net", "#* Show mem box below net box instead of above."},
|
||||
|
||||
{"zfs_arc_cached", "#* Count ZFS ARC in cached and available memory."},
|
||||
|
||||
{"show_swap", "#* If swap memory should be shown in memory box."},
|
||||
|
||||
{"swap_disk", "#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk."},
|
||||
|
||||
{"show_disks", "#* If mem box should be split to also show disks info."},
|
||||
|
||||
{"only_physical", "#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar."},
|
||||
|
||||
{"use_fstab", "#* Read disks list from /etc/fstab. This also disables only_physical."},
|
||||
|
||||
{"zfs_hide_datasets", "#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool)"},
|
||||
|
||||
{"disk_free_priv", "#* Set to true to show available disk space for privileged users."},
|
||||
|
||||
{"show_io_stat", "#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view."},
|
||||
|
||||
{"io_mode", "#* Toggles io mode for disks, showing big graphs for disk read/write speeds."},
|
||||
|
||||
{"io_graph_combined", "#* Set to True to show combined read/write io graphs in io mode."},
|
||||
|
||||
{"io_graph_speeds", "#* Set the top speed for the io graphs in MiB/s (100 by default), use format \"mountpoint:speed\" separate disks with whitespace \" \".\n"
|
||||
"#* Example: \"/mnt/media:100 /:20 /boot:1\"."},
|
||||
|
||||
{"net_download", "#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False."},
|
||||
|
||||
{"net_upload", ""},
|
||||
|
||||
{"net_auto", "#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest."},
|
||||
|
||||
{"net_sync", "#* Sync the auto scaling for download and upload to whichever currently has the highest scale."},
|
||||
|
||||
{"net_iface", "#* Starts with the Network Interface specified here."},
|
||||
|
||||
{"base_10_bitrate", "#* \"True\" shows bitrates in base 10 (Kbps, Mbps). \"False\" shows bitrates in binary sizes (Kibps, Mibps, etc.). \"Auto\" uses base_10_sizes."},
|
||||
|
||||
{"show_battery", "#* Show battery stats in top right if battery is present."},
|
||||
|
||||
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
||||
|
||||
{"show_battery_watts", "#* Show power stats of battery next to charge indicator."},
|
||||
|
||||
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
|
||||
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."},
|
||||
#ifdef GPU_SUPPORT
|
||||
|
||||
{"nvml_measure_pcie_speeds",
|
||||
"#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards."},
|
||||
{"rsmi_measure_pcie_speeds",
|
||||
"#* Measure PCIe throughput on AMD cards, may impact performance on certain cards."},
|
||||
{"gpu_mirror_graph", "#* Horizontally mirror the GPU graph."},
|
||||
{"shown_gpus", "#* Set which GPU vendors to show. Available values are \"nvidia amd intel\""},
|
||||
{"custom_gpu_name0", "#* Custom gpu0 model name, empty string to disable."},
|
||||
{"custom_gpu_name1", "#* Custom gpu1 model name, empty string to disable."},
|
||||
{"custom_gpu_name2", "#* Custom gpu2 model name, empty string to disable."},
|
||||
{"custom_gpu_name3", "#* Custom gpu3 model name, empty string to disable."},
|
||||
{"custom_gpu_name4", "#* Custom gpu4 model name, empty string to disable."},
|
||||
{"custom_gpu_name5", "#* Custom gpu5 model name, empty string to disable."},
|
||||
#endif
|
||||
};
|
||||
|
||||
std::unordered_map<std::string_view, string> strings = {
|
||||
{"color_theme", "Default"},
|
||||
{"shown_boxes", "net proc"},
|
||||
{"graph_symbol", "braille"},
|
||||
{"presets", "net:0:default,proc:0:default"},
|
||||
{"graph_symbol_cpu", "default"},
|
||||
{"graph_symbol_gpu", "default"},
|
||||
{"graph_symbol_mem", "default"},
|
||||
{"graph_symbol_net", "default"},
|
||||
{"graph_symbol_proc", "default"},
|
||||
{"proc_sorting", "cpu lazy"},
|
||||
{"cpu_graph_upper", "Auto"},
|
||||
{"cpu_graph_lower", "Auto"},
|
||||
{"cpu_sensor", "Auto"},
|
||||
{"selected_battery", "Auto"},
|
||||
{"cpu_core_map", ""},
|
||||
{"temp_scale", "celsius"},
|
||||
#ifdef __linux__
|
||||
{"freq_mode", "first"},
|
||||
#endif
|
||||
{"clock_format", "%X"},
|
||||
{"custom_cpu_name", ""},
|
||||
{"disks_filter", ""},
|
||||
{"io_graph_speeds", ""},
|
||||
{"net_iface", ""},
|
||||
{"base_10_bitrate", "Auto"},
|
||||
{"log_level", "WARNING"},
|
||||
{"proc_filter", ""},
|
||||
{"proc_command", ""},
|
||||
{"selected_name", ""},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"custom_gpu_name0", ""},
|
||||
{"custom_gpu_name1", ""},
|
||||
{"custom_gpu_name2", ""},
|
||||
{"custom_gpu_name3", ""},
|
||||
{"custom_gpu_name4", ""},
|
||||
{"custom_gpu_name5", ""},
|
||||
{"show_gpu_info", "Auto"},
|
||||
{"shown_gpus", "nvidia amd intel"}
|
||||
#endif
|
||||
};
|
||||
std::unordered_map<std::string_view, string> stringsTmp;
|
||||
|
||||
std::unordered_map<std::string_view, bool> bools = {
|
||||
{"theme_background", true},
|
||||
{"truecolor", true},
|
||||
{"rounded_corners", true},
|
||||
{"proc_reversed", false},
|
||||
{"proc_tree", false},
|
||||
{"proc_colors", true},
|
||||
{"proc_gradient", true},
|
||||
{"proc_per_core", false},
|
||||
{"proc_mem_bytes", true},
|
||||
{"proc_cpu_graphs", true},
|
||||
{"proc_info_smaps", false},
|
||||
{"proc_left", false},
|
||||
{"proc_filter_kernel", false},
|
||||
{"cpu_invert_lower", true},
|
||||
{"cpu_single_graph", false},
|
||||
{"cpu_bottom", false},
|
||||
{"show_uptime", true},
|
||||
{"show_cpu_watts", true},
|
||||
{"check_temp", true},
|
||||
{"show_coretemp", true},
|
||||
{"show_cpu_freq", true},
|
||||
{"background_update", true},
|
||||
{"mem_graphs", true},
|
||||
{"mem_below_net", false},
|
||||
{"zfs_arc_cached", true},
|
||||
{"show_swap", true},
|
||||
{"swap_disk", true},
|
||||
{"show_disks", true},
|
||||
{"only_physical", true},
|
||||
{"use_fstab", true},
|
||||
{"zfs_hide_datasets", false},
|
||||
{"show_io_stat", true},
|
||||
{"io_mode", false},
|
||||
{"base_10_sizes", false},
|
||||
{"io_graph_combined", false},
|
||||
{"net_auto", true},
|
||||
{"net_sync", true},
|
||||
{"show_battery", true},
|
||||
{"show_battery_watts", true},
|
||||
{"vim_keys", false},
|
||||
{"tty_mode", false},
|
||||
{"disk_free_priv", false},
|
||||
{"force_tty", false},
|
||||
{"lowcolor", false},
|
||||
{"show_detailed", false},
|
||||
{"proc_filtering", false},
|
||||
{"proc_aggregate", false},
|
||||
{"pause_proc_list", false},
|
||||
{"keep_dead_proc_usage", false},
|
||||
#ifdef GPU_SUPPORT
|
||||
{"nvml_measure_pcie_speeds", true},
|
||||
{"rsmi_measure_pcie_speeds", true},
|
||||
{"gpu_mirror_graph", true},
|
||||
#endif
|
||||
{"terminal_sync", true}
|
||||
};
|
||||
std::unordered_map<std::string_view, bool> boolsTmp;
|
||||
|
||||
std::unordered_map<std::string_view, int> ints = {
|
||||
{"update_ms", 2000},
|
||||
{"net_download", 100},
|
||||
{"net_upload", 100},
|
||||
{"detailed_pid", 0},
|
||||
{"selected_pid", 0},
|
||||
{"selected_depth", 0},
|
||||
{"proc_start", 0},
|
||||
{"proc_selected", 0},
|
||||
{"proc_last_selected", 0}
|
||||
};
|
||||
std::unordered_map<std::string_view, int> intsTmp;
|
||||
|
||||
// Returns a valid config dir or an empty optional
|
||||
// The config dir might be read only, a warning is printed, but a path is returned anyway
|
||||
[[nodiscard]] std::optional<fs::path> get_config_dir() noexcept {
|
||||
fs::path config_dir;
|
||||
{
|
||||
std::error_code error;
|
||||
if (const auto xdg_config_home = std::getenv("XDG_CONFIG_HOME"); xdg_config_home != nullptr) {
|
||||
if (fs::exists(xdg_config_home, error)) {
|
||||
config_dir = fs::path(xdg_config_home) / "btop";
|
||||
}
|
||||
} else if (const auto home = std::getenv("HOME"); home != nullptr) {
|
||||
error.clear();
|
||||
if (fs::exists(home, error)) {
|
||||
config_dir = fs::path(home) / ".config" / "btop";
|
||||
}
|
||||
if (error) {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m{} could not be accessed: {}\n", config_dir.string(), error.message());
|
||||
config_dir = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This warnings can be noisy if the user deliberately has a non-writable config dir
|
||||
// offer an alternative | disable messages by default | disable messages if config dir is not writable | disable messages with a flag
|
||||
// FIXME: Make happy path not branch
|
||||
if (not config_dir.empty()) {
|
||||
std::error_code error;
|
||||
if (fs::exists(config_dir, error)) {
|
||||
if (fs::is_directory(config_dir, error)) {
|
||||
struct statvfs stats {};
|
||||
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_write) == fs::perms::owner_write and
|
||||
statvfs(config_dir.c_str(), &stats) == 0 and (stats.f_flag & ST_RDONLY) == 0) {
|
||||
return config_dir;
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not writable\n", fs::absolute(config_dir).string());
|
||||
// If the config is readable we can still use the provided config, but changes will not be persistent
|
||||
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_read) == fs::perms::owner_read) {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
|
||||
return config_dir;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not a directory\n", fs::absolute(config_dir).string());
|
||||
}
|
||||
} else {
|
||||
// Doesn't exist
|
||||
if (fs::create_directories(config_dir, error)) {
|
||||
return config_dir;
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` could not be created: {}\n", fs::absolute(config_dir).string(), error.message());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mCould not determine config path: Make sure `$XDG_CONFIG_HOME` or `$HOME` is set\n");
|
||||
}
|
||||
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
bool _locked(const std::string_view name) {
|
||||
atomic_wait(writelock, true);
|
||||
if (not write_new and rng::find_if(descriptions, [&name](const auto& a) { return a.at(0) == name; }) != descriptions.end())
|
||||
write_new = true;
|
||||
return locked.load();
|
||||
}
|
||||
|
||||
fs::path conf_dir;
|
||||
fs::path conf_file;
|
||||
|
||||
vector<string> available_batteries = {"Auto"};
|
||||
|
||||
vector<string> current_boxes;
|
||||
vector<string> preset_list = {"cpu:0:default,mem:0:default,net:0:default,proc:0:default"};
|
||||
int current_preset = -1;
|
||||
|
||||
bool presetsValid(const string& presets) {
|
||||
vector<string> new_presets = {preset_list.at(0)};
|
||||
|
||||
for (int x = 0; const auto& preset : ssplit(presets)) {
|
||||
if (++x > 9) {
|
||||
validError = "Too many presets entered!";
|
||||
return false;
|
||||
}
|
||||
for (int y = 0; const auto& box : ssplit(preset, ',')) {
|
||||
if (++y > 4) {
|
||||
validError = "Too many boxes entered for preset!";
|
||||
return false;
|
||||
}
|
||||
const auto& vals = ssplit(box, ':');
|
||||
if (vals.size() != 3) {
|
||||
validError = "Malformatted preset in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not is_in(vals.at(0), "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5")) {
|
||||
validError = "Invalid box name in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not is_in(vals.at(1), "0", "1")) {
|
||||
validError = "Invalid position value in config value presets!";
|
||||
return false;
|
||||
}
|
||||
if (not v_contains(valid_graph_symbols_def, vals.at(2))) {
|
||||
validError = "Invalid graph name in config value presets!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
new_presets.push_back(preset);
|
||||
}
|
||||
|
||||
preset_list = std::move(new_presets);
|
||||
return true;
|
||||
}
|
||||
|
||||
//* Apply selected preset
|
||||
bool apply_preset(const string& preset) {
|
||||
string boxes;
|
||||
|
||||
for (const auto& box : ssplit(preset, ',')) {
|
||||
const auto& vals = ssplit(box, ':');
|
||||
boxes += vals.at(0) + ' ';
|
||||
}
|
||||
if (not boxes.empty()) boxes.pop_back();
|
||||
|
||||
auto min_size = Term::get_min_size(boxes);
|
||||
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& box : ssplit(preset, ',')) {
|
||||
const auto& vals = ssplit(box, ':');
|
||||
if (vals.at(0) == "cpu") {
|
||||
set("cpu_bottom", (vals.at(1) != "0"));
|
||||
} else if (vals.at(0) == "mem") {
|
||||
set("mem_below_net", (vals.at(1) != "0"));
|
||||
} else if (vals.at(0) == "proc") {
|
||||
set("proc_left", (vals.at(1) != "0"));
|
||||
}
|
||||
if (vals.at(0).starts_with("gpu")) {
|
||||
set("graph_symbol_gpu", vals.at(2));
|
||||
} else {
|
||||
set(strings.find("graph_symbol_" + vals.at(0))->first, vals.at(2));
|
||||
}
|
||||
}
|
||||
|
||||
if (set_boxes(boxes)) {
|
||||
set("shown_boxes", boxes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void lock() {
|
||||
atomic_wait(writelock);
|
||||
locked = true;
|
||||
}
|
||||
|
||||
string validError;
|
||||
|
||||
bool intValid(const std::string_view name, const string& value) {
|
||||
int i_value;
|
||||
try {
|
||||
i_value = stoi(value);
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
validError = "Invalid numerical value!";
|
||||
return false;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
validError = "Value out of range!";
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
validError = string{e.what()};
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name == "update_ms" and i_value < 100)
|
||||
validError = "Config value update_ms set too low (<100).";
|
||||
|
||||
else if (name == "update_ms" and i_value > ONE_DAY_MILLIS)
|
||||
validError = fmt::format("Config value update_ms set too high (>{}).", ONE_DAY_MILLIS);
|
||||
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool validBoxSizes(const string& boxes) {
|
||||
auto min_size = Term::get_min_size(boxes);
|
||||
return (Term::width >= min_size.at(0) and Term::height >= min_size.at(1));
|
||||
}
|
||||
|
||||
bool stringValid(const std::string_view name, const string& value) {
|
||||
if (name == "log_level" and not v_contains(Logger::log_levels, value))
|
||||
validError = "Invalid log_level: " + value;
|
||||
|
||||
else if (name == "graph_symbol" and not v_contains(valid_graph_symbols, value))
|
||||
validError = "Invalid graph symbol identifier: " + value;
|
||||
|
||||
else if (name.starts_with("graph_symbol_") and (value != "default" and not v_contains(valid_graph_symbols, value)))
|
||||
validError = fmt::format("Invalid graph symbol identifier for {}: {}", name, value);
|
||||
|
||||
else if (name == "shown_boxes" and not Global::init_conf) {
|
||||
if (value.empty())
|
||||
validError = "No boxes selected!";
|
||||
else if (not validBoxSizes(value))
|
||||
validError = "Terminal too small to display entered boxes!";
|
||||
else if (not set_boxes(value))
|
||||
validError = "Invalid box name(s) in shown_boxes!";
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef GPU_SUPPORT
|
||||
else if (name == "show_gpu_info" and not v_contains(show_gpu_values, value))
|
||||
validError = "Invalid value for show_gpu_info: " + value;
|
||||
#endif
|
||||
|
||||
else if (name == "presets" and not presetsValid(value))
|
||||
return false;
|
||||
|
||||
else if (name == "cpu_core_map") {
|
||||
const auto maps = ssplit(value);
|
||||
bool all_good = true;
|
||||
for (const auto& map : maps) {
|
||||
const auto map_split = ssplit(map, ':');
|
||||
if (map_split.size() != 2)
|
||||
all_good = false;
|
||||
else if (not isint(map_split.at(0)) or not isint(map_split.at(1)))
|
||||
all_good = false;
|
||||
|
||||
if (not all_good) {
|
||||
validError = "Invalid formatting of cpu_core_map!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (name == "io_graph_speeds") {
|
||||
const auto maps = ssplit(value);
|
||||
bool all_good = true;
|
||||
for (const auto& map : maps) {
|
||||
const auto map_split = ssplit(map, ':');
|
||||
if (map_split.size() != 2)
|
||||
all_good = false;
|
||||
else if (map_split.at(0).empty() or not isint(map_split.at(1)))
|
||||
all_good = false;
|
||||
|
||||
if (not all_good) {
|
||||
validError = "Invalid formatting of io_graph_speeds!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
else
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string getAsString(const std::string_view name) {
|
||||
if (auto it = bools.find(name); it != bools.end())
|
||||
return it->second ? "True" : "False";
|
||||
if (auto it = ints.find(name); it != ints.end())
|
||||
return to_string(it->second);
|
||||
if (auto it = strings.find(name); it != strings.end())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
void flip(const std::string_view name) {
|
||||
if (_locked(name)) {
|
||||
if (boolsTmp.contains(name)) boolsTmp.at(name) = not boolsTmp.at(name);
|
||||
else boolsTmp.insert_or_assign(name, (not bools.at(name)));
|
||||
}
|
||||
else bools.at(name) = not bools.at(name);
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
if (not locked) return;
|
||||
atomic_wait(Runner::active);
|
||||
atomic_lock lck(writelock, true);
|
||||
try {
|
||||
if (Proc::shown) {
|
||||
ints.at("selected_pid") = Proc::selected_pid;
|
||||
strings.at("selected_name") = Proc::selected_name;
|
||||
ints.at("proc_start") = Proc::start;
|
||||
ints.at("proc_selected") = Proc::selected;
|
||||
ints.at("selected_depth") = Proc::selected_depth;
|
||||
}
|
||||
|
||||
for (auto& item : stringsTmp) {
|
||||
strings.at(item.first) = item.second;
|
||||
}
|
||||
stringsTmp.clear();
|
||||
|
||||
for (auto& item : intsTmp) {
|
||||
ints.at(item.first) = item.second;
|
||||
}
|
||||
intsTmp.clear();
|
||||
|
||||
for (auto& item : boolsTmp) {
|
||||
bools.at(item.first) = item.second;
|
||||
}
|
||||
boolsTmp.clear();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Global::exit_error_msg = "Exception during Config::unlock() : " + string{e.what()};
|
||||
clean_quit(1);
|
||||
}
|
||||
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool set_boxes(const string& boxes) {
|
||||
auto new_boxes = ssplit(boxes);
|
||||
for (auto& box : new_boxes) {
|
||||
if (not v_contains(valid_boxes, box)) return false;
|
||||
#ifdef GPU_SUPPORT
|
||||
if (box.starts_with("gpu")) {
|
||||
int gpu_num = stoi(box.substr(3)) + 1;
|
||||
if (gpu_num > Gpu::count) return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
current_boxes = std::move(new_boxes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool toggle_box(const string& box) {
|
||||
auto old_boxes = current_boxes;
|
||||
auto box_pos = rng::find(current_boxes, box);
|
||||
if (box_pos == current_boxes.end())
|
||||
current_boxes.push_back(box);
|
||||
else
|
||||
current_boxes.erase(box_pos);
|
||||
|
||||
string new_boxes;
|
||||
if (not current_boxes.empty()) {
|
||||
for (const auto& b : current_boxes) new_boxes += b + ' ';
|
||||
new_boxes.pop_back();
|
||||
}
|
||||
|
||||
auto min_size = Term::get_min_size(new_boxes);
|
||||
|
||||
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
|
||||
current_boxes = old_boxes;
|
||||
return false;
|
||||
}
|
||||
|
||||
Config::set("shown_boxes", new_boxes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void load(const fs::path& conf_file, vector<string>& load_warnings) {
|
||||
std::error_code error;
|
||||
if (conf_file.empty())
|
||||
return;
|
||||
else if (not fs::exists(conf_file, error)) {
|
||||
write_new = true;
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream cread(conf_file);
|
||||
if (cread.good()) {
|
||||
vector<string> valid_names;
|
||||
valid_names.reserve(descriptions.size());
|
||||
for (const auto &n : descriptions)
|
||||
valid_names.push_back(n[0]);
|
||||
if (string v_string; cread.peek() != '#' or (getline(cread, v_string, '\n') and not v_string.contains(Global::Version)))
|
||||
write_new = true;
|
||||
while (not cread.eof()) {
|
||||
cread >> std::ws;
|
||||
if (cread.peek() == '#') {
|
||||
cread.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
string name, value;
|
||||
getline(cread, name, '=');
|
||||
if (name.ends_with(' ')) name = trim(name);
|
||||
if (not v_contains(valid_names, name)) {
|
||||
cread.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
cread >> std::ws;
|
||||
|
||||
if (bools.contains(name)) {
|
||||
cread >> value;
|
||||
if (not isbool(value))
|
||||
load_warnings.push_back("Got an invalid bool value for config name: " + name);
|
||||
else
|
||||
bools.at(name) = stobool(value);
|
||||
}
|
||||
else if (ints.contains(name)) {
|
||||
cread >> value;
|
||||
if (not isint(value))
|
||||
load_warnings.push_back("Got an invalid integer value for config name: " + name);
|
||||
else if (not intValid(name, value)) {
|
||||
load_warnings.push_back(validError);
|
||||
}
|
||||
else
|
||||
ints.at(name) = stoi(value);
|
||||
}
|
||||
else if (strings.contains(name)) {
|
||||
if (cread.peek() == '"') {
|
||||
cread.ignore(1);
|
||||
getline(cread, value, '"');
|
||||
}
|
||||
else cread >> value;
|
||||
|
||||
if (not stringValid(name, value))
|
||||
load_warnings.push_back(validError);
|
||||
else
|
||||
strings.at(name) = value;
|
||||
}
|
||||
|
||||
cread.ignore(SSmax, '\n');
|
||||
}
|
||||
|
||||
if (not load_warnings.empty()) write_new = true;
|
||||
}
|
||||
}
|
||||
|
||||
void write() {
|
||||
if (conf_file.empty() or not write_new) return;
|
||||
Logger::debug("Writing new config file");
|
||||
if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
|
||||
std::ofstream cwrite(conf_file, std::ios::trunc);
|
||||
cwrite.imbue(std::locale::classic());
|
||||
if (cwrite.good()) {
|
||||
cwrite << "#? Config file for btop v. " << Global::Version << "\n";
|
||||
for (const auto& [name, description] : descriptions) {
|
||||
cwrite << "\n" << (description.empty() ? "" : description + "\n")
|
||||
<< name << " = ";
|
||||
if (strings.contains(name))
|
||||
cwrite << "\"" << strings.at(name) << "\"";
|
||||
else if (ints.contains(name))
|
||||
cwrite << ints.at(name);
|
||||
else if (bools.contains(name))
|
||||
cwrite << (bools.at(name) ? "True" : "False");
|
||||
cwrite << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto get_xdg_state_dir() -> std::optional<fs::path> {
|
||||
std::optional<fs::path> xdg_state_home;
|
||||
|
||||
{
|
||||
const auto* xdg_state_home_ptr = std::getenv("XDG_STATE_HOME");
|
||||
if (xdg_state_home_ptr != nullptr) {
|
||||
xdg_state_home = std::make_optional(fs::path(xdg_state_home_ptr));
|
||||
} else {
|
||||
const auto* home_ptr = std::getenv("HOME");
|
||||
if (home_ptr != nullptr) {
|
||||
xdg_state_home = std::make_optional(fs::path(home_ptr) / ".local" / "state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xdg_state_home.has_value()) {
|
||||
std::error_code err;
|
||||
fs::create_directories(xdg_state_home.value(), err);
|
||||
if (err) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return xdg_state_home;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto get_log_file() -> std::optional<fs::path> {
|
||||
return get_xdg_state_dir().transform([](auto&& state_home) -> auto { return state_home / "btop.log"; });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
//* Functions and variables for reading and writing the btop config file
|
||||
namespace Config {
|
||||
|
||||
extern std::filesystem::path conf_dir;
|
||||
extern std::filesystem::path conf_file;
|
||||
|
||||
extern std::unordered_map<std::string_view, string> strings;
|
||||
extern std::unordered_map<std::string_view, string> stringsTmp;
|
||||
extern std::unordered_map<std::string_view, bool> bools;
|
||||
extern std::unordered_map<std::string_view, bool> boolsTmp;
|
||||
extern std::unordered_map<std::string_view, int> ints;
|
||||
extern std::unordered_map<std::string_view, int> intsTmp;
|
||||
|
||||
const vector<string> valid_graph_symbols = { "braille", "block", "tty" };
|
||||
const vector<string> valid_graph_symbols_def = { "default", "braille", "block", "tty" };
|
||||
const vector<string> valid_boxes = {
|
||||
"cpu", "mem", "net", "proc"
|
||||
#ifdef GPU_SUPPORT
|
||||
,"gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5"
|
||||
#endif
|
||||
};
|
||||
const vector<string> temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" };
|
||||
#ifdef __linux__
|
||||
const vector<string> freq_modes = { "first", "range", "lowest", "highest", "average" };
|
||||
#endif
|
||||
#ifdef GPU_SUPPORT
|
||||
const vector<string> show_gpu_values = { "Auto", "On", "Off" };
|
||||
#endif
|
||||
const vector<string> base_10_bitrate_values = { "Auto", "True", "False" };
|
||||
extern vector<string> current_boxes;
|
||||
extern vector<string> preset_list;
|
||||
extern vector<string> available_batteries;
|
||||
extern int current_preset;
|
||||
|
||||
constexpr int ONE_DAY_MILLIS = 1000 * 60 * 60 * 24;
|
||||
|
||||
[[nodiscard]] std::optional<std::filesystem::path> get_config_dir() noexcept;
|
||||
|
||||
//* Check if string only contains space separated valid names for boxes and set current_boxes
|
||||
bool set_boxes(const string& boxes);
|
||||
|
||||
bool validBoxSizes(const string& boxes);
|
||||
|
||||
//* Toggle box and update config string shown_boxes
|
||||
bool toggle_box(const string& box);
|
||||
|
||||
//* Parse and setup config value presets
|
||||
bool presetsValid(const string& presets);
|
||||
|
||||
//* Apply selected preset
|
||||
bool apply_preset(const string& preset);
|
||||
|
||||
bool _locked(const std::string_view name);
|
||||
|
||||
//* Return bool for config key <name>
|
||||
inline bool getB(const std::string_view name) { return bools.at(name); }
|
||||
|
||||
//* Return integer for config key <name>
|
||||
inline const int& getI(const std::string_view name) { return ints.at(name); }
|
||||
|
||||
//* Return string for config key <name>
|
||||
inline const string& getS(const std::string_view name) { return strings.at(name); }
|
||||
|
||||
string getAsString(const std::string_view name);
|
||||
|
||||
extern string validError;
|
||||
|
||||
bool intValid(const std::string_view name, const string& value);
|
||||
bool stringValid(const std::string_view name, const string& value);
|
||||
|
||||
//* Set config key <name> to bool <value>
|
||||
inline void set(const std::string_view name, bool value) {
|
||||
if (_locked(name)) boolsTmp.insert_or_assign(name, value);
|
||||
else bools.at(name) = value;
|
||||
}
|
||||
|
||||
//* Set config key <name> to int <value>
|
||||
inline void set(const std::string_view name, const int value) {
|
||||
if (_locked(name)) intsTmp.insert_or_assign(name, value);
|
||||
else ints.at(name) = value;
|
||||
}
|
||||
|
||||
//* Set config key <name> to string <value>
|
||||
inline void set(const std::string_view name, const string& value) {
|
||||
if (_locked(name)) stringsTmp.insert_or_assign(name, value);
|
||||
else strings.at(name) = value;
|
||||
}
|
||||
|
||||
//* Flip config key bool <name>
|
||||
void flip(const std::string_view name);
|
||||
|
||||
//* Lock config and cache changes until unlocked
|
||||
void lock();
|
||||
|
||||
//* Unlock config and write any cached values to config
|
||||
void unlock();
|
||||
|
||||
//* Load the config file from disk
|
||||
void load(const std::filesystem::path& conf_file, vector<string>& load_warnings);
|
||||
|
||||
//* Write the config file to disk
|
||||
void write();
|
||||
|
||||
auto get_log_file() -> std::optional<std::filesystem::path>;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using std::array;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Symbols {
|
||||
const string h_line = "─";
|
||||
const string v_line = "│";
|
||||
const string dotted_v_line = "╎";
|
||||
const string left_up = "┌";
|
||||
const string right_up = "┐";
|
||||
const string left_down = "└";
|
||||
const string right_down = "┘";
|
||||
const string round_left_up = "╭";
|
||||
const string round_right_up = "╮";
|
||||
const string round_left_down = "╰";
|
||||
const string round_right_down = "╯";
|
||||
const string title_left_down = "┘";
|
||||
const string title_right_down = "└";
|
||||
const string title_left = "┐";
|
||||
const string title_right = "┌";
|
||||
const string div_right = "┤";
|
||||
const string div_left = "├";
|
||||
const string div_up = "┬";
|
||||
const string div_down = "┴";
|
||||
|
||||
|
||||
const string up = "↑";
|
||||
const string down = "↓";
|
||||
const string left = "←";
|
||||
const string right = "→";
|
||||
const string enter = "↵";
|
||||
}
|
||||
|
||||
namespace Draw {
|
||||
|
||||
//* Generate if needed and return the btop++ banner
|
||||
string banner_gen(int y=0, int x=0, bool centered=false, bool redraw=false);
|
||||
|
||||
//* An editable text field
|
||||
class TextEdit {
|
||||
size_t pos{};
|
||||
size_t upos{};
|
||||
bool numeric = false;
|
||||
public:
|
||||
string text;
|
||||
TextEdit();
|
||||
explicit TextEdit(string text, bool numeric=false);
|
||||
bool command(const std::string_view key);
|
||||
string operator()(const size_t limit=0);
|
||||
void clear();
|
||||
};
|
||||
|
||||
//* Create a box and return as a string
|
||||
string createBox(
|
||||
const int x, const int y, const int width, const int height, string line_color = "", bool fill = false,
|
||||
const std::string_view title = "", const std::string_view title2 = "", const int num = 0
|
||||
);
|
||||
|
||||
bool update_clock(bool force = false);
|
||||
|
||||
//* Class holding a percentage meter
|
||||
class Meter {
|
||||
int width;
|
||||
string color_gradient;
|
||||
bool invert;
|
||||
array<string, 101> cache;
|
||||
public:
|
||||
Meter();
|
||||
Meter(const int width, string color_gradient, bool invert = false);
|
||||
|
||||
//* Return a string representation of the meter with given value
|
||||
string operator()(int value);
|
||||
};
|
||||
|
||||
//* Class holding a percentage graph
|
||||
class Graph {
|
||||
int width, height;
|
||||
string color_gradient;
|
||||
string out, symbol = "default";
|
||||
bool invert, no_zero;
|
||||
long long offset;
|
||||
long long last = 0, max_value = 0;
|
||||
bool current = true, tty_mode = false;
|
||||
std::unordered_map<bool, vector<string>> graphs = { {true, {}}, {false, {}}};
|
||||
|
||||
//* Create two representations of the graph to switch between to represent two values for each braille character
|
||||
void _create(const deque<long long>& data, int data_offset);
|
||||
|
||||
public:
|
||||
Graph();
|
||||
Graph(int width, int height,
|
||||
const string& color_gradient,
|
||||
const deque<long long>& data,
|
||||
const string& symbol="default",
|
||||
bool invert=false, bool no_zero=false,
|
||||
long long max_value=0, long long offset=0);
|
||||
|
||||
//* Add last value from back of <data> and return string representation of graph
|
||||
string& operator()(const deque<long long>& data, bool data_same=false);
|
||||
|
||||
//* Return string representation of graph
|
||||
string& operator()();
|
||||
};
|
||||
|
||||
//* Calculate sizes of boxes, draw outlines and save to enabled boxes namespaces
|
||||
void calcSizes();
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
extern Draw::TextEdit filter;
|
||||
extern std::unordered_map<size_t, Draw::Graph> p_graphs;
|
||||
extern std::unordered_map<size_t, int> p_counters;
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <fmt/format.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <utility>
|
||||
|
||||
#include "btop_input.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_menu.hpp"
|
||||
#include "btop_draw.hpp"
|
||||
|
||||
using namespace Tools;
|
||||
using namespace std::literals; // for operator""s
|
||||
namespace rng = std::ranges;
|
||||
|
||||
namespace Input {
|
||||
|
||||
//* Map for translating key codes to readable values
|
||||
const std::unordered_map<string, string> Key_escapes = {
|
||||
{"\033", "escape"},
|
||||
{"\x12", "ctrl_r"},
|
||||
{"\n", "enter"},
|
||||
{" ", "space"},
|
||||
{"\x7f", "backspace"},
|
||||
{"\x08", "backspace"},
|
||||
{"[A", "up"},
|
||||
{"OA", "up"},
|
||||
{"[B", "down"},
|
||||
{"OB", "down"},
|
||||
{"[D", "left"},
|
||||
{"OD", "left"},
|
||||
{"[C", "right"},
|
||||
{"OC", "right"},
|
||||
{"[2~", "insert"},
|
||||
{"[4h", "insert"},
|
||||
{"[3~", "delete"},
|
||||
{"[P", "delete"},
|
||||
{"[H", "home"},
|
||||
{"[1~", "home"},
|
||||
{"[F", "end"},
|
||||
{"[4~", "end"},
|
||||
{"[5~", "page_up"},
|
||||
{"[6~", "page_down"},
|
||||
{"\t", "tab"},
|
||||
{"[Z", "shift_tab"},
|
||||
{"OP", "f1"},
|
||||
{"OQ", "f2"},
|
||||
{"OR", "f3"},
|
||||
{"OS", "f4"},
|
||||
{"[15~", "f5"},
|
||||
{"[17~", "f6"},
|
||||
{"[18~", "f7"},
|
||||
{"[19~", "f8"},
|
||||
{"[20~", "f9"},
|
||||
{"[21~", "f10"},
|
||||
{"[23~", "f11"},
|
||||
{"[24~", "f12"}
|
||||
};
|
||||
|
||||
sigset_t signal_mask;
|
||||
std::atomic<bool> polling (false);
|
||||
array<int, 2> mouse_pos;
|
||||
std::unordered_map<string, Mouse_loc> mouse_mappings;
|
||||
|
||||
deque<string> history(50, "");
|
||||
string old_filter;
|
||||
string input;
|
||||
|
||||
bool poll(const uint64_t timeout) {
|
||||
atomic_lock lck(polling);
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
struct timespec wait;
|
||||
struct timespec *waitptr = nullptr;
|
||||
|
||||
if(timeout != std::numeric_limits<uint64_t>::max()) {
|
||||
wait.tv_sec = timeout / 1000;
|
||||
wait.tv_nsec = (timeout % 1000) * 1000000;
|
||||
waitptr = &wait;
|
||||
}
|
||||
|
||||
if(pselect(STDIN_FILENO + 1, &fds, nullptr, nullptr, waitptr, &signal_mask) > 0) {
|
||||
input.clear();
|
||||
char buf[1024];
|
||||
ssize_t count = 0;
|
||||
while((count = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
|
||||
input.append(std::string_view(buf, count));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string get() {
|
||||
string key = input;
|
||||
if (not key.empty()) {
|
||||
//? Remove escape code prefix if present
|
||||
if (key.length() > 1 and key.at(0) == Fx::e.at(0)) {
|
||||
key.erase(0, 1);
|
||||
}
|
||||
//? Detect if input is an mouse event
|
||||
if (key.starts_with("[<")) {
|
||||
std::string_view key_view = key;
|
||||
string mouse_event;
|
||||
if (key_view.starts_with("[<0;") and key_view.find('M') != std::string_view::npos) {
|
||||
mouse_event = "mouse_click";
|
||||
key_view.remove_prefix(4);
|
||||
}
|
||||
// else if (key_view.starts_with("[<0;") and key_view.ends_with('m')) {
|
||||
// mouse_event = "mouse_release";
|
||||
// key_view.remove_prefix(4);
|
||||
// }
|
||||
else if (key_view.starts_with("[<64;")) {
|
||||
mouse_event = "mouse_scroll_up";
|
||||
key_view.remove_prefix(5);
|
||||
}
|
||||
else if (key_view.starts_with("[<65;")) {
|
||||
mouse_event = "mouse_scroll_down";
|
||||
key_view.remove_prefix(5);
|
||||
}
|
||||
else
|
||||
key.clear();
|
||||
|
||||
if (Config::getB("proc_filtering")) {
|
||||
if (mouse_event == "mouse_click") return mouse_event;
|
||||
else return "";
|
||||
}
|
||||
|
||||
//? Get column and line position of mouse and check for any actions mapped to current position
|
||||
if (not key.empty()) {
|
||||
try {
|
||||
const auto delim = key_view.find(';');
|
||||
mouse_pos[0] = stoi((string)key_view.substr(0, delim));
|
||||
mouse_pos[1] = stoi((string)key_view.substr(delim + 1, key_view.find('M', delim)));
|
||||
}
|
||||
catch (const std::invalid_argument&) { mouse_event.clear(); }
|
||||
catch (const std::out_of_range&) { mouse_event.clear(); }
|
||||
|
||||
key = mouse_event;
|
||||
|
||||
if (key == "mouse_click") {
|
||||
const auto& [col, line] = mouse_pos;
|
||||
|
||||
for (const auto& [mapped_key, pos] : (Menu::active ? Menu::mouse_mappings : mouse_mappings)) {
|
||||
if (col >= pos.col and col < pos.col + pos.width and line >= pos.line and line < pos.line + pos.height) {
|
||||
key = mapped_key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (auto it = Key_escapes.find(key); it != Key_escapes.end())
|
||||
key = it->second;
|
||||
else if (ulen(key) > 1)
|
||||
key.clear();
|
||||
|
||||
if (not key.empty()) {
|
||||
history.push_back(key);
|
||||
history.pop_front();
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
string wait() {
|
||||
while(not poll(std::numeric_limits<uint64_t>::max())) {}
|
||||
return get();
|
||||
}
|
||||
|
||||
void interrupt() {
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
// do not need it, actually
|
||||
}
|
||||
|
||||
void process(const std::string_view key) {
|
||||
if (key.empty()) return;
|
||||
try {
|
||||
auto filtering = Config::getB("proc_filtering");
|
||||
auto vim_keys = Config::getB("vim_keys");
|
||||
auto help_key = (vim_keys ? "H" : "h");
|
||||
auto kill_key = (vim_keys ? "K" : "k");
|
||||
//? Global input actions
|
||||
if (not filtering) {
|
||||
bool keep_going = false;
|
||||
if (key == "q") {
|
||||
clean_quit(0);
|
||||
}
|
||||
else if (is_in(key, "escape", "m")) {
|
||||
Menu::show(Menu::Menus::Main);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "f1", "?", help_key)) {
|
||||
Menu::show(Menu::Menus::Help);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "f2", "o")) {
|
||||
Menu::show(Menu::Menus::Options);
|
||||
return;
|
||||
}
|
||||
else if (key.size() == 1 and isint(key)) {
|
||||
auto intKey = std::atoi(key.data());
|
||||
// AltData: 1=net, 2=proc,其他屏蔽
|
||||
if (intKey != 1 and intKey != 2)
|
||||
return;
|
||||
// 映射: 1->net(3), 2->proc(4)
|
||||
static const array<string, 3> altBoxes = {"", "net", "proc"};
|
||||
atomic_wait(Runner::active);
|
||||
|
||||
if (not Config::toggle_box(altBoxes.at(intKey))) {
|
||||
Menu::show(Menu::Menus::SizeError);
|
||||
return;
|
||||
}
|
||||
Config::current_preset = -1;
|
||||
Draw::calcSizes();
|
||||
Runner::run("all", false, true);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "p", "P") and Config::preset_list.size() > 1) {
|
||||
const auto old_preset = Config::current_preset;
|
||||
if (key == "p") {
|
||||
if (++Config::current_preset >= (int)Config::preset_list.size()) Config::current_preset = 0;
|
||||
}
|
||||
else {
|
||||
if (--Config::current_preset < 0) Config::current_preset = Config::preset_list.size() - 1;
|
||||
}
|
||||
atomic_wait(Runner::active);
|
||||
if (not Config::apply_preset(Config::preset_list.at(Config::current_preset))) {
|
||||
Menu::show(Menu::Menus::SizeError);
|
||||
Config::current_preset = old_preset;
|
||||
return;
|
||||
}
|
||||
Draw::calcSizes();
|
||||
Runner::run("all", false, true);
|
||||
return;
|
||||
} else if (is_in(key, "ctrl_r")) {
|
||||
kill(getpid(), SIGUSR2);
|
||||
return;
|
||||
} else
|
||||
keep_going = true;
|
||||
|
||||
if (not keep_going) return;
|
||||
}
|
||||
|
||||
//? Input actions for proc box
|
||||
if (Proc::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
if (filtering) {
|
||||
if (key == "enter" or key == "down") {
|
||||
Config::set("proc_filter", Proc::filter.text);
|
||||
Config::set("proc_filtering", false);
|
||||
old_filter.clear();
|
||||
if(key == "down"){
|
||||
Config::unlock();
|
||||
Config::lock();
|
||||
process("down");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (key == "escape" or key == "mouse_click") {
|
||||
Config::set("proc_filter", old_filter);
|
||||
Config::set("proc_filtering", false);
|
||||
old_filter.clear();
|
||||
}
|
||||
else if (Proc::filter.command(key)) {
|
||||
if (Config::getS("proc_filter") != Proc::filter.text)
|
||||
Config::set("proc_filter", Proc::filter.text);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else if (key == "left" or (vim_keys and key == "h")) {
|
||||
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
|
||||
if (--cur_i < 0)
|
||||
cur_i = Proc::sort_vector.size() - 1;
|
||||
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
|
||||
}
|
||||
else if (key == "right" or (vim_keys and key == "l")) {
|
||||
int cur_i = v_index(Proc::sort_vector, Config::getS("proc_sorting"));
|
||||
if (std::cmp_greater(++cur_i, Proc::sort_vector.size() - 1))
|
||||
cur_i = 0;
|
||||
Config::set("proc_sorting", Proc::sort_vector.at(cur_i));
|
||||
}
|
||||
else if (is_in(key, "f", "/")) {
|
||||
Config::flip("proc_filtering");
|
||||
Proc::filter = Draw::TextEdit{Config::getS("proc_filter")};
|
||||
old_filter = Proc::filter.text;
|
||||
}
|
||||
else if (key == "e") {
|
||||
Config::flip("proc_tree");
|
||||
no_update = false;
|
||||
}
|
||||
else if (is_in(key, "F")) {
|
||||
Config::flip("pause_proc_list");
|
||||
redraw = true;
|
||||
}
|
||||
else if (key == "r")
|
||||
Config::flip("proc_reversed");
|
||||
|
||||
else if (key == "c")
|
||||
Config::flip("proc_per_core");
|
||||
|
||||
else if (key == "%")
|
||||
Config::flip("proc_mem_bytes");
|
||||
|
||||
else if (key == "delete" and not Config::getS("proc_filter").empty())
|
||||
Config::set("proc_filter", ""s);
|
||||
|
||||
else if (key.starts_with("mouse_")) {
|
||||
redraw = false;
|
||||
const auto& [col, line] = mouse_pos;
|
||||
const int y = (Config::getB("show_detailed") ? Proc::y + 8 : Proc::y);
|
||||
const int height = (Config::getB("show_detailed") ? Proc::height - 8 : Proc::height);
|
||||
if (col >= Proc::x + 1 and col < Proc::x + Proc::width and line >= y + 1 and line < y + height - 1) {
|
||||
if (key == "mouse_click") {
|
||||
if (col < Proc::x + Proc::width - 2) {
|
||||
const auto& current_selection = Config::getI("proc_selected");
|
||||
if (current_selection == line - y - 1) {
|
||||
redraw = true;
|
||||
if (Config::getB("proc_tree")) {
|
||||
const int x_pos = col - Proc::x;
|
||||
const int offset = Config::getI("selected_depth") * 3;
|
||||
if (x_pos > offset and x_pos < 4 + offset) {
|
||||
process("space");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// AltData: disable enter-triggered detail toggle
|
||||
return;
|
||||
}
|
||||
else if (current_selection == 0 or line - y - 1 == 0)
|
||||
redraw = true;
|
||||
Config::set("proc_selected", line - y - 1);
|
||||
}
|
||||
else if (line == y + 1) {
|
||||
if (Proc::selection("page_up") == -1) return;
|
||||
}
|
||||
else if (line == y + height - 2) {
|
||||
if (Proc::selection("page_down") == -1) return;
|
||||
}
|
||||
else if (Proc::selection("mousey" + to_string(line - y - 2)) == -1)
|
||||
return;
|
||||
}
|
||||
else
|
||||
goto proc_mouse_scroll;
|
||||
}
|
||||
else if (key == "mouse_click" and Config::getI("proc_selected") > 0) {
|
||||
Config::set("proc_selected", 0);
|
||||
redraw = true;
|
||||
}
|
||||
else
|
||||
keep_going = true;
|
||||
}
|
||||
else if (key == "enter") {
|
||||
// AltData: disable enter-triggered detail toggle
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "+", "-", "space", "u") and Config::getB("proc_tree") and Config::getI("proc_selected") > 0) {
|
||||
atomic_wait(Runner::active);
|
||||
auto& pid = Config::getI("selected_pid");
|
||||
if (key == "+" or key == "space") Proc::expand = pid;
|
||||
if (key == "-" or key == "space") Proc::collapse = pid;
|
||||
if (key == "u") Proc::toggle_children = pid;
|
||||
no_update = false;
|
||||
}
|
||||
else if (is_in(key, "t", kill_key) and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::SignalSend, (key == "t" ? SIGTERM : SIGKILL));
|
||||
return;
|
||||
}
|
||||
else if (key == "s" and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::SignalChoose);
|
||||
return;
|
||||
}
|
||||
else if (key == "N" and (Config::getB("show_detailed") or Config::getI("selected_pid") > 0)) {
|
||||
atomic_wait(Runner::active);
|
||||
if (Config::getB("show_detailed") and Config::getI("proc_selected") == 0 and Proc::detailed.status == "Dead") return;
|
||||
Menu::show(Menu::Menus::Renice);
|
||||
return;
|
||||
}
|
||||
else if (is_in(key, "up", "down", "page_up", "page_down", "home", "end") or (vim_keys and is_in(key, "j", "k", "g", "G"))) {
|
||||
proc_mouse_scroll:
|
||||
redraw = false;
|
||||
auto old_selected = Config::getI("proc_selected");
|
||||
auto new_selected = Proc::selection(key);
|
||||
if (new_selected == -1)
|
||||
return;
|
||||
else if (old_selected != new_selected and (old_selected == 0 or new_selected == 0))
|
||||
redraw = true;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("proc", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for cpu box
|
||||
if (Cpu::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
static uint64_t last_press = 0;
|
||||
|
||||
if (key == "+" and Config::getI("update_ms") <= 86399900) {
|
||||
int add = (Config::getI("update_ms") <= 86399000 and last_press >= time_ms() - 200
|
||||
and rng::all_of(Input::history, [](const auto& str){ return str == "+"; })
|
||||
? 1000 : 100);
|
||||
Config::set("update_ms", Config::getI("update_ms") + add);
|
||||
last_press = time_ms();
|
||||
redraw = true;
|
||||
}
|
||||
else if (key == "-" and Config::getI("update_ms") >= 200) {
|
||||
int sub = (Config::getI("update_ms") >= 2000 and last_press >= time_ms() - 200
|
||||
and rng::all_of(Input::history, [](const auto& str){ return str == "-"; })
|
||||
? 1000 : 100);
|
||||
Config::set("update_ms", Config::getI("update_ms") - sub);
|
||||
last_press = time_ms();
|
||||
redraw = true;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("cpu", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for mem box
|
||||
if (Mem::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
|
||||
if (key == "i") {
|
||||
Config::flip("io_mode");
|
||||
}
|
||||
else if (key == "d") {
|
||||
Config::flip("show_disks");
|
||||
no_update = false;
|
||||
Draw::calcSizes();
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("mem", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//? Input actions for net box
|
||||
if (Net::shown) {
|
||||
bool keep_going = false;
|
||||
bool no_update = true;
|
||||
bool redraw = true;
|
||||
|
||||
if (is_in(key, "b", "n")) {
|
||||
atomic_wait(Runner::active);
|
||||
int c_index = v_index(Net::interfaces, Net::selected_iface);
|
||||
if (c_index != (int)Net::interfaces.size()) {
|
||||
if (key == "b") {
|
||||
if (--c_index < 0) c_index = Net::interfaces.size() - 1;
|
||||
}
|
||||
else if (key == "n") {
|
||||
if (++c_index == (int)Net::interfaces.size()) c_index = 0;
|
||||
}
|
||||
Net::selected_iface = Net::interfaces.at(c_index);
|
||||
Net::rescale = true;
|
||||
}
|
||||
}
|
||||
else if (key == "y") {
|
||||
Config::flip("net_sync");
|
||||
Net::rescale = true;
|
||||
}
|
||||
else if (key == "a") {
|
||||
Config::flip("net_auto");
|
||||
Net::rescale = true;
|
||||
}
|
||||
else if (key == "z") {
|
||||
atomic_wait(Runner::active);
|
||||
auto& ndev = Net::current_net.at(Net::selected_iface);
|
||||
if (ndev.stat.at("download").offset + ndev.stat.at("upload").offset > 0) {
|
||||
ndev.stat.at("download").offset = 0;
|
||||
ndev.stat.at("upload").offset = 0;
|
||||
}
|
||||
else {
|
||||
ndev.stat.at("download").offset = ndev.stat.at("download").last + ndev.stat.at("download").rollover;
|
||||
ndev.stat.at("upload").offset = ndev.stat.at("upload").last + ndev.stat.at("upload").rollover;
|
||||
}
|
||||
no_update = false;
|
||||
}
|
||||
else keep_going = true;
|
||||
|
||||
if (not keep_going) {
|
||||
Runner::run("net", no_update, redraw);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch (const std::exception& e) {
|
||||
throw std::runtime_error { fmt::format(R"(Input::process("{}"))", e.what()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
|
||||
/* The input functions rely on the following termios parameters being set:
|
||||
Non-canonical mode (c_lflags & ~(ICANON))
|
||||
VMIN and VTIME (c_cc) set to 0
|
||||
These will automatically be set when running Term::init() from btop_tools.cpp
|
||||
*/
|
||||
|
||||
//* Functions and variables for handling keyboard and mouse input
|
||||
namespace Input {
|
||||
|
||||
struct Mouse_loc {
|
||||
int line, col, height, width;
|
||||
};
|
||||
|
||||
//? line, col, height, width
|
||||
extern std::unordered_map<string, Mouse_loc> mouse_mappings;
|
||||
|
||||
//* Signal mask used during polling read
|
||||
extern sigset_t signal_mask;
|
||||
|
||||
extern atomic<bool> polling;
|
||||
|
||||
//* Mouse column and line position
|
||||
extern array<int, 2> mouse_pos;
|
||||
|
||||
//* Last entered key
|
||||
extern deque<string> history;
|
||||
|
||||
//* Poll keyboard & mouse input for <timeout> ms and return input availability as a bool
|
||||
bool poll(const uint64_t timeout=0);
|
||||
|
||||
//* Get a key or mouse action from input
|
||||
string get();
|
||||
|
||||
//* Wait until input is available and return key
|
||||
string wait();
|
||||
|
||||
//* Interrupt poll/wait
|
||||
void interrupt();
|
||||
|
||||
//* Clears last entered key
|
||||
void clear();
|
||||
|
||||
//* Process actions for input <key>
|
||||
void process(const std::string_view key);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "btop_input.hpp"
|
||||
|
||||
using std::atomic;
|
||||
using std::bitset;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Menu {
|
||||
|
||||
extern atomic<bool> active;
|
||||
extern string output;
|
||||
extern int signalToSend;
|
||||
extern bool redraw;
|
||||
|
||||
//? line, col, height, width
|
||||
extern std::unordered_map<string, Input::Mouse_loc> mouse_mappings;
|
||||
|
||||
//* Creates a message box centered on screen
|
||||
//? Height of box is determined by size of content vector
|
||||
//? Boxtypes: 0 = OK button | 1 = YES and NO with YES selected | 2 = Same as 1 but with NO selected
|
||||
//? Strings in content vector is not checked for box width overflow
|
||||
class msgBox {
|
||||
string box_contents, button_left, button_right;
|
||||
int height{};
|
||||
int width{};
|
||||
int boxtype{};
|
||||
int selected{};
|
||||
int x{};
|
||||
int y{};
|
||||
public:
|
||||
enum BoxTypes { OK, YES_NO, NO_YES };
|
||||
enum msgReturn {
|
||||
Invalid,
|
||||
Ok_Yes,
|
||||
No_Esc,
|
||||
Select
|
||||
};
|
||||
msgBox();
|
||||
msgBox(int width, int boxtype, const vector<string>& content, std::string_view title);
|
||||
|
||||
//? Draw and return box as a string
|
||||
string operator()();
|
||||
|
||||
//? Process input and returns value from enum Ret
|
||||
int input(const string& key);
|
||||
|
||||
//? Clears content vector and private strings
|
||||
void clear();
|
||||
int getX() const { return x; }
|
||||
int getY() const { return y; }
|
||||
};
|
||||
|
||||
extern bitset<8> menuMask;
|
||||
|
||||
//* Enum for functions in vector menuFuncs
|
||||
enum Menus {
|
||||
SizeError,
|
||||
SignalChoose,
|
||||
SignalSend,
|
||||
SignalReturn,
|
||||
Options,
|
||||
Help,
|
||||
Renice,
|
||||
Main
|
||||
};
|
||||
|
||||
//* Handles redirection of input for menu functions and handles return codes
|
||||
void process(const std::string_view key = "");
|
||||
|
||||
//* Show a menu from enum Menu::Menus
|
||||
void show(int menu, int signal=-1);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
using namespace Tools;
|
||||
|
||||
namespace Cpu {
|
||||
std::optional<std::string> container_engine;
|
||||
|
||||
string trim_name(string name) {
|
||||
auto name_vec = ssplit(name);
|
||||
|
||||
if ((name.contains("Xeon") or v_contains(name_vec, "Duo"s)) and v_contains(name_vec, "CPU"s)) {
|
||||
auto cpu_pos = v_index(name_vec, "CPU"s);
|
||||
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')'))
|
||||
name = name_vec.at(cpu_pos + 1);
|
||||
else
|
||||
name.clear();
|
||||
} else if (v_contains(name_vec, "Ryzen"s)) {
|
||||
auto ryz_pos = v_index(name_vec, "Ryzen"s);
|
||||
name = "Ryzen";
|
||||
int tokens = 0;
|
||||
for (auto i = ryz_pos + 1; i < name_vec.size() && tokens < 2; i++) {
|
||||
const std::string& p = name_vec.at(i);
|
||||
if (p != "AI" && p != "PRO" && p != "H" && p != "HX")
|
||||
tokens++;
|
||||
name += " " + p;
|
||||
}
|
||||
} else if (name.contains("Intel") and v_contains(name_vec, "CPU"s)) {
|
||||
auto cpu_pos = v_index(name_vec, "CPU"s);
|
||||
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')') and name_vec.at(cpu_pos + 1) != "@")
|
||||
name = name_vec.at(cpu_pos + 1);
|
||||
else
|
||||
name.clear();
|
||||
} else
|
||||
name.clear();
|
||||
|
||||
if (name.empty() and not name_vec.empty()) {
|
||||
for (const auto &n : name_vec) {
|
||||
if (n == "@") break;
|
||||
name += n + ' ';
|
||||
}
|
||||
name.pop_back();
|
||||
for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Apple", "Core"}) {
|
||||
name = s_replace(name, replace, "");
|
||||
name = s_replace(name, " ", " ");
|
||||
}
|
||||
name = trim(name);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GPU_SUPPORT
|
||||
namespace Gpu {
|
||||
vector<string> gpu_names;
|
||||
vector<int> gpu_b_height_offsets;
|
||||
std::unordered_map<string, deque<long long>> shared_gpu_percent = {
|
||||
{"gpu-average", {}},
|
||||
{"gpu-vram-total", {}},
|
||||
{"gpu-pwr-total", {}},
|
||||
};
|
||||
long long gpu_pwr_total_max = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Proc {
|
||||
bool set_priority(pid_t pid, int priority) {
|
||||
if (setpriority(PRIO_PROCESS, pid, priority) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void proc_sorter(vector<proc_info>& proc_vec, const string& sorting, bool reverse, bool tree) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::less{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::less{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::less{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 0: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::pid); break;
|
||||
case 1: rng::stable_sort(proc_vec, rng::less{}, &proc_info::name); break;
|
||||
case 2: rng::stable_sort(proc_vec, rng::less{}, &proc_info::cmd); break;
|
||||
case 3: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::threads); break;
|
||||
case 4: rng::stable_sort(proc_vec, rng::less{}, &proc_info::user); break;
|
||||
case 5: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::mem); break;
|
||||
case 6: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_p); break;
|
||||
case 7: rng::stable_sort(proc_vec, rng::greater{}, &proc_info::cpu_c); break;
|
||||
}
|
||||
}
|
||||
|
||||
//* When sorting with "cpu lazy" push processes over threshold cpu usage to the front regardless of cumulative usage
|
||||
if (not tree and not reverse and sorting == "cpu lazy") {
|
||||
double max = 10.0, target = 30.0;
|
||||
for (size_t i = 0, x = 0, offset = 0; i < proc_vec.size(); i++) {
|
||||
if (i <= 5 and proc_vec.at(i).cpu_p > max)
|
||||
max = proc_vec.at(i).cpu_p;
|
||||
else if (i == 6)
|
||||
target = (max > 30.0) ? max : 10.0;
|
||||
if (i == offset and proc_vec.at(i).cpu_p > 30.0)
|
||||
offset++;
|
||||
else if (proc_vec.at(i).cpu_p > target) {
|
||||
rotate(proc_vec.begin() + offset, proc_vec.begin() + i, proc_vec.begin() + i + 1);
|
||||
if (++x > 10) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, bool reverse, bool paused, int& c_index, const int index_max, bool collapsed) {
|
||||
if (proc_vec.size() > 1 and not paused) {
|
||||
if (reverse) {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads < b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem < b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p < b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c < b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (v_index(sort_vector, sorting)) {
|
||||
case 3: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().threads > b.entry.get().threads; }); break;
|
||||
case 5: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().mem > b.entry.get().mem; }); break;
|
||||
case 6: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_p > b.entry.get().cpu_p; }); break;
|
||||
case 7: rng::stable_sort(proc_vec, [](const auto& a, const auto& b) { return a.entry.get().cpu_c > b.entry.get().cpu_c; }); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& r : proc_vec) {
|
||||
r.entry.get().tree_index = (collapsed or r.entry.get().filtered ? index_max : c_index++);
|
||||
if (not r.children.empty()) {
|
||||
tree_sort(r.children, sorting, reverse, paused, c_index, (collapsed or r.entry.get().collapsed or r.entry.get().tree_index == (size_t)index_max));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto matches_filter(const proc_info& proc, const std::string& filter) -> bool {
|
||||
if (filter.starts_with("!")) {
|
||||
if (filter.size() == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// An incomplete regex throws, see issue https://github.com/aristocratos/btop/issues/1133
|
||||
try {
|
||||
std::regex regex { filter.substr(1), std::regex::extended };
|
||||
return std::regex_search(std::to_string(proc.pid), regex) || std::regex_search(proc.name, regex) ||
|
||||
std::regex_match(proc.cmd, regex) || std::regex_search(proc.user, regex);
|
||||
} catch (std::regex_error& /* unused */) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return std::to_string(proc.pid).contains(filter) || s_contains_ic(proc.name, filter) ||
|
||||
s_contains_ic(proc.cmd, filter) || s_contains_ic(proc.user, filter);
|
||||
}
|
||||
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs,
|
||||
int cur_depth, bool collapsed, const string& filter, bool found, bool no_update, bool should_filter) {
|
||||
bool filtering = false;
|
||||
|
||||
//? If filtering, include children of matching processes
|
||||
if (not found and (should_filter or not filter.empty())) {
|
||||
if (!matches_filter(cur_proc, filter)) {
|
||||
filtering = true;
|
||||
cur_proc.filtered = true;
|
||||
filter_found++;
|
||||
}
|
||||
else {
|
||||
found = true;
|
||||
cur_depth = 0;
|
||||
}
|
||||
}
|
||||
else if (cur_proc.filtered) cur_proc.filtered = false;
|
||||
|
||||
cur_proc.depth = cur_depth;
|
||||
|
||||
//? Set tree index position for process if not filtered out or currently in a collapsed sub-tree
|
||||
out_procs.push_back({ cur_proc, {} });
|
||||
if (not collapsed and not filtering) {
|
||||
cur_proc.tree_index = out_procs.size() - 1;
|
||||
|
||||
//? Try to find name of the binary file and append to program name if not the same
|
||||
if (cur_proc.short_cmd.empty() and not cur_proc.cmd.empty()) {
|
||||
std::string_view cmd_view = cur_proc.cmd;
|
||||
cmd_view = cmd_view.substr((size_t)0, std::min(cmd_view.find(' '), cmd_view.size()));
|
||||
cmd_view = cmd_view.substr(std::min(cmd_view.find_last_of('/') + 1, cmd_view.size()));
|
||||
cur_proc.short_cmd = string{cmd_view};
|
||||
}
|
||||
}
|
||||
else {
|
||||
cur_proc.tree_index = in_procs.size();
|
||||
}
|
||||
|
||||
//? Recursive iteration over all children
|
||||
for (auto& p : rng::equal_range(in_procs, cur_proc.pid, rng::less{}, &proc_info::ppid)) {
|
||||
if (collapsed and not filtering) {
|
||||
cur_proc.filtered = true;
|
||||
}
|
||||
|
||||
_tree_gen(p, in_procs, out_procs.back().children, cur_depth + 1, (collapsed or cur_proc.collapsed), filter, found, no_update, should_filter);
|
||||
|
||||
if (not no_update and not filtering and (collapsed or cur_proc.collapsed)) {
|
||||
//auto& parent = cur_proc;
|
||||
if (p.state != 'X') {
|
||||
cur_proc.cpu_p += p.cpu_p;
|
||||
cur_proc.cpu_c += p.cpu_c;
|
||||
cur_proc.mem += p.mem;
|
||||
cur_proc.threads += p.threads;
|
||||
}
|
||||
filter_found++;
|
||||
p.filtered = true;
|
||||
}
|
||||
else if (Config::getB("proc_aggregate") and p.state != 'X') {
|
||||
cur_proc.cpu_p += p.cpu_p;
|
||||
cur_proc.cpu_c += p.cpu_c;
|
||||
cur_proc.mem += p.mem;
|
||||
cur_proc.threads += p.threads;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _collect_prefixes(tree_proc &t, const bool is_last, const string &header) {
|
||||
const bool is_filtered = t.entry.get().filtered;
|
||||
if (is_filtered) t.entry.get().depth = 0;
|
||||
|
||||
if (!t.children.empty()) t.entry.get().prefix = header + (t.entry.get().collapsed ? "[+]─": "[-]─");
|
||||
else t.entry.get().prefix = header + (is_last ? " └─": " ├─");
|
||||
|
||||
for (auto child = t.children.begin(); child != t.children.end(); ++child) {
|
||||
_collect_prefixes(*child, child == (t.children.end() - 1),
|
||||
is_filtered ? "": header + (is_last ? " ": " │ "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto detect_container() -> std::optional<std::string> {
|
||||
std::error_code err;
|
||||
|
||||
if (fs::exists(fs::path("/run/.containerenv"), err)) {
|
||||
return std::make_optional(std::string { "podman" });
|
||||
}
|
||||
if (fs::exists(fs::path("/.dockerenv"), err)) {
|
||||
return std::make_optional(std::string { "docker" });
|
||||
}
|
||||
auto systemd_container = fs::path("/run/systemd/container");
|
||||
if (fs::exists(systemd_container, err)) {
|
||||
auto stream = std::ifstream { systemd_container };
|
||||
auto buf = std::string {};
|
||||
stream >> buf;
|
||||
return std::make_optional(buf);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// From `man 3 getifaddrs`: <net/if.h> must be included before <ifaddrs.h>
|
||||
// clang-format off
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
// clang-format on
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
# include <kvm.h>
|
||||
#endif
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::deque;
|
||||
using std::string;
|
||||
using std::tuple;
|
||||
using std::vector;
|
||||
|
||||
using namespace std::literals; // for operator""s
|
||||
|
||||
void term_resize(bool force=false);
|
||||
void banner_gen();
|
||||
|
||||
extern void clean_quit(int sig);
|
||||
|
||||
namespace Global {
|
||||
extern const vector<array<string, 2>> Banner_src;
|
||||
extern const string Version;
|
||||
extern atomic<bool> quitting;
|
||||
extern string exit_error_msg;
|
||||
extern atomic<bool> thread_exception;
|
||||
extern string banner;
|
||||
extern atomic<bool> resized;
|
||||
extern string overlay;
|
||||
extern string clock;
|
||||
extern uid_t real_uid, set_uid;
|
||||
extern atomic<bool> init_conf;
|
||||
}
|
||||
|
||||
namespace Runner {
|
||||
extern atomic<bool> active;
|
||||
extern atomic<bool> reading;
|
||||
extern atomic<bool> stopping;
|
||||
extern atomic<bool> redraw;
|
||||
extern atomic<bool> coreNum_reset;
|
||||
extern pthread_t runner_id;
|
||||
extern bool pause_output;
|
||||
extern string debug_bg;
|
||||
|
||||
void run(const string& box="", bool no_update = false, bool force_redraw = false);
|
||||
void stop();
|
||||
|
||||
}
|
||||
|
||||
namespace Tools {
|
||||
//* Platform specific function for system_uptime (seconds since last restart)
|
||||
double system_uptime();
|
||||
}
|
||||
|
||||
namespace Shared {
|
||||
//* Initialize platform specific needed variables and check for errors
|
||||
void init();
|
||||
|
||||
extern long coreCount, page_size, clk_tck;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
struct KvmDeleter {
|
||||
void operator()(kvm_t* handle) {
|
||||
kvm_close(handle);
|
||||
}
|
||||
};
|
||||
using KvmPtr = std::unique_ptr<kvm_t, KvmDeleter>;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
namespace Gpu {
|
||||
#ifdef GPU_SUPPORT
|
||||
extern vector<string> box;
|
||||
extern int width, total_height, min_width, min_height;
|
||||
extern vector<int> x_vec, y_vec;
|
||||
extern vector<bool> redraw;
|
||||
extern int shown;
|
||||
extern int count;
|
||||
extern vector<int> shown_panels;
|
||||
extern vector<string> gpu_names;
|
||||
extern vector<int> gpu_b_height_offsets;
|
||||
extern long long gpu_pwr_total_max;
|
||||
|
||||
extern std::unordered_map<string, deque<long long>> shared_gpu_percent; // averages, power/vram total
|
||||
|
||||
const array mem_names { "used"s, "free"s };
|
||||
|
||||
//* Container for process information // TODO
|
||||
/*struct proc_info {
|
||||
unsigned int pid;
|
||||
unsigned long long mem;
|
||||
};*/
|
||||
|
||||
//* Container for supported Gpu::*::collect() functions
|
||||
struct gpu_info_supported {
|
||||
bool gpu_utilization = true,
|
||||
mem_utilization = true,
|
||||
gpu_clock = true,
|
||||
mem_clock = true,
|
||||
pwr_usage = true,
|
||||
pwr_state = true,
|
||||
temp_info = true,
|
||||
mem_total = true,
|
||||
mem_used = true,
|
||||
pcie_txrx = true,
|
||||
encoder_utilization = true,
|
||||
decoder_utilization = true;
|
||||
};
|
||||
|
||||
//* Per-device container for GPU info
|
||||
struct gpu_info {
|
||||
std::unordered_map<string, deque<long long>> gpu_percent = {
|
||||
{"gpu-totals", {}},
|
||||
{"gpu-vram-totals", {}},
|
||||
{"gpu-pwr-totals", {}},
|
||||
};
|
||||
unsigned int gpu_clock_speed; // MHz
|
||||
|
||||
long long pwr_usage; // mW
|
||||
long long pwr_max_usage = 255000;
|
||||
long long pwr_state;
|
||||
|
||||
deque<long long> temp = {0};
|
||||
long long temp_max = 110;
|
||||
|
||||
long long mem_total = 0;
|
||||
long long mem_used = 0;
|
||||
deque<long long> mem_utilization_percent = {0}; // TODO: properly handle GPUs that can't report some stats
|
||||
long long mem_clock_speed = 0; // MHz
|
||||
|
||||
long long pcie_tx = 0; // KB/s
|
||||
long long pcie_rx = 0;
|
||||
|
||||
long long encoder_utilization = 0;
|
||||
long long decoder_utilization = 0;
|
||||
|
||||
gpu_info_supported supported_functions;
|
||||
|
||||
// vector<proc_info> graphics_processes = {}; // TODO
|
||||
// vector<proc_info> compute_processes = {};
|
||||
};
|
||||
|
||||
namespace Nvml {
|
||||
extern bool shutdown();
|
||||
}
|
||||
namespace Rsmi {
|
||||
extern bool shutdown();
|
||||
}
|
||||
|
||||
//* Collect gpu stats and temperatures
|
||||
auto collect(bool no_update = false) -> vector<gpu_info>&;
|
||||
|
||||
//* Draw contents of gpu box using <gpus> as source
|
||||
string draw(const gpu_info& gpu, unsigned long index, bool force_redraw, bool data_same);
|
||||
#else
|
||||
struct gpu_info {
|
||||
bool supported = false;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Cpu {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery, supports_watts;
|
||||
extern string cpuName, cpuHz;
|
||||
extern vector<string> available_fields;
|
||||
extern vector<string> available_sensors;
|
||||
extern tuple<int, float, long, string> current_bat;
|
||||
extern std::optional<std::string> container_engine;
|
||||
|
||||
struct cpu_info {
|
||||
std::unordered_map<string, deque<long long>> cpu_percent = {
|
||||
{"total", {}},
|
||||
{"user", {}},
|
||||
{"nice", {}},
|
||||
{"system", {}},
|
||||
{"idle", {}},
|
||||
{"iowait", {}},
|
||||
{"irq", {}},
|
||||
{"softirq", {}},
|
||||
{"steal", {}},
|
||||
{"guest", {}},
|
||||
{"guest_nice", {}}
|
||||
};
|
||||
vector<deque<long long>> core_percent;
|
||||
vector<deque<long long>> temp;
|
||||
long long temp_max = 0;
|
||||
array<double, 3> load_avg;
|
||||
float usage_watts = 0;
|
||||
std::optional<std::vector<std::int32_t>> active_cpus;
|
||||
};
|
||||
|
||||
//* Collect cpu stats and temperatures
|
||||
auto collect(bool no_update = false) -> cpu_info&;
|
||||
|
||||
//* Draw contents of cpu box using <cpu> as source
|
||||
string draw(const cpu_info& cpu, const vector<Gpu::gpu_info>& gpu, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
//* Parse /proc/cpu info for mapping of core ids
|
||||
auto get_core_mapping() -> std::unordered_map<int, int>;
|
||||
extern std::unordered_map<int, int> core_mapping;
|
||||
|
||||
auto get_cpuHz() -> string;
|
||||
|
||||
//* Get battery info from /sys
|
||||
auto get_battery() -> tuple<int, float, long, string>;
|
||||
|
||||
string trim_name(string);
|
||||
}
|
||||
|
||||
namespace Mem {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool has_swap, shown, redraw;
|
||||
const array mem_names { "used"s, "available"s, "cached"s, "free"s };
|
||||
const array swap_names { "swap_used"s, "swap_free"s };
|
||||
extern int disk_ios;
|
||||
|
||||
struct disk_info {
|
||||
std::filesystem::path dev;
|
||||
string name;
|
||||
string fstype{}; // defaults to ""
|
||||
std::filesystem::path stat{}; // defaults to ""
|
||||
int64_t total{};
|
||||
int64_t used{};
|
||||
int64_t free{};
|
||||
int used_percent{};
|
||||
int free_percent{};
|
||||
|
||||
array<int64_t, 3> old_io = {0, 0, 0};
|
||||
deque<long long> io_read = {};
|
||||
deque<long long> io_write = {};
|
||||
deque<long long> io_activity = {};
|
||||
};
|
||||
|
||||
struct mem_info {
|
||||
std::unordered_map<string, uint64_t> stats =
|
||||
{{"used", 0}, {"available", 0}, {"cached", 0}, {"free", 0},
|
||||
{"swap_total", 0}, {"swap_used", 0}, {"swap_free", 0}};
|
||||
std::unordered_map<string, deque<long long>> percent =
|
||||
{{"used", {}}, {"available", {}}, {"cached", {}}, {"free", {}},
|
||||
{"swap_total", {}}, {"swap_used", {}}, {"swap_free", {}}};
|
||||
std::unordered_map<string, disk_info> disks;
|
||||
vector<string> disks_order;
|
||||
};
|
||||
|
||||
//?* Get total system memory
|
||||
uint64_t get_totalMem();
|
||||
|
||||
//* Collect mem & disks stats
|
||||
auto collect(bool no_update = false) -> mem_info&;
|
||||
|
||||
//* Draw contents of mem box using <mem> as source
|
||||
string draw(const mem_info& mem, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
}
|
||||
|
||||
namespace Net {
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw;
|
||||
extern string selected_iface;
|
||||
extern vector<string> interfaces;
|
||||
extern bool rescale;
|
||||
extern std::unordered_map<string, uint64_t> graph_max;
|
||||
|
||||
struct net_stat {
|
||||
uint64_t speed{};
|
||||
uint64_t top{};
|
||||
uint64_t total{};
|
||||
uint64_t last{};
|
||||
uint64_t offset{};
|
||||
uint64_t rollover{};
|
||||
};
|
||||
|
||||
struct net_info {
|
||||
std::unordered_map<string, deque<long long>> bandwidth = { {"download", {}}, {"upload", {}} };
|
||||
std::unordered_map<string, net_stat> stat = { {"download", {}}, {"upload", {}} };
|
||||
string ipv4{}; // defaults to ""
|
||||
string ipv6{}; // defaults to ""
|
||||
bool connected{};
|
||||
};
|
||||
|
||||
class IfAddrsPtr {
|
||||
struct ifaddrs* ifaddr;
|
||||
int status;
|
||||
public:
|
||||
IfAddrsPtr() { status = getifaddrs(&ifaddr); }
|
||||
~IfAddrsPtr() noexcept { freeifaddrs(ifaddr); }
|
||||
IfAddrsPtr(const IfAddrsPtr &) = delete;
|
||||
IfAddrsPtr& operator=(IfAddrsPtr& other) = delete;
|
||||
IfAddrsPtr(IfAddrsPtr &&) = delete;
|
||||
IfAddrsPtr& operator=(IfAddrsPtr&& other) = delete;
|
||||
[[nodiscard]] constexpr auto operator()() -> struct ifaddrs* { return ifaddr; }
|
||||
[[nodiscard]] constexpr auto get() -> struct ifaddrs* { return ifaddr; }
|
||||
[[nodiscard]] constexpr auto get_status() const noexcept -> int { return status; };
|
||||
};
|
||||
|
||||
extern std::unordered_map<string, net_info> current_net;
|
||||
|
||||
//* Collect net upload/download stats
|
||||
auto collect(bool no_update=false) -> net_info&;
|
||||
|
||||
//* Draw contents of net box using <net> as source
|
||||
string draw(const net_info& net, bool force_redraw = false, bool data_same = false);
|
||||
}
|
||||
|
||||
namespace Proc {
|
||||
extern atomic<int> numpids;
|
||||
|
||||
extern string box;
|
||||
extern int x, y, width, height, min_width, min_height;
|
||||
extern bool shown, redraw;
|
||||
extern int select_max;
|
||||
extern atomic<int> detailed_pid;
|
||||
extern int selected_pid, start, selected, collapse, expand, filter_found, selected_depth, toggle_children;
|
||||
extern string selected_name;
|
||||
|
||||
//? Contains the valid sorting options for processes
|
||||
const vector<string> sort_vector = {
|
||||
"pid",
|
||||
"name",
|
||||
"command",
|
||||
"threads",
|
||||
"user",
|
||||
"memory",
|
||||
"cpu direct",
|
||||
"cpu lazy",
|
||||
};
|
||||
|
||||
//? Translation from process state char to explanative string
|
||||
const std::unordered_map<char, string> proc_states = {
|
||||
{'R', "Running"},
|
||||
{'S', "Sleeping"},
|
||||
{'D', "Waiting"},
|
||||
{'Z', "Zombie"},
|
||||
{'T', "Stopped"},
|
||||
{'t', "Tracing"},
|
||||
{'X', "Dead"},
|
||||
{'x', "Dead"},
|
||||
{'K', "Wakekill"},
|
||||
{'W', "Unknown"},
|
||||
{'P', "Parked"}
|
||||
};
|
||||
|
||||
//* Container for process information
|
||||
struct proc_info {
|
||||
size_t pid{};
|
||||
string name{}; // defaults to ""
|
||||
string cmd{}; // defaults to ""
|
||||
string short_cmd{}; // defaults to ""
|
||||
size_t threads{};
|
||||
int name_offset{};
|
||||
string user{}; // defaults to ""
|
||||
uint64_t mem{};
|
||||
double cpu_p{}; // defaults to = 0.0
|
||||
double cpu_c{}; // defaults to = 0.0
|
||||
char state = '0';
|
||||
int64_t p_nice{};
|
||||
uint64_t ppid{};
|
||||
uint64_t cpu_s{};
|
||||
uint64_t cpu_t{};
|
||||
uint64_t death_time{};
|
||||
string prefix{}; // defaults to ""
|
||||
size_t depth{};
|
||||
size_t tree_index{};
|
||||
bool collapsed{};
|
||||
bool filtered{};
|
||||
};
|
||||
|
||||
//* Container for process info box
|
||||
struct detail_container {
|
||||
size_t last_pid{};
|
||||
bool skip_smaps{};
|
||||
proc_info entry;
|
||||
string elapsed, parent, status, io_read, io_write, memory;
|
||||
long long first_mem = -1;
|
||||
deque<long long> cpu_percent;
|
||||
deque<long long> mem_bytes;
|
||||
};
|
||||
|
||||
//? Contains all info for proc detailed box
|
||||
extern detail_container detailed;
|
||||
|
||||
//* Collect and sort process information from /proc
|
||||
auto collect(bool no_update = false) -> vector<proc_info>&;
|
||||
|
||||
//* Update current selection and view, returns -1 if no change otherwise the current selection
|
||||
int selection(const std::string_view cmd_key);
|
||||
|
||||
//* Draw contents of proc box using <plist> as data source
|
||||
string draw(const vector<proc_info>& plist, bool force_redraw = false, bool data_same = false);
|
||||
|
||||
struct tree_proc {
|
||||
std::reference_wrapper<proc_info> entry;
|
||||
vector<tree_proc> children;
|
||||
};
|
||||
|
||||
//* Change priority (nice) of pid, returns true on success otherwise false
|
||||
bool set_priority(pid_t pid, int priority);
|
||||
|
||||
//* Sort vector of proc_info's
|
||||
void proc_sorter(vector<proc_info>& proc_vec, const string& sorting, bool reverse, bool tree = false);
|
||||
|
||||
//* Recursive sort of process tree
|
||||
void tree_sort(vector<tree_proc>& proc_vec, const string& sorting, bool reverse, bool paused,
|
||||
int& c_index, const int index_max, bool collapsed = false);
|
||||
|
||||
auto matches_filter(const proc_info& proc, const std::string& filter) -> bool;
|
||||
|
||||
//* Generate process tree list
|
||||
void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs,
|
||||
int cur_depth, bool collapsed, const string& filter,
|
||||
bool found = false, bool no_update = false, bool should_filter = false);
|
||||
|
||||
//* Build prefixes for tree view
|
||||
void _collect_prefixes(tree_proc& t, bool is_last, const string &header = "");
|
||||
}
|
||||
|
||||
/// Detect container engine.
|
||||
auto detect_container() -> std::optional<std::string>;
|
||||
@@ -0,0 +1,454 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
#include "btop_theme.hpp"
|
||||
|
||||
using std::round;
|
||||
using std::stoi;
|
||||
using std::to_string;
|
||||
using std::vector;
|
||||
using std::views::iota;
|
||||
|
||||
using namespace Tools;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
string Term::fg, Term::bg;
|
||||
string Fx::reset = reset_base;
|
||||
|
||||
namespace Theme {
|
||||
|
||||
fs::path theme_dir;
|
||||
fs::path user_theme_dir;
|
||||
fs::path custom_theme_dir;
|
||||
vector<string> themes;
|
||||
std::unordered_map<string, string> colors;
|
||||
std::unordered_map<string, array<int, 3>> rgbs;
|
||||
std::unordered_map<string, array<string, 101>> gradients;
|
||||
|
||||
const std::unordered_map<string, string> Default_theme = {
|
||||
{ "main_bg", "#00" },
|
||||
{ "main_fg", "#cc" },
|
||||
{ "title", "#ee" },
|
||||
{ "hi_fg", "#b54040" },
|
||||
{ "selected_bg", "#6a2f2f" },
|
||||
{ "selected_fg", "#ee" },
|
||||
{ "inactive_fg", "#40" },
|
||||
{ "graph_text", "#60" },
|
||||
{ "meter_bg", "#40" },
|
||||
{ "proc_misc", "#0de756" },
|
||||
{ "cpu_box", "#556d59" },
|
||||
{ "mem_box", "#6c6c4b" },
|
||||
{ "net_box", "#5c588d" },
|
||||
{ "proc_box", "#805252" },
|
||||
{ "div_line", "#30" },
|
||||
{ "temp_start", "#4897d4" },
|
||||
{ "temp_mid", "#5474e8" },
|
||||
{ "temp_end", "#ff40b6" },
|
||||
{ "cpu_start", "#77ca9b" },
|
||||
{ "cpu_mid", "#cbc06c" },
|
||||
{ "cpu_end", "#dc4c4c" },
|
||||
{ "free_start", "#384f21" },
|
||||
{ "free_mid", "#b5e685" },
|
||||
{ "free_end", "#dcff85" },
|
||||
{ "cached_start", "#163350" },
|
||||
{ "cached_mid", "#74e6fc" },
|
||||
{ "cached_end", "#26c5ff" },
|
||||
{ "available_start", "#4e3f0e" },
|
||||
{ "available_mid", "#ffd77a" },
|
||||
{ "available_end", "#ffb814" },
|
||||
{ "used_start", "#592b26" },
|
||||
{ "used_mid", "#d9626d" },
|
||||
{ "used_end", "#ff4769" },
|
||||
{ "download_start", "#291f75" },
|
||||
{ "download_mid", "#4f43a3" },
|
||||
{ "download_end", "#b0a9de" },
|
||||
{ "upload_start", "#620665" },
|
||||
{ "upload_mid", "#7d4180" },
|
||||
{ "upload_end", "#dcafde" },
|
||||
{ "process_start", "#80d0a3" },
|
||||
{ "process_mid", "#dcd179" },
|
||||
{ "process_end", "#d45454" },
|
||||
{ "proc_pause_bg", "#b54040" }
|
||||
};
|
||||
|
||||
const std::unordered_map<string, string> TTY_theme = {
|
||||
{ "main_bg", "\x1b[0;40m" },
|
||||
{ "main_fg", "\x1b[37m" },
|
||||
{ "title", "\x1b[97m" },
|
||||
{ "hi_fg", "\x1b[91m" },
|
||||
{ "selected_bg", "\x1b[41m" },
|
||||
{ "selected_fg", "\x1b[97m" },
|
||||
{ "inactive_fg", "\x1b[90m" },
|
||||
{ "graph_text", "\x1b[90m" },
|
||||
{ "meter_bg", "\x1b[90m" },
|
||||
{ "proc_misc", "\x1b[92m" },
|
||||
{ "cpu_box", "\x1b[32m" },
|
||||
{ "mem_box", "\x1b[33m" },
|
||||
{ "net_box", "\x1b[35m" },
|
||||
{ "proc_box", "\x1b[31m" },
|
||||
{ "div_line", "\x1b[90m" },
|
||||
{ "temp_start", "\x1b[94m" },
|
||||
{ "temp_mid", "\x1b[96m" },
|
||||
{ "temp_end", "\x1b[95m" },
|
||||
{ "cpu_start", "\x1b[92m" },
|
||||
{ "cpu_mid", "\x1b[93m" },
|
||||
{ "cpu_end", "\x1b[91m" },
|
||||
{ "free_start", "\x1b[32m" },
|
||||
{ "free_mid", "" },
|
||||
{ "free_end", "\x1b[92m" },
|
||||
{ "cached_start", "\x1b[36m" },
|
||||
{ "cached_mid", "" },
|
||||
{ "cached_end", "\x1b[96m" },
|
||||
{ "available_start", "\x1b[33m" },
|
||||
{ "available_mid", "" },
|
||||
{ "available_end", "\x1b[93m" },
|
||||
{ "used_start", "\x1b[31m" },
|
||||
{ "used_mid", "" },
|
||||
{ "used_end", "\x1b[91m" },
|
||||
{ "download_start", "\x1b[34m" },
|
||||
{ "download_mid", "" },
|
||||
{ "download_end", "\x1b[94m" },
|
||||
{ "upload_start", "\x1b[35m" },
|
||||
{ "upload_mid", "" },
|
||||
{ "upload_end", "\x1b[95m" },
|
||||
{ "process_start", "\x1b[32m" },
|
||||
{ "process_mid", "\x1b[33m" },
|
||||
{ "process_end", "\x1b[31m" },
|
||||
{ "proc_pause_bg", "\x1b[41m" },
|
||||
};
|
||||
|
||||
namespace {
|
||||
//* Convert 24-bit colors to 256 colors
|
||||
int truecolor_to_256(const int& r, const int& g, const int& b) {
|
||||
//? Use upper 232-255 greyscale values if the downscaled red, green and blue are the same value
|
||||
if (const int red = round((double)r / 11); red == round((double)g / 11) and red == round((double)b / 11)) {
|
||||
return 232 + red;
|
||||
}
|
||||
//? Else use 6x6x6 color cube to calculate approximate colors
|
||||
else {
|
||||
return round((double)r / 51) * 36 + round((double)g / 51) * 6 + round((double)b / 51) + 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string hex_to_color(string hexa, bool t_to_256, const string& depth) {
|
||||
if (hexa.size() > 1) {
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) {
|
||||
if (not isxdigit(c)) {
|
||||
Logger::error("Invalid hex value: " + hexa);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||
|
||||
if (hexa.size() == 2) {
|
||||
int h_int = stoi(hexa, nullptr, 16);
|
||||
if (t_to_256) {
|
||||
return pre + to_string(truecolor_to_256(h_int, h_int, h_int)) + "m";
|
||||
} else {
|
||||
string h_str = to_string(h_int);
|
||||
return pre + h_str + ";" + h_str + ";" + h_str + "m";
|
||||
}
|
||||
}
|
||||
else if (hexa.size() == 6) {
|
||||
if (t_to_256) {
|
||||
return pre + to_string(truecolor_to_256(
|
||||
stoi(hexa.substr(0, 2), nullptr, 16),
|
||||
stoi(hexa.substr(2, 2), nullptr, 16),
|
||||
stoi(hexa.substr(4, 2), nullptr, 16))) + "m";
|
||||
} else {
|
||||
return pre +
|
||||
to_string(stoi(hexa.substr(0, 2), nullptr, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(2, 2), nullptr, 16)) + ";" +
|
||||
to_string(stoi(hexa.substr(4, 2), nullptr, 16)) + "m";
|
||||
}
|
||||
}
|
||||
else Logger::error("Invalid size of hex value: " + hexa);
|
||||
}
|
||||
else Logger::error("Hex value missing: " + hexa);
|
||||
return "";
|
||||
}
|
||||
|
||||
string dec_to_color(int r, int g, int b, bool t_to_256, const string& depth) {
|
||||
string pre = Fx::e + (depth == "fg" ? "38" : "48") + ";" + (t_to_256 ? "5;" : "2;");
|
||||
r = std::clamp(r, 0, 255);
|
||||
g = std::clamp(g, 0, 255);
|
||||
b = std::clamp(b, 0, 255);
|
||||
if (t_to_256) return pre + to_string(truecolor_to_256(r, g, b)) + "m";
|
||||
else return pre + to_string(r) + ";" + to_string(g) + ";" + to_string(b) + "m";
|
||||
}
|
||||
|
||||
namespace {
|
||||
//* Convert hex color to a array of decimals
|
||||
array<int, 3> hex_to_dec(string hexa) {
|
||||
if (hexa.size() > 1) {
|
||||
hexa.erase(0, 1);
|
||||
for (auto& c : hexa) {
|
||||
if (not isxdigit(c))
|
||||
return array{-1, -1, -1};
|
||||
}
|
||||
|
||||
if (hexa.size() == 2) {
|
||||
int h_int = stoi(hexa, nullptr, 16);
|
||||
return array{h_int, h_int, h_int};
|
||||
}
|
||||
else if (hexa.size() == 6) {
|
||||
return array{
|
||||
stoi(hexa.substr(0, 2), nullptr, 16),
|
||||
stoi(hexa.substr(2, 2), nullptr, 16),
|
||||
stoi(hexa.substr(4, 2), nullptr, 16)
|
||||
};
|
||||
}
|
||||
}
|
||||
return {-1 ,-1 ,-1};
|
||||
}
|
||||
|
||||
//* Generate colors and rgb decimal vectors for the theme
|
||||
void generateColors(const std::unordered_map<string, string>& source) {
|
||||
vector<string> t_rgb;
|
||||
string depth;
|
||||
bool t_to_256 = Config::getB("lowcolor");
|
||||
colors.clear(); rgbs.clear();
|
||||
for (const auto& [name, color] : Default_theme) {
|
||||
if (name == "main_bg" and not Config::getB("theme_background")) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
depth = (name.ends_with("bg") and name != "meter_bg") ? "bg" : "fg";
|
||||
if (source.contains(name)) {
|
||||
if (name == "main_bg" and source.at(name).empty()) {
|
||||
colors[name] = "\x1b[49m";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).empty() and (name.ends_with("_mid") or name.ends_with("_end"))) {
|
||||
colors[name] = "";
|
||||
rgbs[name] = {-1, -1, -1};
|
||||
continue;
|
||||
}
|
||||
else if (source.at(name).starts_with('#')) {
|
||||
colors[name] = hex_to_color(source.at(name), t_to_256, depth);
|
||||
rgbs[name] = hex_to_dec(source.at(name));
|
||||
}
|
||||
else if (not source.at(name).empty()) {
|
||||
t_rgb = ssplit(source.at(name));
|
||||
if (t_rgb.size() != 3) {
|
||||
Logger::error("Invalid RGB decimal value: \"" + source.at(name) + "\"");
|
||||
} else {
|
||||
colors[name] = dec_to_color(stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2]), t_to_256, depth);
|
||||
rgbs[name] = array{stoi(t_rgb[0]), stoi(t_rgb[1]), stoi(t_rgb[2])};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (not colors.contains(name) and not is_in(name, "meter_bg", "process_start", "process_mid", "process_end", "graph_text")) {
|
||||
Logger::debug("Missing color value for \"" + name + "\". Using value from default.");
|
||||
colors[name] = hex_to_color(color, t_to_256, depth);
|
||||
rgbs[name] = hex_to_dec(color);
|
||||
}
|
||||
}
|
||||
//? Set fallback values for optional colors not defined in theme file
|
||||
if (not colors.contains("meter_bg")) {
|
||||
colors["meter_bg"] = colors.at("inactive_fg");
|
||||
rgbs["meter_bg"] = rgbs.at("inactive_fg");
|
||||
}
|
||||
if (not colors.contains("process_start")) {
|
||||
colors["process_start"] = colors.at("cpu_start");
|
||||
colors["process_mid"] = colors.at("cpu_mid");
|
||||
colors["process_end"] = colors.at("cpu_end");
|
||||
rgbs["process_start"] = rgbs.at("cpu_start");
|
||||
rgbs["process_mid"] = rgbs.at("cpu_mid");
|
||||
rgbs["process_end"] = rgbs.at("cpu_end");
|
||||
}
|
||||
if (not colors.contains("graph_text")) {
|
||||
colors["graph_text"] = colors.at("inactive_fg");
|
||||
rgbs["graph_text"] = rgbs.at("inactive_fg");
|
||||
}
|
||||
}
|
||||
|
||||
//* Generate color gradients from two or three colors, 101 values indexed 0-100
|
||||
void generateGradients() {
|
||||
gradients.clear();
|
||||
bool t_to_256 = Config::getB("lowcolor");
|
||||
|
||||
//? Insert values for processes greyscale gradient and processes color gradient
|
||||
rgbs.insert({
|
||||
{ "proc_start", rgbs["main_fg"] },
|
||||
{ "proc_mid", {-1, -1, -1} },
|
||||
{ "proc_end", rgbs["inactive_fg"] },
|
||||
{ "proc_color_start", rgbs["inactive_fg"] },
|
||||
{ "proc_color_mid", {-1, -1, -1} },
|
||||
{ "proc_color_end", rgbs["process_start"] },
|
||||
});
|
||||
|
||||
for (const auto& [name, source_arr] : rgbs) {
|
||||
if (not name.ends_with("_start")) continue;
|
||||
const string color_name { rtrim(name, "_start") };
|
||||
|
||||
//? input_colors[start,mid,end][red,green,blue]
|
||||
const array<array<int, 3>, 3> input_colors = {
|
||||
source_arr,
|
||||
rgbs[color_name + "_mid"],
|
||||
rgbs[color_name + "_end"]
|
||||
};
|
||||
|
||||
//? output_colors[red,green,blue][0-100]
|
||||
array<array<int, 3>, 101> output_colors;
|
||||
output_colors[0][0] = -1;
|
||||
|
||||
//? Only start iteration if gradient has an end color defined
|
||||
if (input_colors[2][0] >= 0) {
|
||||
|
||||
//? Split iteration in two passes of 50 + 51 instead of one pass of 101 if gradient has start, mid and end values defined
|
||||
int current_range = (input_colors[1][0] >= 0) ? 50 : 100;
|
||||
for (int rgb : iota(0, 3)) {
|
||||
int start = 0, offset = 0;
|
||||
int end = (current_range == 50) ? 1 : 2;
|
||||
for (int i : iota(0, 101)) {
|
||||
output_colors[i][rgb] = input_colors[start][rgb] + (i - offset) * (input_colors[end][rgb] - input_colors[start][rgb]) / current_range;
|
||||
|
||||
//? Switch source arrays from start->mid to mid->end at 50 passes if mid is defined
|
||||
if (i == current_range) { ++start; ++end; offset = 50; }
|
||||
}
|
||||
}
|
||||
}
|
||||
//? Generate color escape codes for the generated rgb decimals
|
||||
array<string, 101> color_gradient;
|
||||
if (output_colors[0][0] != -1) {
|
||||
for (int y = 0; const auto& [red, green, blue] : output_colors)
|
||||
color_gradient[y++] = dec_to_color(red, green, blue, t_to_256);
|
||||
}
|
||||
else {
|
||||
//? If only start was defined fill array with start color
|
||||
color_gradient.fill(colors[name]);
|
||||
}
|
||||
gradients[color_name] = std::move(color_gradient);
|
||||
}
|
||||
}
|
||||
|
||||
//* Set colors and generate gradients for the TTY theme
|
||||
void generateTTYColors() {
|
||||
rgbs.clear();
|
||||
gradients.clear();
|
||||
colors = TTY_theme;
|
||||
if (not Config::getB("theme_background"))
|
||||
colors["main_bg"] = "\x1b[49m";
|
||||
|
||||
for (const auto& c : colors) {
|
||||
if (not c.first.ends_with("_start")) continue;
|
||||
const string base_name { rtrim(c.first, "_start") };
|
||||
string section = "_start";
|
||||
int split = colors.at(base_name + "_mid").empty() ? 50 : 33;
|
||||
for (int i : iota(0, 101)) {
|
||||
gradients[base_name][i] = colors.at(base_name + section);
|
||||
if (i == split) {
|
||||
section = (split == 33) ? "_mid" : "_end";
|
||||
split *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Load a .theme file from disk
|
||||
auto loadFile(const string& filename) {
|
||||
const fs::path filepath = filename;
|
||||
if (not fs::exists(filepath))
|
||||
return Default_theme;
|
||||
|
||||
std::ifstream themefile(filepath);
|
||||
if (themefile.good()) {
|
||||
std::unordered_map<string, string> theme_out;
|
||||
Logger::debug("Loading theme file: " + filename);
|
||||
while (not themefile.bad()) {
|
||||
if (themefile.peek() == '#') {
|
||||
themefile.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
themefile.ignore(SSmax, '[');
|
||||
if (themefile.eof()) break;
|
||||
string name, value;
|
||||
getline(themefile, name, ']');
|
||||
if (not Default_theme.contains(name)) {
|
||||
themefile.ignore(SSmax, '\n');
|
||||
continue;
|
||||
}
|
||||
themefile.ignore(SSmax, '=');
|
||||
themefile >> std::ws;
|
||||
if (themefile.eof()) break;
|
||||
if (themefile.peek() == '"') {
|
||||
themefile.ignore(1);
|
||||
getline(themefile, value, '"');
|
||||
themefile.ignore(SSmax, '\n');
|
||||
}
|
||||
else getline(themefile, value, '\n');
|
||||
|
||||
theme_out[name] = value;
|
||||
}
|
||||
return theme_out;
|
||||
}
|
||||
return Default_theme;
|
||||
}
|
||||
}
|
||||
|
||||
void updateThemes() {
|
||||
themes.clear();
|
||||
themes.push_back("Default");
|
||||
themes.push_back("TTY");
|
||||
|
||||
//? Priority: custom_theme_dir -> user_theme_dir -> theme_dir
|
||||
for (const auto& path : { custom_theme_dir, user_theme_dir, theme_dir } ) {
|
||||
if (path.empty()) continue;
|
||||
for (auto& file : fs::directory_iterator(path)) {
|
||||
if (file.path().extension() == ".theme" and access(file.path().c_str(), R_OK) != -1 and not v_contains(themes, file.path().c_str())) {
|
||||
themes.push_back(file.path().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setTheme() {
|
||||
const auto& theme = Config::getS("color_theme");
|
||||
fs::path theme_path;
|
||||
for (const fs::path p : themes) {
|
||||
if (p == theme or p.stem() == theme or p.filename() == theme) {
|
||||
theme_path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (theme == "TTY" or Config::getB("tty_mode"))
|
||||
generateTTYColors();
|
||||
else {
|
||||
generateColors((theme == "Default" or theme_path.empty() ? Default_theme : loadFile(theme_path)));
|
||||
generateGradients();
|
||||
}
|
||||
Term::fg = colors.at("main_fg");
|
||||
Term::bg = colors.at("main_bg");
|
||||
Fx::reset = Fx::reset_base + Term::fg + Term::bg;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
using std::array;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace Theme {
|
||||
extern std::filesystem::path theme_dir;
|
||||
extern std::filesystem::path user_theme_dir;
|
||||
extern std::filesystem::path custom_theme_dir;
|
||||
|
||||
//* Contains "Default" and "TTY" at indices 0 and 1, otherwise full paths to theme files
|
||||
extern vector<string> themes;
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args hexa: ["#000000"-"#ffffff"] for color, ["#00"-"#ff"] for greyscale
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string hex_to_color(string hexa, bool t_to_256=false, const string& depth="fg");
|
||||
|
||||
//* Generate escape sequence for 24-bit or 256 color and return as a string
|
||||
//* Args r: [0-255], g: [0-255], b: [0-255]
|
||||
//* t_to_256: [true|false] convert 24bit value to 256 color value
|
||||
//* depth: ["fg"|"bg"] for either a foreground color or a background color
|
||||
string dec_to_color(int r, int g, int b, bool t_to_256=false, const string& depth="fg");
|
||||
|
||||
//* Update list of paths for available themes
|
||||
void updateThemes();
|
||||
|
||||
//* Set current theme from current "color_theme" value in config
|
||||
void setTheme();
|
||||
|
||||
extern std::unordered_map<string, string> colors;
|
||||
extern std::unordered_map<string, array<int, 3>> rgbs;
|
||||
extern std::unordered_map<string, array<string, 101>> gradients;
|
||||
|
||||
//* Return escape code for color <name>
|
||||
inline const string& c(const string& name) { return colors.at(name); }
|
||||
|
||||
//* Return array of escape codes for color gradient <name>
|
||||
inline const array<string, 101>& g(const string& name) { return gradients.at(name); }
|
||||
|
||||
//* Return array of red, green and blue in decimal for color <name>
|
||||
inline const std::array<int, 3>& dec(const string& name) { return rgbs.at(name); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,714 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <codecvt>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "widechar_width.hpp"
|
||||
#include "btop_shared.hpp"
|
||||
#include "btop_tools.hpp"
|
||||
#include "btop_config.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::floor;
|
||||
using std::flush;
|
||||
using std::max;
|
||||
using std::string_view;
|
||||
using std::to_string;
|
||||
|
||||
using namespace std::literals; // to use operator""s
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace rng = std::ranges;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
||||
//* Collection of escape codes and functions for terminal manipulation
|
||||
namespace Term {
|
||||
|
||||
atomic<bool> initialized{};
|
||||
atomic<int> width{};
|
||||
atomic<int> height{};
|
||||
string current_tty;
|
||||
|
||||
namespace {
|
||||
struct termios initial_settings;
|
||||
|
||||
//* Toggle terminal input echo
|
||||
bool echo(bool on=true) {
|
||||
struct termios settings;
|
||||
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
||||
if (on) settings.c_lflag |= ECHO;
|
||||
else settings.c_lflag &= ~(ECHO);
|
||||
return 0 == tcsetattr(STDIN_FILENO, TCSANOW, &settings);
|
||||
}
|
||||
|
||||
//* Toggle need for return key when reading input
|
||||
bool linebuffered(bool on=true) {
|
||||
struct termios settings;
|
||||
if (tcgetattr(STDIN_FILENO, &settings)) return false;
|
||||
if (on) settings.c_lflag |= ICANON;
|
||||
else {
|
||||
settings.c_lflag &= ~(ICANON);
|
||||
settings.c_cc[VMIN] = 0;
|
||||
settings.c_cc[VTIME] = 0;
|
||||
}
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
|
||||
if (on) setlinebuf(stdin);
|
||||
else setbuf(stdin, nullptr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool refresh(bool only_check) {
|
||||
// Query dimensions of '/dev/tty' of the 'STDOUT_FILENO' isn't available.
|
||||
// This variable is set in those cases to avoid calls to ioctl
|
||||
constinit static bool uses_dev_tty = false;
|
||||
struct winsize wsize {};
|
||||
if (uses_dev_tty || ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsize) < 0 || (wsize.ws_col == 0 && wsize.ws_row == 0)) {
|
||||
Logger::error(R"(Couldn't determine terminal size of "STDOUT_FILENO"!)");
|
||||
auto dev_tty = open("/dev/tty", O_RDONLY | O_CLOEXEC);
|
||||
if (dev_tty != -1) {
|
||||
ioctl(dev_tty, TIOCGWINSZ, &wsize);
|
||||
close(dev_tty);
|
||||
}
|
||||
else {
|
||||
Logger::error(R"(Couldn't determine terminal size of "/dev/tty"!)");
|
||||
return false;
|
||||
}
|
||||
uses_dev_tty = true;
|
||||
}
|
||||
if (width != wsize.ws_col or height != wsize.ws_row) {
|
||||
if (not only_check) {
|
||||
width = wsize.ws_col;
|
||||
height = wsize.ws_row;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto get_min_size(const string& boxes) -> array<int, 2> {
|
||||
bool cpu = boxes.find("cpu") != string::npos;
|
||||
bool mem = boxes.find("mem") != string::npos;
|
||||
bool net = boxes.find("net") != string::npos;
|
||||
bool proc = boxes.find("proc") != string::npos;
|
||||
#ifdef GPU_SUPPORT
|
||||
int gpu = 0;
|
||||
if (Gpu::count > 0)
|
||||
for (char i = '0'; i <= '5'; i++)
|
||||
gpu += (boxes.contains("gpu"s + i) ? 1 : 0);
|
||||
#endif
|
||||
int width = 0;
|
||||
if (mem) width = Mem::min_width;
|
||||
else if (net) width = Mem::min_width;
|
||||
width += (proc ? Proc::min_width : 0);
|
||||
if (cpu and width < Cpu::min_width) width = Cpu::min_width;
|
||||
#ifdef GPU_SUPPORT
|
||||
if (gpu != 0 and width < Gpu::min_width) width = Gpu::min_width;
|
||||
#endif
|
||||
|
||||
int height = (cpu ? Cpu::min_height : 0);
|
||||
if (proc) height += Proc::min_height;
|
||||
else height += (mem ? Mem::min_height : 0) + (net ? Net::min_height : 0);
|
||||
#ifdef GPU_SUPPORT
|
||||
for (int i = 0; i < gpu; i++)
|
||||
height += Gpu::gpu_b_height_offsets[i] + 4;
|
||||
#endif
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (not initialized) {
|
||||
initialized = (bool)isatty(STDIN_FILENO);
|
||||
if (initialized) {
|
||||
tcgetattr(STDIN_FILENO, &initial_settings);
|
||||
current_tty = (ttyname(STDIN_FILENO) != nullptr ? static_cast<string>(ttyname(STDIN_FILENO)) : "unknown");
|
||||
|
||||
//? Disable stream sync - this does not seem to work on OpenBSD
|
||||
#ifndef __OpenBSD__
|
||||
cout.sync_with_stdio(false);
|
||||
#endif
|
||||
|
||||
//? Disable stream ties
|
||||
cout.tie(nullptr);
|
||||
echo(false);
|
||||
linebuffered(false);
|
||||
refresh();
|
||||
|
||||
cout << alt_screen << hide_cursor << mouse_on << flush;
|
||||
Global::resized = false;
|
||||
}
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void restore() {
|
||||
if (initialized) {
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &initial_settings);
|
||||
cout << mouse_off << clear << Fx::reset << normal_screen << show_cursor << flush;
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
// ! Disabled due to issue when compiling with musl, reverted back to using regex
|
||||
// namespace Fx {
|
||||
// string uncolor(const string& s) {
|
||||
// string out = s;
|
||||
// for (size_t offset = 0, start_pos = 0, end_pos = 0;;) {
|
||||
// start_pos = (offset == 0) ? out.find('\x1b') : offset;
|
||||
// if (start_pos == string::npos)
|
||||
// break;
|
||||
// offset = start_pos + 1;
|
||||
// end_pos = out.find('m', offset);
|
||||
// if (end_pos == string::npos)
|
||||
// break;
|
||||
// else if (auto next_pos = out.find('\x1b', offset); not isdigit(out[end_pos - 1]) or end_pos > next_pos) {
|
||||
// offset = next_pos;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// out.erase(start_pos, (end_pos - start_pos)+1);
|
||||
// offset = 0;
|
||||
// }
|
||||
// out.shrink_to_fit();
|
||||
// return out;
|
||||
// }
|
||||
// }
|
||||
|
||||
namespace Tools {
|
||||
|
||||
size_t wide_ulen(const std::string_view str) {
|
||||
unsigned int chars = 0;
|
||||
try {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
auto w_str = conv.from_bytes((str.size() > 10000 ? str.substr(0, 10000).data() : str.data()));
|
||||
|
||||
for (auto c : w_str) {
|
||||
chars += utf8::wcwidth(c);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
return ulen(str);
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
size_t wide_ulen(const std::wstring_view w_str) {
|
||||
unsigned int chars = 0;
|
||||
|
||||
for (auto c : w_str) {
|
||||
chars += utf8::wcwidth(c);
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
string uresize(string str, const size_t len, bool wide) {
|
||||
if (len < 1 or str.empty())
|
||||
return "";
|
||||
|
||||
if (wide) {
|
||||
try {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
auto w_str = conv.from_bytes((str.size() > 10000 ? str.substr(0, 10000).c_str() : str.c_str()));
|
||||
while (wide_ulen(w_str) > len)
|
||||
w_str.pop_back();
|
||||
string n_str = conv.to_bytes(w_str);
|
||||
return n_str;
|
||||
}
|
||||
catch (...) {
|
||||
return uresize(str, len, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t x = 0, i = 0; i < str.size(); i++) {
|
||||
if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) x++;
|
||||
if (x >= len + 1) {
|
||||
str.resize(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
str.shrink_to_fit();
|
||||
return str;
|
||||
}
|
||||
|
||||
string luresize(string str, const size_t len, bool wide) {
|
||||
if (len < 1 or str.empty())
|
||||
return "";
|
||||
|
||||
for (size_t x = 0, last_pos = 0, i = str.size() - 1; i > 0 ; i--) {
|
||||
if (wide and static_cast<unsigned char>(str.at(i)) > 0xef) {
|
||||
x += 2;
|
||||
last_pos = max((size_t)0, i - 1);
|
||||
}
|
||||
else if ((static_cast<unsigned char>(str.at(i)) & 0xC0) != 0x80) {
|
||||
x++;
|
||||
last_pos = i;
|
||||
}
|
||||
if (x >= len) {
|
||||
str = str.substr(last_pos);
|
||||
str.shrink_to_fit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
string s_replace(const string& str, const string& from, const string& to) {
|
||||
string out = str;
|
||||
for (size_t start_pos = out.find(from); start_pos != std::string::npos; start_pos = out.find(from)) {
|
||||
out.replace(start_pos, from.length(), to);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
string_view ltrim(string_view str, const string_view t_str) {
|
||||
while (str.starts_with(t_str))
|
||||
str.remove_prefix(t_str.size());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
string_view rtrim(string_view str, const string_view t_str) {
|
||||
while (str.ends_with(t_str))
|
||||
str.remove_suffix(t_str.size());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
string ljust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return str + string(max((int)(x - ulen(str, wide)), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
}
|
||||
return str + string(max((int)(x - str.size()), 0), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
string rjust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return string(max((int)(x - ulen(str)), 0), ' ') + str;
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
};
|
||||
return string(max((int)(x - str.size()), 0), ' ') + str;
|
||||
}
|
||||
}
|
||||
|
||||
string cjust(string str, const size_t x, bool utf, bool wide, bool limit) {
|
||||
if (utf) {
|
||||
if (limit and ulen(str, wide) > x)
|
||||
return uresize(str, x, wide);
|
||||
|
||||
return string(max((int)ceil((double)(x - ulen(str)) / 2), 0), ' ') + str + string(max((int)floor((double)(x - ulen(str)) / 2), 0), ' ');
|
||||
}
|
||||
else {
|
||||
if (limit and str.size() > x) {
|
||||
str.resize(x);
|
||||
return str;
|
||||
}
|
||||
return string(max((int)ceil((double)(x - str.size()) / 2), 0), ' ') + str + string(max((int)floor((double)(x - str.size()) / 2), 0), ' ');
|
||||
}
|
||||
}
|
||||
|
||||
string trans(const string& str) {
|
||||
std::string_view oldstr{str};
|
||||
string newstr;
|
||||
newstr.reserve(str.size());
|
||||
for (size_t pos; (pos = oldstr.find(' ')) != string::npos;) {
|
||||
newstr.append(oldstr.substr(0, pos));
|
||||
size_t x = 0;
|
||||
while (pos + x < oldstr.size() and oldstr.at(pos + x) == ' ') x++;
|
||||
newstr.append(Mv::r(x));
|
||||
oldstr.remove_prefix(pos + x);
|
||||
}
|
||||
return (newstr.empty()) ? str : newstr + string{oldstr};
|
||||
}
|
||||
|
||||
string sec_to_dhms(size_t seconds, bool no_days, bool no_seconds) {
|
||||
size_t days = seconds / 86400; seconds %= 86400;
|
||||
size_t hours = seconds / 3600; seconds %= 3600;
|
||||
size_t minutes = seconds / 60; seconds %= 60;
|
||||
string out = (not no_days and days > 0 ? to_string(days) + "d " : "")
|
||||
+ (hours < 10 ? "0" : "") + to_string(hours) + ':'
|
||||
+ (minutes < 10 ? "0" : "") + to_string(minutes)
|
||||
+ (not no_seconds ? ":" + string(std::cmp_less(seconds, 10) ? "0" : "") + to_string(seconds) : "");
|
||||
return out;
|
||||
}
|
||||
|
||||
string floating_humanizer(uint64_t value, bool shorten, size_t start, bool bit, bool per_second) {
|
||||
string out;
|
||||
const size_t mult = (bit) ? 8 : 1;
|
||||
|
||||
bool mega = Config::getB("base_10_sizes");
|
||||
|
||||
// Bitrates
|
||||
if(bit && per_second) {
|
||||
const auto& base_10_bitrate = Config::getS("base_10_bitrate");
|
||||
if(base_10_bitrate == "True") {
|
||||
mega = true;
|
||||
} else if(base_10_bitrate == "False") {
|
||||
mega = false;
|
||||
}
|
||||
// Default or "Auto": Uses base_10_sizes for bitrates
|
||||
}
|
||||
|
||||
// taking advantage of type deduction for array creation (since C++17)
|
||||
// combined with string literals (operator""s)
|
||||
static const array mebiUnits_bit {
|
||||
"bit"s, "Kib"s, "Mib"s,
|
||||
"Gib"s, "Tib"s, "Pib"s,
|
||||
"Eib"s, "Zib"s, "Yib"s,
|
||||
"Bib"s, "GEb"s
|
||||
};
|
||||
static const array mebiUnits_byte {
|
||||
"Byte"s, "KiB"s, "MiB"s,
|
||||
"GiB"s, "TiB"s, "PiB"s,
|
||||
"EiB"s, "ZiB"s, "YiB"s,
|
||||
"BiB"s, "GEB"s
|
||||
};
|
||||
static const array megaUnits_bit {
|
||||
"bit"s, "Kb"s, "Mb"s,
|
||||
"Gb"s, "Tb"s, "Pb"s,
|
||||
"Eb"s, "Zb"s, "Yb"s,
|
||||
"Bb"s, "Gb"s
|
||||
};
|
||||
static const array megaUnits_byte {
|
||||
"Byte"s, "KB"s, "MB"s,
|
||||
"GB"s, "TB"s, "PB"s,
|
||||
"EB"s, "ZB"s, "YB"s,
|
||||
"BB"s, "GB"s
|
||||
};
|
||||
const auto& units = (bit) ? ( mega ? megaUnits_bit : mebiUnits_bit) : ( mega ? megaUnits_byte : mebiUnits_byte);
|
||||
|
||||
value *= 100 * mult;
|
||||
|
||||
if (mega) {
|
||||
while (value >= 100000) {
|
||||
value /= 1000;
|
||||
if (value < 100) {
|
||||
out = fmt::format("{}", value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (value >= 102400) {
|
||||
value >>= 10;
|
||||
if (value < 100) {
|
||||
out = fmt::format("{}", value);
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = fmt::format("{}", value);
|
||||
if (not mega and out.size() == 4 and start > 0) {
|
||||
out.pop_back();
|
||||
out.insert(2, ".");
|
||||
}
|
||||
else if (out.size() == 3 and start > 0) {
|
||||
out.insert(1, ".");
|
||||
}
|
||||
else if (out.size() >= 2) {
|
||||
out.resize(out.size() - 2);
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = "0";
|
||||
}
|
||||
}
|
||||
|
||||
if (shorten) {
|
||||
auto f_pos = out.find(".");
|
||||
if (f_pos == 1 and out.size() > 3) {
|
||||
out = fmt::format("{:.1f}", stod(out));
|
||||
}
|
||||
else if (f_pos != string::npos) {
|
||||
out = fmt::format("{:.0f}", stod(out));
|
||||
}
|
||||
if (out.size() > 3) {
|
||||
out = fmt::format("{:d}.0", out[0] - '0');
|
||||
start++;
|
||||
}
|
||||
out.push_back(units[start][0]);
|
||||
}
|
||||
else out += " " + units[start];
|
||||
|
||||
if (per_second) out += (bit) ? "ps" : "/s";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string operator*(const string& str, int64_t n) {
|
||||
if (n < 1 or str.empty()) {
|
||||
return "";
|
||||
}
|
||||
else if (n == 1) {
|
||||
return str;
|
||||
}
|
||||
|
||||
string new_str;
|
||||
new_str.reserve(str.size() * n);
|
||||
|
||||
for (; n > 0; n--)
|
||||
new_str.append(str);
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
string strf_time(const string& strf) {
|
||||
auto in_time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
std::tm bt {};
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(localtime_r(&in_time_t, &bt), strf.c_str());
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void atomic_wait(const atomic<bool>& atom, bool old) noexcept {
|
||||
while (atom.load(std::memory_order_relaxed) == old ) busy_wait();
|
||||
}
|
||||
|
||||
void atomic_wait_for(const atomic<bool>& atom, bool old, const uint64_t wait_ms) noexcept {
|
||||
const uint64_t start_time = time_ms();
|
||||
while (atom.load(std::memory_order_relaxed) == old and (time_ms() - start_time < wait_ms)) sleep_ms(1);
|
||||
}
|
||||
|
||||
atomic_lock::atomic_lock(atomic<bool>& atom, bool wait) : atom(atom) {
|
||||
if (wait) while (not this->atom.compare_exchange_strong(this->not_true, true));
|
||||
else this->atom.store(true);
|
||||
}
|
||||
|
||||
atomic_lock::~atomic_lock() noexcept {
|
||||
this->atom.store(false);
|
||||
}
|
||||
|
||||
string readfile(const std::filesystem::path& path, const string& fallback) {
|
||||
if (not fs::exists(path)) return fallback;
|
||||
string out;
|
||||
try {
|
||||
std::ifstream file(path);
|
||||
for (string readstr; getline(file, readstr); out += readstr);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Logger::error("readfile() : Exception when reading " + string{path} + " : " + e.what());
|
||||
return fallback;
|
||||
}
|
||||
return (out.empty() ? fallback : out);
|
||||
}
|
||||
|
||||
auto celsius_to(const long long& celsius, const string& scale) -> tuple<long long, string> {
|
||||
if (scale == "celsius")
|
||||
return {celsius, "°C"};
|
||||
else if (scale == "fahrenheit")
|
||||
return {(long long)round((double)celsius * 1.8 + 32), "°F"};
|
||||
else if (scale == "kelvin")
|
||||
return {(long long)round((double)celsius + 273.15), "K "};
|
||||
else if (scale == "rankine")
|
||||
return {(long long)round((double)celsius * 1.8 + 491.67), "°R"};
|
||||
return {0, ""};
|
||||
}
|
||||
|
||||
string hostname() {
|
||||
char host[HOST_NAME_MAX];
|
||||
gethostname(host, HOST_NAME_MAX);
|
||||
host[HOST_NAME_MAX - 1] = '\0';
|
||||
return string{host};
|
||||
}
|
||||
|
||||
string username() {
|
||||
auto user = getenv("LOGNAME");
|
||||
if (user == nullptr or strlen(user) == 0) user = getenv("USER");
|
||||
return (user != nullptr ? user : "");
|
||||
}
|
||||
|
||||
DebugTimer::DebugTimer(string name, bool start, bool delayed_report)
|
||||
: name(std::move(name)), delayed_report(delayed_report) {
|
||||
if (start)
|
||||
this->start();
|
||||
}
|
||||
|
||||
DebugTimer::~DebugTimer() {
|
||||
if (running)
|
||||
this->stop(true);
|
||||
this->force_report();
|
||||
}
|
||||
|
||||
void DebugTimer::start() {
|
||||
if (running) return;
|
||||
running = true;
|
||||
start_time = time_micros();
|
||||
}
|
||||
|
||||
void DebugTimer::stop(bool report) {
|
||||
if (not running) return;
|
||||
running = false;
|
||||
elapsed_time = time_micros() - start_time;
|
||||
if (report) this->report();
|
||||
}
|
||||
|
||||
void DebugTimer::reset(bool restart) {
|
||||
running = false;
|
||||
start_time = 0;
|
||||
elapsed_time = 0;
|
||||
if (restart) this->start();
|
||||
}
|
||||
|
||||
void DebugTimer::stop_rename_reset(const string &new_name, bool report, bool restart) {
|
||||
this->stop(report);
|
||||
name = new_name;
|
||||
this->reset(restart);
|
||||
}
|
||||
|
||||
void DebugTimer::report() {
|
||||
string report_line;
|
||||
if (start_time == 0 and elapsed_time == 0)
|
||||
report_line = fmt::format("DebugTimer::report() warning -> Timer [{}] has not been started!", name);
|
||||
else if (running)
|
||||
report_line = fmt::format(custom_locale, "Timer [{}] (running) currently at {:L} μs", name, time_micros() - start_time);
|
||||
else
|
||||
report_line = fmt::format(custom_locale, "Timer [{}] took {:L} μs", name, elapsed_time);
|
||||
|
||||
if (delayed_report)
|
||||
report_buffer.emplace_back(report_line);
|
||||
else
|
||||
Logger::log_write(log_level, report_line);
|
||||
}
|
||||
|
||||
void DebugTimer::force_report() {
|
||||
if (report_buffer.empty()) return;
|
||||
for (const auto& line : report_buffer)
|
||||
Logger::log_write(log_level, line);
|
||||
report_buffer.clear();
|
||||
}
|
||||
|
||||
uint64_t DebugTimer::elapsed() {
|
||||
if (running)
|
||||
return time_micros() - start_time;
|
||||
return elapsed_time;
|
||||
}
|
||||
|
||||
bool DebugTimer::is_running() {
|
||||
return running;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Logger {
|
||||
using namespace Tools;
|
||||
std::atomic<bool> busy (false);
|
||||
bool first = true;
|
||||
const string tdf = "%Y/%m/%d (%T) | ";
|
||||
|
||||
size_t loglevel;
|
||||
std::optional<std::filesystem::path> logfile;
|
||||
|
||||
//* Wrapper for lowering privileges if using SUID bit and currently isn't using real userid
|
||||
class lose_priv {
|
||||
int status = -1;
|
||||
public:
|
||||
lose_priv() {
|
||||
if (geteuid() != Global::real_uid) {
|
||||
this->status = seteuid(Global::real_uid);
|
||||
}
|
||||
}
|
||||
~lose_priv() noexcept {
|
||||
if (status == 0) {
|
||||
status = seteuid(Global::set_uid);
|
||||
}
|
||||
}
|
||||
lose_priv(const lose_priv& other) = delete;
|
||||
lose_priv& operator=(const lose_priv& other) = delete;
|
||||
lose_priv(lose_priv&& other) = delete;
|
||||
lose_priv& operator=(lose_priv&& other) = delete;
|
||||
};
|
||||
|
||||
void set(const string& level) {
|
||||
loglevel = v_index(log_levels, level);
|
||||
}
|
||||
|
||||
void log_write(const Level level, const std::string_view msg) {
|
||||
if (loglevel < level or !logfile.has_value()) {
|
||||
return;
|
||||
}
|
||||
auto& log_file = logfile.value();
|
||||
atomic_lock lck(busy, true);
|
||||
lose_priv neutered{};
|
||||
std::error_code ec;
|
||||
try {
|
||||
// NOTE: `exist()` could throw but since we return with an empty logfile we don't care
|
||||
if (fs::exists(log_file) and fs::file_size(log_file, ec) > 1024 << 10 and not ec) {
|
||||
auto old_log = log_file;
|
||||
old_log += ".1";
|
||||
|
||||
if (fs::exists(old_log))
|
||||
fs::remove(old_log, ec);
|
||||
|
||||
if (not ec)
|
||||
fs::rename(log_file, old_log, ec);
|
||||
}
|
||||
if (not ec) {
|
||||
std::ofstream lwrite(log_file, std::ios::app);
|
||||
if (first) {
|
||||
first = false;
|
||||
lwrite << "\n" << strf_time(tdf) << "===> btop++ v." << Global::Version << "\n";
|
||||
}
|
||||
lwrite << strf_time(tdf) << log_levels.at(level) << ": " << msg << "\n";
|
||||
}
|
||||
else log_file.clear();
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
log_file.clear();
|
||||
throw std::runtime_error("Exception in Logger::log_write() : " + string{e.what()});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
# define BTOP_DEBUG
|
||||
#endif
|
||||
|
||||
#include <algorithm> // for std::ranges::count_if
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#ifdef BTOP_DEBUG
|
||||
#include <source_location>
|
||||
#endif
|
||||
#ifndef HOST_NAME_MAX
|
||||
#ifdef __APPLE__
|
||||
#define HOST_NAME_MAX 255
|
||||
#else
|
||||
#define HOST_NAME_MAX 64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
using std::array;
|
||||
using std::atomic;
|
||||
using std::string;
|
||||
using std::to_string;
|
||||
using std::string_view;
|
||||
using std::tuple;
|
||||
using std::vector;
|
||||
using namespace fmt::literals;
|
||||
|
||||
//? ------------------------------------------------- NAMESPACES ------------------------------------------------------
|
||||
|
||||
//* Collection of escape codes for text style and formatting
|
||||
namespace Fx {
|
||||
const string e = "\x1b["; //* Escape sequence start
|
||||
const string b = e + "1m"; //* Bold on/off
|
||||
const string ub = e + "22m"; //* Bold off
|
||||
const string d = e + "2m"; //* Dark on
|
||||
const string ud = e + "22m"; //* Dark off
|
||||
const string i = e + "3m"; //* Italic on
|
||||
const string ui = e + "23m"; //* Italic off
|
||||
const string ul = e + "4m"; //* Underline on
|
||||
const string uul = e + "24m"; //* Underline off
|
||||
const string bl = e + "5m"; //* Blink on
|
||||
const string ubl = e + "25m"; //* Blink off
|
||||
const string s = e + "9m"; //* Strike/crossed-out on
|
||||
const string us = e + "29m"; //* Strike/crossed-out on/off
|
||||
|
||||
//* Reset foreground/background color and text effects
|
||||
const string reset_base = e + "0m";
|
||||
|
||||
//* Reset text effects and restore theme foregrund and background color
|
||||
extern string reset;
|
||||
|
||||
//* Regex for matching color, style and cursor move escape sequences
|
||||
const std::regex escape_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m|f|s|u|C|D|A|B){1}");
|
||||
|
||||
//* Regex for matching only color and style escape sequences
|
||||
const std::regex color_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m){1}");
|
||||
|
||||
//* Return a string with all colors and text styling removed
|
||||
inline string uncolor(const string& s) { return std::regex_replace(s, color_regex, ""); }
|
||||
// string uncolor(const string& s);
|
||||
|
||||
}
|
||||
|
||||
//* Collection of escape codes and functions for cursor manipulation
|
||||
namespace Mv {
|
||||
//* Move cursor to <line>, <column>
|
||||
inline string to(int line, int col) { return Fx::e + to_string(line) + ';' + to_string(col) + 'f'; }
|
||||
|
||||
//* Move cursor right <x> columns
|
||||
inline string r(int x) { return Fx::e + to_string(x) + 'C'; }
|
||||
|
||||
//* Move cursor left <x> columns
|
||||
inline string l(int x) { return Fx::e + to_string(x) + 'D'; }
|
||||
|
||||
//* Move cursor up x lines
|
||||
inline string u(int x) { return Fx::e + to_string(x) + 'A'; }
|
||||
|
||||
//* Move cursor down x lines
|
||||
inline string d(int x) { return Fx::e + to_string(x) + 'B'; }
|
||||
|
||||
//* Save cursor position
|
||||
const string save = Fx::e + "s";
|
||||
|
||||
//* Restore saved cursor position
|
||||
const string restore = Fx::e + "u";
|
||||
}
|
||||
|
||||
//* Collection of escape codes and functions for terminal manipulation
|
||||
namespace Term {
|
||||
extern atomic<bool> initialized;
|
||||
extern atomic<int> width;
|
||||
extern atomic<int> height;
|
||||
extern string fg, bg, current_tty;
|
||||
|
||||
const string hide_cursor = Fx::e + "?25l";
|
||||
const string show_cursor = Fx::e + "?25h";
|
||||
const string alt_screen = Fx::e + "?1049h";
|
||||
const string normal_screen = Fx::e + "?1049l";
|
||||
const string clear = Fx::e + "2J" + Fx::e + "0;0f";
|
||||
const string clear_end = Fx::e + "0J";
|
||||
const string clear_begin = Fx::e + "1J";
|
||||
const string mouse_on = Fx::e + "?1002h" + Fx::e + "?1015h" + Fx::e + "?1006h"; //? Enable reporting of mouse position on click and release
|
||||
const string mouse_off = Fx::e + "?1002l" + Fx::e + "?1015l" + Fx::e + "?1006l";
|
||||
const string mouse_direct_on = Fx::e + "?1003h"; //? Enable reporting of mouse position at any movement
|
||||
const string mouse_direct_off = Fx::e + "?1003l";
|
||||
const string sync_start = Fx::e + "?2026h"; //? Start of terminal synchronized output
|
||||
const string sync_end = Fx::e + "?2026l"; //? End of terminal synchronized output
|
||||
|
||||
//* Returns true if terminal has been resized and updates width and height
|
||||
bool refresh(bool only_check=false);
|
||||
|
||||
//* Returns an array with the lowest possible width, height with current box config
|
||||
auto get_min_size(const string& boxes) -> array<int, 2>;
|
||||
|
||||
//* Check for a valid tty, save terminal options and set new options
|
||||
bool init();
|
||||
|
||||
//* Restore terminal options
|
||||
void restore();
|
||||
}
|
||||
|
||||
//* Simple logging implementation
|
||||
namespace Logger {
|
||||
const vector<string> log_levels = {
|
||||
"DISABLED",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
};
|
||||
extern std::optional<std::filesystem::path> logfile;
|
||||
|
||||
enum Level : std::uint8_t {
|
||||
DISABLED = 0,
|
||||
ERROR = 1,
|
||||
WARNING = 2,
|
||||
INFO = 3,
|
||||
DEBUG = 4,
|
||||
};
|
||||
|
||||
//* Set log level, valid arguments: "DISABLED", "ERROR", "WARNING", "INFO" and "DEBUG"
|
||||
void set(const string& level);
|
||||
|
||||
void log_write(const Level level, const std::string_view msg);
|
||||
|
||||
inline void error(const std::string_view msg) {
|
||||
log_write(ERROR, msg);
|
||||
}
|
||||
|
||||
inline void warning(const std::string_view msg) {
|
||||
log_write(WARNING, msg);
|
||||
}
|
||||
|
||||
inline void info(const std::string_view msg) {
|
||||
log_write(INFO, msg);
|
||||
}
|
||||
|
||||
inline void debug(const std::string_view msg) {
|
||||
log_write(DEBUG, msg);
|
||||
}
|
||||
}
|
||||
|
||||
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
|
||||
|
||||
namespace Tools {
|
||||
constexpr auto SSmax = std::numeric_limits<std::streamsize>::max();
|
||||
|
||||
class MyNumPunct : public std::numpunct<char> {
|
||||
protected:
|
||||
virtual char do_thousands_sep() const override { return '\''; }
|
||||
virtual std::string do_grouping() const override { return "\03"; }
|
||||
};
|
||||
|
||||
size_t wide_ulen(const std::string_view str);
|
||||
size_t wide_ulen(const std::wstring_view w_str);
|
||||
|
||||
//* Return number of UTF8 characters in a string (wide=true for column size needed on terminal)
|
||||
inline size_t ulen(const std::string_view str, bool wide = false) {
|
||||
return (wide ? wide_ulen(str) : std::ranges::count_if(str, [](char c) { return (static_cast<unsigned char>(c) & 0xC0) != 0x80; }));
|
||||
}
|
||||
|
||||
//* Resize a string consisting of UTF8 characters (only reduces size)
|
||||
string uresize(const string str, const size_t len, bool wide = false);
|
||||
|
||||
//* Resize a string consisting of UTF8 characters from left (only reduces size)
|
||||
string luresize(const string str, const size_t len, bool wide = false);
|
||||
|
||||
//* Replace <from> in <str> with <to> and return new string
|
||||
string s_replace(const string& str, const string& from, const string& to);
|
||||
|
||||
//* Replace ascii control characters with <replacement> in <str> and return new string
|
||||
inline string replace_ascii_control(string str, const char replacement = ' ') {
|
||||
std::ranges::for_each(str, [&replacement](char& c) { if (static_cast<unsigned char>(c) < 0x20) c = replacement; });
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Capitalize <str>
|
||||
inline string capitalize(string str) {
|
||||
str.at(0) = toupper(str.at(0));
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Return <str> with only uppercase characters
|
||||
inline auto str_to_upper(string str) {
|
||||
std::ranges::for_each(str, [](auto& c) { c = ::toupper(c); } );
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Return <str> with only lowercase characters
|
||||
inline auto str_to_lower(string str) {
|
||||
std::ranges::for_each(str, [](char& c) { c = ::tolower(c); } );
|
||||
return str;
|
||||
}
|
||||
|
||||
//* Check if vector <vec> contains value <find_val>
|
||||
template <typename T, typename T2>
|
||||
inline bool v_contains(const vector<T>& vec, const T2& find_val) {
|
||||
return std::ranges::find(vec, find_val) != vec.end();
|
||||
}
|
||||
|
||||
//* Check if string <str> contains string <find_val>, while ignoring case
|
||||
inline bool s_contains_ic(const std::string_view str, const std::string_view find_val) {
|
||||
auto it = std::search(
|
||||
str.begin(), str.end(),
|
||||
find_val.begin(), find_val.end(),
|
||||
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
|
||||
);
|
||||
return it != str.end();
|
||||
}
|
||||
|
||||
//* Return index of <find_val> from vector <vec>, returns size of <vec> if <find_val> is not present
|
||||
template <typename T>
|
||||
inline size_t v_index(const vector<T>& vec, const T& find_val) {
|
||||
return std::ranges::distance(vec.begin(), std::ranges::find(vec, find_val));
|
||||
}
|
||||
|
||||
//* Compare <first> with all following values
|
||||
template<typename First, typename ... T>
|
||||
inline bool is_in(const First& first, const T& ... t) {
|
||||
return ((first == t) or ...);
|
||||
}
|
||||
|
||||
//* Return current time since epoch in seconds
|
||||
inline uint64_t time_s() {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Return current time since epoch in milliseconds
|
||||
inline uint64_t time_ms() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Return current time since epoch in microseconds
|
||||
inline uint64_t time_micros() {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
//* Check if a string is a valid bool value
|
||||
inline bool isbool(const std::string_view str) {
|
||||
return is_in(str, "true", "false", "True", "False");
|
||||
}
|
||||
|
||||
//* Convert string to bool, returning any value not equal to "true" or "True" as false
|
||||
inline bool stobool(const std::string_view str) {
|
||||
return is_in(str, "true", "True");
|
||||
}
|
||||
|
||||
//* Check if a string is a valid integer value (only positive)
|
||||
constexpr bool isint(const std::string_view str) {
|
||||
return std::ranges::all_of(str, ::isdigit);
|
||||
}
|
||||
|
||||
//* Left-trim <t_str> from <str> and return new string
|
||||
string_view ltrim(string_view str, string_view t_str = " ");
|
||||
|
||||
//* Right-trim <t_str> from <str> and return new string
|
||||
string_view rtrim(string_view str, string_view t_str = " ");
|
||||
|
||||
//* Left/right-trim <t_str> from <str> and return new string
|
||||
inline string_view trim(string_view str, string_view t_str = " ") {
|
||||
return ltrim(rtrim(str, t_str), t_str);
|
||||
}
|
||||
|
||||
//* Split <string> at all occurrences of <delim> and return as vector of strings
|
||||
inline std::vector<std::string> ssplit(std::string_view str, char delim = ' ') {
|
||||
std::vector<std::string> result;
|
||||
std::string token;
|
||||
for (char c : str) {
|
||||
if (c == delim) {
|
||||
if (!token.empty()) { result.push_back(token); token.clear(); }
|
||||
} else { token += c; }
|
||||
}
|
||||
if (!token.empty()) result.push_back(token);
|
||||
return result;
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <ms> milliseconds
|
||||
inline void sleep_ms(const size_t& ms) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
//* Put current thread to sleep for <micros> microseconds
|
||||
inline void sleep_micros(const size_t& micros) {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(micros));
|
||||
}
|
||||
|
||||
//* Left justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string ljust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Right justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string rjust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Center justify string <str> if <x> is greater than <str> length, limit return size to <x> by default
|
||||
string cjust(string str, const size_t x, bool utf = false, bool wide = false, bool limit = true);
|
||||
|
||||
//* Replace whitespaces " " with escape code for move right
|
||||
string trans(const string& str);
|
||||
|
||||
//* Convert seconds to format "<days>d <hours>:<minutes>:<seconds>" and return string
|
||||
string sec_to_dhms(size_t seconds, bool no_days = false, bool no_seconds = false);
|
||||
|
||||
//* Scales up in steps of 1024 to highest positive value unit and returns string with unit suffixed
|
||||
//* bit=True or defaults to bytes
|
||||
//* start=int to set 1024 multiplier starting unit
|
||||
//* short=True always returns 0 decimals and shortens unit to 1 character
|
||||
string floating_humanizer(uint64_t value, bool shorten = false, size_t start = 0, bool bit = false, bool per_second = false);
|
||||
|
||||
//* Add std::string operator * : Repeat string <str> <n> number of times
|
||||
std::string operator*(const string& str, int64_t n);
|
||||
|
||||
template <typename K, typename T>
|
||||
#ifdef BTOP_DEBUG
|
||||
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
|
||||
if (auto it = map.find(key); it != map.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid key: [{}] in file: {} on line: {}", key, loc.file_name(), loc.line()));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#else
|
||||
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}) {
|
||||
if (auto it = map.find(key); it != map.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid key: [{}] (Compile btop with DEBUG=true for more extensive logging!)", key));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
#ifdef BTOP_DEBUG
|
||||
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
|
||||
if (index < vec.size()) {
|
||||
return vec[index];
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid index: [{}] in file: {} on line: {}", index, loc.file_name(), loc.line()));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#else
|
||||
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}) {
|
||||
if (index < vec.size()) {
|
||||
return vec[index];
|
||||
} else {
|
||||
Logger::error(fmt::format("safeVal() called with invalid index: [{}] (Compile btop with DEBUG=true for more extensive logging!)", index));
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//* Return current time in <strf> format
|
||||
string strf_time(const string& strf);
|
||||
|
||||
string hostname();
|
||||
string username();
|
||||
|
||||
static inline void busy_wait (void) {
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
__builtin_ia32_pause();
|
||||
#elif defined __ia64__
|
||||
__asm volatile("hint @pause" : : : "memory");
|
||||
#elif defined __sparc__ && (defined __arch64__ || defined __sparc_v9__)
|
||||
__asm volatile("membar #LoadLoad" : : : "memory");
|
||||
#else
|
||||
__asm volatile("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
void atomic_wait(const atomic<bool>& atom, bool old = true) noexcept;
|
||||
|
||||
void atomic_wait_for(const atomic<bool>& atom, bool old = true, const uint64_t wait_ms = 0) noexcept;
|
||||
|
||||
//* Sets atomic<bool> to true on construct, sets to false on destruct
|
||||
class atomic_lock {
|
||||
atomic<bool>& atom;
|
||||
bool not_true{};
|
||||
public:
|
||||
explicit atomic_lock(atomic<bool>& atom, bool wait = false);
|
||||
~atomic_lock() noexcept;
|
||||
atomic_lock(const atomic_lock& other) = delete;
|
||||
atomic_lock& operator=(const atomic_lock& other) = delete;
|
||||
atomic_lock(atomic_lock&& other) = delete;
|
||||
atomic_lock& operator=(atomic_lock&& other) = delete;
|
||||
};
|
||||
|
||||
//* Read a complete file and return as a string
|
||||
string readfile(const std::filesystem::path& path, const string& fallback = "");
|
||||
|
||||
//* Convert a celsius value to celsius, fahrenheit, kelvin or rankin and return tuple with new value and unit.
|
||||
auto celsius_to(const long long& celsius, const string& scale) -> tuple<long long, string>;
|
||||
}
|
||||
|
||||
namespace Tools {
|
||||
//* Creates a named timer that is started on construct (by default) and reports elapsed time in microseconds to Logger::debug() on destruct if running
|
||||
//* Unless delayed_report is set to false, all reporting is buffered and delayed until DebugTimer is destructed or .force_report() is called
|
||||
//* Usage example: Tools::DebugTimer timer(name:"myTimer", [start:true], [delayed_report:true]) // Create timer and start
|
||||
//* timer.stop(); // Stop timer and report elapsed time
|
||||
//* timer.stop_rename_reset("myTimer2"); // Stop timer, report elapsed time, rename timer, reset and restart
|
||||
class DebugTimer {
|
||||
uint64_t start_time{};
|
||||
uint64_t elapsed_time{};
|
||||
bool running{};
|
||||
std::locale custom_locale = std::locale(std::locale::classic(), new Tools::MyNumPunct);
|
||||
vector<string> report_buffer{};
|
||||
string name{};
|
||||
bool delayed_report{};
|
||||
Logger::Level log_level = Logger::DEBUG;
|
||||
public:
|
||||
DebugTimer() = default;
|
||||
explicit DebugTimer(string name, bool start = true, bool delayed_report = true);
|
||||
~DebugTimer();
|
||||
DebugTimer(const DebugTimer& other) = delete;
|
||||
DebugTimer& operator=(const DebugTimer& other) = delete;
|
||||
DebugTimer(DebugTimer&& other) = delete;
|
||||
DebugTimer& operator=(DebugTimer&& other) = delete;
|
||||
|
||||
void start();
|
||||
void stop(bool report = true);
|
||||
void reset(bool restart = true);
|
||||
//* Stops and reports (default), renames timer then resets and restarts (default)
|
||||
void stop_rename_reset(const string& new_name, bool report = true, bool restart = true);
|
||||
void report();
|
||||
void force_report();
|
||||
uint64_t elapsed();
|
||||
bool is_running();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
constexpr std::string_view GIT_COMMIT = "@GIT_COMMIT@";
|
||||
constexpr std::string_view COMPILER = "@COMPILER@";
|
||||
constexpr std::string_view COMPILER_VERSION = "@COMPILER_VERSION@";
|
||||
constexpr std::string_view CONFIGURE_COMMAND = "@CONFIGURE_COMMAND@";
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+19
@@ -0,0 +1,19 @@
|
||||
enable_language(C)
|
||||
|
||||
add_library(igt OBJECT
|
||||
igt_perf.c
|
||||
intel_device_info.c
|
||||
intel_gpu_top.c
|
||||
intel_name_lookup_shim.c
|
||||
)
|
||||
|
||||
if(BTOP_LTO)
|
||||
# We have checked LTO support already and it's supported :)
|
||||
set_target_properties(igt PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON)
|
||||
endif()
|
||||
|
||||
# Disable all warnings
|
||||
target_compile_options(igt PRIVATE -w)
|
||||
|
||||
# Link igt into btop
|
||||
target_link_libraries(libbtop $<TARGET_OBJECTS:igt>)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+786
@@ -0,0 +1,786 @@
|
||||
/*
|
||||
* Copyright 2013 Intel Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _I915_PCIIDS_H
|
||||
#define _I915_PCIIDS_H
|
||||
|
||||
/*
|
||||
* A pci_device_id struct {
|
||||
* __u32 vendor, device;
|
||||
* __u32 subvendor, subdevice;
|
||||
* __u32 class, class_mask;
|
||||
* kernel_ulong_t driver_data;
|
||||
* };
|
||||
* Don't use C99 here because "class" is reserved and we want to
|
||||
* give userspace flexibility.
|
||||
*/
|
||||
#define INTEL_VGA_DEVICE(id, info) { \
|
||||
0x8086, id, \
|
||||
~0, ~0, \
|
||||
0x030000, 0xff0000, \
|
||||
(unsigned long) info }
|
||||
|
||||
#define INTEL_QUANTA_VGA_DEVICE(info) { \
|
||||
0x8086, 0x16a, \
|
||||
0x152d, 0x8990, \
|
||||
0x030000, 0xff0000, \
|
||||
(unsigned long) info }
|
||||
|
||||
#define INTEL_I810_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7121, ## __VA_ARGS__), /* I810 */ \
|
||||
MACRO__(0x7123, ## __VA_ARGS__), /* I810_DC100 */ \
|
||||
MACRO__(0x7125, ## __VA_ARGS__) /* I810_E */
|
||||
|
||||
#define INTEL_I815_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1132, ## __VA_ARGS__) /* I815*/
|
||||
|
||||
#define INTEL_I830_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3577, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I845G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2562, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I85X_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3582, ## __VA_ARGS__), /* I855_GM */ \
|
||||
MACRO__(0x358e, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_I865G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2572, ## __VA_ARGS__) /* I865_G */
|
||||
|
||||
#define INTEL_I915G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2582, ## __VA_ARGS__), /* I915_G */ \
|
||||
MACRO__(0x258a, ## __VA_ARGS__) /* E7221_G */
|
||||
|
||||
#define INTEL_I915GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2592, ## __VA_ARGS__) /* I915_GM */
|
||||
|
||||
#define INTEL_I945G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2772, ## __VA_ARGS__) /* I945_G */
|
||||
|
||||
#define INTEL_I945GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x27a2, ## __VA_ARGS__), /* I945_GM */ \
|
||||
MACRO__(0x27ae, ## __VA_ARGS__) /* I945_GME */
|
||||
|
||||
#define INTEL_I965G_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2972, ## __VA_ARGS__), /* I946_GZ */ \
|
||||
MACRO__(0x2982, ## __VA_ARGS__), /* G35_G */ \
|
||||
MACRO__(0x2992, ## __VA_ARGS__), /* I965_Q */ \
|
||||
MACRO__(0x29a2, ## __VA_ARGS__) /* I965_G */
|
||||
|
||||
#define INTEL_G33_IDS(MACRO__, ...) \
|
||||
MACRO__(0x29b2, ## __VA_ARGS__), /* Q35_G */ \
|
||||
MACRO__(0x29c2, ## __VA_ARGS__), /* G33_G */ \
|
||||
MACRO__(0x29d2, ## __VA_ARGS__) /* Q33_G */
|
||||
|
||||
#define INTEL_I965GM_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2a02, ## __VA_ARGS__), /* I965_GM */ \
|
||||
MACRO__(0x2a12, ## __VA_ARGS__) /* I965_GME */
|
||||
|
||||
#define INTEL_GM45_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2a42, ## __VA_ARGS__) /* GM45_G */
|
||||
|
||||
#define INTEL_G45_IDS(MACRO__, ...) \
|
||||
MACRO__(0x2e02, ## __VA_ARGS__), /* IGD_E_G */ \
|
||||
MACRO__(0x2e12, ## __VA_ARGS__), /* Q45_G */ \
|
||||
MACRO__(0x2e22, ## __VA_ARGS__), /* G45_G */ \
|
||||
MACRO__(0x2e32, ## __VA_ARGS__), /* G41_G */ \
|
||||
MACRO__(0x2e42, ## __VA_ARGS__), /* B43_G */ \
|
||||
MACRO__(0x2e92, ## __VA_ARGS__) /* B43_G.1 */
|
||||
|
||||
#define INTEL_PNV_G_IDS(MACRO__, ...) \
|
||||
MACRO__(0xa001, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_PNV_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0xa011, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_PNV_IDS(MACRO__, ...) \
|
||||
INTEL_PNV_G_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_PNV_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_D_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0042, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0046, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ILK_IDS(MACRO__, ...) \
|
||||
INTEL_ILK_D_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ILK_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0102, ## __VA_ARGS__), \
|
||||
MACRO__(0x010A, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0112, ## __VA_ARGS__), \
|
||||
MACRO__(0x0122, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_D_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_D_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_D_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0106, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0116, ## __VA_ARGS__), \
|
||||
MACRO__(0x0126, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_M_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_M_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_M_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SNB_IDS(MACRO__, ...) \
|
||||
INTEL_SNB_D_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SNB_M_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_M_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0156, ## __VA_ARGS__) /* GT1 mobile */
|
||||
|
||||
#define INTEL_IVB_M_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0166, ## __VA_ARGS__) /* GT2 mobile */
|
||||
|
||||
#define INTEL_IVB_M_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_M_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_M_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_D_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0152, ## __VA_ARGS__), /* GT1 desktop */ \
|
||||
MACRO__(0x015a, ## __VA_ARGS__) /* GT1 server */
|
||||
|
||||
#define INTEL_IVB_D_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0162, ## __VA_ARGS__), /* GT2 desktop */ \
|
||||
MACRO__(0x016a, ## __VA_ARGS__) /* GT2 server */
|
||||
|
||||
#define INTEL_IVB_D_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_D_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_D_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_IDS(MACRO__, ...) \
|
||||
INTEL_IVB_M_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_IVB_D_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_IVB_Q_IDS(MACRO__, ...) \
|
||||
INTEL_QUANTA_VGA_DEVICE(__VA_ARGS__) /* Quanta transcode */
|
||||
|
||||
#define INTEL_HSW_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A02, ## __VA_ARGS__), /* ULT GT1 desktop */ \
|
||||
MACRO__(0x0A06, ## __VA_ARGS__), /* ULT GT1 mobile */ \
|
||||
MACRO__(0x0A0A, ## __VA_ARGS__), /* ULT GT1 server */ \
|
||||
MACRO__(0x0A0B, ## __VA_ARGS__) /* ULT GT1 reserved */
|
||||
|
||||
#define INTEL_HSW_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A0E, ## __VA_ARGS__) /* ULX GT1 mobile */
|
||||
|
||||
#define INTEL_HSW_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0402, ## __VA_ARGS__), /* GT1 desktop */ \
|
||||
MACRO__(0x0406, ## __VA_ARGS__), /* GT1 mobile */ \
|
||||
MACRO__(0x040A, ## __VA_ARGS__), /* GT1 server */ \
|
||||
MACRO__(0x040B, ## __VA_ARGS__), /* GT1 reserved */ \
|
||||
MACRO__(0x040E, ## __VA_ARGS__), /* GT1 reserved */ \
|
||||
MACRO__(0x0C02, ## __VA_ARGS__), /* SDV GT1 desktop */ \
|
||||
MACRO__(0x0C06, ## __VA_ARGS__), /* SDV GT1 mobile */ \
|
||||
MACRO__(0x0C0A, ## __VA_ARGS__), /* SDV GT1 server */ \
|
||||
MACRO__(0x0C0B, ## __VA_ARGS__), /* SDV GT1 reserved */ \
|
||||
MACRO__(0x0C0E, ## __VA_ARGS__), /* SDV GT1 reserved */ \
|
||||
MACRO__(0x0D02, ## __VA_ARGS__), /* CRW GT1 desktop */ \
|
||||
MACRO__(0x0D06, ## __VA_ARGS__), /* CRW GT1 mobile */ \
|
||||
MACRO__(0x0D0A, ## __VA_ARGS__), /* CRW GT1 server */ \
|
||||
MACRO__(0x0D0B, ## __VA_ARGS__), /* CRW GT1 reserved */ \
|
||||
MACRO__(0x0D0E, ## __VA_ARGS__) /* CRW GT1 reserved */
|
||||
|
||||
#define INTEL_HSW_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A12, ## __VA_ARGS__), /* ULT GT2 desktop */ \
|
||||
MACRO__(0x0A16, ## __VA_ARGS__), /* ULT GT2 mobile */ \
|
||||
MACRO__(0x0A1A, ## __VA_ARGS__), /* ULT GT2 server */ \
|
||||
MACRO__(0x0A1B, ## __VA_ARGS__) /* ULT GT2 reserved */ \
|
||||
|
||||
#define INTEL_HSW_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A1E, ## __VA_ARGS__) /* ULX GT2 mobile */ \
|
||||
|
||||
#define INTEL_HSW_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0412, ## __VA_ARGS__), /* GT2 desktop */ \
|
||||
MACRO__(0x0416, ## __VA_ARGS__), /* GT2 mobile */ \
|
||||
MACRO__(0x041A, ## __VA_ARGS__), /* GT2 server */ \
|
||||
MACRO__(0x041B, ## __VA_ARGS__), /* GT2 reserved */ \
|
||||
MACRO__(0x041E, ## __VA_ARGS__), /* GT2 reserved */ \
|
||||
MACRO__(0x0C12, ## __VA_ARGS__), /* SDV GT2 desktop */ \
|
||||
MACRO__(0x0C16, ## __VA_ARGS__), /* SDV GT2 mobile */ \
|
||||
MACRO__(0x0C1A, ## __VA_ARGS__), /* SDV GT2 server */ \
|
||||
MACRO__(0x0C1B, ## __VA_ARGS__), /* SDV GT2 reserved */ \
|
||||
MACRO__(0x0C1E, ## __VA_ARGS__), /* SDV GT2 reserved */ \
|
||||
MACRO__(0x0D12, ## __VA_ARGS__), /* CRW GT2 desktop */ \
|
||||
MACRO__(0x0D16, ## __VA_ARGS__), /* CRW GT2 mobile */ \
|
||||
MACRO__(0x0D1A, ## __VA_ARGS__), /* CRW GT2 server */ \
|
||||
MACRO__(0x0D1B, ## __VA_ARGS__), /* CRW GT2 reserved */ \
|
||||
MACRO__(0x0D1E, ## __VA_ARGS__) /* CRW GT2 reserved */
|
||||
|
||||
#define INTEL_HSW_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A22, ## __VA_ARGS__), /* ULT GT3 desktop */ \
|
||||
MACRO__(0x0A26, ## __VA_ARGS__), /* ULT GT3 mobile */ \
|
||||
MACRO__(0x0A2A, ## __VA_ARGS__), /* ULT GT3 server */ \
|
||||
MACRO__(0x0A2B, ## __VA_ARGS__), /* ULT GT3 reserved */ \
|
||||
MACRO__(0x0A2E, ## __VA_ARGS__) /* ULT GT3 reserved */
|
||||
|
||||
#define INTEL_HSW_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x0422, ## __VA_ARGS__), /* GT3 desktop */ \
|
||||
MACRO__(0x0426, ## __VA_ARGS__), /* GT3 mobile */ \
|
||||
MACRO__(0x042A, ## __VA_ARGS__), /* GT3 server */ \
|
||||
MACRO__(0x042B, ## __VA_ARGS__), /* GT3 reserved */ \
|
||||
MACRO__(0x042E, ## __VA_ARGS__), /* GT3 reserved */ \
|
||||
MACRO__(0x0C22, ## __VA_ARGS__), /* SDV GT3 desktop */ \
|
||||
MACRO__(0x0C26, ## __VA_ARGS__), /* SDV GT3 mobile */ \
|
||||
MACRO__(0x0C2A, ## __VA_ARGS__), /* SDV GT3 server */ \
|
||||
MACRO__(0x0C2B, ## __VA_ARGS__), /* SDV GT3 reserved */ \
|
||||
MACRO__(0x0C2E, ## __VA_ARGS__), /* SDV GT3 reserved */ \
|
||||
MACRO__(0x0D22, ## __VA_ARGS__), /* CRW GT3 desktop */ \
|
||||
MACRO__(0x0D26, ## __VA_ARGS__), /* CRW GT3 mobile */ \
|
||||
MACRO__(0x0D2A, ## __VA_ARGS__), /* CRW GT3 server */ \
|
||||
MACRO__(0x0D2B, ## __VA_ARGS__), /* CRW GT3 reserved */ \
|
||||
MACRO__(0x0D2E, ## __VA_ARGS__) /* CRW GT3 reserved */
|
||||
|
||||
#define INTEL_HSW_IDS(MACRO__, ...) \
|
||||
INTEL_HSW_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_HSW_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_VLV_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0f30, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f31, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f32, ## __VA_ARGS__), \
|
||||
MACRO__(0x0f33, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_BDW_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1606, ## __VA_ARGS__), /* GT1 ULT */ \
|
||||
MACRO__(0x160B, ## __VA_ARGS__) /* GT1 Iris */
|
||||
|
||||
#define INTEL_BDW_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x160E, ## __VA_ARGS__) /* GT1 ULX */
|
||||
|
||||
#define INTEL_BDW_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1602, ## __VA_ARGS__), /* GT1 ULT */ \
|
||||
MACRO__(0x160A, ## __VA_ARGS__), /* GT1 Server */ \
|
||||
MACRO__(0x160D, ## __VA_ARGS__) /* GT1 Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1616, ## __VA_ARGS__), /* GT2 ULT */ \
|
||||
MACRO__(0x161B, ## __VA_ARGS__) /* GT2 ULT */
|
||||
|
||||
#define INTEL_BDW_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x161E, ## __VA_ARGS__) /* GT2 ULX */
|
||||
|
||||
#define INTEL_BDW_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1612, ## __VA_ARGS__), /* GT2 Halo */ \
|
||||
MACRO__(0x161A, ## __VA_ARGS__), /* GT2 Server */ \
|
||||
MACRO__(0x161D, ## __VA_ARGS__) /* GT2 Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1626, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x162B, ## __VA_ARGS__) /* Iris */ \
|
||||
|
||||
#define INTEL_BDW_ULX_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x162E, ## __VA_ARGS__) /* ULX */
|
||||
|
||||
#define INTEL_BDW_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1622, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x162A, ## __VA_ARGS__), /* Server */ \
|
||||
MACRO__(0x162D, ## __VA_ARGS__) /* Workstation */
|
||||
|
||||
#define INTEL_BDW_ULT_RSVD_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1636, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x163B, ## __VA_ARGS__) /* Iris */
|
||||
|
||||
#define INTEL_BDW_ULX_RSVD_IDS(MACRO__, ...) \
|
||||
MACRO__(0x163E, ## __VA_ARGS__) /* ULX */
|
||||
|
||||
#define INTEL_BDW_RSVD_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_ULT_RSVD_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_ULX_RSVD_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1632, ## __VA_ARGS__), /* ULT */ \
|
||||
MACRO__(0x163A, ## __VA_ARGS__), /* Server */ \
|
||||
MACRO__(0x163D, ## __VA_ARGS__) /* Workstation */
|
||||
|
||||
#define INTEL_BDW_IDS(MACRO__, ...) \
|
||||
INTEL_BDW_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_BDW_RSVD_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CHV_IDS(MACRO__, ...) \
|
||||
MACRO__(0x22b0, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b1, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b2, ## __VA_ARGS__), \
|
||||
MACRO__(0x22b3, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_SKL_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1906, ## __VA_ARGS__), /* ULT GT1 */ \
|
||||
MACRO__(0x1913, ## __VA_ARGS__) /* ULT GT1.5 */
|
||||
|
||||
#define INTEL_SKL_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x190E, ## __VA_ARGS__), /* ULX GT1 */ \
|
||||
MACRO__(0x1915, ## __VA_ARGS__) /* ULX GT1.5 */
|
||||
|
||||
#define INTEL_SKL_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1902, ## __VA_ARGS__), /* DT GT1 */ \
|
||||
MACRO__(0x190A, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x190B, ## __VA_ARGS__), /* Halo GT1 */ \
|
||||
MACRO__(0x1917, ## __VA_ARGS__) /* DT GT1.5 */
|
||||
|
||||
#define INTEL_SKL_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1916, ## __VA_ARGS__), /* ULT GT2 */ \
|
||||
MACRO__(0x1921, ## __VA_ARGS__) /* ULT GT2F */
|
||||
|
||||
#define INTEL_SKL_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x191E, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
#define INTEL_SKL_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x1912, ## __VA_ARGS__), /* DT GT2 */ \
|
||||
MACRO__(0x191A, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x191B, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x191D, ## __VA_ARGS__) /* WKS GT2 */
|
||||
|
||||
#define INTEL_SKL_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1923, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x1926, ## __VA_ARGS__), /* ULT GT3e */ \
|
||||
MACRO__(0x1927, ## __VA_ARGS__) /* ULT GT3e */
|
||||
|
||||
#define INTEL_SKL_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x192A, ## __VA_ARGS__), /* SRV GT3 */ \
|
||||
MACRO__(0x192B, ## __VA_ARGS__), /* Halo GT3e */ \
|
||||
MACRO__(0x192D, ## __VA_ARGS__) /* SRV GT3e */
|
||||
|
||||
#define INTEL_SKL_GT4_IDS(MACRO__, ...) \
|
||||
MACRO__(0x1932, ## __VA_ARGS__), /* DT GT4 */ \
|
||||
MACRO__(0x193A, ## __VA_ARGS__), /* SRV GT4e */ \
|
||||
MACRO__(0x193B, ## __VA_ARGS__), /* Halo GT4e */ \
|
||||
MACRO__(0x193D, ## __VA_ARGS__) /* WKS GT4e */
|
||||
|
||||
#define INTEL_SKL_IDS(MACRO__, ...) \
|
||||
INTEL_SKL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_SKL_GT4_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_BXT_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0A84, ## __VA_ARGS__), \
|
||||
MACRO__(0x1A84, ## __VA_ARGS__), \
|
||||
MACRO__(0x1A85, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A84, ## __VA_ARGS__), /* APL HD Graphics 505 */ \
|
||||
MACRO__(0x5A85, ## __VA_ARGS__) /* APL HD Graphics 500 */
|
||||
|
||||
#define INTEL_GLK_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3184, ## __VA_ARGS__), \
|
||||
MACRO__(0x3185, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_KBL_ULT_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5906, ## __VA_ARGS__), /* ULT GT1 */ \
|
||||
MACRO__(0x5913, ## __VA_ARGS__) /* ULT GT1.5 */
|
||||
|
||||
#define INTEL_KBL_ULX_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x590E, ## __VA_ARGS__), /* ULX GT1 */ \
|
||||
MACRO__(0x5915, ## __VA_ARGS__) /* ULX GT1.5 */
|
||||
|
||||
#define INTEL_KBL_GT1_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_ULX_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5902, ## __VA_ARGS__), /* DT GT1 */ \
|
||||
MACRO__(0x5908, ## __VA_ARGS__), /* Halo GT1 */ \
|
||||
MACRO__(0x590A, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x590B, ## __VA_ARGS__) /* Halo GT1 */
|
||||
|
||||
#define INTEL_KBL_ULT_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5916, ## __VA_ARGS__), /* ULT GT2 */ \
|
||||
MACRO__(0x5921, ## __VA_ARGS__) /* ULT GT2F */
|
||||
|
||||
#define INTEL_KBL_ULX_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x591E, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
#define INTEL_KBL_GT2_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_ULX_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5912, ## __VA_ARGS__), /* DT GT2 */ \
|
||||
MACRO__(0x5917, ## __VA_ARGS__), /* Mobile GT2 */ \
|
||||
MACRO__(0x591A, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x591B, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x591D, ## __VA_ARGS__) /* WKS GT2 */
|
||||
|
||||
#define INTEL_KBL_ULT_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5926, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_KBL_GT3_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_ULT_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5923, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x5927, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_KBL_GT4_IDS(MACRO__, ...) \
|
||||
MACRO__(0x593B, ## __VA_ARGS__) /* Halo GT4 */
|
||||
|
||||
/* AML/KBL Y GT2 */
|
||||
#define INTEL_AML_KBL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x591C, ## __VA_ARGS__), /* ULX GT2 */ \
|
||||
MACRO__(0x87C0, ## __VA_ARGS__) /* ULX GT2 */
|
||||
|
||||
/* AML/CFL Y GT2 */
|
||||
#define INTEL_AML_CFL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x87CA, ## __VA_ARGS__)
|
||||
|
||||
/* CML GT1 */
|
||||
#define INTEL_CML_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9BA2, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA4, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA5, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BA8, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_U_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9B21, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BAA, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BAC, ## __VA_ARGS__)
|
||||
|
||||
/* CML GT2 */
|
||||
#define INTEL_CML_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9BC2, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC4, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC5, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC6, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BC8, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BE6, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BF6, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9B41, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BCA, ## __VA_ARGS__), \
|
||||
MACRO__(0x9BCC, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CML_IDS(MACRO__, ...) \
|
||||
INTEL_CML_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_U_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CML_U_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_KBL_IDS(MACRO__, ...) \
|
||||
INTEL_KBL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_KBL_GT4_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_AML_KBL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* CFL S */
|
||||
#define INTEL_CFL_S_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E90, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x3E93, ## __VA_ARGS__), /* SRV GT1 */ \
|
||||
MACRO__(0x3E99, ## __VA_ARGS__) /* SRV GT1 */
|
||||
|
||||
#define INTEL_CFL_S_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E91, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E92, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E96, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E98, ## __VA_ARGS__), /* SRV GT2 */ \
|
||||
MACRO__(0x3E9A, ## __VA_ARGS__) /* SRV GT2 */
|
||||
|
||||
/* CFL H */
|
||||
#define INTEL_CFL_H_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E9C, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CFL_H_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3E94, ## __VA_ARGS__), /* Halo GT2 */ \
|
||||
MACRO__(0x3E9B, ## __VA_ARGS__) /* Halo GT2 */
|
||||
|
||||
/* CFL U GT2 */
|
||||
#define INTEL_CFL_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA9, ## __VA_ARGS__)
|
||||
|
||||
/* CFL U GT3 */
|
||||
#define INTEL_CFL_U_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA5, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA6, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA7, ## __VA_ARGS__), /* ULT GT3 */ \
|
||||
MACRO__(0x3EA8, ## __VA_ARGS__) /* ULT GT3 */
|
||||
|
||||
#define INTEL_CFL_IDS(MACRO__, ...) \
|
||||
INTEL_CFL_S_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_S_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_H_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_H_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_U_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_CFL_U_GT3_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_AML_CFL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT1 */
|
||||
#define INTEL_WHL_U_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA1, ## __VA_ARGS__), \
|
||||
MACRO__(0x3EA4, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT2 */
|
||||
#define INTEL_WHL_U_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA0, ## __VA_ARGS__), \
|
||||
MACRO__(0x3EA3, ## __VA_ARGS__)
|
||||
|
||||
/* WHL/CFL U GT3 */
|
||||
#define INTEL_WHL_U_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x3EA2, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_WHL_IDS(MACRO__, ...) \
|
||||
INTEL_WHL_U_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_WHL_U_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_WHL_U_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* CNL */
|
||||
#define INTEL_CNL_PORT_F_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5A44, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A4C, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A54, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A5C, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_CNL_IDS(MACRO__, ...) \
|
||||
INTEL_CNL_PORT_F_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A41, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A42, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A4A, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A50, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A51, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A52, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x5A5A, ## __VA_ARGS__)
|
||||
|
||||
/* ICL */
|
||||
#define INTEL_ICL_PORT_F_IDS(MACRO__, ...) \
|
||||
MACRO__(0x8A50, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A52, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A53, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A54, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A56, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A57, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A58, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5A, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5B, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5C, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A70, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A71, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ICL_IDS(MACRO__, ...) \
|
||||
INTEL_ICL_PORT_F_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A51, ## __VA_ARGS__), \
|
||||
MACRO__(0x8A5D, ## __VA_ARGS__)
|
||||
|
||||
/* EHL */
|
||||
#define INTEL_EHL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4541, ## __VA_ARGS__), \
|
||||
MACRO__(0x4551, ## __VA_ARGS__), \
|
||||
MACRO__(0x4555, ## __VA_ARGS__), \
|
||||
MACRO__(0x4557, ## __VA_ARGS__), \
|
||||
MACRO__(0x4570, ## __VA_ARGS__), \
|
||||
MACRO__(0x4571, ## __VA_ARGS__)
|
||||
|
||||
/* JSL */
|
||||
#define INTEL_JSL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4E51, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E55, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E57, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E61, ## __VA_ARGS__), \
|
||||
MACRO__(0x4E71, ## __VA_ARGS__)
|
||||
|
||||
/* TGL */
|
||||
#define INTEL_TGL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A60, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A68, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A70, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_TGL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A78, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC0, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AF8, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_TGL_IDS(MACRO__, ...) \
|
||||
INTEL_TGL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_TGL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* RKL */
|
||||
#define INTEL_RKL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4C80, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8C, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C90, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C9A, ## __VA_ARGS__)
|
||||
|
||||
/* DG1 */
|
||||
#define INTEL_DG1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4905, ## __VA_ARGS__), \
|
||||
MACRO__(0x4906, ## __VA_ARGS__), \
|
||||
MACRO__(0x4907, ## __VA_ARGS__), \
|
||||
MACRO__(0x4908, ## __VA_ARGS__), \
|
||||
MACRO__(0x4909, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-S */
|
||||
#define INTEL_ADLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4680, ## __VA_ARGS__), \
|
||||
MACRO__(0x4682, ## __VA_ARGS__), \
|
||||
MACRO__(0x4688, ## __VA_ARGS__), \
|
||||
MACRO__(0x468A, ## __VA_ARGS__), \
|
||||
MACRO__(0x468B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4690, ## __VA_ARGS__), \
|
||||
MACRO__(0x4692, ## __VA_ARGS__), \
|
||||
MACRO__(0x4693, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-P */
|
||||
#define INTEL_ADLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A8, ## __VA_ARGS__), \
|
||||
MACRO__(0x46AA, ## __VA_ARGS__), \
|
||||
MACRO__(0x462A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4626, ## __VA_ARGS__), \
|
||||
MACRO__(0x4628, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C3, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-N */
|
||||
#define INTEL_ADLN_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46D0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D4, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-S */
|
||||
#define INTEL_RPLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA780, ## __VA_ARGS__), \
|
||||
MACRO__(0xA781, ## __VA_ARGS__), \
|
||||
MACRO__(0xA782, ## __VA_ARGS__), \
|
||||
MACRO__(0xA783, ## __VA_ARGS__), \
|
||||
MACRO__(0xA788, ## __VA_ARGS__), \
|
||||
MACRO__(0xA789, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78A, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78B, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-U */
|
||||
#define INTEL_RPLU_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA721, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A1, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A9, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AC, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AD, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-P */
|
||||
#define INTEL_RPLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA720, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A0, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A8, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AA, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AB, ## __VA_ARGS__)
|
||||
|
||||
/* DG2 */
|
||||
#define INTEL_DG2_G10_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5690, ## __VA_ARGS__), \
|
||||
MACRO__(0x5691, ## __VA_ARGS__), \
|
||||
MACRO__(0x5692, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BE, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BF, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_G11_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5693, ## __VA_ARGS__), \
|
||||
MACRO__(0x5694, ## __VA_ARGS__), \
|
||||
MACRO__(0x5695, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A5, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BA, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BB, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BC, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BD, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_G12_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5696, ## __VA_ARGS__), \
|
||||
MACRO__(0x5697, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A4, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B3, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_DG2_IDS(MACRO__, ...) \
|
||||
INTEL_DG2_G10_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_DG2_G11_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_DG2_G12_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M150_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56C2, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M75_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C1, ## __VA_ARGS__)
|
||||
|
||||
#define INTEL_ATS_M_IDS(MACRO__, ...) \
|
||||
INTEL_ATS_M150_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ATS_M75_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* MTL */
|
||||
#define INTEL_MTL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D40, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
|
||||
#endif /* _I915_PCIIDS_H */
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2022 Intel Corporation
|
||||
*/
|
||||
#ifndef _I915_PCIIDS_LOCAL_H_
|
||||
#define _I915_PCIIDS_LOCAL_H_
|
||||
|
||||
#include "i915_pciids.h"
|
||||
|
||||
/* MTL perf */
|
||||
#ifndef INTEL_MTL_M_IDS
|
||||
#define INTEL_MTL_M_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_GT2_IDS
|
||||
#define INTEL_MTL_P_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_GT3_IDS
|
||||
#define INTEL_MTL_P_GT3_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_MTL_P_IDS
|
||||
#define INTEL_MTL_P_IDS(MACRO__, ...) \
|
||||
INTEL_MTL_P_GT2_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_MTL_P_GT3_IDS(MACRO__, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_GT1_IDS
|
||||
#define INTEL_ARL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_GT2_IDS
|
||||
#define INTEL_ARL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef INTEL_ARL_IDS
|
||||
#define INTEL_ARL_IDS(MACRO__, ...) \
|
||||
INTEL_ARL_GT1_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
INTEL_ARL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* PVC */
|
||||
#ifndef INTEL_PVC_IDS
|
||||
#define INTEL_PVC_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0BD0, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD2, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD5, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD6, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD7, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD8, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDA, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDB, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* _I915_PCIIDS_LOCAL_H */
|
||||
@@ -0,0 +1,210 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <linux/limits.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "igt_perf.h"
|
||||
|
||||
static char *bus_address(int i915, char *path, int pathlen)
|
||||
{
|
||||
struct stat st;
|
||||
int len = -1;
|
||||
int dir;
|
||||
char *s;
|
||||
|
||||
if (fstat(i915, &st) || !S_ISCHR(st.st_mode))
|
||||
return NULL;
|
||||
|
||||
snprintf(path, pathlen, "/sys/dev/char/%d:%d",
|
||||
major(st.st_rdev), minor(st.st_rdev));
|
||||
|
||||
dir = open(path, O_RDONLY);
|
||||
if (dir != -1) {
|
||||
len = readlinkat(dir, "device", path, pathlen - 1);
|
||||
close(dir);
|
||||
}
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
path[len] = '\0';
|
||||
|
||||
/* strip off the relative path */
|
||||
s = strrchr(path, '/');
|
||||
if (s)
|
||||
memmove(path, s + 1, len - (s - path) + 1);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char *i915_perf_device(int i915, char *buf, int buflen)
|
||||
{
|
||||
char *s;
|
||||
|
||||
#define prefix "i915_"
|
||||
#define plen strlen(prefix)
|
||||
|
||||
if (!buf || buflen < plen)
|
||||
return "i915";
|
||||
|
||||
memcpy(buf, prefix, plen);
|
||||
|
||||
if (!bus_address(i915, buf + plen, buflen - plen) ||
|
||||
strcmp(buf + plen, "0000:00:02.0") == 0) /* legacy name for igfx */
|
||||
buf[plen - 1] = '\0';
|
||||
|
||||
/* Convert all colons in the address to '_', thanks perf! */
|
||||
for (s = buf; *s; s++)
|
||||
if (*s == ':')
|
||||
*s = '_';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *xe_perf_device(int xe, char *buf, int buflen)
|
||||
{
|
||||
char *s;
|
||||
char pref[] = "xe_";
|
||||
int len = strlen(pref);
|
||||
|
||||
|
||||
if (!buf || buflen < len)
|
||||
return "xe";
|
||||
|
||||
memcpy(buf, pref, len);
|
||||
|
||||
if (!bus_address(xe, buf + len, buflen - len))
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
/* Convert all colons in the address to '_', thanks perf! */
|
||||
for (s = buf; *s; s++)
|
||||
if (*s == ':')
|
||||
*s = '_';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint64_t xe_perf_type_id(int xe)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
return igt_perf_type_id(xe_perf_device(xe, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
uint64_t i915_perf_type_id(int i915)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
return igt_perf_type_id(i915_perf_device(i915, buf, sizeof(buf)));
|
||||
}
|
||||
|
||||
uint64_t igt_perf_type_id(const char *device)
|
||||
{
|
||||
char buf[64];
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"/sys/bus/event_source/devices/%s/type", device);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
ret = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (ret < 1)
|
||||
return 0;
|
||||
|
||||
buf[ret] = '\0';
|
||||
|
||||
return strtoull(buf, NULL, 0);
|
||||
}
|
||||
|
||||
int igt_perf_events_dir(int i915)
|
||||
{
|
||||
char buf[80];
|
||||
char path[PATH_MAX];
|
||||
|
||||
i915_perf_device(i915, buf, sizeof(buf));
|
||||
snprintf(path, sizeof(path), "/sys/bus/event_source/devices/%s/events", buf);
|
||||
return open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
static int
|
||||
_perf_open(uint64_t type, uint64_t config, int group, uint64_t format)
|
||||
{
|
||||
struct perf_event_attr attr = { };
|
||||
int nr_cpus = get_nprocs_conf();
|
||||
int cpu = 0, ret;
|
||||
|
||||
attr.type = type;
|
||||
if (attr.type == 0)
|
||||
return -ENOENT;
|
||||
|
||||
if (group >= 0)
|
||||
format &= ~PERF_FORMAT_GROUP;
|
||||
|
||||
attr.read_format = format;
|
||||
attr.config = config;
|
||||
attr.use_clockid = 1;
|
||||
attr.clockid = CLOCK_MONOTONIC;
|
||||
|
||||
do {
|
||||
ret = perf_event_open(&attr, -1, cpu++, group, 0);
|
||||
} while ((ret < 0 && errno == EINVAL) && (cpu < nr_cpus));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int perf_igfx_open(uint64_t config)
|
||||
{
|
||||
return _perf_open(igt_perf_type_id("i915"), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_igfx_open_group(uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(igt_perf_type_id("i915"), config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
|
||||
int perf_xe_open(int xe, uint64_t config)
|
||||
{
|
||||
return _perf_open(xe_perf_type_id(xe), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_i915_open(int i915, uint64_t config)
|
||||
{
|
||||
return _perf_open(i915_perf_type_id(i915), config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int perf_i915_open_group(int i915, uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(i915_perf_type_id(i915), config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
|
||||
int igt_perf_open(uint64_t type, uint64_t config)
|
||||
{
|
||||
return _perf_open(type, config, -1,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED);
|
||||
}
|
||||
|
||||
int igt_perf_open_group(uint64_t type, uint64_t config, int group)
|
||||
{
|
||||
return _perf_open(type, config, group,
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef I915_PERF_H
|
||||
#define I915_PERF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/perf_event.h>
|
||||
#endif
|
||||
|
||||
//#include "igt_gt.h"
|
||||
|
||||
static inline int
|
||||
perf_event_open(struct perf_event_attr *attr,
|
||||
pid_t pid,
|
||||
int cpu,
|
||||
int group_fd,
|
||||
unsigned long flags)
|
||||
{
|
||||
#ifndef __NR_perf_event_open
|
||||
#if defined(__i386__)
|
||||
#define __NR_perf_event_open 336
|
||||
#elif defined(__x86_64__)
|
||||
#define __NR_perf_event_open 298
|
||||
#else
|
||||
#define __NR_perf_event_open 0
|
||||
#endif
|
||||
#endif
|
||||
attr->size = sizeof(*attr);
|
||||
return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
|
||||
}
|
||||
|
||||
uint64_t igt_perf_type_id(const char *device);
|
||||
int igt_perf_events_dir(int i915);
|
||||
int igt_perf_open(uint64_t type, uint64_t config);
|
||||
int igt_perf_open_group(uint64_t type, uint64_t config, int group);
|
||||
|
||||
const char *i915_perf_device(int i915, char *buf, int buflen);
|
||||
uint64_t i915_perf_type_id(int i915);
|
||||
|
||||
const char *xe_perf_device(int xe, char *buf, int buflen);
|
||||
uint64_t xe_perf_type_id(int);
|
||||
|
||||
int perf_igfx_open(uint64_t config);
|
||||
int perf_igfx_open_group(uint64_t config, int group);
|
||||
|
||||
int perf_i915_open(int i915, uint64_t config);
|
||||
int perf_i915_open_group(int i915, uint64_t config, int group);
|
||||
|
||||
int perf_xe_open(int xe, uint64_t config);
|
||||
|
||||
#endif /* I915_PERF_H */
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright © 2007 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _INTEL_CHIPSET_H
|
||||
#define _INTEL_CHIPSET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BIT(x) (1ul <<(x))
|
||||
|
||||
struct intel_device_info {
|
||||
unsigned graphics_ver;
|
||||
unsigned graphics_rel;
|
||||
unsigned display_ver;
|
||||
unsigned gt; /* 0 if unknown */
|
||||
bool has_4tile : 1;
|
||||
bool has_flatccs : 1;
|
||||
bool has_oam : 1;
|
||||
bool is_mobile : 1;
|
||||
bool is_whitney : 1;
|
||||
bool is_almador : 1;
|
||||
bool is_brookdale : 1;
|
||||
bool is_montara : 1;
|
||||
bool is_springdale : 1;
|
||||
bool is_grantsdale : 1;
|
||||
bool is_alviso : 1;
|
||||
bool is_lakeport : 1;
|
||||
bool is_calistoga : 1;
|
||||
bool is_bearlake : 1;
|
||||
bool is_pineview : 1;
|
||||
bool is_broadwater : 1;
|
||||
bool is_crestline : 1;
|
||||
bool is_eaglelake : 1;
|
||||
bool is_cantiga : 1;
|
||||
bool is_ironlake : 1;
|
||||
bool is_arrandale : 1;
|
||||
bool is_sandybridge : 1;
|
||||
bool is_ivybridge : 1;
|
||||
bool is_valleyview : 1;
|
||||
bool is_haswell : 1;
|
||||
bool is_broadwell : 1;
|
||||
bool is_cherryview : 1;
|
||||
bool is_skylake : 1;
|
||||
bool is_broxton : 1;
|
||||
bool is_kabylake : 1;
|
||||
bool is_geminilake : 1;
|
||||
bool is_coffeelake : 1;
|
||||
bool is_cometlake : 1;
|
||||
bool is_cannonlake : 1;
|
||||
bool is_icelake : 1;
|
||||
bool is_elkhartlake : 1;
|
||||
bool is_jasperlake : 1;
|
||||
bool is_tigerlake : 1;
|
||||
bool is_rocketlake : 1;
|
||||
bool is_dg1 : 1;
|
||||
bool is_dg2 : 1;
|
||||
bool is_alderlake_s : 1;
|
||||
bool is_raptorlake_s : 1;
|
||||
bool is_alderlake_p : 1;
|
||||
bool is_alderlake_n : 1;
|
||||
bool is_meteorlake : 1;
|
||||
bool is_pontevecchio : 1;
|
||||
bool is_lunarlake : 1;
|
||||
bool is_battlemage : 1;
|
||||
const char *codename;
|
||||
};
|
||||
|
||||
const struct intel_device_info *intel_get_device_info(uint16_t devid) __attribute__((pure));
|
||||
|
||||
extern enum pch_type intel_pch;
|
||||
|
||||
enum pch_type {
|
||||
PCH_NONE,
|
||||
PCH_IBX,
|
||||
PCH_CPT,
|
||||
PCH_LPT,
|
||||
};
|
||||
|
||||
void intel_check_pch(void);
|
||||
|
||||
#define HAS_IBX (intel_pch == PCH_IBX)
|
||||
#define HAS_CPT (intel_pch == PCH_CPT)
|
||||
#define HAS_LPT (intel_pch == PCH_LPT)
|
||||
|
||||
#define IP_VER(ver, rel) ((ver) << 8 | (rel))
|
||||
|
||||
/* Exclude chipset #defines, they just add noise */
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
|
||||
#define PCI_CHIP_I810 0x7121
|
||||
#define PCI_CHIP_I810_DC100 0x7123
|
||||
#define PCI_CHIP_I810_E 0x7125
|
||||
#define PCI_CHIP_I815 0x1132
|
||||
|
||||
#define PCI_CHIP_I830_M 0x3577
|
||||
#define PCI_CHIP_845_G 0x2562
|
||||
#define PCI_CHIP_I854_G 0x358e
|
||||
#define PCI_CHIP_I855_GM 0x3582
|
||||
#define PCI_CHIP_I865_G 0x2572
|
||||
|
||||
#define PCI_CHIP_I915_G 0x2582
|
||||
#define PCI_CHIP_E7221_G 0x258A
|
||||
#define PCI_CHIP_I915_GM 0x2592
|
||||
#define PCI_CHIP_I945_G 0x2772
|
||||
#define PCI_CHIP_I945_GM 0x27A2
|
||||
#define PCI_CHIP_I945_GME 0x27AE
|
||||
|
||||
#define PCI_CHIP_I965_G 0x29A2
|
||||
#define PCI_CHIP_I965_Q 0x2992
|
||||
#define PCI_CHIP_I965_G_1 0x2982
|
||||
#define PCI_CHIP_I946_GZ 0x2972
|
||||
#define PCI_CHIP_I965_GM 0x2A02
|
||||
#define PCI_CHIP_I965_GME 0x2A12
|
||||
|
||||
#define PCI_CHIP_GM45_GM 0x2A42
|
||||
|
||||
#define PCI_CHIP_Q45_G 0x2E12
|
||||
#define PCI_CHIP_G45_G 0x2E22
|
||||
#define PCI_CHIP_G41_G 0x2E32
|
||||
|
||||
#endif /* __GTK_DOC_IGNORE__ */
|
||||
|
||||
#define IS_915G(devid) (intel_get_device_info(devid)->is_grantsdale)
|
||||
#define IS_915GM(devid) (intel_get_device_info(devid)->is_alviso)
|
||||
|
||||
#define IS_915(devid) (IS_915G(devid) || IS_915GM(devid))
|
||||
|
||||
#define IS_945G(devid) (intel_get_device_info(devid)->is_lakeport)
|
||||
#define IS_945GM(devid) (intel_get_device_info(devid)->is_calistoga)
|
||||
|
||||
#define IS_945(devid) (IS_945G(devid) || \
|
||||
IS_945GM(devid) || \
|
||||
IS_G33(devid))
|
||||
|
||||
#define IS_PINEVIEW(devid) (intel_get_device_info(devid)->is_pineview)
|
||||
#define IS_G33(devid) (intel_get_device_info(devid)->is_bearlake || \
|
||||
intel_get_device_info(devid)->is_pineview)
|
||||
|
||||
#define IS_BROADWATER(devid) (intel_get_device_info(devid)->is_broadwater)
|
||||
#define IS_CRESTLINE(devid) (intel_get_device_info(devid)->is_crestline)
|
||||
|
||||
#define IS_GM45(devid) (intel_get_device_info(devid)->is_cantiga)
|
||||
#define IS_G45(devid) (intel_get_device_info(devid)->is_eaglelake)
|
||||
#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid))
|
||||
|
||||
#define IS_IRONLAKE(devid) (intel_get_device_info(devid)->is_ironlake)
|
||||
#define IS_ARRANDALE(devid) (intel_get_device_info(devid)->is_arrandale)
|
||||
#define IS_SANDYBRIDGE(devid) (intel_get_device_info(devid)->is_sandybridge)
|
||||
#define IS_IVYBRIDGE(devid) (intel_get_device_info(devid)->is_ivybridge)
|
||||
#define IS_VALLEYVIEW(devid) (intel_get_device_info(devid)->is_valleyview)
|
||||
#define IS_HASWELL(devid) (intel_get_device_info(devid)->is_haswell)
|
||||
#define IS_BROADWELL(devid) (intel_get_device_info(devid)->is_broadwell)
|
||||
#define IS_CHERRYVIEW(devid) (intel_get_device_info(devid)->is_cherryview)
|
||||
#define IS_SKYLAKE(devid) (intel_get_device_info(devid)->is_skylake)
|
||||
#define IS_BROXTON(devid) (intel_get_device_info(devid)->is_broxton)
|
||||
#define IS_KABYLAKE(devid) (intel_get_device_info(devid)->is_kabylake)
|
||||
#define IS_GEMINILAKE(devid) (intel_get_device_info(devid)->is_geminilake)
|
||||
#define IS_COFFEELAKE(devid) (intel_get_device_info(devid)->is_coffeelake)
|
||||
#define IS_COMETLAKE(devid) (intel_get_device_info(devid)->is_cometlake)
|
||||
#define IS_CANNONLAKE(devid) (intel_get_device_info(devid)->is_cannonlake)
|
||||
#define IS_ICELAKE(devid) (intel_get_device_info(devid)->is_icelake)
|
||||
#define IS_TIGERLAKE(devid) (intel_get_device_info(devid)->is_tigerlake)
|
||||
#define IS_ROCKETLAKE(devid) (intel_get_device_info(devid)->is_rocketlake)
|
||||
#define IS_DG1(devid) (intel_get_device_info(devid)->is_dg1)
|
||||
#define IS_DG2(devid) (intel_get_device_info(devid)->is_dg2)
|
||||
#define IS_ALDERLAKE_S(devid) (intel_get_device_info(devid)->is_alderlake_s)
|
||||
#define IS_RAPTORLAKE_S(devid) (intel_get_device_info(devid)->is_raptorlake_s)
|
||||
#define IS_ALDERLAKE_P(devid) (intel_get_device_info(devid)->is_alderlake_p)
|
||||
#define IS_ALDERLAKE_N(devid) (intel_get_device_info(devid)->is_alderlake_n)
|
||||
#define IS_METEORLAKE(devid) (intel_get_device_info(devid)->is_meteorlake)
|
||||
#define IS_PONTEVECCHIO(devid) (intel_get_device_info(devid)->is_pontevecchio)
|
||||
#define IS_LUNARLAKE(devid) (intel_get_device_info(devid)->is_lunarlake)
|
||||
#define IS_BATTLEMAGE(devid) (intel_get_device_info(devid)->is_battlemage)
|
||||
|
||||
#define IS_GEN(devid, x) (intel_get_device_info(devid)->graphics_ver == x)
|
||||
#define AT_LEAST_GEN(devid, x) (intel_get_device_info(devid)->graphics_ver >= x)
|
||||
#define AT_LEAST_DISPLAY(devid, x) (intel_get_device_info(devid)->display_ver >= x)
|
||||
|
||||
#define IS_GEN2(devid) IS_GEN(devid, 2)
|
||||
#define IS_GEN3(devid) IS_GEN(devid, 3)
|
||||
#define IS_GEN4(devid) IS_GEN(devid, 4)
|
||||
#define IS_GEN5(devid) IS_GEN(devid, 5)
|
||||
#define IS_GEN6(devid) IS_GEN(devid, 6)
|
||||
#define IS_GEN7(devid) IS_GEN(devid, 7)
|
||||
#define IS_GEN8(devid) IS_GEN(devid, 8)
|
||||
#define IS_GEN9(devid) IS_GEN(devid, 9)
|
||||
#define IS_GEN10(devid) IS_GEN(devid, 10)
|
||||
#define IS_GEN11(devid) IS_GEN(devid, 11)
|
||||
#define IS_GEN12(devid) IS_GEN(devid, 12)
|
||||
|
||||
#define IS_MOBILE(devid) (intel_get_device_info(devid)->is_mobile)
|
||||
#define IS_965(devid) AT_LEAST_GEN(devid, 4)
|
||||
|
||||
#define HAS_BSD_RING(devid) AT_LEAST_GEN(devid, 5)
|
||||
#define HAS_BLT_RING(devid) AT_LEAST_GEN(devid, 6)
|
||||
|
||||
#define HAS_PCH_SPLIT(devid) (AT_LEAST_GEN(devid, 5) && \
|
||||
!(IS_VALLEYVIEW(devid) || \
|
||||
IS_CHERRYVIEW(devid) || \
|
||||
IS_BROXTON(devid)))
|
||||
|
||||
#define HAS_4TILE(devid) (intel_get_device_info(devid)->has_4tile)
|
||||
|
||||
#define HAS_FLATCCS(devid) (intel_get_device_info(devid)->has_flatccs)
|
||||
|
||||
#define HAS_OAM(devid) (intel_get_device_info(devid)->has_oam)
|
||||
|
||||
#endif /* _INTEL_CHIPSET_H */
|
||||
+653
@@ -0,0 +1,653 @@
|
||||
#include "intel_chipset.h"
|
||||
#include "i915_pciids.h"
|
||||
#include "i915_pciids_local.h"
|
||||
#include "xe_pciids.h"
|
||||
|
||||
#include <strings.h> /* ffs() */
|
||||
|
||||
// from pciaccess.h
|
||||
#define PCI_MATCH_ANY (~0U)
|
||||
|
||||
// from pciaccess.h
|
||||
struct pci_id_match {
|
||||
/**
|
||||
* \name Device / vendor matching controls
|
||||
*
|
||||
* Control the search based on the device, vendor, subdevice, or subvendor
|
||||
* IDs. Setting any of these fields to \c PCI_MATCH_ANY will cause the
|
||||
* field to not be used in the comparison.
|
||||
*/
|
||||
/*@{*/
|
||||
uint32_t vendor_id;
|
||||
uint32_t device_id;
|
||||
uint32_t subvendor_id;
|
||||
uint32_t subdevice_id;
|
||||
/*@}*/
|
||||
|
||||
|
||||
/**
|
||||
* \name Device class matching controls
|
||||
*
|
||||
*/
|
||||
/*@{*/
|
||||
uint32_t device_class;
|
||||
uint32_t device_class_mask;
|
||||
/*@}*/
|
||||
|
||||
intptr_t match_data;
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_generic_info = {
|
||||
.graphics_ver = 0,
|
||||
.display_ver = 0,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i810_info = {
|
||||
.graphics_ver = 1,
|
||||
.display_ver = 1,
|
||||
.is_whitney = true,
|
||||
.codename = "solano" /* 815 == "whitney" ? or vice versa? */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i815_info = {
|
||||
.graphics_ver = 1,
|
||||
.display_ver = 1,
|
||||
.is_whitney = true,
|
||||
.codename = "whitney"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i830_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_almador = true,
|
||||
.codename = "almador"
|
||||
};
|
||||
static const struct intel_device_info intel_i845_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_brookdale = true,
|
||||
.codename = "brookdale"
|
||||
};
|
||||
static const struct intel_device_info intel_i855_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_mobile = true,
|
||||
.is_montara = true,
|
||||
.codename = "montara"
|
||||
};
|
||||
static const struct intel_device_info intel_i865_info = {
|
||||
.graphics_ver = 2,
|
||||
.display_ver = 2,
|
||||
.is_springdale = true,
|
||||
.codename = "spingdale"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i915_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_grantsdale = true,
|
||||
.codename = "grantsdale"
|
||||
};
|
||||
static const struct intel_device_info intel_i915m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_alviso = true,
|
||||
.codename = "alviso"
|
||||
};
|
||||
static const struct intel_device_info intel_i945_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_lakeport = true,
|
||||
.codename = "lakeport"
|
||||
};
|
||||
static const struct intel_device_info intel_i945m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_calistoga = true,
|
||||
.codename = "calistoga"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g33_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_bearlake = true,
|
||||
.codename = "bearlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_g_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_pineview = true,
|
||||
.codename = "pineview"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_m_info = {
|
||||
.graphics_ver = 3,
|
||||
.display_ver = 3,
|
||||
.is_mobile = true,
|
||||
.is_pineview = true,
|
||||
.codename = "pineview"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_broadwater = true,
|
||||
.codename = "broadwater"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965m_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_mobile = true,
|
||||
.is_crestline = true,
|
||||
.codename = "crestline"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g45_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_eaglelake = true,
|
||||
.codename = "eaglelake"
|
||||
};
|
||||
static const struct intel_device_info intel_gm45_info = {
|
||||
.graphics_ver = 4,
|
||||
.display_ver = 4,
|
||||
.is_mobile = true,
|
||||
.is_cantiga = true,
|
||||
.codename = "cantiga"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_info = {
|
||||
.graphics_ver = 5,
|
||||
.display_ver = 5,
|
||||
.is_ironlake = true,
|
||||
.codename = "ironlake" /* clarkdale? */
|
||||
};
|
||||
static const struct intel_device_info intel_ironlake_m_info = {
|
||||
.graphics_ver = 5,
|
||||
.display_ver = 5,
|
||||
.is_mobile = true,
|
||||
.is_arrandale = true,
|
||||
.codename = "arrandale"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_info = {
|
||||
.graphics_ver = 6,
|
||||
.display_ver = 6,
|
||||
.is_sandybridge = true,
|
||||
.codename = "sandybridge"
|
||||
};
|
||||
static const struct intel_device_info intel_sandybridge_m_info = {
|
||||
.graphics_ver = 6,
|
||||
.display_ver = 6,
|
||||
.is_mobile = true,
|
||||
.is_sandybridge = true,
|
||||
.codename = "sandybridge"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_ivybridge = true,
|
||||
.codename = "ivybridge"
|
||||
};
|
||||
static const struct intel_device_info intel_ivybridge_m_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_mobile = true,
|
||||
.is_ivybridge = true,
|
||||
.codename = "ivybridge"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_info = {
|
||||
.graphics_ver = 7,
|
||||
.display_ver = 7,
|
||||
.is_valleyview = true,
|
||||
.codename = "valleyview"
|
||||
};
|
||||
|
||||
#define HASWELL_FIELDS \
|
||||
.graphics_ver = 7, \
|
||||
.display_ver = 7, \
|
||||
.is_haswell = true, \
|
||||
.codename = "haswell"
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt1_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt2_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_gt3_info = {
|
||||
HASWELL_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
#define BROADWELL_FIELDS \
|
||||
.graphics_ver = 8, \
|
||||
.display_ver = 8, \
|
||||
.is_broadwell = true, \
|
||||
.codename = "broadwell"
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt1_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt2_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt3_info = {
|
||||
BROADWELL_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_unknown_info = {
|
||||
BROADWELL_FIELDS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cherryview_info = {
|
||||
.graphics_ver = 8,
|
||||
.display_ver = 8,
|
||||
.is_cherryview = true,
|
||||
.codename = "cherryview"
|
||||
};
|
||||
|
||||
#define SKYLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.codename = "skylake", \
|
||||
.is_skylake = true
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt1_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt2_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt3_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt4_info = {
|
||||
SKYLAKE_FIELDS,
|
||||
.gt = 4,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broxton_info = {
|
||||
.graphics_ver = 9,
|
||||
.display_ver = 9,
|
||||
.is_broxton = true,
|
||||
.codename = "broxton"
|
||||
};
|
||||
|
||||
#define KABYLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_kabylake = true, \
|
||||
.codename = "kabylake"
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt1_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt2_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt3_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt4_info = {
|
||||
KABYLAKE_FIELDS,
|
||||
.gt = 4,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_geminilake_info = {
|
||||
.graphics_ver = 9,
|
||||
.display_ver = 9,
|
||||
.is_geminilake = true,
|
||||
.codename = "geminilake"
|
||||
};
|
||||
|
||||
#define COFFEELAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_coffeelake = true, \
|
||||
.codename = "coffeelake"
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt1_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt2_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_coffeelake_gt3_info = {
|
||||
COFFEELAKE_FIELDS,
|
||||
.gt = 3,
|
||||
};
|
||||
|
||||
#define COMETLAKE_FIELDS \
|
||||
.graphics_ver = 9, \
|
||||
.display_ver = 9, \
|
||||
.is_cometlake = true, \
|
||||
.codename = "cometlake"
|
||||
|
||||
static const struct intel_device_info intel_cometlake_gt1_info = {
|
||||
COMETLAKE_FIELDS,
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cometlake_gt2_info = {
|
||||
COMETLAKE_FIELDS,
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cannonlake_info = {
|
||||
.graphics_ver = 10,
|
||||
.display_ver = 10,
|
||||
.is_cannonlake = true,
|
||||
.codename = "cannonlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_icelake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_icelake = true,
|
||||
.codename = "icelake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_elkhartlake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_elkhartlake = true,
|
||||
.codename = "elkhartlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_jasperlake_info = {
|
||||
.graphics_ver = 11,
|
||||
.display_ver = 11,
|
||||
.is_jasperlake = true,
|
||||
.codename = "jasperlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_tigerlake_gt1_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_tigerlake = true,
|
||||
.codename = "tigerlake",
|
||||
.gt = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_tigerlake_gt2_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_tigerlake = true,
|
||||
.codename = "tigerlake",
|
||||
.gt = 2,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_rocketlake_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_rocketlake = true,
|
||||
.codename = "rocketlake"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_dg1_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 10,
|
||||
.display_ver = 12,
|
||||
.is_dg1 = true,
|
||||
.codename = "dg1"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_dg2_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 55,
|
||||
.display_ver = 13,
|
||||
.has_4tile = true,
|
||||
.is_dg2 = true,
|
||||
.codename = "dg2",
|
||||
.has_flatccs = true,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_s_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_alderlake_s = true,
|
||||
.codename = "alderlake_s"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_raptorlake_s_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 12,
|
||||
.is_raptorlake_s = true,
|
||||
.codename = "raptorlake_s"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_p_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 13,
|
||||
.is_alderlake_p = true,
|
||||
.codename = "alderlake_p"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_alderlake_n_info = {
|
||||
.graphics_ver = 12,
|
||||
.display_ver = 13,
|
||||
.is_alderlake_n = true,
|
||||
.codename = "alderlake_n"
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ats_m_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 55,
|
||||
.display_ver = 0, /* no display support */
|
||||
.is_dg2 = true,
|
||||
.has_4tile = true,
|
||||
.codename = "ats_m",
|
||||
.has_flatccs = true,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_meteorlake_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 70,
|
||||
.display_ver = 14,
|
||||
.has_4tile = true,
|
||||
.has_oam = true,
|
||||
.is_meteorlake = true,
|
||||
.codename = "meteorlake",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pontevecchio_info = {
|
||||
.graphics_ver = 12,
|
||||
.graphics_rel = 60,
|
||||
.is_pontevecchio = true,
|
||||
.codename = "pontevecchio",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_lunarlake_info = {
|
||||
.graphics_ver = 20,
|
||||
.graphics_rel = 4,
|
||||
.display_ver = 20,
|
||||
.has_4tile = true,
|
||||
.has_flatccs = true,
|
||||
.has_oam = true,
|
||||
.is_lunarlake = true,
|
||||
.codename = "lunarlake",
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_battlemage_info = {
|
||||
.graphics_ver = 20,
|
||||
.graphics_rel = 1,
|
||||
.display_ver = 14,
|
||||
.has_4tile = true,
|
||||
.has_flatccs = true,
|
||||
.is_battlemage = true,
|
||||
.codename = "battlemage",
|
||||
};
|
||||
|
||||
static const struct pci_id_match intel_device_match[] = {
|
||||
INTEL_I810_IDS(INTEL_VGA_DEVICE, &intel_i810_info),
|
||||
INTEL_I815_IDS(INTEL_VGA_DEVICE, &intel_i815_info),
|
||||
|
||||
INTEL_I830_IDS(INTEL_VGA_DEVICE, &intel_i830_info),
|
||||
INTEL_I845G_IDS(INTEL_VGA_DEVICE, &intel_i845_info),
|
||||
INTEL_I85X_IDS(INTEL_VGA_DEVICE, &intel_i855_info),
|
||||
INTEL_I865G_IDS(INTEL_VGA_DEVICE, &intel_i865_info),
|
||||
|
||||
INTEL_I915G_IDS(INTEL_VGA_DEVICE, &intel_i915_info),
|
||||
INTEL_I915GM_IDS(INTEL_VGA_DEVICE, &intel_i915m_info),
|
||||
INTEL_I945G_IDS(INTEL_VGA_DEVICE, &intel_i945_info),
|
||||
INTEL_I945GM_IDS(INTEL_VGA_DEVICE, &intel_i945m_info),
|
||||
|
||||
INTEL_G33_IDS(INTEL_VGA_DEVICE, &intel_g33_info),
|
||||
INTEL_PNV_G_IDS(INTEL_VGA_DEVICE, &intel_pineview_g_info),
|
||||
INTEL_PNV_M_IDS(INTEL_VGA_DEVICE, &intel_pineview_m_info),
|
||||
|
||||
INTEL_I965G_IDS(INTEL_VGA_DEVICE, &intel_i965_info),
|
||||
INTEL_I965GM_IDS(INTEL_VGA_DEVICE, &intel_i965m_info),
|
||||
|
||||
INTEL_G45_IDS(INTEL_VGA_DEVICE, &intel_g45_info),
|
||||
INTEL_GM45_IDS(INTEL_VGA_DEVICE, &intel_gm45_info),
|
||||
|
||||
INTEL_ILK_D_IDS(INTEL_VGA_DEVICE, &intel_ironlake_info),
|
||||
INTEL_ILK_M_IDS(INTEL_VGA_DEVICE, &intel_ironlake_m_info),
|
||||
|
||||
INTEL_SNB_D_IDS(INTEL_VGA_DEVICE, &intel_sandybridge_info),
|
||||
INTEL_SNB_M_IDS(INTEL_VGA_DEVICE, &intel_sandybridge_m_info),
|
||||
|
||||
INTEL_IVB_D_IDS(INTEL_VGA_DEVICE, &intel_ivybridge_info),
|
||||
INTEL_IVB_M_IDS(INTEL_VGA_DEVICE, &intel_ivybridge_m_info),
|
||||
|
||||
INTEL_HSW_GT1_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt1_info),
|
||||
INTEL_HSW_GT2_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt2_info),
|
||||
INTEL_HSW_GT3_IDS(INTEL_VGA_DEVICE, &intel_haswell_gt3_info),
|
||||
|
||||
INTEL_VLV_IDS(INTEL_VGA_DEVICE, &intel_valleyview_info),
|
||||
|
||||
INTEL_BDW_GT1_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt1_info),
|
||||
INTEL_BDW_GT2_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt2_info),
|
||||
INTEL_BDW_GT3_IDS(INTEL_VGA_DEVICE, &intel_broadwell_gt3_info),
|
||||
INTEL_BDW_RSVD_IDS(INTEL_VGA_DEVICE, &intel_broadwell_unknown_info),
|
||||
|
||||
INTEL_CHV_IDS(INTEL_VGA_DEVICE, &intel_cherryview_info),
|
||||
|
||||
INTEL_SKL_GT1_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt1_info),
|
||||
INTEL_SKL_GT2_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt2_info),
|
||||
INTEL_SKL_GT3_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt3_info),
|
||||
INTEL_SKL_GT4_IDS(INTEL_VGA_DEVICE, &intel_skylake_gt4_info),
|
||||
|
||||
INTEL_BXT_IDS(INTEL_VGA_DEVICE, &intel_broxton_info),
|
||||
|
||||
INTEL_KBL_GT1_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt1_info),
|
||||
INTEL_KBL_GT2_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt2_info),
|
||||
INTEL_KBL_GT3_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt3_info),
|
||||
INTEL_KBL_GT4_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt4_info),
|
||||
INTEL_AML_KBL_GT2_IDS(INTEL_VGA_DEVICE, &intel_kabylake_gt2_info),
|
||||
|
||||
INTEL_GLK_IDS(INTEL_VGA_DEVICE, &intel_geminilake_info),
|
||||
|
||||
INTEL_CFL_S_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_CFL_S_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_H_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_CFL_H_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_CFL_U_GT3_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt3_info),
|
||||
INTEL_WHL_U_GT1_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt1_info),
|
||||
INTEL_WHL_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
INTEL_WHL_U_GT3_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt3_info),
|
||||
INTEL_AML_CFL_GT2_IDS(INTEL_VGA_DEVICE, &intel_coffeelake_gt2_info),
|
||||
|
||||
INTEL_CML_GT1_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt1_info),
|
||||
INTEL_CML_GT2_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt2_info),
|
||||
INTEL_CML_U_GT1_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt1_info),
|
||||
INTEL_CML_U_GT2_IDS(INTEL_VGA_DEVICE, &intel_cometlake_gt2_info),
|
||||
|
||||
INTEL_CNL_IDS(INTEL_VGA_DEVICE, &intel_cannonlake_info),
|
||||
|
||||
INTEL_ICL_IDS(INTEL_VGA_DEVICE, &intel_icelake_info),
|
||||
|
||||
INTEL_EHL_IDS(INTEL_VGA_DEVICE, &intel_elkhartlake_info),
|
||||
INTEL_JSL_IDS(INTEL_VGA_DEVICE, &intel_jasperlake_info),
|
||||
|
||||
INTEL_TGL_GT1_IDS(INTEL_VGA_DEVICE, &intel_tigerlake_gt1_info),
|
||||
INTEL_TGL_GT2_IDS(INTEL_VGA_DEVICE, &intel_tigerlake_gt2_info),
|
||||
INTEL_RKL_IDS(INTEL_VGA_DEVICE, &intel_rocketlake_info),
|
||||
|
||||
INTEL_DG1_IDS(INTEL_VGA_DEVICE, &intel_dg1_info),
|
||||
INTEL_DG2_IDS(INTEL_VGA_DEVICE, &intel_dg2_info),
|
||||
|
||||
INTEL_ADLS_IDS(INTEL_VGA_DEVICE, &intel_alderlake_s_info),
|
||||
INTEL_RPLS_IDS(INTEL_VGA_DEVICE, &intel_raptorlake_s_info),
|
||||
INTEL_ADLP_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_RPLU_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_RPLP_IDS(INTEL_VGA_DEVICE, &intel_alderlake_p_info),
|
||||
INTEL_ADLN_IDS(INTEL_VGA_DEVICE, &intel_alderlake_n_info),
|
||||
|
||||
INTEL_ATS_M_IDS(INTEL_VGA_DEVICE, &intel_ats_m_info),
|
||||
|
||||
INTEL_MTL_IDS(INTEL_VGA_DEVICE, &intel_meteorlake_info),
|
||||
|
||||
INTEL_PVC_IDS(INTEL_VGA_DEVICE, &intel_pontevecchio_info),
|
||||
|
||||
XE_LNL_IDS(INTEL_VGA_DEVICE, &intel_lunarlake_info),
|
||||
|
||||
XE_BMG_IDS(INTEL_VGA_DEVICE, &intel_battlemage_info),
|
||||
|
||||
INTEL_VGA_DEVICE(PCI_MATCH_ANY, &intel_generic_info),
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_get_device_info:
|
||||
* @devid: pci device id
|
||||
*
|
||||
* Looks up the Intel GFX device info for the given device id.
|
||||
*
|
||||
* Returns:
|
||||
* The associated intel_get_device_info
|
||||
*/
|
||||
const struct intel_device_info *intel_get_device_info(uint16_t devid)
|
||||
{
|
||||
static const struct intel_device_info *cache = &intel_generic_info;
|
||||
static uint16_t cached_devid;
|
||||
int i;
|
||||
|
||||
if (cached_devid == devid)
|
||||
goto out;
|
||||
|
||||
/* XXX Presort table and bsearch! */
|
||||
for (i = 0; intel_device_match[i].device_id != PCI_MATCH_ANY; i++) {
|
||||
if (devid == intel_device_match[i].device_id)
|
||||
break;
|
||||
}
|
||||
|
||||
cached_devid = devid;
|
||||
cache = (void *)intel_device_match[i].match_data;
|
||||
|
||||
out:
|
||||
return cache;
|
||||
}
|
||||
+697
@@ -0,0 +1,697 @@
|
||||
/*
|
||||
* Copyright © 2007-2023 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "intel_gpu_top.h"
|
||||
#include "i915_drm.h"
|
||||
#include "igt_perf.h"
|
||||
|
||||
#ifdef __clang__ //? Workaround for missing asprintf when compiling with clang, taken from https://stackoverflow.com/a/4899487
|
||||
int asprintf(char **ret, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
*ret = NULL; /* Ensure value can be passed to free() */
|
||||
|
||||
va_start(ap, format);
|
||||
int count = vsnprintf(NULL, 0, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (count >= 0)
|
||||
{
|
||||
char* buffer = malloc(count + 1);
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
va_start(ap, format);
|
||||
count = vsnprintf(buffer, count + 1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
free(buffer);
|
||||
return count;
|
||||
}
|
||||
*ret = buffer;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((format(scanf,3,4)))
|
||||
static int igt_sysfs_scanf(int dir, const char *attr, const char *fmt, ...)
|
||||
{
|
||||
FILE *file;
|
||||
int fd;
|
||||
int ret = -1;
|
||||
|
||||
fd = openat(dir, attr, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
file = fdopen(fd, "r");
|
||||
if (file) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vfscanf(file, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fclose(file);
|
||||
} else {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pmu_parse(struct pmu_counter *pmu, const char *path, const char *str)
|
||||
{
|
||||
locale_t locale, oldlocale;
|
||||
bool result = true;
|
||||
char buf[128] = {};
|
||||
int dir;
|
||||
|
||||
dir = open(path, O_RDONLY);
|
||||
if (dir < 0)
|
||||
return -errno;
|
||||
|
||||
/* Replace user environment with plain C to match kernel format */
|
||||
locale = newlocale(LC_ALL, "C", 0);
|
||||
oldlocale = uselocale(locale);
|
||||
|
||||
result &= igt_sysfs_scanf(dir, "type", "%"PRIu64, &pmu->type) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "event=%"PRIx64, &pmu->config) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s.scale", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "%lf", &pmu->scale) == 1;
|
||||
|
||||
snprintf(buf, sizeof(buf) - 1, "events/%s.unit", str);
|
||||
result &= igt_sysfs_scanf(dir, buf, "%127s", buf) == 1;
|
||||
pmu->units = strdup(buf);
|
||||
|
||||
uselocale(oldlocale);
|
||||
freelocale(locale);
|
||||
|
||||
close(dir);
|
||||
|
||||
if (!result)
|
||||
return -EINVAL;
|
||||
|
||||
if (isnan(pmu->scale) || !pmu->scale)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rapl_parse(struct pmu_counter *pmu, const char *str)
|
||||
{
|
||||
const char *expected_units = "Joules";
|
||||
int err;
|
||||
|
||||
err = pmu_parse(pmu, "/sys/devices/power", str);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!pmu->units || strcmp(pmu->units, expected_units)) {
|
||||
fprintf(stderr,
|
||||
"Unexpected units for RAPL %s: found '%s', expected '%s'\n",
|
||||
str, pmu->units, expected_units);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rapl_open(struct pmu_counter *pmu,
|
||||
const char *domain,
|
||||
struct engines *engines)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (rapl_parse(pmu, domain) < 0)
|
||||
return;
|
||||
|
||||
fd = igt_perf_open_group(pmu->type, pmu->config, engines->rapl_fd);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (engines->rapl_fd == -1)
|
||||
engines->rapl_fd = fd;
|
||||
|
||||
pmu->idx = engines->num_rapl++;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
static void gpu_power_open(struct pmu_counter *pmu,
|
||||
struct engines *engines)
|
||||
{
|
||||
rapl_open(pmu, "energy-gpu", engines);
|
||||
}
|
||||
|
||||
static void pkg_power_open(struct pmu_counter *pmu,
|
||||
struct engines *engines)
|
||||
{
|
||||
rapl_open(pmu, "energy-pkg", engines);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_pmu_config(int dirfd, const char *name, const char *counter)
|
||||
{
|
||||
char buf[128], *p;
|
||||
int fd, ret;
|
||||
|
||||
ret = snprintf(buf, sizeof(buf), "%s-%s", name, counter);
|
||||
if (ret < 0 || ret == sizeof(buf))
|
||||
return -1;
|
||||
|
||||
fd = openat(dirfd, buf, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
ret = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (ret <= 0)
|
||||
return -1;
|
||||
|
||||
p = index(buf, '0');
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
return strtoul(p, NULL, 0);
|
||||
}
|
||||
|
||||
#define engine_ptr(engines, n) (&engines->engine + (n))
|
||||
|
||||
static const char *class_display_name(unsigned int class)
|
||||
{
|
||||
switch (class) {
|
||||
case I915_ENGINE_CLASS_RENDER:
|
||||
return "Render/3D";
|
||||
case I915_ENGINE_CLASS_COPY:
|
||||
return "Blitter";
|
||||
case I915_ENGINE_CLASS_VIDEO:
|
||||
return "Video";
|
||||
case I915_ENGINE_CLASS_VIDEO_ENHANCE:
|
||||
return "VideoEnhance";
|
||||
case I915_ENGINE_CLASS_COMPUTE:
|
||||
return "Compute";
|
||||
default:
|
||||
return "[unknown]";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *class_short_name(unsigned int class)
|
||||
{
|
||||
switch (class) {
|
||||
case I915_ENGINE_CLASS_RENDER:
|
||||
return "RCS";
|
||||
case I915_ENGINE_CLASS_COPY:
|
||||
return "BCS";
|
||||
case I915_ENGINE_CLASS_VIDEO:
|
||||
return "VCS";
|
||||
case I915_ENGINE_CLASS_VIDEO_ENHANCE:
|
||||
return "VECS";
|
||||
case I915_ENGINE_CLASS_COMPUTE:
|
||||
return "CCS";
|
||||
default:
|
||||
return "UNKN";
|
||||
}
|
||||
}
|
||||
|
||||
static int engine_cmp(const void *__a, const void *__b)
|
||||
{
|
||||
const struct engine *a = (struct engine *)__a;
|
||||
const struct engine *b = (struct engine *)__b;
|
||||
|
||||
if (a->class != b->class)
|
||||
return a->class - b->class;
|
||||
else
|
||||
return a->instance - b->instance;
|
||||
}
|
||||
|
||||
#define is_igpu(x) (strcmp(x, "i915") == 0)
|
||||
|
||||
struct engines *discover_engines(const char *device)
|
||||
{
|
||||
char sysfs_root[PATH_MAX];
|
||||
struct engines *engines;
|
||||
struct dirent *dent;
|
||||
int ret = 0;
|
||||
DIR *d;
|
||||
|
||||
snprintf(sysfs_root, sizeof(sysfs_root),
|
||||
"/sys/devices/%s/events", device);
|
||||
|
||||
engines = malloc(sizeof(struct engines));
|
||||
if (!engines)
|
||||
return NULL;
|
||||
|
||||
memset(engines, 0, sizeof(*engines));
|
||||
|
||||
engines->num_engines = 0;
|
||||
engines->device = device;
|
||||
engines->discrete = !is_igpu(device);
|
||||
|
||||
d = opendir(sysfs_root);
|
||||
if (!d)
|
||||
goto err;
|
||||
|
||||
while ((dent = readdir(d)) != NULL) {
|
||||
const char *endswith = "-busy";
|
||||
const unsigned int endlen = strlen(endswith);
|
||||
struct engine *engine =
|
||||
engine_ptr(engines, engines->num_engines);
|
||||
char buf[256];
|
||||
|
||||
if (dent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
if (strlen(dent->d_name) >= sizeof(buf)) {
|
||||
ret = ENAMETOOLONG;
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(buf, dent->d_name);
|
||||
|
||||
/* xxxN-busy */
|
||||
if (strlen(buf) < (endlen + 4))
|
||||
continue;
|
||||
if (strcmp(&buf[strlen(buf) - endlen], endswith))
|
||||
continue;
|
||||
|
||||
memset(engine, 0, sizeof(*engine));
|
||||
|
||||
buf[strlen(buf) - endlen] = 0;
|
||||
engine->name = strdup(buf);
|
||||
if (!engine->name) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
engine->busy.config = get_pmu_config(dirfd(d), engine->name,
|
||||
"busy");
|
||||
if (engine->busy.config == -1) {
|
||||
ret = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Double check config is an engine config. */
|
||||
if (engine->busy.config >= __I915_PMU_OTHER(0)) {
|
||||
free((void *)engine->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
engine->class = (engine->busy.config &
|
||||
(__I915_PMU_OTHER(0) - 1)) >>
|
||||
I915_PMU_CLASS_SHIFT;
|
||||
|
||||
engine->instance = (engine->busy.config >>
|
||||
I915_PMU_SAMPLE_BITS) &
|
||||
((1 << I915_PMU_SAMPLE_INSTANCE_BITS) - 1);
|
||||
|
||||
ret = asprintf(&engine->display_name, "%s/%u",
|
||||
class_display_name(engine->class),
|
||||
engine->instance);
|
||||
if (ret <= 0) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = asprintf(&engine->short_name, "%s/%u",
|
||||
class_short_name(engine->class),
|
||||
engine->instance);
|
||||
if (ret <= 0) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
engines->num_engines++;
|
||||
engines = realloc(engines, sizeof(struct engines) +
|
||||
engines->num_engines * sizeof(struct engine));
|
||||
if (!engines) {
|
||||
ret = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
errno = ret;
|
||||
goto err;
|
||||
}
|
||||
|
||||
qsort(engine_ptr(engines, 0), engines->num_engines,
|
||||
sizeof(struct engine), engine_cmp);
|
||||
|
||||
engines->root = d;
|
||||
|
||||
return engines;
|
||||
|
||||
err:
|
||||
free(engines);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_engines(struct engines *engines)
|
||||
{
|
||||
struct pmu_counter **pmu, *free_list[] = {
|
||||
&engines->r_gpu,
|
||||
&engines->r_pkg,
|
||||
&engines->imc_reads,
|
||||
&engines->imc_writes,
|
||||
NULL
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
if (!engines)
|
||||
return;
|
||||
|
||||
for (pmu = &free_list[0]; *pmu; pmu++) {
|
||||
if ((*pmu)->present)
|
||||
free((char *)(*pmu)->units);
|
||||
}
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
|
||||
free((char *)engine->name);
|
||||
free((char *)engine->short_name);
|
||||
free((char *)engine->display_name);
|
||||
}
|
||||
|
||||
closedir(engines->root);
|
||||
|
||||
free(engines->class);
|
||||
free(engines);
|
||||
}
|
||||
|
||||
#define _open_pmu(type, cnt, pmu, fd) \
|
||||
({ \
|
||||
int fd__; \
|
||||
\
|
||||
fd__ = igt_perf_open_group((type), (pmu)->config, (fd)); \
|
||||
if (fd__ >= 0) { \
|
||||
if ((fd) == -1) \
|
||||
(fd) = fd__; \
|
||||
(pmu)->present = true; \
|
||||
(pmu)->idx = (cnt)++; \
|
||||
} \
|
||||
\
|
||||
fd__; \
|
||||
})
|
||||
|
||||
static int imc_parse(struct pmu_counter *pmu, const char *str)
|
||||
{
|
||||
return pmu_parse(pmu, "/sys/devices/uncore_imc", str);
|
||||
}
|
||||
|
||||
static void
|
||||
imc_open(struct pmu_counter *pmu,
|
||||
const char *domain,
|
||||
struct engines *engines)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (imc_parse(pmu, domain) < 0)
|
||||
return;
|
||||
|
||||
fd = igt_perf_open_group(pmu->type, pmu->config, engines->imc_fd);
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (engines->imc_fd == -1)
|
||||
engines->imc_fd = fd;
|
||||
|
||||
pmu->idx = engines->num_imc++;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
static void imc_writes_open(struct pmu_counter *pmu, struct engines *engines)
|
||||
{
|
||||
imc_open(pmu, "data_writes", engines);
|
||||
}
|
||||
|
||||
static void imc_reads_open(struct pmu_counter *pmu, struct engines *engines)
|
||||
{
|
||||
imc_open(pmu, "data_reads", engines);
|
||||
}
|
||||
|
||||
static int get_num_gts(uint64_t type)
|
||||
{
|
||||
int fd, cnt;
|
||||
|
||||
errno = 0;
|
||||
for (cnt = 0; cnt < MAX_GTS; cnt++) {
|
||||
fd = igt_perf_open(type, __I915_PMU_INTERRUPTS(cnt));
|
||||
if (fd < 0)
|
||||
break;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (!cnt || (errno && errno != ENOENT))
|
||||
cnt = -errno;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void init_aggregate_counters(struct engines *engines)
|
||||
{
|
||||
struct pmu_counter *pmu;
|
||||
|
||||
pmu = &engines->freq_req;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_REQUESTED_FREQUENCY;
|
||||
pmu->present = true;
|
||||
|
||||
pmu = &engines->freq_act;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_ACTUAL_FREQUENCY;
|
||||
pmu->present = true;
|
||||
|
||||
pmu = &engines->rc6;
|
||||
pmu->type = igt_perf_type_id(engines->device);
|
||||
pmu->config = I915_PMU_RC6_RESIDENCY;
|
||||
pmu->present = true;
|
||||
}
|
||||
|
||||
int pmu_init(struct engines *engines)
|
||||
{
|
||||
unsigned int i;
|
||||
int fd;
|
||||
uint64_t type = igt_perf_type_id(engines->device);
|
||||
|
||||
engines->fd = -1;
|
||||
engines->num_counters = 0;
|
||||
engines->num_gts = get_num_gts(type);
|
||||
if (engines->num_gts <= 0)
|
||||
return -1;
|
||||
|
||||
engines->irq.config = I915_PMU_INTERRUPTS;
|
||||
fd = _open_pmu(type, engines->num_counters, &engines->irq, engines->fd);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
init_aggregate_counters(engines);
|
||||
|
||||
for (i = 0; i < engines->num_gts; i++) {
|
||||
engines->freq_req_gt[i].config = __I915_PMU_REQUESTED_FREQUENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->freq_req_gt[i], engines->fd);
|
||||
|
||||
engines->freq_act_gt[i].config = __I915_PMU_ACTUAL_FREQUENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->freq_act_gt[i], engines->fd);
|
||||
|
||||
engines->rc6_gt[i].config = __I915_PMU_RC6_RESIDENCY(i);
|
||||
_open_pmu(type, engines->num_counters, &engines->rc6_gt[i], engines->fd);
|
||||
}
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
struct {
|
||||
struct pmu_counter *pmu;
|
||||
const char *counter;
|
||||
} *cnt, counters[] = {
|
||||
{ .pmu = &engine->busy, .counter = "busy" },
|
||||
{ .pmu = &engine->wait, .counter = "wait" },
|
||||
{ .pmu = &engine->sema, .counter = "sema" },
|
||||
{ .pmu = NULL, .counter = NULL },
|
||||
};
|
||||
|
||||
for (cnt = counters; cnt->pmu; cnt++) {
|
||||
if (!cnt->pmu->config)
|
||||
cnt->pmu->config =
|
||||
get_pmu_config(dirfd(engines->root),
|
||||
engine->name,
|
||||
cnt->counter);
|
||||
fd = _open_pmu(type, engines->num_counters, cnt->pmu,
|
||||
engines->fd);
|
||||
if (fd >= 0)
|
||||
engine->num_counters++;
|
||||
}
|
||||
}
|
||||
|
||||
engines->rapl_fd = -1;
|
||||
if (!engines->discrete) {
|
||||
gpu_power_open(&engines->r_gpu, engines);
|
||||
pkg_power_open(&engines->r_pkg, engines);
|
||||
}
|
||||
|
||||
engines->imc_fd = -1;
|
||||
imc_reads_open(&engines->imc_reads, engines);
|
||||
imc_writes_open(&engines->imc_writes, engines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t pmu_read_multi(int fd, unsigned int num, uint64_t *val)
|
||||
{
|
||||
uint64_t buf[2 + num];
|
||||
unsigned int i;
|
||||
ssize_t len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
assert(len == sizeof(buf));
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
val[i] = buf[2 + i];
|
||||
|
||||
return buf[1];
|
||||
}
|
||||
|
||||
double pmu_calc(struct pmu_pair *p, double d, double t, double s)
|
||||
{
|
||||
double v;
|
||||
|
||||
v = p->cur - p->prev;
|
||||
v /= d;
|
||||
v /= t;
|
||||
v *= s;
|
||||
|
||||
if (s == 100.0 && v > 100.0)
|
||||
v = 100.0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void __update_sample(struct pmu_counter *counter, uint64_t val)
|
||||
{
|
||||
counter->val.prev = counter->val.cur;
|
||||
counter->val.cur = val;
|
||||
}
|
||||
|
||||
static void update_sample(struct pmu_counter *counter, uint64_t *val)
|
||||
{
|
||||
if (counter->present)
|
||||
__update_sample(counter, val[counter->idx]);
|
||||
}
|
||||
|
||||
void pmu_sample(struct engines *engines)
|
||||
{
|
||||
const int num_val = engines->num_counters;
|
||||
uint64_t val[2 + num_val];
|
||||
unsigned int i;
|
||||
|
||||
engines->ts.prev = engines->ts.cur;
|
||||
engines->ts.cur = pmu_read_multi(engines->fd, num_val, val);
|
||||
|
||||
engines->freq_req.val.cur = engines->freq_req.val.prev = 0;
|
||||
engines->freq_act.val.cur = engines->freq_act.val.prev = 0;
|
||||
engines->rc6.val.cur = engines->rc6.val.prev = 0;
|
||||
|
||||
for (i = 0; i < engines->num_gts; i++) {
|
||||
update_sample(&engines->freq_req_gt[i], val);
|
||||
engines->freq_req.val.cur += engines->freq_req_gt[i].val.cur;
|
||||
engines->freq_req.val.prev += engines->freq_req_gt[i].val.prev;
|
||||
|
||||
update_sample(&engines->freq_act_gt[i], val);
|
||||
engines->freq_act.val.cur += engines->freq_act_gt[i].val.cur;
|
||||
engines->freq_act.val.prev += engines->freq_act_gt[i].val.prev;
|
||||
|
||||
update_sample(&engines->rc6_gt[i], val);
|
||||
engines->rc6.val.cur += engines->rc6_gt[i].val.cur;
|
||||
engines->rc6.val.prev += engines->rc6_gt[i].val.prev;
|
||||
}
|
||||
|
||||
engines->freq_req.val.cur /= engines->num_gts;
|
||||
engines->freq_req.val.prev /= engines->num_gts;
|
||||
|
||||
engines->freq_act.val.cur /= engines->num_gts;
|
||||
engines->freq_act.val.prev /= engines->num_gts;
|
||||
|
||||
engines->rc6.val.cur /= engines->num_gts;
|
||||
engines->rc6.val.prev /= engines->num_gts;
|
||||
|
||||
update_sample(&engines->irq, val);
|
||||
|
||||
for (i = 0; i < engines->num_engines; i++) {
|
||||
struct engine *engine = engine_ptr(engines, i);
|
||||
|
||||
update_sample(&engine->busy, val);
|
||||
update_sample(&engine->sema, val);
|
||||
update_sample(&engine->wait, val);
|
||||
}
|
||||
|
||||
if (engines->num_rapl) {
|
||||
pmu_read_multi(engines->rapl_fd, engines->num_rapl, val);
|
||||
update_sample(&engines->r_gpu, val);
|
||||
update_sample(&engines->r_pkg, val);
|
||||
}
|
||||
|
||||
if (engines->num_imc) {
|
||||
pmu_read_multi(engines->imc_fd, engines->num_imc, val);
|
||||
update_sample(&engines->imc_reads, val);
|
||||
update_sample(&engines->imc_writes, val);
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
#ifndef INTEL_GPU_TOP_H
|
||||
#define INTEL_GPU_TOP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
|
||||
struct pmu_pair {
|
||||
uint64_t cur;
|
||||
uint64_t prev;
|
||||
};
|
||||
|
||||
struct pmu_counter {
|
||||
uint64_t type;
|
||||
uint64_t config;
|
||||
unsigned int idx;
|
||||
struct pmu_pair val;
|
||||
double scale;
|
||||
const char *units;
|
||||
bool present;
|
||||
};
|
||||
|
||||
struct engine_class {
|
||||
unsigned int engine_class;
|
||||
const char *name;
|
||||
unsigned int num_engines;
|
||||
};
|
||||
|
||||
struct engine {
|
||||
const char *name;
|
||||
char *display_name;
|
||||
char *short_name;
|
||||
|
||||
unsigned int class;
|
||||
unsigned int instance;
|
||||
|
||||
unsigned int num_counters;
|
||||
|
||||
struct pmu_counter busy;
|
||||
struct pmu_counter wait;
|
||||
struct pmu_counter sema;
|
||||
};
|
||||
|
||||
#define MAX_GTS 4
|
||||
struct engines {
|
||||
unsigned int num_engines;
|
||||
unsigned int num_classes;
|
||||
struct engine_class *class;
|
||||
unsigned int num_counters;
|
||||
DIR *root;
|
||||
int fd;
|
||||
struct pmu_pair ts;
|
||||
|
||||
int rapl_fd;
|
||||
struct pmu_counter r_gpu, r_pkg;
|
||||
unsigned int num_rapl;
|
||||
|
||||
int imc_fd;
|
||||
struct pmu_counter imc_reads;
|
||||
struct pmu_counter imc_writes;
|
||||
unsigned int num_imc;
|
||||
|
||||
struct pmu_counter freq_req;
|
||||
struct pmu_counter freq_req_gt[MAX_GTS];
|
||||
struct pmu_counter freq_act;
|
||||
struct pmu_counter freq_act_gt[MAX_GTS];
|
||||
struct pmu_counter irq;
|
||||
struct pmu_counter rc6;
|
||||
struct pmu_counter rc6_gt[MAX_GTS];
|
||||
|
||||
bool discrete;
|
||||
char *device;
|
||||
|
||||
int num_gts;
|
||||
|
||||
/* Do not edit below this line.
|
||||
* This structure is reallocated every time a new engine is
|
||||
* found and size is increased by sizeof (engine).
|
||||
*/
|
||||
|
||||
struct engine engine;
|
||||
|
||||
};
|
||||
|
||||
struct engines *discover_engines(const char *device);
|
||||
void free_engines(struct engines *engines);
|
||||
int pmu_init(struct engines *engines);
|
||||
void pmu_sample(struct engines *engines);
|
||||
double pmu_calc(struct pmu_pair *p, double d, double t, double s);
|
||||
|
||||
char* find_intel_gpu_dir();
|
||||
char* get_intel_device_id(const char* vendor_path);
|
||||
char *get_intel_device_name(const char *device_id);
|
||||
|
||||
#endif
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "intel_gpu_top.h"
|
||||
#include "intel_chipset.h"
|
||||
|
||||
#define VENDOR_ID "0x8086"
|
||||
#define SYSFS_PATH "/sys/class/drm"
|
||||
#define VENDOR_FILE "vendor"
|
||||
#define DEVICE_FILE "device"
|
||||
|
||||
char* find_intel_gpu_dir() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
static char path[256];
|
||||
char vendor_path[256];
|
||||
char vendor_id[16];
|
||||
|
||||
if ((dir = opendir(SYSFS_PATH)) == NULL) {
|
||||
perror("opendir");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// Construct the path to the vendor file
|
||||
snprintf(vendor_path, sizeof(vendor_path), "%s/%s/device/%s", SYSFS_PATH, entry->d_name, VENDOR_FILE);
|
||||
|
||||
// Check if the vendor file exists
|
||||
if (access(vendor_path, F_OK) != -1) {
|
||||
FILE *file = fopen(vendor_path, "r");
|
||||
if (file) {
|
||||
if (fgets(vendor_id, sizeof(vendor_id), file)) {
|
||||
// Trim the newline character
|
||||
vendor_id[strcspn(vendor_id, "\n")] = 0;
|
||||
|
||||
if (strcmp(vendor_id, VENDOR_ID) == 0) {
|
||||
// Return the parent directory (i.e., /sys/class/drm/card*)
|
||||
snprintf(path, sizeof(path), "%s/%s", SYSFS_PATH, entry->d_name);
|
||||
fclose(file);
|
||||
closedir(dir);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return NULL; // Intel GPU not found
|
||||
}
|
||||
|
||||
char* get_intel_device_id(const char* gpu_dir) {
|
||||
static char device_path[256];
|
||||
char device_id[16];
|
||||
|
||||
// Construct the path to the device file
|
||||
snprintf(device_path, sizeof(device_path), "%s/device/%s", gpu_dir, DEVICE_FILE);
|
||||
|
||||
FILE *file = fopen(device_path, "r");
|
||||
if (file) {
|
||||
if (fgets(device_id, sizeof(device_id), file)) {
|
||||
fclose(file);
|
||||
// Trim the newline character
|
||||
device_id[strcspn(device_id, "\n")] = 0;
|
||||
// Return a copy of the device ID
|
||||
return strdup(device_id);
|
||||
}
|
||||
fclose(file);
|
||||
} else {
|
||||
perror("fopen");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_intel_device_name(const char *device_id) {
|
||||
uint16_t devid = strtol(device_id, NULL, 16);
|
||||
char dev_name[256];
|
||||
char full_name[256];
|
||||
const struct intel_device_info *info = intel_get_device_info(devid);
|
||||
if (info) {
|
||||
if (info->codename == NULL) {
|
||||
strcpy(dev_name, "(unknown)");
|
||||
} else {
|
||||
strcpy(dev_name, info->codename);
|
||||
dev_name[0] = toupper(dev_name[0]);
|
||||
}
|
||||
snprintf(full_name, sizeof(full_name), "Intel %s (Gen%u)", dev_name, info->graphics_ver);
|
||||
return strdup(full_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
0f02dc176959e6296866b1bafd3982e277a5e44b
|
||||
https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
|
||||
@@ -0,0 +1,218 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2022 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _XE_PCIIDS_H_
|
||||
#define _XE_PCIIDS_H_
|
||||
|
||||
/*
|
||||
* Lists below can be turned into initializers for a struct pci_device_id
|
||||
* by defining INTEL_VGA_DEVICE:
|
||||
*
|
||||
* #define INTEL_VGA_DEVICE(id, info) { \
|
||||
* 0x8086, id, \
|
||||
* ~0, ~0, \
|
||||
* 0x030000, 0xff0000, \
|
||||
* (unsigned long) info }
|
||||
*
|
||||
* And then calling like:
|
||||
*
|
||||
* XE_TGL_12_GT1_IDS(INTEL_VGA_DEVICE, ## __VA_ARGS__)
|
||||
*
|
||||
* To turn them into something else, just provide a different macro passed as
|
||||
* first argument.
|
||||
*/
|
||||
|
||||
/* TGL */
|
||||
#define XE_TGL_GT1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A60, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A68, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A70, ## __VA_ARGS__)
|
||||
|
||||
#define XE_TGL_GT2_IDS(MACRO__, ...) \
|
||||
MACRO__(0x9A40, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A49, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A59, ## __VA_ARGS__), \
|
||||
MACRO__(0x9A78, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC0, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AC9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x9AF8, ## __VA_ARGS__)
|
||||
|
||||
#define XE_TGL_IDS(MACRO__, ...) \
|
||||
XE_TGL_GT1_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_TGL_GT2_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* RKL */
|
||||
#define XE_RKL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4C80, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C8C, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C90, ## __VA_ARGS__), \
|
||||
MACRO__(0x4C9A, ## __VA_ARGS__)
|
||||
|
||||
/* DG1 */
|
||||
#define XE_DG1_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4905, ## __VA_ARGS__), \
|
||||
MACRO__(0x4906, ## __VA_ARGS__), \
|
||||
MACRO__(0x4907, ## __VA_ARGS__), \
|
||||
MACRO__(0x4908, ## __VA_ARGS__), \
|
||||
MACRO__(0x4909, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-S */
|
||||
#define XE_ADLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0x4680, ## __VA_ARGS__), \
|
||||
MACRO__(0x4682, ## __VA_ARGS__), \
|
||||
MACRO__(0x4688, ## __VA_ARGS__), \
|
||||
MACRO__(0x468A, ## __VA_ARGS__), \
|
||||
MACRO__(0x468B, ## __VA_ARGS__), \
|
||||
MACRO__(0x4690, ## __VA_ARGS__), \
|
||||
MACRO__(0x4692, ## __VA_ARGS__), \
|
||||
MACRO__(0x4693, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-P */
|
||||
#define XE_ADLP_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x46A8, ## __VA_ARGS__), \
|
||||
MACRO__(0x46AA, ## __VA_ARGS__), \
|
||||
MACRO__(0x462A, ## __VA_ARGS__), \
|
||||
MACRO__(0x4626, ## __VA_ARGS__), \
|
||||
MACRO__(0x4628, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46B3, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C2, ## __VA_ARGS__), \
|
||||
MACRO__(0x46C3, ## __VA_ARGS__)
|
||||
|
||||
/* ADL-N */
|
||||
#define XE_ADLN_IDS(MACRO__, ...) \
|
||||
MACRO__(0x46D0, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D1, ## __VA_ARGS__), \
|
||||
MACRO__(0x46D2, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-S */
|
||||
#define XE_RPLS_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA780, ## __VA_ARGS__), \
|
||||
MACRO__(0xA781, ## __VA_ARGS__), \
|
||||
MACRO__(0xA782, ## __VA_ARGS__), \
|
||||
MACRO__(0xA783, ## __VA_ARGS__), \
|
||||
MACRO__(0xA788, ## __VA_ARGS__), \
|
||||
MACRO__(0xA789, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78A, ## __VA_ARGS__), \
|
||||
MACRO__(0xA78B, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-U */
|
||||
#define XE_RPLU_IDS(MACRO__, ...) \
|
||||
MACRO__(0xA721, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A1, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A9, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AC, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AD, ## __VA_ARGS__)
|
||||
|
||||
/* RPL-P */
|
||||
#define XE_RPLP_IDS(MACRO__, ...) \
|
||||
XE_RPLU_IDS(MACRO__, ## __VA_ARGS__), \
|
||||
MACRO__(0xA720, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A0, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7A8, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AA, ## __VA_ARGS__), \
|
||||
MACRO__(0xA7AB, ## __VA_ARGS__)
|
||||
|
||||
/* DG2 */
|
||||
#define XE_DG2_G10_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5690, ## __VA_ARGS__), \
|
||||
MACRO__(0x5691, ## __VA_ARGS__), \
|
||||
MACRO__(0x5692, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BE, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BF, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_G11_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5693, ## __VA_ARGS__), \
|
||||
MACRO__(0x5694, ## __VA_ARGS__), \
|
||||
MACRO__(0x5695, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A5, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A6, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B1, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BA, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BB, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BC, ## __VA_ARGS__), \
|
||||
MACRO__(0x56BD, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_G12_IDS(MACRO__, ...) \
|
||||
MACRO__(0x5696, ## __VA_ARGS__), \
|
||||
MACRO__(0x5697, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A3, ## __VA_ARGS__), \
|
||||
MACRO__(0x56A4, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B2, ## __VA_ARGS__), \
|
||||
MACRO__(0x56B3, ## __VA_ARGS__)
|
||||
|
||||
#define XE_DG2_IDS(MACRO__, ...) \
|
||||
XE_DG2_G10_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_DG2_G11_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_DG2_G12_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M150_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C0, ## __VA_ARGS__), \
|
||||
MACRO__(0x56C2, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M75_IDS(MACRO__, ...) \
|
||||
MACRO__(0x56C1, ## __VA_ARGS__)
|
||||
|
||||
#define XE_ATS_M_IDS(MACRO__, ...) \
|
||||
XE_ATS_M150_IDS(MACRO__, ## __VA_ARGS__),\
|
||||
XE_ATS_M75_IDS(MACRO__, ## __VA_ARGS__)
|
||||
|
||||
/* MTL / ARL */
|
||||
#define XE_MTL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x7D40, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D41, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D45, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D51, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D55, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D60, ## __VA_ARGS__), \
|
||||
MACRO__(0x7D67, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD1, ## __VA_ARGS__), \
|
||||
MACRO__(0x7DD5, ## __VA_ARGS__)
|
||||
|
||||
/* PVC */
|
||||
#define XE_PVC_IDS(MACRO__, ...) \
|
||||
MACRO__(0x0B69, ## __VA_ARGS__), \
|
||||
MACRO__(0x0B6E, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD4, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD5, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD6, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD7, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD8, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BD9, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDA, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BDB, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE0, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE1, ## __VA_ARGS__), \
|
||||
MACRO__(0x0BE5, ## __VA_ARGS__)
|
||||
|
||||
#define XE_LNL_IDS(MACRO__, ...) \
|
||||
MACRO__(0x6420, ## __VA_ARGS__), \
|
||||
MACRO__(0x64A0, ## __VA_ARGS__), \
|
||||
MACRO__(0x64B0, ## __VA_ARGS__)
|
||||
|
||||
#define XE_BMG_IDS(MACRO__, ...) \
|
||||
MACRO__(0xE202, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20B, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20C, ## __VA_ARGS__), \
|
||||
MACRO__(0xE20D, ## __VA_ARGS__), \
|
||||
MACRO__(0xE212, ## __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "btop.hpp"
|
||||
|
||||
#include <iterator>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
auto main(int argc, const char* argv[]) -> int {
|
||||
return btop_main(std::views::counted(std::next(argv), argc - 1) | std::ranges::to<std::vector<std::string_view>>());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021 Brian Callahan <bcallah@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct sysctls {
|
||||
const char *name;
|
||||
int mib0;
|
||||
int mib1;
|
||||
int mib2;
|
||||
} sysctlnames[] = {
|
||||
{ "hw.machine", CTL_HW, HW_MACHINE, 0 },
|
||||
{ "hw.model", CTL_HW, HW_MODEL, 0 },
|
||||
{ "hw.ncpu", CTL_HW, HW_NCPU, 0 },
|
||||
{ "hw.byteorder", CTL_HW, HW_BYTEORDER, 0 },
|
||||
{ "hw.pagesize", CTL_HW, HW_PAGESIZE, 0 },
|
||||
{ "hw.disknames", CTL_HW, HW_DISKNAMES, 0 },
|
||||
{ "hw.diskcount", CTL_HW, HW_DISKCOUNT, 0 },
|
||||
{ "hw.sensors", CTL_HW, HW_SENSORS, 0 },
|
||||
{ "hw.model", CTL_HW, HW_MODEL, 0 },
|
||||
{ "hw.ncpu", CTL_HW, HW_NCPU, 0 },
|
||||
{ "hw.byteorder", CTL_HW, HW_BYTEORDER, 0 },
|
||||
{ "hw.pagesize", CTL_HW, HW_PAGESIZE, 0 },
|
||||
{ "hw.disknames", CTL_HW, HW_DISKNAMES, 0 },
|
||||
{ "hw.diskcount", CTL_HW, HW_DISKCOUNT, 0 },
|
||||
{ "hw.sensors", CTL_HW, HW_SENSORS, 0 },
|
||||
{ "hw.cpuspeed", CTL_HW, HW_CPUSPEED, 0 },
|
||||
{ "hw.setperf", CTL_HW, HW_SETPERF, 0 },
|
||||
{ "hw.vendor", CTL_HW, HW_VENDOR, 0 },
|
||||
{ "hw.product", CTL_HW, HW_PRODUCT, 0 },
|
||||
{ "hw.serialno", CTL_HW, HW_SERIALNO, 0 },
|
||||
{ "hw.uuid", CTL_HW, HW_UUID, 0 },
|
||||
{ "hw.physmem", CTL_HW, HW_PHYSMEM64, 0 },
|
||||
{ "hw.usermem", CTL_HW, HW_USERMEM64, 0 },
|
||||
{ "hw.ncpufound", CTL_HW, HW_NCPUFOUND, 0 },
|
||||
{ "hw.allowpowerdown", CTL_HW, HW_ALLOWPOWERDOWN, 0 },
|
||||
{ "hw.perfpolicy", CTL_HW, HW_PERFPOLICY, 0 },
|
||||
{ "hw.smt", CTL_HW, HW_SMT, 0 },
|
||||
{ "hw.ncpuonline", CTL_HW, HW_NCPUONLINE, 0 },
|
||||
{ "hw.cpuspeed", CTL_HW, HW_CPUSPEED, 0 },
|
||||
{ "hw.setperf", CTL_HW, HW_SETPERF, 0 },
|
||||
{ "hw.vendor", CTL_HW, HW_VENDOR, 0 },
|
||||
{ "hw.product", CTL_HW, HW_PRODUCT, 0 },
|
||||
{ "hw.serialno", CTL_HW, HW_SERIALNO, 0 },
|
||||
{ "hw.uuid", CTL_HW, HW_UUID, 0 },
|
||||
{ "hw.physmem", CTL_HW, HW_PHYSMEM64, 0 },
|
||||
{ "hw.usermem", CTL_HW, HW_USERMEM64, 0 },
|
||||
{ "hw.ncpufound", CTL_HW, HW_NCPUFOUND, 0 },
|
||||
{ "hw.allowpowerdown", CTL_HW, HW_ALLOWPOWERDOWN, 0 },
|
||||
{ "hw.perfpolicy", CTL_HW, HW_PERFPOLICY, 0 },
|
||||
{ "hw.smt", CTL_HW, HW_SMT, 0 },
|
||||
{ "hw.ncpuonline", CTL_HW, HW_NCPUONLINE, 0 },
|
||||
{ "kern.ostype", CTL_KERN, KERN_OSTYPE, 0 },
|
||||
{ "kern.osrelease", CTL_KERN, KERN_OSRELEASE, 0 },
|
||||
{ "kern.osrevision", CTL_KERN, KERN_OSREV, 0 },
|
||||
{ "kern.version", CTL_KERN, KERN_VERSION, 0 },
|
||||
{ "kern.maxvnodes", CTL_KERN, KERN_MAXVNODES, 0 },
|
||||
{ "kern.maxproc", CTL_KERN, KERN_MAXPROC, 0 },
|
||||
{ "kern.maxfiles", CTL_KERN, KERN_MAXFILES, 0 },
|
||||
{ "kern.argmax", CTL_KERN, KERN_ARGMAX, 0 },
|
||||
{ "kern.securelevel", CTL_KERN, KERN_SECURELVL, 0 },
|
||||
{ "kern.hostname", CTL_KERN, KERN_HOSTNAME, 0 },
|
||||
{ "kern.hostid", CTL_KERN, KERN_HOSTID, 0 },
|
||||
{ "kern.clockrate", CTL_KERN, KERN_CLOCKRATE, 0 },
|
||||
{ "kern.profiling", CTL_KERN, KERN_PROF, 0 },
|
||||
{ "kern.posix1version", CTL_KERN, KERN_POSIX1, 0 },
|
||||
{ "kern.ngroups", CTL_KERN, KERN_NGROUPS, 0 },
|
||||
{ "kern.job_control", CTL_KERN, KERN_JOB_CONTROL, 0 },
|
||||
{ "kern.saved_ids", CTL_KERN, KERN_SAVED_IDS, 0 },
|
||||
{ "kern.boottime", CTL_KERN, KERN_BOOTTIME, 0 },
|
||||
{ "kern.domainname", CTL_KERN, KERN_DOMAINNAME, 0 },
|
||||
{ "kern.maxpartitions", CTL_KERN, KERN_MAXPARTITIONS, 0 },
|
||||
{ "kern.rawpartition", CTL_KERN, KERN_RAWPARTITION, 0 },
|
||||
{ "kern.maxthread", CTL_KERN, KERN_MAXTHREAD, 0 },
|
||||
{ "kern.nthreads", CTL_KERN, KERN_NTHREADS, 0 },
|
||||
{ "kern.osversion", CTL_KERN, KERN_OSVERSION, 0 },
|
||||
{ "kern.somaxconn", CTL_KERN, KERN_SOMAXCONN, 0 },
|
||||
{ "kern.sominconn", CTL_KERN, KERN_SOMINCONN, 0 },
|
||||
{ "kern.nosuidcoredump", CTL_KERN, KERN_NOSUIDCOREDUMP, 0 },
|
||||
{ "kern.fsync", CTL_KERN, KERN_FSYNC, 0 },
|
||||
{ "kern.sysvmsg", CTL_KERN, KERN_SYSVMSG, 0 },
|
||||
{ "kern.sysvsem", CTL_KERN, KERN_SYSVSEM, 0 },
|
||||
{ "kern.sysvshm", CTL_KERN, KERN_SYSVSHM, 0 },
|
||||
{ "kern.msgbufsize", CTL_KERN, KERN_MSGBUFSIZE, 0 },
|
||||
{ "kern.malloc", CTL_KERN, KERN_MALLOCSTATS, 0 },
|
||||
{ "kern.cp_time", CTL_KERN, KERN_CPTIME, 0 },
|
||||
{ "kern.nchstats", CTL_KERN, KERN_NCHSTATS, 0 },
|
||||
{ "kern.forkstat", CTL_KERN, KERN_FORKSTAT, 0 },
|
||||
{ "kern.tty", CTL_KERN, KERN_TTY, 0 },
|
||||
{ "kern.ccpu", CTL_KERN, KERN_CCPU, 0 },
|
||||
{ "kern.fscale", CTL_KERN, KERN_FSCALE, 0 },
|
||||
{ "kern.nprocs", CTL_KERN, KERN_NPROCS, 0 },
|
||||
{ "kern.msgbuf", CTL_KERN, KERN_MSGBUF, 0 },
|
||||
{ "kern.pool", CTL_KERN, KERN_POOL, 0 },
|
||||
{ "kern.stackgap_random", CTL_KERN, KERN_STACKGAPRANDOM, 0 },
|
||||
{ "kern.sysvipc_info", CTL_KERN, KERN_SYSVIPC_INFO, 0 },
|
||||
{ "kern.allowkmem", CTL_KERN, KERN_ALLOWKMEM, 0 },
|
||||
{ "kern.witnesswatch", CTL_KERN, KERN_WITNESSWATCH, 0 },
|
||||
{ "kern.splassert", CTL_KERN, KERN_SPLASSERT, 0 },
|
||||
{ "kern.procargs", CTL_KERN, KERN_PROC_ARGS, 0 },
|
||||
{ "kern.nfiles", CTL_KERN, KERN_NFILES, 0 },
|
||||
{ "kern.ttycount", CTL_KERN, KERN_TTYCOUNT, 0 },
|
||||
{ "kern.numvnodes", CTL_KERN, KERN_NUMVNODES, 0 },
|
||||
{ "kern.mbstat", CTL_KERN, KERN_MBSTAT, 0 },
|
||||
{ "kern.witness", CTL_KERN, KERN_WITNESS, 0 },
|
||||
{ "kern.seminfo", CTL_KERN, KERN_SEMINFO, 0 },
|
||||
{ "kern.shminfo", CTL_KERN, KERN_SHMINFO, 0 },
|
||||
{ "kern.intrcnt", CTL_KERN, KERN_INTRCNT, 0 },
|
||||
{ "kern.watchdog", CTL_KERN, KERN_WATCHDOG, 0 },
|
||||
{ "kern.proc", CTL_KERN, KERN_PROC, 0 },
|
||||
{ "kern.maxclusters", CTL_KERN, KERN_MAXCLUSTERS, 0 },
|
||||
{ "kern.evcount", CTL_KERN, KERN_EVCOUNT, 0 },
|
||||
{ "kern.timecounter", CTL_KERN, KERN_TIMECOUNTER, 0 },
|
||||
{ "kern.maxlocksperuid", CTL_KERN, KERN_MAXLOCKSPERUID, 0 },
|
||||
{ "kern.cp_time2", CTL_KERN, KERN_CPTIME2, 0 },
|
||||
{ "kern.bufcachepercent", CTL_KERN, KERN_CACHEPCT, 0 },
|
||||
{ "kern.file", CTL_KERN, KERN_FILE, 0 },
|
||||
{ "kern.wxabort", CTL_KERN, KERN_WXABORT, 0 },
|
||||
{ "kern.consdev", CTL_KERN, KERN_CONSDEV, 0 },
|
||||
{ "kern.netlivelocks", CTL_KERN, KERN_NETLIVELOCKS, 0 },
|
||||
{ "kern.pool_debug", CTL_KERN, KERN_POOL_DEBUG, 0 },
|
||||
{ "kern.proc_cwd", CTL_KERN, KERN_PROC_CWD, 0 },
|
||||
{ "kern.proc_nobroadcastkill", CTL_KERN, KERN_PROC_NOBROADCASTKILL, 0 },
|
||||
{ "kern.proc_vmap", CTL_KERN, KERN_PROC_VMMAP, 0 },
|
||||
{ "kern.global_ptrace", CTL_KERN, KERN_GLOBAL_PTRACE, 0 },
|
||||
{ "kern.consbufsize", CTL_KERN, KERN_CONSBUFSIZE, 0 },
|
||||
{ "kern.consbuf", CTL_KERN, KERN_CONSBUF, 0 },
|
||||
{ "kern.audio", CTL_KERN, KERN_AUDIO, 0 },
|
||||
{ "kern.cpustats", CTL_KERN, KERN_CPUSTATS, 0 },
|
||||
{ "kern.pfstatus", CTL_KERN, KERN_PFSTATUS, 0 },
|
||||
{ "kern.timeout_stats", CTL_KERN, KERN_TIMEOUT_STATS, 0 },
|
||||
{ "kern.utc_offset", CTL_KERN, KERN_UTC_OFFSET, 0 },
|
||||
{ "vm.vmmeter", CTL_VM, VM_METER, 0 },
|
||||
{ "vm.loadavg", CTL_VM, VM_LOADAVG, 0 },
|
||||
{ "vm.psstrings", CTL_VM, VM_PSSTRINGS, 0 },
|
||||
{ "vm.uvmexp", CTL_VM, VM_UVMEXP, 0 },
|
||||
{ "vm.swapencrypt", CTL_VM, VM_SWAPENCRYPT, 0 },
|
||||
{ "vm.nkmempages", CTL_VM, VM_NKMEMPAGES, 0 },
|
||||
{ "vm.anonmin", CTL_VM, VM_ANONMIN, 0 },
|
||||
{ "vm.vtextmin", CTL_VM, VM_VTEXTMIN, 0 },
|
||||
{ "vm.vnodemin", CTL_VM, VM_VNODEMIN, 0 },
|
||||
{ "vm.maxslp", CTL_VM, VM_MAXSLP, 0 },
|
||||
{ "vm.uspace", CTL_VM, VM_USPACE, 0 },
|
||||
{ "vm.malloc_conf", CTL_VM, VM_MALLOC_CONF, 0 },
|
||||
{ NULL, 0, 0, 0 },
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2021 Brian Callahan <bcallah@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../btop_tools.hpp"
|
||||
|
||||
int
|
||||
sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen)
|
||||
{
|
||||
int i, mib[2];
|
||||
|
||||
for (i = 0; i < 132; i++) {
|
||||
// for (i = 0; i < sizeof(sysctlnames) / sizeof(sysctlnames[0]); i++) {
|
||||
if (!strcmp(name, sysctlnames[i].name)) {
|
||||
mib[0] = sysctlnames[i].mib0;
|
||||
mib[1] = sysctlnames[i].mib1;
|
||||
|
||||
return sysctl(mib, 2, oldp, oldlenp, newp, newlen);
|
||||
}
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Brian Callahan <bcallah@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
extern int sysctlbyname(const char *, void *, size_t *, void *, size_t);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <Availability.h>
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
|
||||
#include "sensors.hpp"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
|
||||
|
||||
#include <string>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
typedef struct __IOHIDEvent *IOHIDEventRef;
|
||||
typedef struct __IOHIDServiceClient *IOHIDServiceClientRef;
|
||||
#ifdef __LP64__
|
||||
typedef double IOHIDFloat;
|
||||
#else
|
||||
typedef float IOHIDFloat;
|
||||
#endif
|
||||
|
||||
#define IOHIDEventFieldBase(type) (type << 16)
|
||||
#define kIOHIDEventTypeTemperature 15
|
||||
|
||||
IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator);
|
||||
int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client, CFDictionaryRef match);
|
||||
int IOHIDEventSystemClientSetMatchingMultiple(IOHIDEventSystemClientRef client, CFArrayRef match);
|
||||
IOHIDEventRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef, int64_t, int32_t, int64_t);
|
||||
CFStringRef IOHIDServiceClientCopyProperty(IOHIDServiceClientRef service, CFStringRef property);
|
||||
IOHIDFloat IOHIDEventGetFloatValue(IOHIDEventRef event, int32_t field);
|
||||
|
||||
// create a dict ref, like for temperature sensor {"PrimaryUsagePage":0xff00, "PrimaryUsage":0x5}
|
||||
CFDictionaryRef matching(int page, int usage) {
|
||||
CFNumberRef nums[2];
|
||||
CFStringRef keys[2];
|
||||
|
||||
keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);
|
||||
keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);
|
||||
nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);
|
||||
nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);
|
||||
|
||||
CFDictionaryRef dict = CFDictionaryCreate(0, (const void **)keys, (const void **)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(keys[0]);
|
||||
CFRelease(keys[1]);
|
||||
return dict;
|
||||
}
|
||||
|
||||
double getValue(IOHIDServiceClientRef sc) {
|
||||
IOHIDEventRef event = IOHIDServiceClientCopyEvent(sc, kIOHIDEventTypeTemperature, 0, 0); // here we use ...CopyEvent
|
||||
IOHIDFloat temp = 0.0;
|
||||
if (event != 0) {
|
||||
temp = IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(kIOHIDEventTypeTemperature));
|
||||
CFRelease(event);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
} // extern C
|
||||
|
||||
long long Cpu::ThermalSensors::getSensors() {
|
||||
CFDictionaryRef thermalSensors = matching(0xff00, 5); // 65280_10 = FF00_16
|
||||
// thermalSensors's PrimaryUsagePage should be 0xff00 for M1 chip, instead of 0xff05
|
||||
// can be checked by ioreg -lfx
|
||||
IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
|
||||
IOHIDEventSystemClientSetMatching(system, thermalSensors);
|
||||
CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system);
|
||||
std::vector<double> temps;
|
||||
if (matchingsrvs) {
|
||||
long count = CFArrayGetCount(matchingsrvs);
|
||||
for (int i = 0; i < count; i++) {
|
||||
IOHIDServiceClientRef sc = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(matchingsrvs, i);
|
||||
if (sc) {
|
||||
CFStringRef name = IOHIDServiceClientCopyProperty(sc, CFSTR("Product")); // here we use ...CopyProperty
|
||||
if (name) {
|
||||
char buf[200];
|
||||
CFStringGetCString(name, buf, 200, kCFStringEncodingASCII);
|
||||
std::string n(buf);
|
||||
// this is just a guess, nobody knows which sensors mean what
|
||||
// on my system PMU tdie 3 and 9 are missing...
|
||||
// there is also PMU tdev1-8 but it has negative values??
|
||||
// there is also eACC for efficiency package but it only has 2 entries
|
||||
// and pACC for performance but it has 7 entries (2 - 9) WTF
|
||||
if (n.starts_with("eACC") or n.starts_with("pACC")) {
|
||||
temps.push_back(getValue(sc));
|
||||
}
|
||||
CFRelease(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(matchingsrvs);
|
||||
}
|
||||
CFRelease(system);
|
||||
CFRelease(thermalSensors);
|
||||
if (temps.empty()) return 0ll;
|
||||
return round(std::accumulate(temps.begin(), temps.end(), 0ll) / temps.size());
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include <Availability.h>
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
|
||||
namespace Cpu {
|
||||
class ThermalSensors {
|
||||
public:
|
||||
long long getSensors();
|
||||
};
|
||||
} // namespace Cpu
|
||||
#endif
|
||||
@@ -0,0 +1,154 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#include "smc.hpp"
|
||||
|
||||
static constexpr size_t MaxIndexCount = sizeof("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") - 1;
|
||||
static constexpr const char *KeyIndexes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
static UInt32 _strtoul(char *str, int size, int base) {
|
||||
UInt32 total = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (base == 16) {
|
||||
total += str[i] << (size - 1 - i) * 8;
|
||||
} else {
|
||||
total += (unsigned char)(str[i] << (size - 1 - i) * 8);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static void _ultostr(char *str, UInt32 val) {
|
||||
str[0] = '\0';
|
||||
snprintf(str, 5, "%c%c%c%c",
|
||||
(unsigned int)val >> 24,
|
||||
(unsigned int)val >> 16,
|
||||
(unsigned int)val >> 8,
|
||||
(unsigned int)val);
|
||||
}
|
||||
|
||||
namespace Cpu {
|
||||
|
||||
SMCConnection::SMCConnection() {
|
||||
CFMutableDictionaryRef matchingDictionary = IOServiceMatching("AppleSMC");
|
||||
result = IOServiceGetMatchingServices(0, matchingDictionary, &iterator);
|
||||
if (result != kIOReturnSuccess) {
|
||||
throw std::runtime_error("failed to get AppleSMC");
|
||||
}
|
||||
|
||||
device = IOIteratorNext(iterator);
|
||||
IOObjectRelease(iterator);
|
||||
if (device == 0) {
|
||||
throw std::runtime_error("failed to get SMC device");
|
||||
}
|
||||
|
||||
result = IOServiceOpen(device, mach_task_self(), 0, &conn);
|
||||
IOObjectRelease(device);
|
||||
if (result != kIOReturnSuccess) {
|
||||
throw std::runtime_error("failed to get SMC connection");
|
||||
}
|
||||
}
|
||||
SMCConnection::~SMCConnection() {
|
||||
IOServiceClose(conn);
|
||||
}
|
||||
|
||||
long long SMCConnection::getSMCTemp(char *key) {
|
||||
SMCVal_t val;
|
||||
kern_return_t result;
|
||||
result = SMCReadKey(key, &val);
|
||||
if (result == kIOReturnSuccess) {
|
||||
if (val.dataSize > 0) {
|
||||
if (strcmp(val.dataType, DATATYPE_SP78) == 0) {
|
||||
// convert sp78 value to temperature
|
||||
int intValue = val.bytes[0] * 256 + (unsigned char)val.bytes[1];
|
||||
return static_cast<long long>(intValue / 256.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// core means physical core in SMC, while in core map it's cpu threads :-/ Only an issue on hackintosh?
|
||||
// this means we can only get the T per physical core
|
||||
// another issue with the SMC API is that the key is always 4 chars -> what with systems with more than 9 physical cores?
|
||||
// no Mac models with more than 18 threads are released, so no problem so far
|
||||
// according to VirtualSMC docs (hackintosh fake SMC) the enumeration follows with alphabetic chars - not implemented yet here (nor in VirtualSMC)
|
||||
long long SMCConnection::getTemp(int core) {
|
||||
char key[] = SMC_KEY_CPU_TEMP;
|
||||
if (core >= 0) {
|
||||
if ((size_t)core > MaxIndexCount) {
|
||||
return -1;
|
||||
}
|
||||
snprintf(key, 5, "TC%1cc", KeyIndexes[core]);
|
||||
}
|
||||
long long result = getSMCTemp(key);
|
||||
if (result == -1) {
|
||||
// try again with C
|
||||
snprintf(key, 5, "TC%1dC", KeyIndexes[core]);
|
||||
result = getSMCTemp(key);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
kern_return_t SMCConnection::SMCReadKey(UInt32Char_t key, SMCVal_t *val) {
|
||||
kern_return_t result;
|
||||
SMCKeyData_t inputStructure;
|
||||
SMCKeyData_t outputStructure;
|
||||
|
||||
memset(&inputStructure, 0, sizeof(SMCKeyData_t));
|
||||
memset(&outputStructure, 0, sizeof(SMCKeyData_t));
|
||||
memset(val, 0, sizeof(SMCVal_t));
|
||||
|
||||
inputStructure.key = _strtoul(key, 4, 16);
|
||||
inputStructure.data8 = SMC_CMD_READ_KEYINFO;
|
||||
|
||||
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
|
||||
if (result != kIOReturnSuccess)
|
||||
return result;
|
||||
|
||||
val->dataSize = outputStructure.keyInfo.dataSize;
|
||||
_ultostr(val->dataType, outputStructure.keyInfo.dataType);
|
||||
inputStructure.keyInfo.dataSize = val->dataSize;
|
||||
inputStructure.data8 = SMC_CMD_READ_BYTES;
|
||||
|
||||
result = SMCCall(KERNEL_INDEX_SMC, &inputStructure, &outputStructure);
|
||||
if (result != kIOReturnSuccess)
|
||||
return result;
|
||||
|
||||
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
|
||||
|
||||
return kIOReturnSuccess;
|
||||
}
|
||||
|
||||
kern_return_t SMCConnection::SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure) {
|
||||
size_t structureInputSize;
|
||||
size_t structureOutputSize;
|
||||
|
||||
structureInputSize = sizeof(SMCKeyData_t);
|
||||
structureOutputSize = sizeof(SMCKeyData_t);
|
||||
|
||||
return IOConnectCallStructMethod(conn, index,
|
||||
// inputStructure
|
||||
inputStructure, structureInputSize,
|
||||
// outputStructure
|
||||
outputStructure, &structureOutputSize);
|
||||
}
|
||||
|
||||
} // namespace Cpu
|
||||
@@ -0,0 +1,117 @@
|
||||
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
indent = tab
|
||||
tab-size = 4
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#define VERSION "0.01"
|
||||
|
||||
#define KERNEL_INDEX_SMC 2
|
||||
|
||||
#define SMC_CMD_READ_BYTES 5
|
||||
#define SMC_CMD_WRITE_BYTES 6
|
||||
#define SMC_CMD_READ_INDEX 8
|
||||
#define SMC_CMD_READ_KEYINFO 9
|
||||
#define SMC_CMD_READ_PLIMIT 11
|
||||
#define SMC_CMD_READ_VERS 12
|
||||
|
||||
#define DATATYPE_FPE2 "fpe2"
|
||||
#define DATATYPE_UINT8 "ui8 "
|
||||
#define DATATYPE_UINT16 "ui16"
|
||||
#define DATATYPE_UINT32 "ui32"
|
||||
#define DATATYPE_SP78 "sp78"
|
||||
|
||||
// key values
|
||||
#define SMC_KEY_CPU_TEMP "TC0P" // proximity temp?
|
||||
#define SMC_KEY_CPU_DIODE_TEMP "TC0D" // diode temp?
|
||||
#define SMC_KEY_CPU_DIE_TEMP "TC0F" // die temp?
|
||||
#define SMC_KEY_CPU1_TEMP "TC1C"
|
||||
#define SMC_KEY_CPU2_TEMP "TC2C" // etc
|
||||
#define SMC_KEY_FAN0_RPM_CUR "F0Ac"
|
||||
|
||||
typedef struct {
|
||||
char major;
|
||||
char minor;
|
||||
char build;
|
||||
char reserved[1];
|
||||
UInt16 release;
|
||||
} SMCKeyData_vers_t;
|
||||
|
||||
typedef struct {
|
||||
UInt16 version;
|
||||
UInt16 length;
|
||||
UInt32 cpuPLimit;
|
||||
UInt32 gpuPLimit;
|
||||
UInt32 memPLimit;
|
||||
} SMCKeyData_pLimitData_t;
|
||||
|
||||
typedef struct {
|
||||
UInt32 dataSize;
|
||||
UInt32 dataType;
|
||||
char dataAttributes;
|
||||
} SMCKeyData_keyInfo_t;
|
||||
|
||||
typedef char SMCBytes_t[32];
|
||||
|
||||
typedef struct {
|
||||
UInt32 key;
|
||||
SMCKeyData_vers_t vers;
|
||||
SMCKeyData_pLimitData_t pLimitData;
|
||||
SMCKeyData_keyInfo_t keyInfo;
|
||||
char result;
|
||||
char status;
|
||||
char data8;
|
||||
UInt32 data32;
|
||||
SMCBytes_t bytes;
|
||||
} SMCKeyData_t;
|
||||
|
||||
typedef char UInt32Char_t[5];
|
||||
|
||||
typedef struct {
|
||||
UInt32Char_t key;
|
||||
UInt32 dataSize;
|
||||
UInt32Char_t dataType;
|
||||
SMCBytes_t bytes;
|
||||
} SMCVal_t;
|
||||
|
||||
namespace Cpu {
|
||||
class SMCConnection {
|
||||
public:
|
||||
SMCConnection();
|
||||
virtual ~SMCConnection();
|
||||
|
||||
long long getTemp(int core);
|
||||
|
||||
private:
|
||||
kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val);
|
||||
long long getSMCTemp(char *key);
|
||||
kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure);
|
||||
|
||||
io_connect_t conn;
|
||||
kern_return_t result;
|
||||
mach_port_t masterPort;
|
||||
io_iterator_t iterator;
|
||||
io_object_t device;
|
||||
};
|
||||
} // namespace Cpu
|
||||
Reference in New Issue
Block a user