#[cfg(feature = "gui")]
use eframe::egui;
#[cfg(feature = "gui")]
fn layout_with_underlined_part(label: &str, underlined: &str) -> egui::text::LayoutJob {
let mut job = egui::text::LayoutJob::default();
let parts = label.split_once(underlined);
let (before, after) = parts.expect("underlined must be present in label");
if before.len() > 0 {
job.append(
before,
0.0,
egui::TextFormat { ..Default::default() },
);
}
job.append(
underlined,
0.0,
egui::TextFormat { underline: egui::Stroke::new(1.0, egui::Color32::GRAY), ..Default::default() },
);
if after.len() > 0 {
job.append(
after,
0.0,
egui::TextFormat { ..Default::default() },
);
}
job
}
#[cfg(feature = "gui")]
pub const TTIP_PROCLIST_SHOW: &str = "Show process list.";
#[cfg(feature = "gui")]
pub const TTIP_PROCLIST_HIDE: &str = "Hide process list.";
#[cfg(feature = "gui")]
pub fn filter() -> egui::text::LayoutJob {
layout_with_underlined_part("Filter:", "F")
}
pub fn processes(count: usize) -> String {
format!("{} process{}", count, if count != 1 {"es"} else {""})
}
#[cfg(feature = "gui")]
pub const TTIP_HELP: &str = "show HELP info";
#[cfg(feature = "gui")]
pub const TTIP_CPU: &str = "show CPU info";
pub const STATUS_PROCESSES_DIED_EARLY: &str = "All started processes stopped before thread affinities could be set";
pub const STATUS_THREAD_AFFINITIES_CANCELED: &str = "Thread order/core selection canceled";
pub fn status_failed_to_set_thread_affinities(pid: &sysinfo::Pid, name: &String, error: &anyhow::Error ) -> String {
format!("ERROR: failed to set thread affinties for process {}/{} (permissions?): {}", pid, name, error)
}
pub const STATUS_THREAD_AFFINITIES_SET: &str = "Success setting thread affinities for";
pub fn status_failed_to_get_affinity(pid: &sysinfo::Pid) -> String {
format!("ERROR: failed to get CPU affinity for process {} or its thread", pid)
}
pub const STATUS_GROUP_SELECT_FAILED: &str = "ERROR: group select failed: could not get the set of CPUs in a group";
pub const STATUS_PROC_AFFINITY_SUCCESS: &str = "Success setting process affinity for";
pub const STATUS_FAILED_SET_AFFINITY: &str = "ERROR: failed to set process or thread affinity (permissions? dead process?)";
pub const STATUS_PROCESS_DIED: &str = "Selected process died";
pub const HELP_RUN: &str =
r"# **RUN**
Type command to **RUN:**, and
click **run** to run it.
By default, the command's process
affinities will be set.
Optionally, type **subprocess** to
instead set affinities of any
(fuzzy) matching process launched
by the command.
Unpack **threads** and specify
thread **count** to set affinities
of threads launched by the
process, and set time since start
to **apply thread affinities** at.
Up to **count** threads will have
affinities set as specified in
**threads**. **thread order** will
set affinities of any further
threads.
Affinities are only applied at
specified time; threads stopped
before or started after will
be unaffected.
";
#[cfg(feature = "gui")]
pub const HELP_RUN_SHORTCUTS: &str =
r"| Action | Shortcut |
| --------------- | ----------- |
| Edit process | Ctrl-r |
| Edit subprocess | Ctrl-p |
| Thread count | Ctrl-t |
| Run the command | Ctrl-Enter |
| Clear threads | Ctrl-BSpace |
| Thr. apply time | Ctrl-h |
| disable SMT | Ctrl-n |
| TO: HW threads | Ctrl-1 |
| TO: cores | Ctrl-2 |
| TO: L3 | Ctrl-3 |
| TO: None | Ctrl-0 |
| TO: ignore main | Ctrl-- |
";
#[cfg(feature = "tui")]
pub const HELP_RUN_SHORTCUTS: &str =
r"| Action | Shortcut |
| --------------- | ----------- |
| Process to run | <:>,<e> |
| Subproc. to set | <!>,<p> |
| Thr. apply time | <r> |
| Run the process | <Ctrl-Enter>|
| Thread count | t |
";
pub const HELP_VIEW: &str =
r"# **VIEW**
Click a core, core group or set
a **thread order** to **EDIT**
affinities.
Unpack **threads** to view
affinities of each thread.
";
#[cfg(feature = "gui")]
pub const HELP_VIEW_SHORTCUTS: &str =
r"| Action | Shortcut |
| --------------- | ----------- |
| RUN mode | F3 |
| EDIT mode | F5 |
| disable SMT | Ctrl-n |
| disable SMT | Ctrl-n |
| TO: HW threads | Ctrl-1 |
| TO: cores | Ctrl-2 |
| TO: L3 | Ctrl-3 |
| TO: None | Ctrl-0 |
| TO: ignore main | Ctrl-- |
";
#[cfg(feature = "tui")]
pub const HELP_VIEW_SHORTCUTS: &str = "";
pub const HELP_EDIT: &str =
r"# **EDIT**
Click cores or core groups to edit
affinities.
Unpack **threads** to edit
affinities of each thread.
Click **apply** to set selected
affinities.
";
#[cfg(feature = "gui")]
pub const HELP_EDIT_SHORTCUTS: &str =
r"| Action | Shortcut |
| --------------- | ----------- |
| RUN mode | F3 |
| VIEW mode | F4 |
| Apply affinity | Ctrl-Enter |
| Clear threads | Ctrl-BSpace |
| disable SMT | Ctrl-n |
| TO: HW threads | Ctrl-1 |
| TO: cores | Ctrl-2 |
| TO: L3 | Ctrl-3 |
| TO: None | Ctrl-0 |
| TO: ignore main | Ctrl-- |
";
#[cfg(feature = "tui")]
pub const HELP_EDIT_SHORTCUTS: &str = "";
pub const HELP_MAIN: &str =
r"## Modes
* **RUN** a command with affinities
* **VIEW** affinities of a process
* **EDIT** affinities of a process
Select a process to **VIEW** or
**EDIT** on the left panel
";
#[cfg(feature = "gui")]
pub const HELP_MAIN_SHORTCUTS_GUI: &str =
r"
| Action | Shortcut |
| --------------- | -------- |
| Process filter | <Ctrl-f> |
| Left pane | <F10> |
| Help | <F1> |
| CPU info | <F2> |
";
pub const HELP_MAIN_SHORTCUTS_TUI: &str =
r"
| Action | Shortcut |
| --------------- | -------- |
| Quit | <Ctrl-c> |
| Process filter | </>,<?> |
| Left pane | <F10>,<.>|
| Help | <F1> |
| CPU info | <F2> |
| Run process | <F3> |
| View affinity | <F4> |
| Edit affinity | <F5> |
| Process select | <↓>/<↑> |
| Process panel | '>'/'<' |
| Cores: navig. | 🆆 🅰 🆂 🅳 |
| Cores: in | <Enter> |
| Cores: out | <Esc> |
| Cores: select | <Space> |
| Thread navig. | 🅷 🅹 🅺 🅻 |
| Proc<->thread | <Tab> |
| TO: next order | '+' |
| TO: ignore main | '-' |
| disable SMT | 'n' |
";
pub const HELP_MAIN_RUN: &str = ", or type command to **RUN**";
#[cfg(feature = "gui")]
pub const CPU_INFO: &str = "CPU Information";
#[cfg(feature = "gui")]
pub fn run() -> egui::text::LayoutJob {
layout_with_underlined_part("RUN:", "R")
}
#[cfg(feature = "gui")]
pub const TTIP_RUN: &str = "Run a process with specified affinity.";
#[cfg(feature = "gui")]
pub fn subprocess() -> egui::text::LayoutJob {
layout_with_underlined_part("subprocess", "p")
}
#[cfg(feature = "gui")]
pub const TTIP_SUBPROCESS: &str = "Instead of applying affinity to launched process,\n apply it to subprocess/es with names matching this.";
#[cfg(feature = "gui")]
pub const TTIP_VIEW: &str = "View CPU affinity of a process and its threads.";
#[cfg(feature = "gui")]
pub const TTIP_EDIT: &str = "Edit CPU affinity of a running process.";
#[cfg(feature = "gui")]
pub const TTIP_RUN_SWITCH: &str = "go to run mode";
#[cfg(feature = "gui")]
pub const TTIP_VIEW_SWITCH: &str = "go to view mode";
#[cfg(feature = "gui")]
pub const TTIP_EDIT_SWITCH: &str = "go to edit mode";
#[cfg(feature = "gui")]
pub fn no_smt() -> egui::text::LayoutJob {
layout_with_underlined_part(NO_SMT, "n")
}
pub const NO_SMT: &str = "no HT/SMT";
#[cfg(feature = "gui")]
pub const TTIP_NO_SMT: &str = "Select only one thread per physical core.";
#[cfg(feature = "gui")]
pub fn apply_thread_affinities() -> egui::text::LayoutJob {
layout_with_underlined_part(APPLY_THREAD_AFFINITIES, "h")
}
pub const APPLY_THREAD_AFFINITIES: &str = "apply thread affinities @ ";
#[cfg(feature = "gui")]
pub const TTIP_APPLY_THREAD_AFFINITIES: &str =
r"Delay from process start to apply thread affinities at.
Affinities will not be set for any threads started *after* this time";
#[cfg(feature = "gui")]
pub const TTIP_APPLY_RUN: &str = "Run specified command";
#[cfg(feature = "gui")]
pub const TTIP_APPLY: &str = "Set process and its threads to use selected cores.";
pub const THREADS: &str = "threads";
pub const CLEAR: &str = "clear";
#[cfg(feature = "gui")]
pub const TTIP_THREADS: &str = "View and control which threads can use which cores.\nBy default, each thread uses all cores allowed by its process.";
pub const THREADS_COUNT: &str = "count";
#[cfg(feature = "gui")]
pub const TTIP_THREADS_COUNT_RUN: &str =
r"Number of threads to manually set affinity for.
If the process runs *fewer* threads, excess entries
will be ignored. If it spawns *more* threads, their
affinity will be set by thread order, if any, or
default to process affinity. Affinities will
be assigned in thread launch order.";
#[cfg(feature = "gui")]
pub const TTIP_THREADS_CLEAR: &str = "Clears selected cores for all threads.";
#[cfg(feature = "gui")]
pub const TTIP_THREADS_COUNT: &str = "number of threads currently running in this process";
pub const THREAD_ORDER: &str = "thread order";
#[cfg(feature = "gui")]
pub const TTIP_ORDER_PU: &str = "Bind each thread to a separate hardware thread ('hyper-thread').\nMultiple threads on a core may fight for time/resources";
#[cfg(feature = "gui")]
pub const TTIP_ORDER_CORES: &str = "Bind each thread to a unique physical core.\nReduces thread-contention within the process.";
#[cfg(feature = "gui")]
pub const TTIP_ORDER_L3: &str = "Bind each thread to a core group with a separate L3 cache.\nMaximizes cache per thread, increases thread synchronization overhead";
#[cfg(feature = "gui")]
pub const TTIP_ORDER_NONE: &str = "Apply user-specified affinity, don't specify affinity for any more threads";
#[cfg(feature = "gui")]
pub const TTIP_ORDER: &str =
r"Thread orders assign different cores to each thread,
e.g. to improve benchmark consistency or reduce resource conflicts.
If more threads than cores exit, cores are assigned in a cyclic fashion.";
pub const IGNORE_MAIN: &str = "ignore main";
#[cfg(feature = "gui")]
pub const TTIP_IGNORE_MAIN: &str = "Exclude main thread from thread order.\nUse when there is one 'main' and N 'worker' threads.";
#[cfg(feature = "gui")]
pub const OK: &str = "Ok";
pub const ERROR: &str = "ERROR";